From 9eddaebda57e710666045133f7e9937a2f4c41c6 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 27 Dec 2017 21:37:21 +0000 Subject: [PATCH] Provide standalone version of `ssl_encrypt_buf` The previous version of the record encryption function `ssl_encrypt_buf` takes the entire SSL context as an argument, while intuitively, it should only depend on the current security parameters and the record buffer. Analyzing the exact dependencies, it turned out that in addition to the currently active `ssl_transform` instance and the record information, the encryption function needs access to - the negotiated protocol version, and - the status of the encrypt-then-MAC extension. This commit moves these two fields into `ssl_transform` and changes the signature of `ssl_encrypt_buf` to only use an instance of `ssl_transform` and an instance of the new `ssl_record` type. The `ssl_context` instance is *solely* kept for the debugging macros which need an SSL context instance. The benefit of the change is twofold: 1) It avoids the need of the MPS to deal with instances of `ssl_context`. The MPS should only work with records and opaque security parameters, which is what the change in this commit makes progress towards. 2) It significantly eases testing of the encryption function: independent of any SSL context, the encryption function can be passed some record buffer to encrypt alongside some arbitrary choice of parameters, and e.g. be checked to not overflow the provided memory. --- include/mbedtls/ssl_internal.h | 12 +- library/ssl_tls.c | 350 ++++++++++++++++++++------------- 2 files changed, 221 insertions(+), 141 deletions(-) diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index 600d4d104..03a4473cc 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -581,6 +581,12 @@ struct mbedtls_ssl_transform mbedtls_cipher_context_t cipher_ctx_enc; /*!< encryption context */ mbedtls_cipher_context_t cipher_ctx_dec; /*!< decryption context */ +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + int encrypt_then_mac; /*!< flag for EtM activation */ +#endif + + int minor_ver; + /* * Session specific compression layer */ @@ -593,11 +599,6 @@ struct mbedtls_ssl_transform /* * Internal representation of record frames * - * The header layout is chosen to facilitate the computation of - * authentication tags which often use the header bytes laid out - * exactly as in the struct; note that it does not match what's - * transferred on the wire. - * * Instances come in two flavors: * (1) Encrypted * These always have data_offset = 0 @@ -617,7 +618,6 @@ typedef struct uint8_t ctr[8]; /*!< Record sequence number */ uint8_t type; /*!< Record type */ uint8_t ver[2]; /*!< SSL/TLS version */ - uint8_t len[2]; /*!< Content length, little endian */ unsigned char *buf; /*!< Memory buffer enclosing the record content */ size_t buf_len; /*!< Buffer length */ diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 780a682cc..b0dcf1d33 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -757,6 +757,10 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> derive keys" ) ); +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + transform->encrypt_then_mac = session->encrypt_then_mac; +#endif + transform->minor_ver = ssl->minor_ver; ciphersuite_info = handshake->ciphersuite_info; cipher_info = mbedtls_cipher_info_from_type( ciphersuite_info->cipher ); @@ -1734,23 +1738,75 @@ static void ssl_read_memory( unsigned char *p, size_t len ) /* * Encryption/decryption functions */ -static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) + +static void ssl_extract_add_data_from_record( unsigned char* add_data, + mbedtls_record *rec ) +{ + memcpy( add_data, rec->ctr, sizeof( rec->ctr ) ); + add_data[8] = rec->type; + memcpy( add_data + 9, rec->ver, sizeof( rec->ver ) ); + add_data[11] = ( rec->data_len >> 8 ) & 0xFF; + add_data[12] = rec->data_len & 0xFF; +} + +static int ssl_encrypt_buf( mbedtls_ssl_context *ssl, + mbedtls_ssl_transform *transform, + mbedtls_record *rec, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) { mbedtls_cipher_mode_t mode; int auth_done = 0; + unsigned char * data; + unsigned char add_data[13]; + size_t post_avail; + + /* The SSL context is only used for debugging purposes! */ +#if !defined(MBEDTLS_SSL_DEBUG_C) + ((void) ssl); +#endif + + /* The PRNG is used for dynamic IV generation that's used + * for CBC transformations in TLS 1.1 and TLS 1.2. */ +#if !( defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_AES_C) || \ + defined(MBEDTLS_ARIA_C) || \ + defined(MBEDTLS_CAMELLIA_C) ) && \ + ( defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) ) ) + ((void) f_rng); + ((void) p_rng); +#endif MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> encrypt buf" ) ); - if( ssl->session_out == NULL || ssl->transform_out == NULL ) + if( transform == NULL ) { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no transform provided to encrypt_buf" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + if( rec == NULL || + rec->buf == NULL || + rec->buf_len < rec->data_offset || + rec->buf_len - rec->data_offset < rec->data_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad record structure provided to encrypt_buf" ) ); return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); } - mode = mbedtls_cipher_get_cipher_mode( &ssl->transform_out->cipher_ctx_enc ); - + post_avail = rec->buf_len - ( rec->data_len + rec->data_offset ); + data = rec->buf + rec->data_offset; MBEDTLS_SSL_DEBUG_BUF( 4, "before encrypt: output payload", - ssl->out_msg, ssl->out_msglen ); + data, rec->data_len ); + + mode = mbedtls_cipher_get_cipher_mode( &transform->cipher_ctx_enc ); + + if( rec->data_len > MBEDTLS_SSL_OUT_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Record content %u too large, maximum %d", + (unsigned) rec->data_len, + MBEDTLS_SSL_OUT_CONTENT_LEN ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } /* * Add MAC before if needed @@ -1759,40 +1815,42 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) if( mode == MBEDTLS_MODE_STREAM || ( mode == MBEDTLS_MODE_CBC #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) - && ssl->session_out->encrypt_then_mac == MBEDTLS_SSL_ETM_DISABLED + && transform->encrypt_then_mac == MBEDTLS_SSL_ETM_DISABLED #endif ) ) { + if( post_avail < transform->maclen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Buffer provided for encrypted record not large enough" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + #if defined(MBEDTLS_SSL_PROTO_SSL3) - if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + if( transform->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) { unsigned char mac[SSL_MAC_MAX_BYTES]; - - ssl_mac( &ssl->transform_out->md_ctx_enc, - ssl->transform_out->mac_enc, - ssl->out_msg, ssl->out_msglen, - ssl->out_ctr, ssl->out_msgtype, - mac ); - - memcpy( ssl->out_msg + ssl->out_msglen, mac, ssl->transform_out->maclen ); + ssl_mac( &transform->md_ctx_enc, transform->mac_enc, + data, rec->data_len, rec->ctr, rec->type, mac ); + memcpy( data + rec->data_len, mac, transform->maclen ); } else #endif #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ defined(MBEDTLS_SSL_PROTO_TLS1_2) - if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 ) + if( transform->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 ) { unsigned char mac[MBEDTLS_SSL_MAC_ADD]; - mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_ctr, 8 ); - mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_hdr, 3 ); - mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_len, 2 ); - mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, - ssl->out_msg, ssl->out_msglen ); - mbedtls_md_hmac_finish( &ssl->transform_out->md_ctx_enc, mac ); - mbedtls_md_hmac_reset( &ssl->transform_out->md_ctx_enc ); + ssl_extract_add_data_from_record( add_data, rec ); - memcpy( ssl->out_msg + ssl->out_msglen, mac, ssl->transform_out->maclen ); + mbedtls_md_hmac_update( &transform->md_ctx_enc, add_data, + sizeof( add_data ) ); + mbedtls_md_hmac_update( &transform->md_ctx_enc, + data, rec->data_len ); + mbedtls_md_hmac_finish( &transform->md_ctx_enc, mac ); + mbedtls_md_hmac_reset( &transform->md_ctx_enc ); + + memcpy( data + rec->data_len, mac, transform->maclen ); } else #endif @@ -1801,11 +1859,11 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); } - MBEDTLS_SSL_DEBUG_BUF( 4, "computed mac", - ssl->out_msg + ssl->out_msglen, - ssl->transform_out->maclen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "computed mac", data + rec->data_len, + transform->maclen ); - ssl->out_msglen += ssl->transform_out->maclen; + rec->data_len += transform->maclen; + post_avail -= transform->maclen; auth_done++; } #endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */ @@ -1817,23 +1875,21 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) if( mode == MBEDTLS_MODE_STREAM ) { int ret; - size_t olen = 0; - + size_t olen; MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " - "including %d bytes of padding", - ssl->out_msglen, 0 ) ); + "including %d bytes of padding", + rec->data_len, 0 ) ); - if( ( ret = mbedtls_cipher_crypt( &ssl->transform_out->cipher_ctx_enc, - ssl->transform_out->iv_enc, - ssl->transform_out->ivlen, - ssl->out_msg, ssl->out_msglen, - ssl->out_msg, &olen ) ) != 0 ) + if( ( ret = mbedtls_cipher_crypt( &transform->cipher_ctx_enc, + transform->iv_enc, transform->ivlen, + data, rec->data_len, + data, &olen ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); return( ret ); } - if( ssl->out_msglen != olen ) + if( rec->data_len != olen ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); @@ -1849,24 +1905,17 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) mode == MBEDTLS_MODE_CHACHAPOLY ) { int ret; - size_t enc_msglen, olen; - unsigned char *enc_msg; - unsigned char add_data[13]; unsigned char iv[12]; - mbedtls_ssl_transform *transform = ssl->transform_out; - size_t explicit_ivlen = transform->ivlen - transform->fixed_ivlen; + size_t explicit_iv_len = transform->ivlen - transform->fixed_ivlen; - /* - * Prepare additional authenticated data - */ - memcpy( add_data, ssl->out_ctr, 8 ); - add_data[8] = ssl->out_msgtype; - mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, - ssl->conf->transport, add_data + 9 ); - add_data[11] = ( ssl->out_msglen >> 8 ) & 0xFF; - add_data[12] = ssl->out_msglen & 0xFF; - - MBEDTLS_SSL_DEBUG_BUF( 4, "additional data for AEAD", add_data, 13 ); + /* Check that there's space for both the authentication tag + * and the explicit IV before and after the record content. */ + if( post_avail < transform->taglen || + rec->data_offset < explicit_iv_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Buffer provided for encrypted record not large enough" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } /* * Generate IV @@ -1875,9 +1924,10 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) { /* GCM and CCM: fixed || explicit (=seqnum) */ memcpy( iv, transform->iv_enc, transform->fixed_ivlen ); - memcpy( iv + transform->fixed_ivlen, ssl->out_ctr, 8 ); - memcpy( ssl->out_iv, ssl->out_ctr, 8 ); - + memcpy( iv + transform->fixed_ivlen, rec->ctr, + explicit_iv_len ); + /* Prefix record content with explicit IV. */ + memcpy( data - explicit_iv_len, rec->ctr, explicit_iv_len ); } else if( transform->ivlen == 12 && transform->fixed_ivlen == 12 ) { @@ -1887,7 +1937,7 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) memcpy( iv, transform->iv_enc, transform->fixed_ivlen ); for( i = 0; i < 8; i++ ) - iv[i+4] ^= ssl->out_ctr[i]; + iv[i+4] ^= rec->ctr[i]; } else { @@ -1899,45 +1949,36 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_BUF( 4, "IV used (internal)", iv, transform->ivlen ); MBEDTLS_SSL_DEBUG_BUF( 4, "IV used (transmitted)", - ssl->out_iv, explicit_ivlen ); - - /* - * Fix message length with added IV - */ - enc_msg = ssl->out_msg; - enc_msglen = ssl->out_msglen; - ssl->out_msglen += explicit_ivlen; - + data - explicit_iv_len, explicit_iv_len ); + MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD", + add_data, 13 ); MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " "including 0 bytes of padding", - ssl->out_msglen ) ); + rec->data_len ) ); /* * Encrypt and authenticate */ + + ssl_extract_add_data_from_record( add_data, rec ); if( ( ret = mbedtls_cipher_auth_encrypt( &transform->cipher_ctx_enc, - iv, transform->ivlen, - add_data, 13, - enc_msg, enc_msglen, - enc_msg, &olen, - enc_msg + enc_msglen, - ssl->transform_out->taglen ) ) != 0 ) + iv, transform->ivlen, + add_data, 13, /* add data */ + data, rec->data_len, /* source */ + data, &rec->data_len, /* destination */ + data + rec->data_len, transform->taglen ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_auth_encrypt", ret ); return( ret ); } - if( olen != enc_msglen ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); - return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); - } + MBEDTLS_SSL_DEBUG_BUF( 4, "after encrypt: tag", + data + rec->data_len, transform->taglen ); - ssl->out_msglen += ssl->transform_out->taglen; + rec->data_len += transform->taglen + explicit_iv_len; + rec->data_offset -= explicit_iv_len; + post_avail -= transform->taglen; auth_done++; - - MBEDTLS_SSL_DEBUG_BUF( 4, "after encrypt: tag", enc_msg + enc_msglen, - ssl->transform_out->taglen ); } else #endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C */ @@ -1946,81 +1987,97 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) if( mode == MBEDTLS_MODE_CBC ) { int ret; - unsigned char *enc_msg; - size_t enc_msglen, padlen, olen = 0, i; + size_t padlen, i; + size_t olen; - padlen = ssl->transform_out->ivlen - ( ssl->out_msglen + 1 ) % - ssl->transform_out->ivlen; - if( padlen == ssl->transform_out->ivlen ) + /* Currently we're always using minimal padding + * (up to 255 bytes would be allowed). */ + padlen = transform->ivlen - ( rec->data_len + 1 ) % transform->ivlen; + if( padlen == transform->ivlen ) padlen = 0; + /* Check there's enough space in the buffer for the padding. */ + if( post_avail < padlen + 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Buffer provided for encrypted record not large enough" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + for( i = 0; i <= padlen; i++ ) - ssl->out_msg[ssl->out_msglen + i] = (unsigned char) padlen; + data[rec->data_len + i] = (unsigned char) padlen; - ssl->out_msglen += padlen + 1; - - enc_msglen = ssl->out_msglen; - enc_msg = ssl->out_msg; + rec->data_len += padlen + 1; + post_avail -= padlen + 1; #if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) /* * Prepend per-record IV for block cipher in TLS v1.1 and up as per * Method 1 (6.2.3.2. in RFC4346 and RFC5246) */ - if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + if( transform->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) { + if( f_rng == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "No PRNG provided to encrypt_record routine" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( rec->data_offset < transform->ivlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Buffer provided for encrypted record not large enough" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + /* * Generate IV */ - ret = ssl->conf->f_rng( ssl->conf->p_rng, ssl->transform_out->iv_enc, - ssl->transform_out->ivlen ); + ret = f_rng( p_rng, transform->iv_enc, transform->ivlen ); if( ret != 0 ) return( ret ); - memcpy( ssl->out_iv, ssl->transform_out->iv_enc, - ssl->transform_out->ivlen ); + memcpy( data - transform->ivlen, transform->iv_enc, + transform->ivlen ); - /* - * Fix pointer positions and message length with added IV - */ - enc_msg = ssl->out_msg; - enc_msglen = ssl->out_msglen; - ssl->out_msglen += ssl->transform_out->ivlen; } #endif /* MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1_2 */ MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " "including %d bytes of IV and %d bytes of padding", - ssl->out_msglen, ssl->transform_out->ivlen, + rec->data_len, transform->ivlen, padlen + 1 ) ); - if( ( ret = mbedtls_cipher_crypt( &ssl->transform_out->cipher_ctx_enc, - ssl->transform_out->iv_enc, - ssl->transform_out->ivlen, - enc_msg, enc_msglen, - enc_msg, &olen ) ) != 0 ) + if( ( ret = mbedtls_cipher_crypt( &transform->cipher_ctx_enc, + transform->iv_enc, + transform->ivlen, + data, rec->data_len, + data, &olen ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); return( ret ); } - if( enc_msglen != olen ) + if( rec->data_len != olen ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); } #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) - if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 ) + if( transform->minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 ) { /* * Save IV in SSL3 and TLS1 */ - memcpy( ssl->transform_out->iv_enc, - ssl->transform_out->cipher_ctx_enc.iv, - ssl->transform_out->ivlen ); + memcpy( transform->iv_enc, transform->cipher_ctx_enc.iv, + transform->ivlen ); } + else #endif + { + data -= transform->ivlen; + rec->data_offset -= transform->ivlen; + rec->data_len += transform->ivlen; + } #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) if( auth_done == 0 ) @@ -2035,27 +2092,30 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) * IV + // except for TLS 1.0 * ENC(content + padding + padding_length)); */ - unsigned char pseudo_hdr[13]; + + if( post_avail < transform->maclen) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Buffer provided for encrypted record not large enough" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } MBEDTLS_SSL_DEBUG_MSG( 3, ( "using encrypt then mac" ) ); + MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", add_data, + sizeof( add_data ) ); - memcpy( pseudo_hdr + 0, ssl->out_ctr, 8 ); - memcpy( pseudo_hdr + 8, ssl->out_hdr, 3 ); - pseudo_hdr[11] = (unsigned char)( ( ssl->out_msglen >> 8 ) & 0xFF ); - pseudo_hdr[12] = (unsigned char)( ( ssl->out_msglen ) & 0xFF ); + ssl_extract_add_data_from_record( add_data, rec ); - MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", pseudo_hdr, 13 ); + mbedtls_md_hmac_update( &transform->md_ctx_enc, add_data, + sizeof( add_data ) ); + mbedtls_md_hmac_update( &transform->md_ctx_enc, + data, rec->data_len ); + mbedtls_md_hmac_finish( &transform->md_ctx_enc, mac ); + mbedtls_md_hmac_reset( &transform->md_ctx_enc ); - mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, pseudo_hdr, 13 ); - mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, - ssl->out_iv, ssl->out_msglen ); - mbedtls_md_hmac_finish( &ssl->transform_out->md_ctx_enc, mac ); - mbedtls_md_hmac_reset( &ssl->transform_out->md_ctx_enc ); + memcpy( data + rec->data_len, mac, transform->maclen ); - memcpy( ssl->out_iv + ssl->out_msglen, mac, - ssl->transform_out->maclen ); - - ssl->out_msglen += ssl->transform_out->maclen; + rec->data_len += transform->maclen; + post_avail -= transform->maclen; auth_done++; } #endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ @@ -3684,15 +3744,35 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush ) if( ssl->transform_out != NULL ) { - if( ( ret = ssl_encrypt_buf( ssl ) ) != 0 ) + mbedtls_record rec; + + rec.buf = ssl->out_iv; + rec.buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN - + ( ssl->out_iv - ssl->out_buf ); + rec.data_len = ssl->out_msglen; + rec.data_offset = ssl->out_msg - rec.buf; + + memcpy( &rec.ctr[0], ssl->out_ctr, 8 ); + mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + ssl->conf->transport, rec.ver ); + rec.type = ssl->out_msgtype; + + if( ( ret = ssl_encrypt_buf( ssl, ssl->transform_out, &rec, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "ssl_encrypt_buf", ret ); return( ret ); } - len = ssl->out_msglen; - ssl->out_len[0] = (unsigned char)( len >> 8 ); - ssl->out_len[1] = (unsigned char)( len ); + if( rec.data_offset != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + ssl->out_msglen = rec.data_len; + ssl->out_len[0] = (unsigned char)( rec.data_len >> 8 ); + ssl->out_len[1] = (unsigned char)( rec.data_len ); } protected_record_size = len + mbedtls_ssl_hdr_len( ssl );