Store TLS version in SSL session structure
Instances of `mbedtls_ssl_session` represent data enabling session resumption. With the introduction of TLS 1.3, the format of this data changes. We therefore need TLS-version field as part of `mbedtlsl_ssl_session` which allows distinguish 1.2 and 1.3 sessions. This commit introduces such a TLS-version field to mbedtls_ssl_session. The change has a few ramifications: - Session serialization/deserialization routines need to be adjusted. This is achieved by adding the TLS-version after the header of Mbed TLS version+config, and by having the subsequent structure of the serialized data depend on the value of this field. The details are described in terms of the RFC 8446 presentation language. The 1.2 session (de)serialization are moved into static helper functions, while the top-level session (de)serialization only parses the Mbed TLS version+config header and the TLS-version field, and dispatches according to the found version. This way, it will be easy to add support for TLS 1.3 sessions in the future. - Tests for session serialization need to be adjusted - Once we add support for TLS 1.3, with runtime negotiation of 1.2 vs. 1.3, we will need to have some logic comparing the TLS version of the proposed session to the negotiated TLS version. For now, however, we only support TLS 1.2, and no such logic is needed. Instead, we just store the TLS version in the session structure at the same point when we populate mbedtls_ssl_context.minor_ver. The change introduces some overlap between `mbedtls_ssl_session.minor_ver` and `mbedtls_ssl_context.minor_ver`, which should be studied and potentially resolved. However, with both fields being private and explicitly marked so, this can happen in a later change. Signed-off-by: Hanno Becker <hanno.becker@arm.com>
This commit is contained in:
parent
ac6cc9fbc4
commit
fadbdbb576
5 changed files with 171 additions and 80 deletions
|
@ -927,6 +927,8 @@ struct mbedtls_ssl_session
|
|||
|
||||
unsigned char exported;
|
||||
|
||||
unsigned char MBEDTLS_PRIVATE(minor_ver); /*!< The TLS version used in the session. */
|
||||
|
||||
#if defined(MBEDTLS_X509_CRT_PARSE_C)
|
||||
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
|
||||
mbedtls_x509_crt *MBEDTLS_PRIVATE(peer_cert); /*!< peer X.509 cert chain */
|
||||
|
|
|
@ -2024,6 +2024,7 @@ static int ssl_parse_server_hello( mbedtls_ssl_context *ssl )
|
|||
MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, version", buf + 0, 2 );
|
||||
mbedtls_ssl_read_version( &ssl->major_ver, &ssl->minor_ver,
|
||||
ssl->conf->transport, buf + 0 );
|
||||
ssl->session_negotiate->minor_ver = ssl->minor_ver;
|
||||
|
||||
if( ssl->major_ver < ssl->conf->min_major_ver ||
|
||||
ssl->minor_ver < ssl->conf->min_minor_ver ||
|
||||
|
|
|
@ -1392,6 +1392,7 @@ read_record_header:
|
|||
|
||||
mbedtls_ssl_read_version( &ssl->major_ver, &ssl->minor_ver,
|
||||
ssl->conf->transport, buf );
|
||||
ssl->session_negotiate->minor_ver = ssl->minor_ver;
|
||||
|
||||
ssl->handshake->max_major_ver = ssl->major_ver;
|
||||
ssl->handshake->max_minor_ver = ssl->minor_ver;
|
||||
|
|
|
@ -4550,6 +4550,8 @@ static unsigned char ssl_serialized_session_header[] = {
|
|||
* Serialize a session in the following format:
|
||||
* (in the presentation language of TLS, RFC 8446 section 3)
|
||||
*
|
||||
* struct {
|
||||
*
|
||||
* opaque mbedtls_version[3]; // major, minor, patch
|
||||
* opaque session_format[2]; // version-specific 16-bit field determining
|
||||
* // the format of the remaining
|
||||
|
@ -4562,6 +4564,25 @@ static unsigned char ssl_serialized_session_header[] = {
|
|||
* // the setting of those compile-time
|
||||
* // configuration options which influence
|
||||
* // the structure of mbedtls_ssl_session.
|
||||
*
|
||||
* uint8_t minor_ver; // Possible values:
|
||||
* // - TLS 1.2 (MBEDTLS_SSL_MINOR_VERSION_3)
|
||||
*
|
||||
* select (serialized_session.minor_ver) {
|
||||
*
|
||||
* case MBEDTLS_SSL_MINOR_VERSION_3: // TLS 1.2
|
||||
* serialized_session_tls12 data;
|
||||
*
|
||||
* };
|
||||
*
|
||||
* } serialized_session;
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
|
||||
/* Serialization of TLS 1.2 sessions:
|
||||
*
|
||||
* struct {
|
||||
* uint64 start_time;
|
||||
* uint8 ciphersuite[2]; // defined by the standard
|
||||
* uint8 compression; // 0 or 1
|
||||
|
@ -4575,19 +4596,16 @@ static unsigned char ssl_serialized_session_header[] = {
|
|||
* uint8 mfl_code; // up to 255 according to standard
|
||||
* uint8 trunc_hmac; // 0 or 1
|
||||
* uint8 encrypt_then_mac; // 0 or 1
|
||||
* } serialized_session_tls12;
|
||||
*
|
||||
* The order is the same as in the definition of the structure, except
|
||||
* verify_result is put before peer_cert so that all mandatory fields come
|
||||
* together in one block.
|
||||
*/
|
||||
static int ssl_session_save( const mbedtls_ssl_session *session,
|
||||
unsigned char omit_header,
|
||||
static size_t ssl_session_save_tls12( const mbedtls_ssl_session *session,
|
||||
unsigned char *buf,
|
||||
size_t buf_len,
|
||||
size_t *olen )
|
||||
size_t buf_len )
|
||||
{
|
||||
unsigned char *p = buf;
|
||||
size_t used = 0;
|
||||
|
||||
#if defined(MBEDTLS_HAVE_TIME)
|
||||
uint64_t start;
|
||||
#endif
|
||||
|
@ -4597,23 +4615,6 @@ static int ssl_session_save( const mbedtls_ssl_session *session,
|
|||
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
|
||||
#endif /* MBEDTLS_X509_CRT_PARSE_C */
|
||||
|
||||
|
||||
if( !omit_header )
|
||||
{
|
||||
/*
|
||||
* Add version identifier
|
||||
*/
|
||||
|
||||
used += sizeof( ssl_serialized_session_header );
|
||||
|
||||
if( used <= buf_len )
|
||||
{
|
||||
memcpy( p, ssl_serialized_session_header,
|
||||
sizeof( ssl_serialized_session_header ) );
|
||||
p += sizeof( ssl_serialized_session_header );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Time
|
||||
*/
|
||||
|
@ -4756,9 +4757,61 @@ static int ssl_session_save( const mbedtls_ssl_session *session,
|
|||
*p++ = (unsigned char)( ( session->encrypt_then_mac ) & 0xFF );
|
||||
#endif
|
||||
|
||||
/* Done */
|
||||
*olen = used;
|
||||
return( used );
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
|
||||
|
||||
static int ssl_session_save( const mbedtls_ssl_session *session,
|
||||
unsigned char omit_header,
|
||||
unsigned char *buf,
|
||||
size_t buf_len,
|
||||
size_t *olen )
|
||||
{
|
||||
unsigned char *p = buf;
|
||||
size_t used = 0;
|
||||
|
||||
if( !omit_header )
|
||||
{
|
||||
/*
|
||||
* Add Mbed TLS version identifier
|
||||
*/
|
||||
|
||||
used += sizeof( ssl_serialized_session_header );
|
||||
|
||||
if( used <= buf_len )
|
||||
{
|
||||
memcpy( p, ssl_serialized_session_header,
|
||||
sizeof( ssl_serialized_session_header ) );
|
||||
p += sizeof( ssl_serialized_session_header );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TLS version identifier
|
||||
*/
|
||||
used += 1;
|
||||
if( used <= buf_len )
|
||||
{
|
||||
*p++ = session->minor_ver;
|
||||
}
|
||||
|
||||
/* Forward to version-specific serialization routine. */
|
||||
switch( session->minor_ver )
|
||||
{
|
||||
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
|
||||
case MBEDTLS_SSL_MINOR_VERSION_3:
|
||||
{
|
||||
size_t remaining_len = used <= buf_len ? buf_len - used : 0;
|
||||
used += ssl_session_save_tls12( session, p, remaining_len );
|
||||
break;
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
|
||||
|
||||
default:
|
||||
return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
|
||||
}
|
||||
|
||||
*olen = used;
|
||||
if( used > buf_len )
|
||||
return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
|
||||
|
||||
|
@ -4782,13 +4835,10 @@ int mbedtls_ssl_session_save( const mbedtls_ssl_session *session,
|
|||
* This internal version is wrapped by a public function that cleans up in
|
||||
* case of error, and has an extra option omit_header.
|
||||
*/
|
||||
static int ssl_session_load( mbedtls_ssl_session *session,
|
||||
unsigned char omit_header,
|
||||
static int ssl_session_load_tls12( mbedtls_ssl_session *session,
|
||||
const unsigned char *buf,
|
||||
size_t len )
|
||||
{
|
||||
const unsigned char *p = buf;
|
||||
const unsigned char * const end = buf + len;
|
||||
#if defined(MBEDTLS_HAVE_TIME)
|
||||
uint64_t start;
|
||||
#endif
|
||||
|
@ -4798,22 +4848,8 @@ static int ssl_session_load( mbedtls_ssl_session *session,
|
|||
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
|
||||
#endif /* MBEDTLS_X509_CRT_PARSE_C */
|
||||
|
||||
if( !omit_header )
|
||||
{
|
||||
/*
|
||||
* Check version identifier
|
||||
*/
|
||||
|
||||
if( (size_t)( end - p ) < sizeof( ssl_serialized_session_header ) )
|
||||
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
|
||||
|
||||
if( memcmp( p, ssl_serialized_session_header,
|
||||
sizeof( ssl_serialized_session_header ) ) != 0 )
|
||||
{
|
||||
return( MBEDTLS_ERR_SSL_VERSION_MISMATCH );
|
||||
}
|
||||
p += sizeof( ssl_serialized_session_header );
|
||||
}
|
||||
const unsigned char *p = buf;
|
||||
const unsigned char * const end = buf + len;
|
||||
|
||||
/*
|
||||
* Time
|
||||
|
@ -4998,6 +5034,54 @@ static int ssl_session_load( mbedtls_ssl_session *session,
|
|||
return( 0 );
|
||||
}
|
||||
|
||||
static int ssl_session_load( mbedtls_ssl_session *session,
|
||||
unsigned char omit_header,
|
||||
const unsigned char *buf,
|
||||
size_t len )
|
||||
{
|
||||
const unsigned char *p = buf;
|
||||
const unsigned char * const end = buf + len;
|
||||
|
||||
if( !omit_header )
|
||||
{
|
||||
/*
|
||||
* Check Mbed TLS version identifier
|
||||
*/
|
||||
|
||||
if( (size_t)( end - p ) < sizeof( ssl_serialized_session_header ) )
|
||||
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
|
||||
|
||||
if( memcmp( p, ssl_serialized_session_header,
|
||||
sizeof( ssl_serialized_session_header ) ) != 0 )
|
||||
{
|
||||
return( MBEDTLS_ERR_SSL_VERSION_MISMATCH );
|
||||
}
|
||||
p += sizeof( ssl_serialized_session_header );
|
||||
}
|
||||
|
||||
/*
|
||||
* TLS version identifier
|
||||
*/
|
||||
if( 1 > (size_t)( end - p ) )
|
||||
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
|
||||
session->minor_ver = *p++;
|
||||
|
||||
/* Dispatch according to TLS version. */
|
||||
switch( session->minor_ver )
|
||||
{
|
||||
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
|
||||
case MBEDTLS_SSL_MINOR_VERSION_3: /* TLS 1.2 */
|
||||
{
|
||||
size_t remaining_len = ( end - p );
|
||||
return( ssl_session_load_tls12( session, p, remaining_len ) );
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
|
||||
|
||||
default:
|
||||
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Deserialize session: public wrapper for error cleaning
|
||||
*/
|
||||
|
|
|
@ -1435,13 +1435,14 @@ cleanup:
|
|||
* Populate a session structure for serialization tests.
|
||||
* Choose dummy values, mostly non-0 to distinguish from the init default.
|
||||
*/
|
||||
static int ssl_populate_session( mbedtls_ssl_session *session,
|
||||
static int ssl_populate_session_tls12( mbedtls_ssl_session *session,
|
||||
int ticket_len,
|
||||
const char *crt_file )
|
||||
{
|
||||
#if defined(MBEDTLS_HAVE_TIME)
|
||||
session->start = mbedtls_time( NULL ) - 42;
|
||||
#endif
|
||||
session->minor_ver = MBEDTLS_SSL_MINOR_VERSION_3;
|
||||
session->ciphersuite = 0xabcd;
|
||||
session->compression = 1;
|
||||
session->id_len = sizeof( session->id );
|
||||
|
@ -1449,7 +1450,7 @@ static int ssl_populate_session( mbedtls_ssl_session *session,
|
|||
memset( session->master, 17, sizeof( session->master ) );
|
||||
|
||||
#if defined(MBEDTLS_X509_CRT_PARSE_C) && defined(MBEDTLS_FS_IO)
|
||||
if( strlen( crt_file ) != 0 )
|
||||
if( crt_file != NULL && strlen( crt_file ) != 0 )
|
||||
{
|
||||
mbedtls_x509_crt tmp_crt;
|
||||
int ret;
|
||||
|
@ -4008,7 +4009,7 @@ void ssl_serialize_session_save_load( int ticket_len, char *crt_file )
|
|||
mbedtls_ssl_session_init( &restored );
|
||||
|
||||
/* Prepare a dummy session to work on */
|
||||
TEST_ASSERT( ssl_populate_session( &original, ticket_len, crt_file ) == 0 );
|
||||
TEST_ASSERT( ssl_populate_session_tls12( &original, ticket_len, crt_file ) == 0 );
|
||||
|
||||
/* Serialize it */
|
||||
TEST_ASSERT( mbedtls_ssl_session_save( &original, NULL, 0, &len )
|
||||
|
@ -4026,6 +4027,7 @@ void ssl_serialize_session_save_load( int ticket_len, char *crt_file )
|
|||
#if defined(MBEDTLS_HAVE_TIME)
|
||||
TEST_ASSERT( original.start == restored.start );
|
||||
#endif
|
||||
TEST_ASSERT( original.minor_ver == restored.minor_ver );
|
||||
TEST_ASSERT( original.ciphersuite == restored.ciphersuite );
|
||||
TEST_ASSERT( original.compression == restored.compression );
|
||||
TEST_ASSERT( original.id_len == restored.id_len );
|
||||
|
@ -4104,7 +4106,7 @@ void ssl_serialize_session_load_save( int ticket_len, char *crt_file )
|
|||
mbedtls_ssl_session_init( &session );
|
||||
|
||||
/* Prepare a dummy session to work on */
|
||||
TEST_ASSERT( ssl_populate_session( &session, ticket_len, crt_file ) == 0 );
|
||||
TEST_ASSERT( ssl_populate_session_tls12( &session, ticket_len, crt_file ) == 0 );
|
||||
|
||||
/* Get desired buffer size for serializing */
|
||||
TEST_ASSERT( mbedtls_ssl_session_save( &session, NULL, 0, &len0 )
|
||||
|
@ -4154,7 +4156,7 @@ void ssl_serialize_session_save_buf_size( int ticket_len, char *crt_file )
|
|||
mbedtls_ssl_session_init( &session );
|
||||
|
||||
/* Prepare dummy session and get serialized size */
|
||||
TEST_ASSERT( ssl_populate_session( &session, ticket_len, crt_file ) == 0 );
|
||||
TEST_ASSERT( ssl_populate_session_tls12( &session, ticket_len, crt_file ) == 0 );
|
||||
TEST_ASSERT( mbedtls_ssl_session_save( &session, NULL, 0, &good_len )
|
||||
== MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
|
||||
|
||||
|
@ -4190,7 +4192,7 @@ void ssl_serialize_session_load_buf_size( int ticket_len, char *crt_file )
|
|||
mbedtls_ssl_session_init( &session );
|
||||
|
||||
/* Prepare serialized session data */
|
||||
TEST_ASSERT( ssl_populate_session( &session, ticket_len, crt_file ) == 0 );
|
||||
TEST_ASSERT( ssl_populate_session_tls12( &session, ticket_len, crt_file ) == 0 );
|
||||
TEST_ASSERT( mbedtls_ssl_session_save( &session, NULL, 0, &good_len )
|
||||
== MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
|
||||
TEST_ASSERT( ( good_buf = mbedtls_calloc( 1, good_len ) ) != NULL );
|
||||
|
@ -4235,6 +4237,7 @@ void ssl_session_serialize_version_check( int corrupt_major,
|
|||
corrupt_config == 1 };
|
||||
|
||||
mbedtls_ssl_session_init( &session );
|
||||
ssl_populate_session_tls12( &session, 0, NULL );
|
||||
|
||||
/* Infer length of serialized session. */
|
||||
TEST_ASSERT( mbedtls_ssl_session_save( &session,
|
||||
|
|
Loading…
Reference in a new issue