Merge remote-tracking branch 'public/pr/2421' into development

* public/pr/2421: (68 commits)
  Fix unused variable warning in ssl_parse_certificate_coordinate()
  Add missing compile time guard in ssl_client2
  Update programs/ssl/query_config.c
  ssl_client2: Reset peer CRT info string on reconnect
  Add further debug statements on assertion failures
  Fix typo in documentation of ssl_parse_certificate_chain()
  Add debug output in case of assertion failure
  Fix typo in SSL ticket documentation
  Add config sanity check for !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
  ssl_client2: Zeroize peer CRT info buffer when reconnecting
  Reintroduce numerous ssl-opt.sh tests if !MBEDTLS_SSL_KEEP_PEER_CERT
  ssl_client2: Extract peer CRT info from verification callback
  Improve documentation of mbedtls_ssl_get_peer_cert()
  Improve documentation of MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
  Fix indentation of Doxygen comment in ssl_internal.h
  Set peer CRT length only after successful allocation
  Remove question in comment about verify flags on cli vs. server
  Remove misleading and redundant guard around restartable ECC field
  Add test for !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE to all.sh
  Free peer CRT chain immediately after verifying it
  ...
This commit is contained in:
Simon Butcher 2019-03-01 12:46:07 +00:00
commit 535ee4a35b
19 changed files with 901 additions and 452 deletions

View File

@ -16,6 +16,13 @@ Features
API Changes
* Add a new X.509 API call `mbedtls_x509_parse_der_nocopy()`.
See the Features section for more information.
* Allow to opt in to the removal the API mbedtls_ssl_get_peer_cert()
for the benefit of saving RAM, by disabling the new compile-time
option MBEDTLS_SSL_KEEP_PEER_CERTIFICATE (enabled by default for
API stability). Disabling this option makes mbedtls_ssl_get_peer_cert()
always return NULL, and removes the peer_cert field from the
mbedtls_ssl_session structure which otherwise stores the peer's
certificate.
Bugfix
* Fix a compilation issue with mbedtls_ecp_restart_ctx not being defined

View File

