in tls/s2n_record_write.c [256:354]
static S2N_RESULT s2n_record_write_mac(struct s2n_connection *conn, struct s2n_blob *record_header,
struct s2n_blob *plaintext, struct s2n_stuffer *out, uint32_t *bytes_written)
{
RESULT_ENSURE_REF(conn);
RESULT_ENSURE_REF(conn->server);
RESULT_ENSURE_REF(conn->client);
RESULT_ENSURE_REF(record_header);
RESULT_ENSURE_REF(plaintext);
RESULT_ENSURE_REF(out);
RESULT_ENSURE_REF(bytes_written);
*bytes_written = 0;
struct s2n_hmac_state *mac = &conn->server->server_record_mac;
const struct s2n_cipher_suite *cipher_suite = conn->server->cipher_suite;
uint8_t *sequence_number = conn->server->server_sequence_number;
if (conn->mode == S2N_CLIENT) {
mac = &conn->client->client_record_mac;
cipher_suite = conn->client->cipher_suite;
sequence_number = conn->client->client_sequence_number;
}
RESULT_ENSURE_REF(cipher_suite);
RESULT_ENSURE_REF(cipher_suite->record_alg);
if (cipher_suite->record_alg->hmac_alg == S2N_HMAC_NONE) {
/* If the S2N_HMAC_NONE algorithm is specified, a MAC should not be explicitly written.
* This is the case for AEAD and Composite cipher types, where the MAC is written as part
* of encryption. This is also the case for plaintext handshake records, where the null
* stream cipher is used.
*/
return S2N_RESULT_OK;
}
/**
*= https://www.rfc-editor.org/rfc/rfc5246#section-6.2.3.1
*# The MAC is generated as:
*#
*# MAC(MAC_write_key, seq_num +
*/
RESULT_GUARD_POSIX(s2n_hmac_update(mac, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN));
struct s2n_stuffer header_stuffer = { 0 };
RESULT_GUARD_POSIX(s2n_stuffer_init_written(&header_stuffer, record_header));
/**
*= https://www.rfc-editor.org/rfc/rfc5246#section-6.2.3.1
*# TLSCompressed.type +
*/
void *record_type_byte = s2n_stuffer_raw_read(&header_stuffer, sizeof(uint8_t));
RESULT_ENSURE_REF(record_type_byte);
RESULT_GUARD_POSIX(s2n_hmac_update(mac, record_type_byte, sizeof(uint8_t)));
/**
*= https://www.rfc-editor.org/rfc/rfc5246#section-6.2.3.1
*# TLSCompressed.version +
*/
void *protocol_version_bytes = s2n_stuffer_raw_read(&header_stuffer, S2N_TLS_PROTOCOL_VERSION_LEN);
RESULT_ENSURE_REF(protocol_version_bytes);
if (conn->actual_protocol_version > S2N_SSLv3) {
/* SSLv3 doesn't include the protocol version in the MAC. */
RESULT_GUARD_POSIX(s2n_hmac_update(mac, protocol_version_bytes, S2N_TLS_PROTOCOL_VERSION_LEN));
}
/**
*= https://www.rfc-editor.org/rfc/rfc5246#section-6.2.3.1
*# TLSCompressed.length +
*
* Note that the length field refers to the length of the plaintext content, not the length of
* TLSCiphertext fragment written to the record header, which accounts for additional fields
* such as the padding and MAC.
*/
uint8_t content_length_bytes[sizeof(uint16_t)] = { 0 };
struct s2n_blob content_length_blob = { 0 };
RESULT_GUARD_POSIX(s2n_blob_init(&content_length_blob, content_length_bytes, sizeof(content_length_bytes)));
struct s2n_stuffer content_length_stuffer = { 0 };
RESULT_GUARD_POSIX(s2n_stuffer_init(&content_length_stuffer, &content_length_blob));
RESULT_GUARD_POSIX(s2n_stuffer_write_uint16(&content_length_stuffer, plaintext->size));
RESULT_GUARD_POSIX(s2n_hmac_update(mac, content_length_bytes, sizeof(content_length_bytes)));
/**
*= https://www.rfc-editor.org/rfc/rfc5246#section-6.2.3.1
*# TLSCompressed.fragment);
*#
*# where "+" denotes concatenation.
*/
RESULT_GUARD_POSIX(s2n_hmac_update(mac, plaintext->data, plaintext->size));
uint8_t mac_digest_size = 0;
RESULT_GUARD_POSIX(s2n_hmac_digest_size(mac->alg, &mac_digest_size));
uint8_t *digest = s2n_stuffer_raw_write(out, mac_digest_size);
RESULT_ENSURE_REF(digest);
RESULT_GUARD_POSIX(s2n_hmac_digest(mac, digest, mac_digest_size));
*bytes_written = mac_digest_size;
RESULT_GUARD_POSIX(s2n_hmac_reset(mac));
return S2N_RESULT_OK;
}