diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index d736c2101..6dcc43b93 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -787,6 +787,22 @@ typedef int mbedtls_ssl_async_resume_t( mbedtls_ssl_context *ssl, typedef void mbedtls_ssl_async_cancel_t( mbedtls_ssl_context *ssl ); #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#define MBEDTLS_SSL_PEER_CERT_DIGEST_MAX_LEN 48 +#if defined(MBEDTLS_SHA256_C) +#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE MBEDTLS_MD_SHA256 +#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN 32 +#elif defined(MBEDTLS_SHA512_C) +#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE MBEDTLS_MD_SHA384 +#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN 48 +#elif defined(MBEDTLS_SHA1_C) +#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE MBEDTLS_MD_SHA1 +#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN 20 +#else +#error "Bad configuration - need SHA-1, SHA-256 or SHA-512 enabled to compute digest of peer CRT." +#endif +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + /* * This structure is used for storing current session data. */ @@ -802,7 +818,14 @@ struct mbedtls_ssl_session unsigned char master[48]; /*!< the master secret */ #if defined(MBEDTLS_X509_CRT_PARSE_C) - mbedtls_x509_crt *peer_cert; /*!< peer X.509 cert chain */ + mbedtls_x509_crt *peer_cert; /*!< peer X.509 cert chain */ +#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + /*! The digest of the peer's end-CRT. This must be kept to detect CRT + * changes during renegotiation, mitigating the triple handshake attack. */ + unsigned char *peer_cert_digest; + size_t peer_cert_digest_len; + mbedtls_md_type_t peer_cert_digest_type; +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ #endif /* MBEDTLS_X509_CRT_PARSE_C */ uint32_t verify_result; /*!< verification result */ diff --git a/library/ssl_tls.c b/library/ssl_tls.c index ac652d2d7..26832bc96 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -304,6 +304,22 @@ int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst, return( ret ); } } + +#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + if( src->peer_cert_digest != NULL ) + { + dst->peer_cert_digest_len = src->peer_cert_digest_len; + dst->peer_cert_digest = + mbedtls_calloc( 1, dst->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; + } +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + #endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) @@ -5733,6 +5749,17 @@ static void ssl_clear_peer_cert( mbedtls_ssl_session *session ) mbedtls_free( session->peer_cert ); session->peer_cert = NULL; } + +#if !defined(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 */ } /*