@ -280,6 +280,14 @@
#error "MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) && \
!defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) && \
( !defined(MBEDTLS_SHA256_C) && \
!defined(MBEDTLS_SHA512_C) && \
!defined(MBEDTLS_SHA1_C) )
#error "!MBEDTLS_SSL_KEEP_PEER_CERTIFICATE requires MBEDTLS_SHA512_C, MBEDTLS_SHA256_C or MBEDTLS_SHA1_C"
#endif
#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) && \
( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
#error "MBEDTLS_MEMORY_BUFFER_ALLOC_C defined, but not all prerequisites"

View File

@ -1374,6 +1374,28 @@
*/
#define MBEDTLS_SSL_FALLBACK_SCSV
/**
* \def MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
*
* This option controls the availability of the API mbedtls_ssl_get_peer_cert()
* giving access to the peer's certificate after completion of the handshake.
*
* Unless you need mbedtls_ssl_peer_cert() in your application, it is
* recommended to disable this option for reduced RAM usage.
*
* \note If this option is disabled, mbedtls_ssl_get_peer_cert() is still
* defined, but always returns \c NULL.
*
* \note This option has no influence on the protection against the
* triple handshake attack. Even if it is disabled, Mbed TLS will
* still ensure that certificates do not change during renegotiation,
* for exaple by keeping a hash of the peer's certificate.
*
* Comment this macro to disable storing the peer's certificate
* after the handshake.
*/
#define MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
/**
* \def MBEDTLS_SSL_HW_RECORD_ACCEL
*

View File

@ -787,6 +787,25 @@ 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_KEY_EXCHANGE__WITH_CERT__ENABLED) && \
!defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
#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
/* This is already checked in check_config.h, but be sure. */
#error "Bad configuration - need SHA-1, SHA-256 or SHA-512 enabled to compute digest of peer CRT."
#endif
#endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED &&
!MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
/*
* This structure is used for storing current session data.
*/
@ -802,7 +821,15 @@ struct mbedtls_ssl_session
unsigned char master[48]; /*!< the master secret */
#if defined(MBEDTLS_X509_CRT_PARSE_C)
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
mbedtls_x509_crt *peer_cert; /*!< peer X.509 cert chain */
#else /* 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 */
@ -2972,18 +2999,34 @@ int mbedtls_ssl_get_max_out_record_payload( const mbedtls_ssl_context *ssl );
#if defined(MBEDTLS_X509_CRT_PARSE_C)
/**
* \brief Return the peer certificate from the current connection
* \brief Return the peer certificate from the current connection.
*
* Note: Can be NULL in case no certificate was sent during
* the handshake. Different calls for the same connection can
* return the same or different pointers for the same
* certificate and even a different certificate altogether.
* The peer cert CAN change in a single connection if
* renegotiation is performed.
* \param ssl The SSL context to use. This must be initialized and setup.
*
* \param ssl SSL context
* \return The current peer certificate, if available.
* The returned certificate is owned by the SSL context and
* is valid only until the next call to the SSL API.
* \return \c NULL if no peer certificate is available. This might
* be because the chosen ciphersuite doesn't use CRTs
* (PSK-based ciphersuites, for example), or because
* #MBEDTLS_SSL_KEEP_PEER_CERTIFICATE has been disabled,
* allowing the stack to free the peer's CRT to save memory.
*
* \return the current peer certificate
* \note For one-time inspection of the peer's certificate during
* the handshake, consider registering an X.509 CRT verification
* callback through mbedtls_ssl_conf_verify() instead of calling
* this function. Using mbedtls_ssl_conf_verify() also comes at
* the benefit of allowing you to influence the verification
* process, for example by masking expected and tolerated
* verification failures.
*
* \warning You must not use the pointer returned by this function
* after any further call to the SSL API, including
* mbedtls_ssl_read() and mbedtls_ssl_write(); this is
* because the pointer might change during renegotiation,
* which happens transparently to the user.
* If you want to use the certificate across API calls,
* you must make a copy.
*/
const mbedtls_x509_crt *mbedtls_ssl_get_peer_cert( const mbedtls_ssl_context *ssl );
#endif /* MBEDTLS_X509_CRT_PARSE_C */

View File

@ -70,7 +70,8 @@ struct mbedtls_ssl_cache_entry
mbedtls_time_t timestamp; /*!< entry timestamp */
#endif
mbedtls_ssl_session session; /*!< entry session */
#if defined(MBEDTLS_X509_CRT_PARSE_C)
#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
mbedtls_x509_buf peer_cert; /*!< entry peer_cert */
#endif
mbedtls_ssl_cache_entry *next; /*!< chain pointer */

View File

@ -486,6 +486,24 @@ static inline int mbedtls_ssl_ciphersuite_cert_req_allowed( const mbedtls_ssl_ci
}
}
static inline int mbedtls_ssl_ciphersuite_uses_srv_cert( const mbedtls_ssl_ciphersuite_t *info )
{
switch( info->key_exchange )
{
case MBEDTLS_KEY_EXCHANGE_RSA:
case MBEDTLS_KEY_EXCHANGE_RSA_PSK:
case MBEDTLS_KEY_EXCHANGE_DHE_RSA:
case MBEDTLS_KEY_EXCHANGE_ECDH_RSA:
case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA:
case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA:
case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA:
return( 1 );
default:
return( 0 );
}
}
#if defined(MBEDTLS_KEY_EXCHANGE__SOME__DHE_ENABLED)
static inline int mbedtls_ssl_ciphersuite_uses_dhe( const mbedtls_ssl_ciphersuite_t *info )
{

View File

@ -331,8 +331,13 @@ struct mbedtls_ssl_handshake_params
ssl_ecrs_cke_ecdh_calc_secret, /*!< ClientKeyExchange: ECDH step 2 */
ssl_ecrs_crt_vrfy_sign, /*!< CertificateVerify: pk_sign() */
} ecrs_state; /*!< current (or last) operation */
mbedtls_x509_crt *ecrs_peer_cert; /*!< The peer's CRT chain. */
size_t ecrs_n; /*!< place for saving a length */
#endif
#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
!defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
mbedtls_pk_context peer_pubkey; /*!< The public key from the peer. */
#endif /* MBEDTLS_X509_CRT_PARSE_C && !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
#if defined(MBEDTLS_SSL_PROTO_DTLS)
unsigned int out_msg_seq; /*!< Outgoing handshake sequence number */
unsigned int in_msg_seq; /*!< Incoming handshake sequence number */
@ -766,6 +771,9 @@ int mbedtls_ssl_dtls_replay_check( mbedtls_ssl_context *ssl );
void mbedtls_ssl_dtls_replay_update( mbedtls_ssl_context *ssl );
#endif
int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst,
const mbedtls_ssl_session *src );
/* constant-time buffer comparison */
static inline int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n )
{

View File

@ -70,6 +70,7 @@ typedef struct mbedtls_x509_crt
mbedtls_x509_time valid_from; /**< Start time of certificate validity. */
mbedtls_x509_time valid_to; /**< End time of certificate validity. */
mbedtls_x509_buf pk_raw;
mbedtls_pk_context pk; /**< Container for the public key context. */
mbedtls_x509_buf issuer_id; /**< Optional X.509 v2/v3 issuer unique identifier. */

View File

@ -40,6 +40,7 @@
#endif
#include "mbedtls/ssl_cache.h"
#include "mbedtls/ssl_internal.h"
#include <string.h>
@ -92,16 +93,24 @@ int mbedtls_ssl_cache_get( void *data, mbedtls_ssl_session *session )
entry->session.id_len ) != 0 )
continue;
memcpy( session->master, entry->session.master, 48 );
ret = mbedtls_ssl_session_copy( session, &entry->session );
if( ret != 0 )
{
ret = 1;
goto exit;
}
session->verify_result = entry->session.verify_result;
#if defined(MBEDTLS_X509_CRT_PARSE_C)
#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
/*
* Restore peer certificate (without rest of the original chain)
*/
if( entry->peer_cert.p != NULL )
{
/* `session->peer_cert` is NULL after the call to
* mbedtls_ssl_session_copy(), because cache entries
* have the `peer_cert` field set to NULL. */
if( ( session->peer_cert = mbedtls_calloc( 1,
sizeof(mbedtls_x509_crt) ) ) == NULL )
{
@ -119,7 +128,7 @@ int mbedtls_ssl_cache_get( void *data, mbedtls_ssl_session *session )
goto exit;
}
}
#endif /* MBEDTLS_X509_CRT_PARSE_C */
#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
ret = 0;
goto exit;
@ -239,9 +248,8 @@ int mbedtls_ssl_cache_set( void *data, const mbedtls_ssl_session *session )
#endif
}
memcpy( &cur->session, session, sizeof( mbedtls_ssl_session ) );
#if defined(MBEDTLS_X509_CRT_PARSE_C)
#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
/*
* If we're reusing an entry, free its certificate first
*/
@ -250,26 +258,43 @@ int mbedtls_ssl_cache_set( void *data, const mbedtls_ssl_session *session )
mbedtls_free( cur->peer_cert.p );
memset( &cur->peer_cert, 0, sizeof(mbedtls_x509_buf) );
}
#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
/*
* Store peer certificate
*/
if( session->peer_cert != NULL )
/* Copy the entire session; this temporarily makes a copy of the
* X.509 CRT structure even though we only want to store the raw CRT.
* This inefficiency will go away as soon as we implement on-demand
* parsing of CRTs, in which case there's no need for the `peer_cert`
* field anymore in the first place, and we're done after this call. */
ret = mbedtls_ssl_session_copy( &cur->session, session );
if( ret != 0 )
{
cur->peer_cert.p = mbedtls_calloc( 1, session->peer_cert->raw.len );
ret = 1;
goto exit;
}
#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
/* If present, free the X.509 structure and only store the raw CRT data. */
if( cur->session.peer_cert != NULL )
{
cur->peer_cert.p =
mbedtls_calloc( 1, cur->session.peer_cert->raw.len );
if( cur->peer_cert.p == NULL )
{
ret = 1;
goto exit;
}
memcpy( cur->peer_cert.p, session->peer_cert->raw.p,
session->peer_cert->raw.len );
memcpy( cur->peer_cert.p,
cur->session.peer_cert->raw.p,
cur->session.peer_cert->raw.len );
cur->peer_cert.len = session->peer_cert->raw.len;
mbedtls_x509_crt_free( cur->session.peer_cert );
mbedtls_free( cur->session.peer_cert );
cur->session.peer_cert = NULL;
}
#endif /* MBEDTLS_X509_CRT_PARSE_C */
#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
ret = 0;
@ -311,9 +336,10 @@ void mbedtls_ssl_cache_free( mbedtls_ssl_cache_context *cache )
mbedtls_ssl_session_free( &prv->session );
#if defined(MBEDTLS_X509_CRT_PARSE_C)
#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
mbedtls_free( prv->peer_cert.p );
#endif /* MBEDTLS_X509_CRT_PARSE_C */
#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
mbedtls_free( prv );
}

