mirror of
https://github.com/Mbed-TLS/mbedtls.git
synced 2025-07-28 00:21:48 +03:00
Merge pull request #6167 from yuhaoth/pr/finalize-tls13-session-tickets
This commit is contained in:
@ -121,14 +121,170 @@ static int ssl_tls13_parse_key_exchange_modes_ext( mbedtls_ssl_context *ssl,
|
||||
|
||||
#define SSL_TLS1_3_OFFERED_PSK_NOT_MATCH 1
|
||||
#define SSL_TLS1_3_OFFERED_PSK_MATCH 0
|
||||
|
||||
#if defined(MBEDTLS_SSL_SESSION_TICKETS)
|
||||
|
||||
MBEDTLS_CHECK_RETURN_CRITICAL
|
||||
static int ssl_tls13_offered_psks_check_identity_match_ticket(
|
||||
mbedtls_ssl_context *ssl,
|
||||
const unsigned char *identity,
|
||||
size_t identity_len,
|
||||
uint32_t obfuscated_ticket_age,
|
||||
mbedtls_ssl_session *session )
|
||||
{
|
||||
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
||||
unsigned char *ticket_buffer;
|
||||
#if defined(MBEDTLS_HAVE_TIME)
|
||||
mbedtls_time_t now;
|
||||
uint64_t age_in_s;
|
||||
int64_t age_diff_in_ms;
|
||||
#endif
|
||||
|
||||
((void) obfuscated_ticket_age);
|
||||
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> check_identity_match_ticket" ) );
|
||||
|
||||
/* Ticket parser is not configured, Skip */
|
||||
if( ssl->conf->f_ticket_parse == NULL || identity_len == 0 )
|
||||
return( 0 );
|
||||
|
||||
/* We create a copy of the encrypted ticket since the ticket parsing
|
||||
* function is allowed to use its input buffer as an output buffer
|
||||
* (in-place decryption). We do, however, need the original buffer for
|
||||
* computing the PSK binder value.
|
||||
*/
|
||||
ticket_buffer = mbedtls_calloc( 1, identity_len );
|
||||
if( ticket_buffer == NULL )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) );
|
||||
return ( MBEDTLS_ERR_SSL_ALLOC_FAILED );
|
||||
}
|
||||
memcpy( ticket_buffer, identity, identity_len );
|
||||
|
||||
if( ( ret = ssl->conf->f_ticket_parse( ssl->conf->p_ticket,
|
||||
session,
|
||||
ticket_buffer, identity_len ) ) != 0 )
|
||||
{
|
||||
if( ret == MBEDTLS_ERR_SSL_INVALID_MAC )
|
||||
MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket is not authentic" ) );
|
||||
else if( ret == MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED )
|
||||
MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket is expired" ) );
|
||||
else
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "ticket_parse", ret );
|
||||
}
|
||||
|
||||
/* We delete the temporary buffer */
|
||||
mbedtls_free( ticket_buffer );
|
||||
|
||||
if( ret != 0 )
|
||||
goto exit;
|
||||
|
||||
ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
|
||||
#if defined(MBEDTLS_HAVE_TIME)
|
||||
now = mbedtls_time( NULL );
|
||||
|
||||
if( now < session->start )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG(
|
||||
3, ( "Ticket expired: now=%" MBEDTLS_PRINTF_LONGLONG
|
||||
", start=%" MBEDTLS_PRINTF_LONGLONG,
|
||||
(long long)now, (long long)session->start ) );
|
||||
goto exit;
|
||||
}
|
||||
|
||||
age_in_s = (uint64_t)( now - session->start );
|
||||
|
||||
/* RFC 8446 section 4.6.1
|
||||
*
|
||||
* Servers MUST NOT use any value greater than 604800 seconds (7 days).
|
||||
*
|
||||
* RFC 8446 section 4.2.11.1
|
||||
*
|
||||
* Clients MUST NOT attempt to use tickets which have ages greater than
|
||||
* the "ticket_lifetime" value which was provided with the ticket.
|
||||
*
|
||||
* For time being, the age MUST be less than 604800 seconds (7 days).
|
||||
*/
|
||||
if( age_in_s > 604800 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG(
|
||||
3, ( "Ticket expired: Ticket age exceed limitation ticket_age=%lu",
|
||||
(long unsigned int)age_in_s ) );
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* RFC 8446 section 4.2.10
|
||||
*
|
||||
* For PSKs provisioned via NewSessionTicket, a server MUST validate that
|
||||
* the ticket age for the selected PSK identity (computed by subtracting
|
||||
* ticket_age_add from PskIdentity.obfuscated_ticket_age modulo 2^32) is
|
||||
* within a small tolerance of the time since the ticket was issued.
|
||||
*
|
||||
* NOTE: When `now == session->start`, `age_diff_in_ms` may be negative
|
||||
* as the age units are different on the server (s) and in the
|
||||
* client (ms) side. Add a -1000 ms tolerance window to take this
|
||||
* into account.
|
||||
*/
|
||||
age_diff_in_ms = age_in_s * 1000;
|
||||
age_diff_in_ms -= ( obfuscated_ticket_age - session->ticket_age_add );
|
||||
if( age_diff_in_ms <= -1000 ||
|
||||
age_diff_in_ms > MBEDTLS_SSL_TLS1_3_TICKET_AGE_TOLERANCE )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG(
|
||||
3, ( "Ticket expired: Ticket age outside tolerance window "
|
||||
"( diff=%d )", (int)age_diff_in_ms ) );
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
#endif /* MBEDTLS_HAVE_TIME */
|
||||
|
||||
exit:
|
||||
if( ret != 0 )
|
||||
mbedtls_ssl_session_free( session );
|
||||
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= check_identity_match_ticket" ) );
|
||||
return( ret );
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_SESSION_TICKETS */
|
||||
|
||||
MBEDTLS_CHECK_RETURN_CRITICAL
|
||||
static int ssl_tls13_offered_psks_check_identity_match(
|
||||
mbedtls_ssl_context *ssl,
|
||||
const unsigned char *identity,
|
||||
size_t identity_len,
|
||||
int *psk_type )
|
||||
uint32_t obfuscated_ticket_age,
|
||||
int *psk_type,
|
||||
mbedtls_ssl_session *session )
|
||||
{
|
||||
((void) session);
|
||||
((void) obfuscated_ticket_age);
|
||||
*psk_type = MBEDTLS_SSL_TLS1_3_PSK_EXTERNAL;
|
||||
|
||||
MBEDTLS_SSL_DEBUG_BUF( 4, "identity", identity, identity_len );
|
||||
ssl->handshake->resume = 0;
|
||||
|
||||
#if defined(MBEDTLS_SSL_SESSION_TICKETS)
|
||||
if( ssl_tls13_offered_psks_check_identity_match_ticket(
|
||||
ssl, identity, identity_len, obfuscated_ticket_age,
|
||||
session ) == SSL_TLS1_3_OFFERED_PSK_MATCH )
|
||||
{
|
||||
ssl->handshake->resume = 1;
|
||||
*psk_type = MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION;
|
||||
mbedtls_ssl_set_hs_psk( ssl,
|
||||
session->resumption_key,
|
||||
session->resumption_key_len );
|
||||
|
||||
MBEDTLS_SSL_DEBUG_BUF( 4, "Ticket-resumed PSK:",
|
||||
session->resumption_key,
|
||||
session->resumption_key_len );
|
||||
MBEDTLS_SSL_DEBUG_MSG( 4, ( "ticket: obfuscated_ticket_age: %u",
|
||||
(unsigned)obfuscated_ticket_age ) );
|
||||
return( SSL_TLS1_3_OFFERED_PSK_MATCH );
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_SESSION_TICKETS */
|
||||
|
||||
/* Check identity with external configured function */
|
||||
if( ssl->conf->f_psk != NULL )
|
||||
{
|
||||
@ -256,6 +412,7 @@ static int ssl_tls13_select_ciphersuite_for_psk(
|
||||
return( MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_SSL_SESSION_TICKETS)
|
||||
MBEDTLS_CHECK_RETURN_CRITICAL
|
||||
static int ssl_tls13_select_ciphersuite_for_resumption(
|
||||
mbedtls_ssl_context *ssl,
|
||||
@ -265,15 +422,46 @@ static int ssl_tls13_select_ciphersuite_for_resumption(
|
||||
uint16_t *selected_ciphersuite,
|
||||
const mbedtls_ssl_ciphersuite_t **selected_ciphersuite_info )
|
||||
{
|
||||
((void) ssl);
|
||||
((void) session);
|
||||
((void) cipher_suites);
|
||||
((void) cipher_suites_end);
|
||||
|
||||
*selected_ciphersuite = 0;
|
||||
*selected_ciphersuite_info = NULL;
|
||||
return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
|
||||
for( const unsigned char *p = cipher_suites; p < cipher_suites_end; p += 2 )
|
||||
{
|
||||
uint16_t cipher_suite = MBEDTLS_GET_UINT16_BE( p, 0 );
|
||||
const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
|
||||
|
||||
if( cipher_suite != session->ciphersuite )
|
||||
continue;
|
||||
|
||||
ciphersuite_info = ssl_tls13_validate_peer_ciphersuite( ssl,
|
||||
cipher_suite );
|
||||
if( ciphersuite_info == NULL )
|
||||
continue;
|
||||
|
||||
*selected_ciphersuite = cipher_suite;
|
||||
*selected_ciphersuite_info = ciphersuite_info;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
return( MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE );
|
||||
}
|
||||
|
||||
MBEDTLS_CHECK_RETURN_CRITICAL
|
||||
static int ssl_tls13_session_copy_ticket( mbedtls_ssl_session *dst,
|
||||
const mbedtls_ssl_session *src )
|
||||
{
|
||||
dst->ticket_age_add = src->ticket_age_add;
|
||||
dst->ticket_flags = src->ticket_flags;
|
||||
dst->resumption_key_len = src->resumption_key_len;
|
||||
if( src->resumption_key_len == 0 )
|
||||
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
|
||||
memcpy( dst->resumption_key, src->resumption_key, src->resumption_key_len );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_SESSION_TICKETS */
|
||||
|
||||
/* Parser for pre_shared_key extension in client hello
|
||||
* struct {
|
||||
* opaque identity<1..2^16-1>;
|
||||
@ -343,17 +531,23 @@ static int ssl_tls13_parse_pre_shared_key_ext( mbedtls_ssl_context *ssl,
|
||||
{
|
||||
const unsigned char *identity;
|
||||
size_t identity_len;
|
||||
uint32_t obfuscated_ticket_age;
|
||||
const unsigned char *binder;
|
||||
size_t binder_len;
|
||||
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
||||
int psk_type;
|
||||
uint16_t cipher_suite;
|
||||
const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
|
||||
#if defined(MBEDTLS_SSL_SESSION_TICKETS)
|
||||
mbedtls_ssl_session session;
|
||||
mbedtls_ssl_session_init( &session );
|
||||
#endif
|
||||
|
||||
MBEDTLS_SSL_CHK_BUF_READ_PTR( p_identity_len, identities_end, 2 + 1 + 4 );
|
||||
identity_len = MBEDTLS_GET_UINT16_BE( p_identity_len, 0 );
|
||||
identity = p_identity_len + 2;
|
||||
MBEDTLS_SSL_CHK_BUF_READ_PTR( identity, identities_end, identity_len + 4 );
|
||||
obfuscated_ticket_age = MBEDTLS_GET_UINT32_BE( identity , identity_len );
|
||||
p_identity_len += identity_len + 6;
|
||||
|
||||
MBEDTLS_SSL_CHK_BUF_READ_PTR( p_binder_len, binders_end, 1 + 32 );
|
||||
@ -367,7 +561,8 @@ static int ssl_tls13_parse_pre_shared_key_ext( mbedtls_ssl_context *ssl,
|
||||
continue;
|
||||
|
||||
ret = ssl_tls13_offered_psks_check_identity_match(
|
||||
ssl, identity, identity_len, &psk_type );
|
||||
ssl, identity, identity_len, obfuscated_ticket_age,
|
||||
&psk_type, &session );
|
||||
if( ret != SSL_TLS1_3_OFFERED_PSK_MATCH )
|
||||
continue;
|
||||
|
||||
@ -380,9 +575,15 @@ static int ssl_tls13_parse_pre_shared_key_ext( mbedtls_ssl_context *ssl,
|
||||
&cipher_suite, &ciphersuite_info );
|
||||
break;
|
||||
case MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION:
|
||||
#if defined(MBEDTLS_SSL_SESSION_TICKETS)
|
||||
ret = ssl_tls13_select_ciphersuite_for_resumption(
|
||||
ssl, ciphersuites, ciphersuites_end, NULL,
|
||||
ssl, ciphersuites, ciphersuites_end, &session,
|
||||
&cipher_suite, &ciphersuite_info );
|
||||
if( ret != 0 )
|
||||
mbedtls_ssl_session_free( &session );
|
||||
#else
|
||||
ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
|
||||
@ -406,6 +607,9 @@ static int ssl_tls13_parse_pre_shared_key_ext( mbedtls_ssl_context *ssl,
|
||||
/* For security reasons, the handshake should be aborted when we
|
||||
* fail to validate a binder value. See RFC 8446 section 4.2.11.2
|
||||
* and appendix E.6. */
|
||||
#if defined(MBEDTLS_SSL_SESSION_TICKETS)
|
||||
mbedtls_ssl_session_free( &session );
|
||||
#endif
|
||||
MBEDTLS_SSL_DEBUG_MSG( 3, ( "Invalid binder." ) );
|
||||
MBEDTLS_SSL_DEBUG_RET( 1,
|
||||
"ssl_tls13_offered_psks_check_binder_match" , ret );
|
||||
@ -418,11 +622,20 @@ static int ssl_tls13_parse_pre_shared_key_ext( mbedtls_ssl_context *ssl,
|
||||
matched_identity = identity_id;
|
||||
|
||||
/* Update handshake parameters */
|
||||
ssl->session_negotiate->ciphersuite = cipher_suite;
|
||||
ssl->handshake->ciphersuite_info = ciphersuite_info;
|
||||
ssl->session_negotiate->ciphersuite = cipher_suite;
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "overwrite ciphersuite: %04x - %s",
|
||||
cipher_suite, ciphersuite_info->name ) );
|
||||
|
||||
#if defined(MBEDTLS_SSL_SESSION_TICKETS)
|
||||
if( psk_type == MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION )
|
||||
{
|
||||
ret = ssl_tls13_session_copy_ticket( ssl->session_negotiate,
|
||||
&session );
|
||||
mbedtls_ssl_session_free( &session );
|
||||
if( ret != 0 )
|
||||
return( ret );
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_SESSION_TICKETS */
|
||||
}
|
||||
|
||||
if( p_identity_len != identities_end || p_binder_len != binders_end )
|
||||
@ -2366,11 +2579,11 @@ static int ssl_tls13_process_client_finished( mbedtls_ssl_context *ssl )
|
||||
if( ret != 0 )
|
||||
return( ret );
|
||||
|
||||
ret = mbedtls_ssl_tls13_generate_resumption_master_secret( ssl );
|
||||
ret = mbedtls_ssl_tls13_compute_resumption_master_secret( ssl );
|
||||
if( ret != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_RET( 1,
|
||||
"mbedtls_ssl_tls13_generate_resumption_master_secret ", ret );
|
||||
"mbedtls_ssl_tls13_compute_resumption_master_secret", ret );
|
||||
}
|
||||
|
||||
mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_HANDSHAKE_WRAPUP );
|
||||
|
Reference in New Issue
Block a user