Free peer CRT chain immediately after verifying it

If we don't need to store the peer's CRT chain permanently, we may
free it immediately after verifying it. Moreover, since we parse the
CRT chain in-place from the input buffer in this case, pointers from
the CRT structure remain valid after freeing the structure, and we
use that to extract the digest and pubkey from the CRT after freeing
the structure.
This commit is contained in:
Hanno Becker 2019-02-08 14:59:05 +00:00
parent 0cc7af5be5
commit 34106f6ae2

View file

@ -6587,6 +6587,58 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl,
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;
@ -6679,54 +6731,40 @@ crt_verify:
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 );
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 );
unsigned char *crt_start, *pk_start;
size_t crt_len, pk_len;
ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
goto exit;
}
ret = mbedtls_md( mbedtls_md_info_from_type(
MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE ),
chain->raw.p, chain->raw.len,
ssl->session_negotiate->peer_cert_digest );
if( ret != 0 )
goto exit;
/* 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. */
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;
#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
crt_start = chain->raw.p;
crt_len = chain->raw.len;
#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
/* Make a copy of the peer's raw public key. */
mbedtls_pk_init( &ssl->handshake->peer_pubkey );
{
unsigned char *p, *end;
p = chain->pk_raw.p;
end = p + chain->pk_raw.len;
ret = mbedtls_pk_parse_subpubkey( &p, end,
&ssl->handshake->peer_pubkey );
pk_start = chain->pk_raw.p;
pk_len = chain->pk_raw.len;
/* Free the CRT structures before computing
* digest and copying the peer's public key. */
mbedtls_x509_crt_free( chain );
mbedtls_free( chain );
chain = NULL;
ret = ssl_remember_peer_crt_digest( ssl, crt_start, crt_len );
if( ret != 0 )
goto exit;
ret = ssl_remember_peer_pubkey( ssl, pk_start, pk_len );
if( ret != 0 )
{
/* We should have parsed the public key before. */
ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
goto exit;
}
}
#else
#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 */
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) );