View File

@ -2265,6 +2265,7 @@ static int ssl_write_encrypted_pms( mbedtls_ssl_context *ssl,
int ret;
size_t len_bytes = ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ? 0 : 2;
unsigned char *p = ssl->handshake->premaster + pms_offset;
mbedtls_pk_context * peer_pk;
if( offset + len_bytes > MBEDTLS_SSL_OUT_CONTENT_LEN )
{
@ -2290,23 +2291,28 @@ static int ssl_write_encrypted_pms( mbedtls_ssl_context *ssl,
ssl->handshake->pmslen = 48;
#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
peer_pk = &ssl->handshake->peer_pubkey;
#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
if( ssl->session_negotiate->peer_cert == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) );
return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
/* Should never happen */
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
peer_pk = &ssl->session_negotiate->peer_cert->pk;
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
/*
* Now write it out, encrypted
*/
if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk,
MBEDTLS_PK_RSA ) )
if( ! mbedtls_pk_can_do( peer_pk, MBEDTLS_PK_RSA ) )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "certificate key type mismatch" ) );
return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH );
}
if( ( ret = mbedtls_pk_encrypt( &ssl->session_negotiate->peer_cert->pk,
if( ( ret = mbedtls_pk_encrypt( peer_pk,
p, ssl->handshake->pmslen,
ssl->out_msg + offset + len_bytes, olen,
MBEDTLS_SSL_OUT_CONTENT_LEN - offset - len_bytes,
@ -2326,6 +2332,10 @@ static int ssl_write_encrypted_pms( mbedtls_ssl_context *ssl,
}
#endif
#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
/* We don't need the peer's public key anymore. Free it. */
mbedtls_pk_free( peer_pk );
#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
return( 0 );
}
#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED ||
@ -2401,21 +2411,27 @@ static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl )
{
int ret;
const mbedtls_ecp_keypair *peer_key;
mbedtls_pk_context * peer_pk;
#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
peer_pk = &ssl->handshake->peer_pubkey;
#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
if( ssl->session_negotiate->peer_cert == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) );
return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
/* Should never happen */
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
peer_pk = &ssl->session_negotiate->peer_cert->pk;
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk,
MBEDTLS_PK_ECKEY ) )
if( ! mbedtls_pk_can_do( peer_pk, MBEDTLS_PK_ECKEY ) )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "server key not ECDH capable" ) );
return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH );
}
peer_key = mbedtls_pk_ec( ssl->session_negotiate->peer_cert->pk );
peer_key = mbedtls_pk_ec( *peer_pk );
if( ( ret = mbedtls_ecdh_get_params( &ssl->handshake->ecdh_ctx, peer_key,
MBEDTLS_ECDH_THEIRS ) ) != 0 )
@ -2430,6 +2446,13 @@ static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl )
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
}
#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
/* We don't need the peer's public key anymore. Free it,
* so that more RAM is available for upcoming expensive
* operations like ECDHE. */
mbedtls_pk_free( peer_pk );
#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
return( ret );
}
#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) ||
@ -2640,6 +2663,8 @@ start_processing:
size_t params_len = p - params;
void *rs_ctx = NULL;
mbedtls_pk_context * peer_pk;
/*
* Handle the digitally-signed structure
*/
@ -2742,18 +2767,22 @@ start_processing:
MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen );
#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
peer_pk = &ssl->handshake->peer_pubkey;
#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
if( ssl->session_negotiate->peer_cert == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
/* Should never happen */
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
peer_pk = &ssl->session_negotiate->peer_cert->pk;
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
/*
* Verify signature
*/
if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk, pk_alg ) )
if( !mbedtls_pk_can_do( peer_pk, pk_alg ) )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
@ -2766,8 +2795,7 @@ start_processing:
rs_ctx = &ssl->handshake->ecrs_ctx.pk;
#endif
if( ( ret = mbedtls_pk_verify_restartable(
&ssl->session_negotiate->peer_cert->pk,
if( ( ret = mbedtls_pk_verify_restartable( peer_pk,
md_alg, hash, hashlen, p, sig_len, rs_ctx ) ) != 0 )
{
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
@ -2782,6 +2810,13 @@ start_processing:
#endif
return( ret );
}
#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
/* We don't need the peer's public key anymore. Free it,
* so that more RAM is available for upcoming expensive
* operations like ECDHE. */
mbedtls_pk_free( peer_pk );
#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
}
#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */
@ -3456,12 +3491,7 @@ ecdh_calc_secret:
return( 0 );
}
#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \
!defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \
!defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) && \
!defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \
!defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)&& \
!defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
#if !defined(MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED)
static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl )
{
const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
@ -3476,11 +3506,7 @@ static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl )
return( ret );
}
if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) );
ssl->state++;
@ -3490,7 +3516,7 @@ static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl )
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
#else
#else /* !MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */
static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl )
{
int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
@ -3519,11 +3545,7 @@ static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl )
return( ret );
}
if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) );
ssl->state++;
@ -3666,12 +3688,7 @@ sign:
return( ret );
}
#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED &&
!MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED &&
!MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED &&
!MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED &&
!MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED &&
!MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */
#endif /* MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */
#if defined(MBEDTLS_SSL_SESSION_TICKETS)
static int ssl_parse_new_session_ticket( mbedtls_ssl_context *ssl )

