diff options
Diffstat (limited to 'library/ssl_tls.c')
-rw-r--r-- | library/ssl_tls.c | 804 |
1 files changed, 497 insertions, 307 deletions
diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 4c23f0e..660d548 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -279,13 +279,15 @@ static unsigned int ssl_mfl_code_to_length( int mfl ) } #endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ -#if defined(MBEDTLS_SSL_CLI_C) -static int ssl_session_copy( mbedtls_ssl_session *dst, const mbedtls_ssl_session *src ) +int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst, + const mbedtls_ssl_session *src ) { mbedtls_ssl_session_free( dst ); memcpy( dst, src, sizeof( mbedtls_ssl_session ) ); #if defined(MBEDTLS_X509_CRT_PARSE_C) + +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) if( src->peer_cert != NULL ) { int ret; @@ -304,6 +306,21 @@ static int ssl_session_copy( mbedtls_ssl_session *dst, const mbedtls_ssl_session return( ret ); } } +#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + if( src->peer_cert_digest != NULL ) + { + dst->peer_cert_digest = + mbedtls_calloc( 1, src->peer_cert_digest_len ); + if( dst->peer_cert_digest == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + memcpy( dst->peer_cert_digest, src->peer_cert_digest, + src->peer_cert_digest_len ); + dst->peer_cert_digest_type = src->peer_cert_digest_type; + dst->peer_cert_digest_len = src->peer_cert_digest_len; + } +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + #endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) @@ -319,7 +336,6 @@ static int ssl_session_copy( mbedtls_ssl_session *dst, const mbedtls_ssl_session return( 0 ); } -#endif /* MBEDTLS_SSL_CLI_C */ #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) int (*mbedtls_ssl_hw_record_init)( mbedtls_ssl_context *ssl, @@ -5554,16 +5570,33 @@ int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl, return( 0 ); } +#if defined(MBEDTLS_X509_CRT_PARSE_C) +static void ssl_clear_peer_cert( mbedtls_ssl_session *session ) +{ +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + if( session->peer_cert != NULL ) + { + mbedtls_x509_crt_free( session->peer_cert ); + mbedtls_free( session->peer_cert ); + session->peer_cert = NULL; + } +#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + if( session->peer_cert_digest != NULL ) + { + /* Zeroization is not necessary. */ + mbedtls_free( session->peer_cert_digest ); + session->peer_cert_digest = NULL; + session->peer_cert_digest_type = MBEDTLS_MD_NONE; + session->peer_cert_digest_len = 0; + } +#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + /* * Handshake functions */ -#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \ - !defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) && \ - !defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \ - !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \ - !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && \ - !defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) && \ - !defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +#if !defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) /* No certificate support -> dummy functions */ int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl ) { @@ -5571,10 +5604,7 @@ int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) ); - if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || - ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || - ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || - ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) ) { MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); ssl->state++; @@ -5591,10 +5621,7 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) ); - if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || - ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || - ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || - ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) ) { MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); ssl->state++; @@ -5605,7 +5632,7 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); } -#else +#else /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ /* Some certificate support -> implement write and parse */ int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl ) @@ -5617,10 +5644,7 @@ int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) ); - if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || - ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || - ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || - ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) ) { MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); ssl->state++; @@ -5725,6 +5749,8 @@ write_msg: } #if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C) + +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) static int ssl_check_peer_crt_unchanged( mbedtls_ssl_context *ssl, unsigned char *crt_buf, size_t crt_buf_len ) @@ -5739,65 +5765,51 @@ static int ssl_check_peer_crt_unchanged( mbedtls_ssl_context *ssl, return( memcmp( peer_crt->raw.p, crt_buf, crt_buf_len ) ); } +#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +static int ssl_check_peer_crt_unchanged( mbedtls_ssl_context *ssl, + unsigned char *crt_buf, + size_t crt_buf_len ) +{ + int ret; + unsigned char const * const peer_cert_digest = + ssl->session->peer_cert_digest; + mbedtls_md_type_t const peer_cert_digest_type = + ssl->session->peer_cert_digest_type; + mbedtls_md_info_t const * const digest_info = + mbedtls_md_info_from_type( peer_cert_digest_type ); + unsigned char tmp_digest[MBEDTLS_SSL_PEER_CERT_DIGEST_MAX_LEN]; + size_t digest_len; + + if( peer_cert_digest == NULL || digest_info == NULL ) + return( -1 ); + + digest_len = mbedtls_md_get_size( digest_info ); + if( digest_len > MBEDTLS_SSL_PEER_CERT_DIGEST_MAX_LEN ) + return( -1 ); + + ret = mbedtls_md( digest_info, crt_buf, crt_buf_len, tmp_digest ); + if( ret != 0 ) + return( -1 ); + + return( memcmp( tmp_digest, peer_cert_digest, digest_len ) ); +} +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ #endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */ /* * Once the certificate message is read, parse it into a cert chain and * perform basic checks, but leave actual verification to the caller */ -static int ssl_parse_certificate_chain( mbedtls_ssl_context *ssl ) +static int ssl_parse_certificate_chain( mbedtls_ssl_context *ssl, + mbedtls_x509_crt *chain ) { int ret; +#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C) + int crt_cnt=0; +#endif size_t i, n; uint8_t alert; -#if defined(MBEDTLS_SSL_SRV_C) -#if defined(MBEDTLS_SSL_PROTO_SSL3) - /* - * Check if the client sent an empty certificate - */ - if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && - ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) - { - if( ssl->in_msglen == 2 && - ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT && - ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_WARNING && - ssl->in_msg[1] == MBEDTLS_SSL_ALERT_MSG_NO_CERT ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "SSLv3 client has no certificate" ) ); - - /* The client was asked for a certificate but didn't send - one. The client should know what's going on, so we - don't send an alert. */ - ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING; - return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE ); - } - } -#endif /* MBEDTLS_SSL_PROTO_SSL3 */ - -#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ - defined(MBEDTLS_SSL_PROTO_TLS1_2) - if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && - ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_0 ) - { - if( ssl->in_hslen == 3 + mbedtls_ssl_hs_hdr_len( ssl ) && - ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && - ssl->in_msg[0] == MBEDTLS_SSL_HS_CERTIFICATE && - memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ), "\0\0\0", 3 ) == 0 ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "TLSv1 client has no certificate" ) ); - - /* The client was asked for a certificate but didn't send - one. The client should know what's going on, so we - don't send an alert. */ - ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING; - return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE ); - } - } -#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ - MBEDTLS_SSL_PROTO_TLS1_2 */ -#endif /* MBEDTLS_SSL_SRV_C */ - if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); @@ -5834,14 +5846,6 @@ static int ssl_parse_certificate_chain( mbedtls_ssl_context *ssl ) /* Make &ssl->in_msg[i] point to the beginning of the CRT chain. */ i += 3; - /* In case we tried to reuse a session but it failed */ - if( ssl->session_negotiate->peer_cert != NULL ) - { - mbedtls_x509_crt_free( ssl->session_negotiate->peer_cert ); - mbedtls_free( ssl->session_negotiate->peer_cert ); - ssl->session_negotiate->peer_cert = NULL; - } - /* Iterate through and parse the CRTs in the provided chain. */ while( i < ssl->in_hslen ) { @@ -5879,66 +5883,40 @@ static int ssl_parse_certificate_chain( mbedtls_ssl_context *ssl ) } /* Check if we're handling the first CRT in the chain. */ - if( ssl->session_negotiate->peer_cert == NULL ) +#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C) + if( crt_cnt++ == 0 && + ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && + ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) { /* During client-side renegotiation, check that the server's * end-CRTs hasn't changed compared to the initial handshake, * mitigating the triple handshake attack. On success, reuse * the original end-CRT instead of parsing it again. */ -#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C) - if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && - ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) - { - MBEDTLS_SSL_DEBUG_MSG( 3, ( "Check that peer CRT hasn't changed during renegotiation" ) ); - if( ssl_check_peer_crt_unchanged( ssl, - &ssl->in_msg[i], - n ) != 0 ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "new server cert during renegotiation" ) ); - mbedtls_ssl_send_alert_message( ssl, - MBEDTLS_SSL_ALERT_LEVEL_FATAL, - MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED ); - return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); - } - - /* Move CRT chain structure to new session instance. */ - ssl->session_negotiate->peer_cert = ssl->session->peer_cert; - ssl->session->peer_cert = NULL; - - /* Delete all remaining CRTs from the original CRT chain. */ - mbedtls_x509_crt_free( - ssl->session_negotiate->peer_cert->next ); - mbedtls_free( ssl->session_negotiate->peer_cert->next ); - ssl->session_negotiate->peer_cert->next = NULL; - - i += n; - continue; - } -#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */ - - /* Outside of client-side renegotiation, create a fresh X.509 CRT - * instance to parse the end-CRT into. */ - - ssl->session_negotiate->peer_cert = - mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) ); - if( ssl->session_negotiate->peer_cert == NULL ) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Check that peer CRT hasn't changed during renegotiation" ) ); + if( ssl_check_peer_crt_unchanged( ssl, + &ssl->in_msg[i], + n ) != 0 ) { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", - sizeof( mbedtls_x509_crt ) ) ); + MBEDTLS_SSL_DEBUG_MSG( 1, ( "new server cert during renegotiation" ) ); mbedtls_ssl_send_alert_message( ssl, - MBEDTLS_SSL_ALERT_LEVEL_FATAL, - MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR ); - return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); } - mbedtls_x509_crt_init( ssl->session_negotiate->peer_cert ); - - /* Intentional fall through */ + /* Now we can safely free the original chain. */ + ssl_clear_peer_cert( ssl->session ); } +#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */ /* Parse the next certificate in the chain. */ - ret = mbedtls_x509_crt_parse_der( ssl->session_negotiate->peer_cert, - ssl->in_msg + i, n ); +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + ret = mbedtls_x509_crt_parse_der( chain, ssl->in_msg + i, n ); +#else + /* If we don't need to store the CRT chain permanently, parse + * it in-place from the input buffer instead of making a copy. */ + ret = mbedtls_x509_crt_parse_der_nocopy( chain, ssl->in_msg + i, n ); +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ switch( ret ) { case 0: /*ok*/ @@ -5966,60 +5944,316 @@ static int ssl_parse_certificate_chain( mbedtls_ssl_context *ssl ) i += n; } - MBEDTLS_SSL_DEBUG_CRT( 3, "peer certificate", ssl->session_negotiate->peer_cert ); + MBEDTLS_SSL_DEBUG_CRT( 3, "peer certificate", chain ); return( 0 ); } -int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) +#if defined(MBEDTLS_SSL_SRV_C) +static int ssl_srv_check_client_no_crt_notification( mbedtls_ssl_context *ssl ) { - int ret; - const mbedtls_ssl_ciphersuite_t * const ciphersuite_info = - ssl->transform_negotiate->ciphersuite_info; -#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) - const int authmode = ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET - ? ssl->handshake->sni_authmode - : ssl->conf->authmode; -#else - const int authmode = ssl->conf->authmode; -#endif - void *rs_ctx = NULL; + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + return( -1 ); - MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) ); +#if defined(MBEDTLS_SSL_PROTO_SSL3) + /* + * Check if the client sent an empty certificate + */ + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + if( ssl->in_msglen == 2 && + ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT && + ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_WARNING && + ssl->in_msg[1] == MBEDTLS_SSL_ALERT_MSG_NO_CERT ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "SSLv3 client has no certificate" ) ); + return( 0 ); + } + + return( -1 ); + } +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ - if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || - ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || - ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || - ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->in_hslen == 3 + mbedtls_ssl_hs_hdr_len( ssl ) && + ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_msg[0] == MBEDTLS_SSL_HS_CERTIFICATE && + memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ), "\0\0\0", 3 ) == 0 ) { - MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); - ssl->state++; + MBEDTLS_SSL_DEBUG_MSG( 1, ( "TLSv1 client has no certificate" ) ); return( 0 ); } + return( -1 ); +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ +} +#endif /* MBEDTLS_SSL_SRV_C */ + +/* Check if a certificate message is expected. + * Return either + * - SSL_CERTIFICATE_EXPECTED, or + * - SSL_CERTIFICATE_SKIP + * indicating whether a Certificate message is expected or not. + */ +#define SSL_CERTIFICATE_EXPECTED 0 +#define SSL_CERTIFICATE_SKIP 1 +static int ssl_parse_certificate_coordinate( mbedtls_ssl_context *ssl, + int authmode ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->transform_negotiate->ciphersuite_info; + + if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) ) + return( SSL_CERTIFICATE_SKIP ); + #if defined(MBEDTLS_SSL_SRV_C) - if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && - ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) { - MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); - ssl->state++; + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + return( SSL_CERTIFICATE_SKIP ); + + if( authmode == MBEDTLS_SSL_VERIFY_NONE ) + { + ssl->session_negotiate->verify_result = + MBEDTLS_X509_BADCERT_SKIP_VERIFY; + return( SSL_CERTIFICATE_SKIP ); + } + } +#else + ((void) authmode); +#endif /* MBEDTLS_SSL_SRV_C */ + + return( SSL_CERTIFICATE_EXPECTED ); +} + +static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl, + int authmode, + mbedtls_x509_crt *chain, + void *rs_ctx ) +{ + int ret = 0; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->transform_negotiate->ciphersuite_info; + mbedtls_x509_crt *ca_chain; + mbedtls_x509_crl *ca_crl; + + if( authmode == MBEDTLS_SSL_VERIFY_NONE ) return( 0 ); + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_ca_chain != NULL ) + { + ca_chain = ssl->handshake->sni_ca_chain; + ca_crl = ssl->handshake->sni_ca_crl; + } + else +#endif + { + ca_chain = ssl->conf->ca_chain; + ca_crl = ssl->conf->ca_crl; + } + + /* + * Main check: verify certificate + */ + ret = mbedtls_x509_crt_verify_restartable( + chain, + ca_chain, ca_crl, + ssl->conf->cert_profile, + ssl->hostname, + &ssl->session_negotiate->verify_result, + ssl->conf->f_vrfy, ssl->conf->p_vrfy, rs_ctx ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret ); } - if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && - authmode == MBEDTLS_SSL_VERIFY_NONE ) +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + return( MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS ); +#endif + + /* + * Secondary checks: always done, but change 'ret' only if it was 0 + */ + +#if defined(MBEDTLS_ECP_C) { - ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_SKIP_VERIFY; - MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + const mbedtls_pk_context *pk = &chain->pk; - ssl->state++; - return( 0 ); + /* If certificate uses an EC key, make sure the curve is OK */ + if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) && + mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id ) != 0 ) + { + ssl->session_negotiate->verify_result |= MBEDTLS_X509_BADCERT_BAD_KEY; + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (EC key curve)" ) ); + if( ret == 0 ) + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; + } } +#endif /* MBEDTLS_ECP_C */ + + if( mbedtls_ssl_check_cert_usage( chain, + ciphersuite_info, + ! ssl->conf->endpoint, + &ssl->session_negotiate->verify_result ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (usage extensions)" ) ); + if( ret == 0 ) + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; + } + + /* mbedtls_x509_crt_verify_with_profile is supposed to report a + * verification failure through MBEDTLS_ERR_X509_CERT_VERIFY_FAILED, + * with details encoded in the verification flags. All other kinds + * of error codes, including those from the user provided f_vrfy + * functions, are treated as fatal and lead to a failure of + * ssl_parse_certificate even if verification was optional. */ + if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL && + ( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED || + ret == MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ) ) + { + ret = 0; + } + + if( ca_chain == NULL && authmode == MBEDTLS_SSL_VERIFY_REQUIRED ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no CA chain" ) ); + ret = MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED; + } + + if( ret != 0 ) + { + uint8_t alert; + + /* The certificate may have been rejected for several reasons. + Pick one and send the corresponding alert. Which alert to send + may be a subject of debate in some cases. */ + if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_OTHER ) + alert = MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED; + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_CN_MISMATCH ) + alert = MBEDTLS_SSL_ALERT_MSG_BAD_CERT; + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_KEY_USAGE ) + alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT; + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXT_KEY_USAGE ) + alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT; + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NS_CERT_TYPE ) + alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT; + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_PK ) + alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT; + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_KEY ) + alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT; + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXPIRED ) + alert = MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED; + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_REVOKED ) + alert = MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED; + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NOT_TRUSTED ) + alert = MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA; + else + alert = MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN; + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + alert ); + } + +#if defined(MBEDTLS_DEBUG_C) + if( ssl->session_negotiate->verify_result != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "! Certificate verification flags %x", + ssl->session_negotiate->verify_result ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Certificate verification flags clear" ) ); + } +#endif /* MBEDTLS_DEBUG_C */ + + return( ret ); +} + +#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) +static int ssl_remember_peer_crt_digest( mbedtls_ssl_context *ssl, + unsigned char *start, size_t len ) +{ + int ret; + /* Remember digest of the peer's end-CRT. */ + ssl->session_negotiate->peer_cert_digest = + mbedtls_calloc( 1, MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN ); + if( ssl->session_negotiate->peer_cert_digest == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", + sizeof( MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN ) ) ); + mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR ); + + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + ret = mbedtls_md( mbedtls_md_info_from_type( + MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE ), + start, len, + ssl->session_negotiate->peer_cert_digest ); + + ssl->session_negotiate->peer_cert_digest_type = + MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE; + ssl->session_negotiate->peer_cert_digest_len = + MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN; + + return( ret ); +} + +static int ssl_remember_peer_pubkey( mbedtls_ssl_context *ssl, + unsigned char *start, size_t len ) +{ + unsigned char *end = start + len; + int ret; + + /* Make a copy of the peer's raw public key. */ + mbedtls_pk_init( &ssl->handshake->peer_pubkey ); + ret = mbedtls_pk_parse_subpubkey( &start, end, + &ssl->handshake->peer_pubkey ); + if( ret != 0 ) + { + /* We should have parsed the public key before. */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + return( 0 ); +} +#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + +int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + int crt_expected; +#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + const int authmode = ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET + ? ssl->handshake->sni_authmode + : ssl->conf->authmode; +#else + const int authmode = ssl->conf->authmode; #endif + void *rs_ctx = NULL; + mbedtls_x509_crt *chain = NULL; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) ); + + crt_expected = ssl_parse_certificate_coordinate( ssl, authmode ); + if( crt_expected == SSL_CERTIFICATE_SKIP ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + goto exit; + } #if defined(MBEDTLS_SSL__ECP_RESTARTABLE) if( ssl->handshake->ecrs_enabled && ssl->handshake->ecrs_state == ssl_ecrs_crt_verify ) { + chain = ssl->handshake->ecrs_peer_cert; + ssl->handshake->ecrs_peer_cert = NULL; goto crt_verify; } #endif @@ -6029,22 +6263,44 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) /* mbedtls_ssl_read_record may have sent an alert already. We let it decide whether to alert. */ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); - return( ret ); + goto exit; } - if( ( ret = ssl_parse_certificate_chain( ssl ) ) != 0 ) - { #if defined(MBEDTLS_SSL_SRV_C) - if( ret == MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE && - authmode == MBEDTLS_SSL_VERIFY_OPTIONAL ) - { + if( ssl_srv_check_client_no_crt_notification( ssl ) == 0 ) + { + ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING; + + if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL ) ret = 0; - } -#endif + else + ret = MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE; - ssl->state++; - return( ret ); + goto exit; + } +#endif /* MBEDTLS_SSL_SRV_C */ + + /* Clear existing peer CRT structure in case we tried to + * reuse a session but it failed, and allocate a new one. */ + ssl_clear_peer_cert( ssl->session_negotiate ); + + chain = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) ); + if( chain == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", + sizeof( mbedtls_x509_crt ) ) ); + mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR ); + + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto exit; } + mbedtls_x509_crt_init( chain ); + + ret = ssl_parse_certificate_chain( ssl, chain ); + if( ret != 0 ) + goto exit; #if defined(MBEDTLS_SSL__ECP_RESTARTABLE) if( ssl->handshake->ecrs_enabled) @@ -6055,154 +6311,71 @@ crt_verify: rs_ctx = &ssl->handshake->ecrs_ctx; #endif - if( authmode != MBEDTLS_SSL_VERIFY_NONE ) - { - mbedtls_x509_crt *ca_chain; - mbedtls_x509_crl *ca_crl; - -#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) - if( ssl->handshake->sni_ca_chain != NULL ) - { - ca_chain = ssl->handshake->sni_ca_chain; - ca_crl = ssl->handshake->sni_ca_crl; - } - else -#endif - { - ca_chain = ssl->conf->ca_chain; - ca_crl = ssl->conf->ca_crl; - } - - /* - * Main check: verify certificate - */ - ret = mbedtls_x509_crt_verify_restartable( - ssl->session_negotiate->peer_cert, - ca_chain, ca_crl, - ssl->conf->cert_profile, - ssl->hostname, - &ssl->session_negotiate->verify_result, - ssl->conf->f_vrfy, ssl->conf->p_vrfy, rs_ctx ); - - if( ret != 0 ) - { - MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret ); - } + ret = ssl_parse_certificate_verify( ssl, authmode, + chain, rs_ctx ); + if( ret != 0 ) + goto exit; -#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) - if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) - return( MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS ); -#endif +#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + { + unsigned char *crt_start, *pk_start; + size_t crt_len, pk_len; - /* - * Secondary checks: always done, but change 'ret' only if it was 0 - */ + /* We parse the CRT chain without copying, so + * these pointers point into the input buffer, + * and are hence still valid after freeing the + * CRT chain. */ -#if defined(MBEDTLS_ECP_C) - { - const mbedtls_pk_context *pk = &ssl->session_negotiate->peer_cert->pk; + crt_start = chain->raw.p; + crt_len = chain->raw.len; - /* If certificate uses an EC key, make sure the curve is OK */ - if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) && - mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id ) != 0 ) - { - ssl->session_negotiate->verify_result |= MBEDTLS_X509_BADCERT_BAD_KEY; + pk_start = chain->pk_raw.p; + pk_len = chain->pk_raw.len; - MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (EC key curve)" ) ); - if( ret == 0 ) - ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; - } - } -#endif /* MBEDTLS_ECP_C */ + /* Free the CRT structures before computing + * digest and copying the peer's public key. */ + mbedtls_x509_crt_free( chain ); + mbedtls_free( chain ); + chain = NULL; - if( mbedtls_ssl_check_cert_usage( ssl->session_negotiate->peer_cert, - ciphersuite_info, - ! ssl->conf->endpoint, - &ssl->session_negotiate->verify_result ) != 0 ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (usage extensions)" ) ); - if( ret == 0 ) - ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; - } + ret = ssl_remember_peer_crt_digest( ssl, crt_start, crt_len ); + if( ret != 0 ) + goto exit; - /* mbedtls_x509_crt_verify_with_profile is supposed to report a - * verification failure through MBEDTLS_ERR_X509_CERT_VERIFY_FAILED, - * with details encoded in the verification flags. All other kinds - * of error codes, including those from the user provided f_vrfy - * functions, are treated as fatal and lead to a failure of - * ssl_parse_certificate even if verification was optional. */ - if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL && - ( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED || - ret == MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ) ) - { - ret = 0; - } + ret = ssl_remember_peer_pubkey( ssl, pk_start, pk_len ); + if( ret != 0 ) + goto exit; + } +#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + /* Pass ownership to session structure. */ + ssl->session_negotiate->peer_cert = chain; + chain = NULL; +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ - if( ca_chain == NULL && authmode == MBEDTLS_SSL_VERIFY_REQUIRED ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no CA chain" ) ); - ret = MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED; - } + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) ); - if( ret != 0 ) - { - uint8_t alert; +exit: - /* The certificate may have been rejected for several reasons. - Pick one and send the corresponding alert. Which alert to send - may be a subject of debate in some cases. */ - if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_OTHER ) - alert = MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED; - else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_CN_MISMATCH ) - alert = MBEDTLS_SSL_ALERT_MSG_BAD_CERT; - else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_KEY_USAGE ) - alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT; - else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXT_KEY_USAGE ) - alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT; - else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NS_CERT_TYPE ) - alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT; - else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_PK ) - alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT; - else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_KEY ) - alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT; - else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXPIRED ) - alert = MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED; - else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_REVOKED ) - alert = MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED; - else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NOT_TRUSTED ) - alert = MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA; - else - alert = MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN; - mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, - alert ); - } + if( ret == 0 ) + ssl->state++; -#if defined(MBEDTLS_DEBUG_C) - if( ssl->session_negotiate->verify_result != 0 ) - { - MBEDTLS_SSL_DEBUG_MSG( 3, ( "! Certificate verification flags %x", - ssl->session_negotiate->verify_result ) ); - } - else - { - MBEDTLS_SSL_DEBUG_MSG( 3, ( "Certificate verification flags clear" ) ); - } -#endif /* MBEDTLS_DEBUG_C */ +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS ) + { + ssl->handshake->ecrs_peer_cert = chain; + chain = NULL; } +#endif - ssl->state++; - - MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) ); + if( chain != NULL ) + { + mbedtls_x509_crt_free( chain ); + mbedtls_free( chain ); + } return( ret ); } -#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED - !MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED - !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED - !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED - !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED - !MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED - !MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ int mbedtls_ssl_write_change_cipher_spec( mbedtls_ssl_context *ssl ) { @@ -7065,6 +7238,11 @@ static void ssl_handshake_params_init( mbedtls_ssl_handshake_params *handshake ) #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) handshake->sni_authmode = MBEDTLS_SSL_VERIFY_UNSET; #endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) && \ + !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + mbedtls_pk_init( &handshake->peer_pubkey ); +#endif } static void ssl_transform_init( mbedtls_ssl_transform *transform ) @@ -7614,7 +7792,8 @@ int mbedtls_ssl_set_session( mbedtls_ssl_context *ssl, const mbedtls_ssl_session return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); } - if( ( ret = ssl_session_copy( ssl->session_negotiate, session ) ) != 0 ) + if( ( ret = mbedtls_ssl_session_copy( ssl->session_negotiate, + session ) ) != 0 ) return( ret ); ssl->handshake->resume = 1; @@ -8533,12 +8712,17 @@ const mbedtls_x509_crt *mbedtls_ssl_get_peer_cert( const mbedtls_ssl_context *ss if( ssl == NULL || ssl->session == NULL ) return( NULL ); +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) return( ssl->session->peer_cert ); +#else + return( NULL ); +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ } #endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_SSL_CLI_C) -int mbedtls_ssl_get_session( const mbedtls_ssl_context *ssl, mbedtls_ssl_session *dst ) +int mbedtls_ssl_get_session( const mbedtls_ssl_context *ssl, + mbedtls_ssl_session *dst ) { if( ssl == NULL || dst == NULL || @@ -8548,7 +8732,7 @@ int mbedtls_ssl_get_session( const mbedtls_ssl_context *ssl, mbedtls_ssl_session return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); } - return( ssl_session_copy( dst, ssl->session ) ); + return( mbedtls_ssl_session_copy( dst, ssl->session ) ); } #endif /* MBEDTLS_SSL_CLI_C */ @@ -9402,8 +9586,18 @@ void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ) #if defined(MBEDTLS_SSL__ECP_RESTARTABLE) mbedtls_x509_crt_restart_free( &handshake->ecrs_ctx ); + if( handshake->ecrs_peer_cert != NULL ) + { + mbedtls_x509_crt_free( handshake->ecrs_peer_cert ); + mbedtls_free( handshake->ecrs_peer_cert ); + } #endif +#if defined(MBEDTLS_X509_CRT_PARSE_C) && \ + !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + mbedtls_pk_free( &handshake->peer_pubkey ); +#endif /* MBEDTLS_X509_CRT_PARSE_C && !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + #if defined(MBEDTLS_SSL_PROTO_DTLS) mbedtls_free( handshake->verify_cookie ); ssl_flight_free( handshake->flight ); @@ -9425,11 +9619,7 @@ void mbedtls_ssl_session_free( mbedtls_ssl_session *session ) return; #if defined(MBEDTLS_X509_CRT_PARSE_C) - if( session->peer_cert != NULL ) - { - mbedtls_x509_crt_free( session->peer_cert ); - mbedtls_free( session->peer_cert ); - } + ssl_clear_peer_cert( session ); #endif #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) |