Parse and verify peer CRT chain in local variable
`mbedtls_ssl_parse_certificate()` parses the peer's certificate chain
directly into the `peer_cert` field of the `mbedtls_ssl_session`
structure being established. To allow to optionally remove this field
from the session structure, this commit changes this to parse the peer's
chain into a local variable instead first, which can then either be freed
after CRT verification - in case the chain should not be stored - or
mapped to the `peer_cert` if it should be kept. For now, only the latter
is implemented.
diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index e76f4f8..7cd0d1c 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -331,6 +331,9 @@
ssl_ecrs_cke_ecdh_calc_secret, /*!< ClientKeyExchange: ECDH step 2 */
ssl_ecrs_crt_vrfy_sign, /*!< CertificateVerify: pk_sign() */
} ecrs_state; /*!< current (or last) operation */
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+ mbedtls_x509_crt *ecrs_peer_cert; /*!< The peer's CRT chain. */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
size_t ecrs_n; /*!< place for saving a length */
#endif
#if defined(MBEDTLS_SSL_PROTO_DTLS)
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index d4df533..4ca8f32 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -6176,6 +6176,7 @@
const int authmode = ssl->conf->authmode;
#endif
void *rs_ctx = NULL;
+ mbedtls_x509_crt *chain = NULL;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) );
@@ -6190,6 +6191,8 @@
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
@@ -6199,7 +6202,7 @@
/* 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 defined(MBEDTLS_SSL_SRV_C)
@@ -6219,22 +6222,24 @@
/* 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 );
- ssl->session_negotiate->peer_cert =
- mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) );
- if( ssl->session_negotiate->peer_cert == NULL )
+
+ 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 );
- return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
- }
- mbedtls_x509_crt_init( ssl->session_negotiate->peer_cert );
- ret = ssl_parse_certificate_chain( ssl, ssl->session_negotiate->peer_cert );
+ ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
+ goto exit;
+ }
+ mbedtls_x509_crt_init( chain );
+
+ ret = ssl_parse_certificate_chain( ssl, chain );
if( ret != 0 )
- return( ret );
+ goto exit;
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
if( ssl->handshake->ecrs_enabled)
@@ -6246,12 +6251,12 @@
#endif
ret = ssl_parse_certificate_verify( ssl, authmode,
- ssl->session_negotiate->peer_cert,
- rs_ctx );
+ chain, rs_ctx );
if( ret != 0 )
- return( ret );
+ goto exit;
#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+
/* Remember digest of the peer's end-CRT. */
ssl->session_negotiate->peer_cert_digest =
mbedtls_calloc( 1, MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN );
@@ -6262,15 +6267,16 @@
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_ERR_SSL_ALLOC_FAILED;
+ goto exit;
}
ret = mbedtls_md( mbedtls_md_info_from_type(
- MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE ),
- ssl->session_negotiate->peer_cert->raw.p,
- ssl->session_negotiate->peer_cert->raw.len,
+ MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE ),
+ chain->raw.p, chain->raw.len,
ssl->session_negotiate->peer_cert_digest );
if( ret != 0 )
- return( ret );
+ goto exit;
ssl->session_negotiate->peer_cert_digest_type =
MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE;
@@ -6278,11 +6284,30 @@
MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN;
#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+ ssl->session_negotiate->peer_cert = chain;
+ chain = NULL;
+
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) );
exit:
- ssl->state++;
+ if( ret == 0 )
+ ssl->state++;
+
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+ if( ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS )
+ {
+ ssl->handshake->ecrs_peer_cert = chain;
+ chain = NULL;
+ }
+#endif
+
+ if( chain != NULL )
+ {
+ mbedtls_x509_crt_free( chain );
+ mbedtls_free( chain );
+ }
+
return( ret );
}
#endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */
@@ -9487,6 +9512,11 @@
#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_SSL_PROTO_DTLS)