View File

@ -2680,12 +2680,7 @@ static int ssl_write_server_hello( mbedtls_ssl_context *ssl )
return( ret );
}
#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \
!defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \
!defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) && \
!defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \
!defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)&& \
!defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
#if !defined(MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED)
static int ssl_write_certificate_request( mbedtls_ssl_context *ssl )
{
const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
@ -2693,11 +2688,7 @@ static int ssl_write_certificate_request( mbedtls_ssl_context *ssl )
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate request" ) );
if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_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_cert_req_allowed( ciphersuite_info ) )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate request" ) );
ssl->state++;
@ -2707,7 +2698,7 @@ static int ssl_write_certificate_request( mbedtls_ssl_context *ssl )
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
#else
#else /* !MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */
static int ssl_write_certificate_request( mbedtls_ssl_context *ssl )
{
int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
@ -2731,11 +2722,7 @@ static int ssl_write_certificate_request( mbedtls_ssl_context *ssl )
#endif
authmode = ssl->conf->authmode;
if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_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_cert_req_allowed( ciphersuite_info ) ||
authmode == MBEDTLS_SSL_VERIFY_NONE )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate request" ) );
@ -2874,12 +2861,7 @@ static int ssl_write_certificate_request( mbedtls_ssl_context *ssl )
return( ret );
}
#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED &&
!MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED &&
!MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED &&
!MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED &&
!MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED &&
!MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */
#endif /* MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */
#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \
defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)
@ -4048,12 +4030,7 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl )
return( 0 );
}
#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \
!defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \
!defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) && \
!defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \
!defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)&& \
!defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
#if !defined(MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED)
static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
{
const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
@ -4061,11 +4038,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) );
if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) );
ssl->state++;
@ -4075,7 +4048,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
#else
#else /* !MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */
static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
{
int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
@ -4089,21 +4062,33 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
mbedtls_md_type_t md_alg;
const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
ssl->transform_negotiate->ciphersuite_info;
mbedtls_pk_context * peer_pk;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) );
if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ||
ssl->session_negotiate->peer_cert == NULL )
if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) );
ssl->state++;
return( 0 );
}
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
if( ssl->session_negotiate->peer_cert == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) );
ssl->state++;
return( 0 );
}
#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
if( ssl->session_negotiate->peer_cert_digest == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) );
ssl->state++;
return( 0 );
}
#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
/* Read the message without adding it to the checksum */
ret = mbedtls_ssl_read_record( ssl, 0 /* no checksum update */ );
if( 0 != ret )
@ -4124,6 +4109,17 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
i = mbedtls_ssl_hs_hdr_len( ssl );
#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
peer_pk = &ssl->handshake->peer_pubkey;
#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
if( ssl->session_negotiate->peer_cert == NULL )
{
/* Should never happen */
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
peer_pk = &ssl->session_negotiate->peer_cert->pk;
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
/*
* struct {
* SignatureAndHashAlgorithm algorithm; -- TLS 1.2 only
@ -4138,8 +4134,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
hashlen = 36;
/* For ECDSA, use SHA-1, not MD-5 + SHA-1 */
if( mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk,
MBEDTLS_PK_ECDSA ) )
if( mbedtls_pk_can_do( peer_pk, MBEDTLS_PK_ECDSA ) )
{
hash_start += 16;
hashlen -= 16;
@ -4194,7 +4189,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
/*
* Check the certificate's key type matches the signature alg
*/
if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk, pk_alg ) )
if( !mbedtls_pk_can_do( peer_pk, pk_alg ) )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "sig_alg doesn't match cert key" ) );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
@ -4227,7 +4222,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
/* Calculate hash and verify signature */
ssl->handshake->calc_verify( ssl, hash );
if( ( ret = mbedtls_pk_verify( &ssl->session_negotiate->peer_cert->pk,
if( ( ret = mbedtls_pk_verify( peer_pk,
md_alg, hash_start, hashlen,
ssl->in_msg + i, sig_len ) ) != 0 )
{
@ -4241,12 +4236,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
return( ret );
}
#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED &&
!MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED &&
!MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED &&
!MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED &&
!MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED &&
!MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */
#endif /* MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */
#if defined(MBEDTLS_SSL_SESSION_TICKETS)
static int ssl_write_new_session_ticket( mbedtls_ssl_context *ssl )

View File

@ -187,9 +187,16 @@ int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx,
/*
* Serialize a session in the following format:
*
* - If MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is enabled:
* 0 . n-1 session structure, n = sizeof(mbedtls_ssl_session)
* n . n+2 peer_cert length = m (0 if no certificate)
* n+3 . n+2+m peer cert ASN.1
*
* - If MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is disabled:
* 0 . n-1 session structure, n = sizeof(mbedtls_ssl_session)
* n . n length of peer certificate digest = k (0 if no digest)
* n+1 . n+k peer certificate digest (digest type encoded in session)
*/
static int ssl_save_session( const mbedtls_ssl_session *session,
unsigned char *buf, size_t buf_len,
@ -198,17 +205,25 @@ static int ssl_save_session( const mbedtls_ssl_session *session,
unsigned char *p = buf;
size_t left = buf_len;
#if defined(MBEDTLS_X509_CRT_PARSE_C)
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
size_t cert_len;
#else
size_t cert_digest_len;
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
#endif /* MBEDTLS_X509_CRT_PARSE_C */
if( left < sizeof( mbedtls_ssl_session ) )
return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
/* This also copies the values of pointer fields in the
* session to be serialized, but they'll be ignored when
* loading the session through ssl_load_session(). */
memcpy( p, session, sizeof( mbedtls_ssl_session ) );
p += sizeof( mbedtls_ssl_session );
left -= sizeof( mbedtls_ssl_session );
#if defined(MBEDTLS_X509_CRT_PARSE_C)
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
if( session->peer_cert == NULL )
cert_len = 0;
else
@ -220,11 +235,31 @@ static int ssl_save_session( const mbedtls_ssl_session *session,
*p++ = (unsigned char)( ( cert_len >> 16 ) & 0xFF );
*p++ = (unsigned char)( ( cert_len >> 8 ) & 0xFF );
*p++ = (unsigned char)( ( cert_len ) & 0xFF );
left -= 3;
if( session->peer_cert != NULL )
memcpy( p, session->peer_cert->raw.p, cert_len );
p += cert_len;
left -= cert_len;
#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
if( session->peer_cert_digest != NULL )
cert_digest_len = 0;
else
cert_digest_len = session->peer_cert_digest_len;
if( left < 1 + cert_digest_len )
return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
*p++ = (unsigned char) cert_digest_len;
left--;
if( session->peer_cert_digest != NULL )
memcpy( p, session->peer_cert_digest, cert_digest_len );
p += cert_digest_len;
left -= cert_digest_len;
#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
#endif /* MBEDTLS_X509_CRT_PARSE_C */
*olen = p - buf;
@ -241,7 +276,11 @@ static int ssl_load_session( mbedtls_ssl_session *session,
const unsigned char *p = buf;
const unsigned char * const end = buf + len;
#if defined(MBEDTLS_X509_CRT_PARSE_C)
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
size_t cert_len;
#else
size_t cert_digest_len;
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
#endif /* MBEDTLS_X509_CRT_PARSE_C */
if( sizeof( mbedtls_ssl_session ) > (size_t)( end - p ) )
@ -250,18 +289,29 @@ static int ssl_load_session( mbedtls_ssl_session *session,
memcpy( session, p, sizeof( mbedtls_ssl_session ) );
p += sizeof( mbedtls_ssl_session );
/* Non-NULL pointer fields of `session` are meaningless
* and potentially harmful. Zeroize them for safety. */
#if defined(MBEDTLS_X509_CRT_PARSE_C)
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
session->peer_cert = NULL;
#else
session->peer_cert_digest = NULL;
#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
#endif /* MBEDTLS_X509_CRT_PARSE_C */
#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
session->ticket = NULL;
#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
#if defined(MBEDTLS_X509_CRT_PARSE_C)
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
/* Deserialize CRT from the end of the ticket. */
if( 3 > (size_t)( end - p ) )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2];
p += 3;
if( cert_len == 0 )
{
session->peer_cert = NULL;
}
else
if( cert_len != 0 )
{
int ret;
@ -286,6 +336,30 @@ static int ssl_load_session( mbedtls_ssl_session *session,
p += cert_len;
}
#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
/* Deserialize CRT digest from the end of the ticket. */
if( 1 > (size_t)( end - p ) )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
cert_digest_len = (size_t) p[0];
p++;
if( cert_digest_len != 0 )
{
if( cert_digest_len > (size_t)( end - p ) ||
cert_digest_len != session->peer_cert_digest_len )
{
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
session->peer_cert_digest = mbedtls_calloc( 1, cert_digest_len );
if( session->peer_cert_digest == NULL )
return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
memcpy( session->peer_cert_digest, p, cert_digest_len );
p += cert_digest_len;
}
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
#endif /* MBEDTLS_X509_CRT_PARSE_C */
if( p != end )

View File

@ -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,16 +5883,15 @@ 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],
@ -5901,44 +5904,19 @@ static int ssl_parse_certificate_chain( mbedtls_ssl_context *ssl )
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;
/* 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 );
#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,100 +5944,103 @@ 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 =
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT )
return( -1 );
#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 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( 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 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;
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 )
{
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
const int authmode = ssl->conf->authmode;
#endif
void *rs_ctx = NULL;
((void) authmode);
#endif /* MBEDTLS_SSL_SRV_C */
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 )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
ssl->state++;
return( 0 );
return( SSL_CERTIFICATE_EXPECTED );
}
#if defined(MBEDTLS_SSL_SRV_C)
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER &&
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
ssl->state++;
return( 0 );
}
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER &&
authmode == MBEDTLS_SSL_VERIFY_NONE )
{
ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_SKIP_VERIFY;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
ssl->state++;
return( 0 );
}
#endif
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
if( ssl->handshake->ecrs_enabled &&
ssl->handshake->ecrs_state == ssl_ecrs_crt_verify )
{
goto crt_verify;
}
#endif
if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
{
/* 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 );
}
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 )
{
ret = 0;
}
#endif
ssl->state++;
return( ret );
}
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
if( ssl->handshake->ecrs_enabled)
ssl->handshake->ecrs_state = ssl_ecrs_crt_verify;
crt_verify:
if( ssl->handshake->ecrs_enabled)
rs_ctx = &ssl->handshake->ecrs_ctx;
#endif
if( authmode != MBEDTLS_SSL_VERIFY_NONE )
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 )
{
@ -6077,7 +6058,7 @@ crt_verify:
* Main check: verify certificate
*/
ret = mbedtls_x509_crt_verify_restartable(
ssl->session_negotiate->peer_cert,
chain,
ca_chain, ca_crl,
ssl->conf->cert_profile,
ssl->hostname,
@ -6100,7 +6081,7 @@ crt_verify:
#if defined(MBEDTLS_ECP_C)
{
const mbedtls_pk_context *pk = &ssl->session_negotiate->peer_cert->pk;
const mbedtls_pk_context *pk = &chain->pk;
/* If certificate uses an EC key, make sure the curve is OK */
if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) &&
@ -6115,7 +6096,7 @@ crt_verify:
}
#endif /* MBEDTLS_ECP_C */
if( mbedtls_ssl_check_cert_usage( ssl->session_negotiate->peer_cert,
if( mbedtls_ssl_check_cert_usage( chain,
ciphersuite_info,
! ssl->conf->endpoint,
&ssl->session_negotiate->verify_result ) != 0 )
@ -6188,21 +6169,213 @@ crt_verify:
MBEDTLS_SSL_DEBUG_MSG( 3, ( "Certificate verification flags clear" ) );
}
#endif /* MBEDTLS_DEBUG_C */
}
ssl->state++;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) );
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 */
#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
if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
{
/* 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 );
goto exit;
}
#if defined(MBEDTLS_SSL_SRV_C)
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;
else
ret = MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE;
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)
ssl->handshake->ecrs_state = ssl_ecrs_crt_verify;
crt_verify:
if( ssl->handshake->ecrs_enabled)
rs_ctx = &ssl->handshake->ecrs_ctx;
#endif
ret = ssl_parse_certificate_verify( ssl, authmode,
chain, rs_ctx );
if( ret != 0 )
goto exit;
#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
{
unsigned char *crt_start, *pk_start;
size_t crt_len, pk_len;
/* 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. */
crt_start = chain->raw.p;
crt_len = chain->raw.len;
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 )
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 */
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) );
exit:
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 */
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)

