Adapt record encryption/decryption routines to change of record type

This commit modifies the code surrounding the invocations of
ssl_decrypt_buf() and ssl_encrypt_buf() to deal with a change
of record content type during CID-based record encryption/decryption.
This commit is contained in:
Hanno Becker 2019-05-08 11:57:13 +01:00
parent f9c6a4bea1
commit 6430faf098

View file

@ -4136,7 +4136,9 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush )
unsigned i; unsigned i;
size_t protected_record_size; size_t protected_record_size;
ssl->out_hdr[0] = (unsigned char) ssl->out_msgtype; /* Skip writing the record content type to after the encryption,
* as it may change when using the CID extension. */
mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver,
ssl->conf->transport, ssl->out_hdr + 1 ); ssl->conf->transport, ssl->out_hdr + 1 );
@ -4177,6 +4179,8 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush )
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
} }
/* Update the record content type and CID. */
ssl->out_msgtype = rec.type;
#if defined(MBEDTLS_SSL_CID ) #if defined(MBEDTLS_SSL_CID )
memcpy( ssl->out_cid, rec.cid, rec.cid_len ); memcpy( ssl->out_cid, rec.cid, rec.cid_len );
#endif /* MBEDTLS_SSL_CID */ #endif /* MBEDTLS_SSL_CID */
@ -4204,6 +4208,9 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush )
} }
#endif /* MBEDTLS_SSL_PROTO_DTLS */ #endif /* MBEDTLS_SSL_PROTO_DTLS */
/* Now write the potentially updated record content type. */
ssl->out_hdr[0] = (unsigned char) ssl->out_msgtype;
MBEDTLS_SSL_DEBUG_MSG( 3, ( "output record: msgtype = %d, " MBEDTLS_SSL_DEBUG_MSG( 3, ( "output record: msgtype = %d, "
"version = [%d:%d], msglen = %d", "version = [%d:%d], msglen = %d",
ssl->out_hdr[0], ssl->out_hdr[1], ssl->out_hdr[0], ssl->out_hdr[1],
@ -5056,6 +5063,20 @@ static int ssl_prepare_record_content( mbedtls_ssl_context *ssl )
return( ret ); return( ret );
} }
if( ssl->in_msgtype != rec.type )
{
MBEDTLS_SSL_DEBUG_MSG( 4, ( "record type after decrypt (before %d): %d",
ssl->in_msgtype, rec.type ) );
}
/* The record content type may change during decryption,
* so re-read it. */
ssl->in_msgtype = rec.type;
/* Also update the input buffer, because unfortunately
* the server-side ssl_parse_client_hello() reparses the
* record header when receiving a ClientHello initiating
* a renegotiation. */
ssl->in_hdr[0] = rec.type;
ssl->in_msg = rec.buf + rec.data_offset; ssl->in_msg = rec.buf + rec.data_offset;
ssl->in_msglen = rec.data_len; ssl->in_msglen = rec.data_len;
ssl->in_len[0] = (unsigned char)( rec.data_len >> 8 ); ssl->in_len[0] = (unsigned char)( rec.data_len >> 8 );
@ -5064,6 +5085,21 @@ static int ssl_prepare_record_content( mbedtls_ssl_context *ssl )
MBEDTLS_SSL_DEBUG_BUF( 4, "input payload after decrypt", MBEDTLS_SSL_DEBUG_BUF( 4, "input payload after decrypt",
ssl->in_msg, ssl->in_msglen ); ssl->in_msg, ssl->in_msglen );
#if defined(MBEDTLS_SSL_CID)
/* We have already checked the record content type
* in ssl_parse_record_header(), failing or silently
* dropping the record in the case of an unknown type.
*
* Since with the use of CIDs, the record content type
* might change during decryption, re-check the record
* content type, but treat a failure as fatal this time. */
if( ssl_check_record_type( ssl->in_msgtype ) )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "unknown record type" ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
#endif /* MBEDTLS_SSL_CID */
if( ssl->in_msglen > MBEDTLS_SSL_IN_CONTENT_LEN ) if( ssl->in_msglen > MBEDTLS_SSL_IN_CONTENT_LEN )
{ {
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) );