Allow passing any X.509 CRT chain to ssl_parse_certificate_chain()
This commit modifies the helper `ssl_parse_certificate_chain()` to
accep any target X.509 CRT chain instead of hardcoding it to
`session_negotiate->peer_cert`. This increases modularity and paves
the way towards removing `mbedtls_ssl_session::peer_cert`.
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 01428f0..fd69763 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -5740,9 +5740,13 @@
* 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, crt_cnt=0;
+ int ret;
+#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C)
+ int crt_cnt=0;
+#endif
size_t i, n;
uint8_t alert;
@@ -5819,58 +5823,34 @@
}
/* Check if we're handling the first CRT in the chain. */
- if( crt_cnt++ == 0 )
+#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( 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 );
- }
-
- /* Now we can safely free the original chain. */
- ssl_clear_peer_cert( ssl->session );
-
- /* Intentional fallthrough. */
+ 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 );
}
+
+ /* Now we can safely free the original chain. */
+ ssl_clear_peer_cert( ssl->session );
+ }
#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( 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 );
-
- /* Intentional fall through */
- }
-
/* Parse the next certificate in the chain. */
- ret = mbedtls_x509_crt_parse_der( ssl->session_negotiate->peer_cert,
- ssl->in_msg + i, n );
+ ret = mbedtls_x509_crt_parse_der( chain, ssl->in_msg + i, n );
switch( ret )
{
case 0: /*ok*/
@@ -5898,7 +5878,7 @@
i += n;
}
- MBEDTLS_SSL_DEBUG_CRT( 3, "peer certificate", ssl->session_negotiate->peer_cert );
+ MBEDTLS_SSL_DEBUG_CRT( 3, "peer certificate", chain );
return( 0 );
}
@@ -6179,10 +6159,24 @@
}
#endif /* MBEDTLS_SSL_SRV_C */
- /* In case we tried to reuse a session but it failed. */
+ /* 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 )
+ {
+ 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 );
- if( ( ret = ssl_parse_certificate_chain( ssl ) ) != 0 )
+ ret = ssl_parse_certificate_chain( ssl, ssl->session_negotiate->peer_cert );
+ if( ret != 0 )
return( ret );
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)