diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 5a02182c0e..5e493f5f27 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -1201,6 +1201,11 @@ struct mbedtls_ssl_session #if defined(MBEDTLS_SSL_PROTO_TLS1_3) mbedtls_ssl_tls13_application_secrets MBEDTLS_PRIVATE(app_secrets); #endif +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + uint8_t MBEDTLS_PRIVATE(hostname_len); /*!< host_name length */ + char *MBEDTLS_PRIVATE(hostname); /*!< host name binded with tickets */ + uint8_t hostname_mismatch; /*!< whether new host_name match with saved one */ +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ }; /* @@ -3662,6 +3667,27 @@ void mbedtls_ssl_conf_sig_algs( mbedtls_ssl_config *conf, * On too long input failure, old hostname is unchanged. */ int mbedtls_ssl_set_hostname( mbedtls_ssl_context *ssl, const char *hostname ); + +/** + * \brief Reset the hostname to the new server name when reconnection. + * + * \param ssl SSL context + * \param hostname the server hostname, may be NULL + * \param rec_hostname the server rec_hostname, may be NULL + + * \note Maximum hostname length MBEDTLS_SSL_MAX_HOST_NAME_LEN. + * + * \return 0 if successful, MBEDTLS_ERR_SSL_ALLOC_FAILED on + * allocation failure, MBEDTLS_ERR_SSL_BAD_INPUT_DATA on + * too long input rec_hostname. + * + * Rec_hostname set to the one provided on success. + * On allocation failure hostname is unchanged. + * On too long input failure, old hostname is unchanged. + */ +int mbedtls_ssl_reset_hostname( mbedtls_ssl_context *ssl, + const char *hostname, + const char *rec_hostname ); #endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) diff --git a/library/ssl_client.c b/library/ssl_client.c index 1b591253f8..bd9edf15f0 100644 --- a/library/ssl_client.c +++ b/library/ssl_client.c @@ -54,6 +54,7 @@ static int ssl_write_hostname_ext( mbedtls_ssl_context *ssl, { unsigned char *p = buf; size_t hostname_len; + size_t cmp_hostname_len; *olen = 0; @@ -64,8 +65,25 @@ static int ssl_write_hostname_ext( mbedtls_ssl_context *ssl, ( "client hello, adding server name extension: %s", ssl->hostname ) ); + ssl->session_negotiate->hostname_mismatch = 0; hostname_len = strlen( ssl->hostname ); + cmp_hostname_len = hostname_len < ssl->session_negotiate->hostname_len ? + hostname_len : ssl->session_negotiate->hostname_len; + + if( hostname_len != ssl->session_negotiate->hostname_len || + memcmp( ssl->hostname, ssl->session_negotiate->hostname, cmp_hostname_len ) ) + ssl->session_negotiate->hostname_mismatch = 1; + + if( ssl->session_negotiate->hostname == NULL ) + { + ssl->session_negotiate->hostname = mbedtls_calloc( 1, hostname_len ); + if( ssl->session_negotiate->hostname == NULL ) + return MBEDTLS_ERR_SSL_ALLOC_FAILED; + memcpy(ssl->session_negotiate->hostname, ssl->hostname, hostname_len); + } + ssl->session_negotiate->hostname_len = hostname_len; + MBEDTLS_SSL_CHK_BUF_PTR( p, end, hostname_len + 9 ); /* diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 9741a6ef5f..9238761639 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -297,6 +297,18 @@ int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst, } #endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( src->hostname != NULL ) + { + dst->hostname = mbedtls_calloc( 1, src->hostname_len + 1 ); + if( dst->hostname == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + memcpy( dst->hostname, src->hostname, src->hostname_len ); + dst->hostname[src->hostname_len] = '\0'; + } +#endif + return( 0 ); } @@ -1978,6 +1990,11 @@ static int ssl_tls13_session_save( const mbedtls_ssl_session *session, #if defined(MBEDTLS_SSL_CLI_C) if( session->endpoint == MBEDTLS_SSL_IS_CLIENT ) { +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + needed += 1 /* hostname_len */ + + session->hostname_len; /* hostname */ +#endif + needed += 4 /* ticket_lifetime */ + 2; /* ticket_len */ @@ -2004,6 +2021,19 @@ static int ssl_tls13_session_save( const mbedtls_ssl_session *session, memcpy( p, session->resumption_key, session->resumption_key_len ); p += session->resumption_key_len; +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) && defined(MBEDTLS_SSL_CLI_C) + if( session->endpoint == MBEDTLS_SSL_IS_CLIENT && + session->hostname_len != 0 && + session->hostname != NULL ) + { + /* save host name */ + p[0] = session->hostname_len; + p++; + memcpy( p, session->hostname, session->hostname_len ); + p += session->hostname_len; + } +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION && MBEDTLS_SSL_CLI_C */ + #if defined(MBEDTLS_HAVE_TIME) && defined(MBEDTLS_SSL_SRV_C) if( session->endpoint == MBEDTLS_SSL_IS_SERVER ) { @@ -2062,6 +2092,22 @@ static int ssl_tls13_session_load( mbedtls_ssl_session *session, memcpy( session->resumption_key, p, session->resumption_key_len ); p += session->resumption_key_len; +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) && defined(MBEDTLS_SSL_CLI_C) + if( session->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + /* load host name */ + session->hostname_len = p[0]; + p += 1; + if( end - p < session->hostname_len ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + session->hostname = mbedtls_calloc( 1, session->hostname_len ); + if( session->hostname == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + memcpy( session->hostname, p, session->hostname_len ); + p += session->hostname_len; + } +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION && MBEDTLS_SSL_CLI_C */ + #if defined(MBEDTLS_HAVE_TIME) && defined(MBEDTLS_SSL_SRV_C) if( session->endpoint == MBEDTLS_SSL_IS_SERVER ) { @@ -2430,6 +2476,39 @@ int mbedtls_ssl_set_hostname( mbedtls_ssl_context *ssl, const char *hostname ) return( 0 ); } + +int mbedtls_ssl_reset_hostname( mbedtls_ssl_context *ssl, + const char *hostname, + const char *rec_hostname ) +{ + /* Initialize to suppress unnecessary compiler warning */ + size_t rec_hostname_len = 0; + + if( hostname == NULL || rec_hostname == NULL ) + return( 0 ); + + rec_hostname_len = strlen( rec_hostname ); + if( rec_hostname_len > MBEDTLS_SSL_MAX_HOST_NAME_LEN ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( rec_hostname_len == strlen( hostname ) && + memcmp( hostname, rec_hostname, rec_hostname_len ) == 0 ) + return( 0 ); + + if( ssl->hostname != NULL ) + { + mbedtls_platform_zeroize( ssl->hostname, strlen( ssl->hostname ) ); + mbedtls_free( ssl->hostname ); + ssl->hostname = NULL; + ssl->hostname = mbedtls_calloc( 1, rec_hostname_len + 1 ); + if( ssl->hostname == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + memcpy( ssl->hostname, rec_hostname, rec_hostname_len ); + ssl->hostname[rec_hostname_len] = '\0'; + } + + return( 0 ); +} #endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) @@ -3679,6 +3758,10 @@ void mbedtls_ssl_session_free( mbedtls_ssl_session *session ) mbedtls_free( session->ticket ); #endif +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + mbedtls_free( session->hostname ); +#endif + mbedtls_platform_zeroize( session, sizeof( mbedtls_ssl_session ) ); } diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c index 61a1bad578..60b1e05f43 100644 --- a/library/ssl_tls13_server.c +++ b/library/ssl_tls13_server.c @@ -235,6 +235,20 @@ static int ssl_tls13_offered_psks_check_identity_match_ticket( (int)age_diff_in_ms ) ); goto exit; } +#if 0 +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->session_negotiate->hostname != NULL && + ssl->session_negotiate->hostname_len != 0 && + memcmp( ssl->session_negotiate->hostname, + ssl->session->hostname, ssl->session->hostname_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( + 3, ( "Session hostname not matched with stored session ticket" ) ); + goto exit; + } + +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ +#endif ret = 0; diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 6377162b2d..bc93352707 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -366,6 +366,7 @@ int main( void ) "\n usage: ssl_client2 param=<>...\n" \ "\n acceptable parameters:\n" \ " server_name=%%s default: localhost\n" \ + " rec_server_name=%%s default: localhost\n" \ " server_addr=%%s default: given by name\n" \ " server_port=%%d default: 4433\n" \ " request_page=%%s default: \".\"\n" \ @@ -455,6 +456,7 @@ int main( void ) struct options { const char *server_name; /* hostname of the server (client only) */ + const char *rec_s_name; /* hostname of the server (re-connect) */ const char *server_addr; /* address of the server (client only) */ const char *server_port; /* port on which the ssl service runs */ int debug_level; /* level of debugging */ @@ -876,6 +878,7 @@ int main( int argc, char *argv[] ) } opt.server_name = DFL_SERVER_NAME; + opt.rec_s_name = DFL_SERVER_NAME; opt.server_addr = DFL_SERVER_ADDR; opt.server_port = DFL_SERVER_PORT; opt.debug_level = DFL_DEBUG_LEVEL; @@ -961,6 +964,8 @@ int main( int argc, char *argv[] ) if( strcmp( p, "server_name" ) == 0 ) opt.server_name = q; + else if( strcmp( p, "rec_server_name" ) == 0 ) + opt.rec_s_name = q; else if( strcmp( p, "server_addr" ) == 0 ) opt.server_addr = q; else if( strcmp( p, "server_port" ) == 0 ) @@ -3113,6 +3118,16 @@ reconnect: goto exit; } +#if defined(MBEDTLS_X509_CRT_PARSE_C) + if( ( ret = mbedtls_ssl_reset_hostname( &ssl, opt.server_name, + opt.rec_s_name ) ) != 0 ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_reset_hostname returned %d\n\n", + ret ); + goto exit; + } +#endif + if( ( ret = mbedtls_net_connect( &server_fd, opt.server_addr, opt.server_port, opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM ? diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 48dd89e357..414b8607bb 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -12873,6 +12873,47 @@ run_test "TLS 1.2: Check rsa_pss_rsae compatibility issue, m->G" \ -c "Protocol is TLSv1.2" \ -c "HTTP/1.0 200 [Oo][Kk]" +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 +requires_config_enabled MBEDTLS_SSL_SESSION_TICKETS +requires_config_enabled MBEDTLS_SSL_SRV_C +requires_config_enabled MBEDTLS_SSL_CLI_C +requires_config_enabled MBEDTLS_DEBUG_C +run_test "TLS 1.3: NewSessionTicket: servername check, m->m" \ + "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=1 \ + sni=localhost,data_files/server2.crt,data_files/server2.key,-,-,-,polarssl.example,data_files/server1-nospace.crt,data_files/server1.key,-,-,-" \ + "$P_CLI debug_level=4 server_name=localhost reco_mode=1 reconnect=1" \ + 0 \ + -c "Protocol is TLSv1.3" \ + -c "got new session ticket." \ + -c "Saving session for reuse... ok" \ + -c "Reconnecting with saved session" \ + -c "HTTP/1.0 200 OK" \ + -s "=> write NewSessionTicket msg" \ + -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET" \ + -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET_FLUSH" \ + -s "key exchange mode: ephemeral" \ + -s "key exchange mode: psk_ephemeral" \ + -s "found pre_shared_key extension" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 +requires_config_enabled MBEDTLS_SSL_SESSION_TICKETS +requires_config_enabled MBEDTLS_SSL_SRV_C +requires_config_enabled MBEDTLS_SSL_CLI_C +requires_config_enabled MBEDTLS_DEBUG_C +run_test "TLS 1.3: NewSessionTicket: servername negative check, m->m" \ + "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=1 \ + sni=localhost,data_files/server2.crt,data_files/server2.key,-,-,-,polarssl.example,data_files/server1-nospace.crt,data_files/server1.key,-,-,-" \ + "$P_CLI debug_level=4 server_name=localhost rec_server_name=remote reco_mode=1 reconnect=1" \ + 1 \ + -c "Protocol is TLSv1.3" \ + -c "got new session ticket." \ + -c "Saving session for reuse... ok" \ + -c "Reconnecting with saved session" \ + -c "hostname mismatch the session ticker, should not resume" \ + -s "=> write NewSessionTicket msg" \ + -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET" \ + -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET_FLUSH" + # Test heap memory usage after handshake requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2 requires_config_enabled MBEDTLS_MEMORY_DEBUG