View File

@ -459,6 +459,9 @@ static const char *features[] = {
#if defined(MBEDTLS_SSL_FALLBACK_SCSV)
"MBEDTLS_SSL_FALLBACK_SCSV",
#endif /* MBEDTLS_SSL_FALLBACK_SCSV */
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
"MBEDTLS_SSL_KEEP_PEER_CERTIFICATE",
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL)
"MBEDTLS_SSL_HW_RECORD_ACCEL",
#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */

View File

@ -996,11 +996,13 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt,
/*
* SubjectPublicKeyInfo
*/
crt->pk_raw.p = p;
if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &crt->pk ) ) != 0 )
{
mbedtls_x509_crt_free( crt );
return( ret );
}
crt->pk_raw.len = p - crt->pk_raw.p;
/*
* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,

View File

@ -1266,6 +1266,14 @@ int query_config( const char *config )
}
#endif /* MBEDTLS_SSL_FALLBACK_SCSV */
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
if( strcmp( "MBEDTLS_SSL_KEEP_PEER_CERTIFICATE", config ) == 0 )
{
MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_KEEP_PEER_CERTIFICATE );
return( 0 );
}
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL)
if( strcmp( "MBEDTLS_SSL_HW_RECORD_ACCEL", config ) == 0 )
{

View File

@ -478,6 +478,8 @@ static int my_send( void *ctx, const unsigned char *buf, size_t len )
}
#if defined(MBEDTLS_X509_CRT_PARSE_C)
static unsigned char peer_crt_info[1024];
/*
* Enabled if debug_level > 1 in code below
*/
@ -487,8 +489,14 @@ static int my_verify( void *data, mbedtls_x509_crt *crt,
char buf[1024];
((void) data);
mbedtls_printf( "\nVerify requested for (Depth %d):\n", depth );
mbedtls_x509_crt_info( buf, sizeof( buf ) - 1, "", crt );
if( depth == 0 )
memcpy( peer_crt_info, buf, sizeof( buf ) );
if( opt.debug_level == 0 )
return( 0 );
mbedtls_printf( "\nVerify requested for (Depth %d):\n", depth );
mbedtls_printf( "%s", buf );
if ( ( *flags ) == 0 )
@ -1503,8 +1511,8 @@ int main( int argc, char *argv[] )
mbedtls_ssl_conf_sig_hashes( &conf, ssl_sig_hashes_for_test );
}
if( opt.debug_level > 0 )
mbedtls_ssl_conf_verify( &conf, my_verify, NULL );
memset( peer_crt_info, 0, sizeof( peer_crt_info ) );
#endif /* MBEDTLS_X509_CRT_PARSE_C */
if( opt.auth_mode != DFL_AUTH_MODE )
@ -1833,13 +1841,8 @@ int main( int argc, char *argv[] )
else
mbedtls_printf( " ok\n" );
if( mbedtls_ssl_get_peer_cert( &ssl ) != NULL )
{
mbedtls_printf( " . Peer certificate information ...\n" );
mbedtls_x509_crt_info( (char *) buf, sizeof( buf ) - 1, " ",
mbedtls_ssl_get_peer_cert( &ssl ) );
mbedtls_printf( "%s\n", buf );
}
mbedtls_printf( "%s\n", peer_crt_info );
#endif /* MBEDTLS_X509_CRT_PARSE_C */
#if defined(MBEDTLS_SSL_RENEGOTIATION)
@ -2144,6 +2147,10 @@ send_request:
mbedtls_printf( " . Restarting connection from same port..." );
fflush( stdout );
#if defined(MBEDTLS_X509_CRT_PARSE_C)
memset( peer_crt_info, 0, sizeof( peer_crt_info ) );
#endif /* MBEDTLS_X509_CRT_PARSE_C */
if( ( ret = mbedtls_ssl_session_reset( &ssl ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_session_reset returned -0x%x\n\n",
@ -2215,6 +2222,10 @@ reconnect:
mbedtls_printf( " . Reconnecting with saved session..." );
#if defined(MBEDTLS_X509_CRT_PARSE_C)
memset( peer_crt_info, 0, sizeof( peer_crt_info ) );
#endif /* MBEDTLS_X509_CRT_PARSE_C */
if( ( ret = mbedtls_ssl_session_reset( &ssl ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_session_reset returned -0x%x\n\n",

View File

@ -467,9 +467,12 @@ int main( int argc, char *argv[] )
/*
* 5. Print the certificate
*/
#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
mbedtls_printf( " . Peer certificate information ... skipped\n" );
#else
mbedtls_printf( " . Peer certificate information ...\n" );
ret = mbedtls_x509_crt_info( (char *) buf, sizeof( buf ) - 1, " ",
ssl.session->peer_cert );
mbedtls_ssl_get_peer_cert( &ssl ) );
if( ret == -1 )
{
mbedtls_printf( " failed\n ! mbedtls_x509_crt_info returned %d\n\n", ret );
@ -477,6 +480,7 @@ int main( int argc, char *argv[] )
}
mbedtls_printf( "%s\n", buf );
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
mbedtls_ssl_close_notify( &ssl );

View File

@ -968,6 +968,22 @@ component_test_no_max_fragment_length () {
if_build_succeeded tests/ssl-opt.sh -f "Max fragment length"
}
component_test_asan_remove_peer_certificate () {
msg "build: default config with MBEDTLS_SSL_KEEP_PEER_CERTIFICATE disabled (ASan build)"
scripts/config.pl unset MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
make
msg "test: !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE"
make test
msg "test: ssl-opt.sh, !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE"
if_build_succeeded tests/ssl-opt.sh
msg "test: compat.sh, !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE"
if_build_succeeded tests/compat.sh
}
component_test_no_max_fragment_length_small_ssl_out_content_len () {
msg "build: no MFL extension, small SSL_OUT_CONTENT_LEN (ASan build)"
scripts/config.pl unset MBEDTLS_SSL_MAX_FRAGMENT_LENGTH