Commit 863dfb59 authored by Nathaniel Wesley Filardo's avatar Nathaniel Wesley Filardo Committed by Marcel Stör
Browse files

SSL rampage (#2938)

* Remove stale putative MD2 support

This hasn't worked in a while, presumably since one of our upstream
merges.  Don't bother making it work, since MD2 is generally considered
insecure.

* Land mbedtls 2.16.3-77-gf02988e57

* TLS: remove some dead code from espconn_mbedtls

There was some... frankly kind of scary buffer and data shuffling if
ESP8266_PLATFORM was defined.  Since we don't, in fact, define that
preprocessor symbol, just drop the code lest anyone (possibly future-me)
be scared.

* TLS: espconn_mbedtls: run through astyle

No functional changes

* TLS: espconn_mbedtls: put the file_params on the stack

There's no need to malloc a structure that's used only locally.

* TLS: Further minor tidying of mbedtls glue

What an absolute shitshow this is.  mbedtls should absolutely not
be mentioned inside sys/socket.h and app/mbedtls/app/lwIPSocket.c is not
so much glue as it as a complete copy of a random subset of lwIP; it
should go, but we aren't there yet.

Get rid of the mysterious "mbedlts_record" struct, which housed merely a
length of bytes sent solely for gating the "record sent" callback.

Remove spurious __attribute__((weak)) from symbols not otherwise
defined and rename them to emphasize that they are not actually part of
mbedtls proper.

* TLS: Rampage esp mbedtls glue and delete unused code

This at least makes the shitshow smaller

* TLS: lwip: fix some memp definitions

I presume these also need the new arguments

* TLS: Remove more non-NodeMCU code from our mbedtls

* TLS: drop support for 1.1

Depending on who you ask it's either EOL already or EOL soon, so
we may as well get rid of it now.
parent f5672207
......@@ -46,6 +46,7 @@
#include "mbedtls/debug.h"
#include "mbedtls/ssl.h"
#include "mbedtls/ssl_internal.h"
#include "mbedtls/platform_util.h"
#include <string.h>
......@@ -53,10 +54,8 @@
#include "mbedtls/oid.h"
#endif
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
static void ssl_reset_in_out_pointers( mbedtls_ssl_context *ssl );
static uint32_t ssl_get_hs_total_len( mbedtls_ssl_context const *ssl );
/* Length of the "epoch" field in the record header */
static inline size_t ssl_ep_len( const mbedtls_ssl_context *ssl )
......@@ -100,7 +99,101 @@ static int ssl_check_timer( mbedtls_ssl_context *ssl )
return( 0 );
}
static void ssl_update_out_pointers( mbedtls_ssl_context *ssl,
mbedtls_ssl_transform *transform );
static void ssl_update_in_pointers( mbedtls_ssl_context *ssl,
mbedtls_ssl_transform *transform );
#define SSL_DONT_FORCE_FLUSH 0
#define SSL_FORCE_FLUSH 1
#if defined(MBEDTLS_SSL_PROTO_DTLS)
/* Forward declarations for functions related to message buffering. */
static void ssl_buffering_free( mbedtls_ssl_context *ssl );
static void ssl_buffering_free_slot( mbedtls_ssl_context *ssl,
uint8_t slot );
static void ssl_free_buffered_record( mbedtls_ssl_context *ssl );
static int ssl_load_buffered_message( mbedtls_ssl_context *ssl );
static int ssl_load_buffered_record( mbedtls_ssl_context *ssl );
static int ssl_buffer_message( mbedtls_ssl_context *ssl );
static int ssl_buffer_future_record( mbedtls_ssl_context *ssl );
static int ssl_next_record_is_in_datagram( mbedtls_ssl_context *ssl );
static size_t ssl_get_current_mtu( const mbedtls_ssl_context *ssl );
static size_t ssl_get_maximum_datagram_size( mbedtls_ssl_context const *ssl )
{
size_t mtu = ssl_get_current_mtu( ssl );
if( mtu != 0 && mtu < MBEDTLS_SSL_OUT_BUFFER_LEN )
return( mtu );
return( MBEDTLS_SSL_OUT_BUFFER_LEN );
}
static int ssl_get_remaining_space_in_datagram( mbedtls_ssl_context const *ssl )
{
size_t const bytes_written = ssl->out_left;
size_t const mtu = ssl_get_maximum_datagram_size( ssl );
/* Double-check that the write-index hasn't gone
* past what we can transmit in a single datagram. */
if( bytes_written > mtu )
{
/* Should never happen... */
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
return( (int) ( mtu - bytes_written ) );
}
static int ssl_get_remaining_payload_in_datagram( mbedtls_ssl_context const *ssl )
{
int ret;
size_t remaining, expansion;
size_t max_len = MBEDTLS_SSL_OUT_CONTENT_LEN;
#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
const size_t mfl = mbedtls_ssl_get_max_frag_len( ssl );
if( max_len > mfl )
max_len = mfl;
/* By the standard (RFC 6066 Sect. 4), the MFL extension
* only limits the maximum record payload size, so in theory
* we would be allowed to pack multiple records of payload size
* MFL into a single datagram. However, this would mean that there's
* no way to explicitly communicate MTU restrictions to the peer.
*
* The following reduction of max_len makes sure that we never
* write datagrams larger than MFL + Record Expansion Overhead.
*/
if( max_len <= ssl->out_left )
return( 0 );
max_len -= ssl->out_left;
#endif
ret = ssl_get_remaining_space_in_datagram( ssl );
if( ret < 0 )
return( ret );
remaining = (size_t) ret;
ret = mbedtls_ssl_get_record_expansion( ssl );
if( ret < 0 )
return( ret );
expansion = (size_t) ret;
if( remaining <= expansion )
return( 0 );
remaining -= expansion;
if( remaining >= max_len )
remaining = max_len;
return( (int) remaining );
}
/*
* Double the retransmit timeout value, within the allowed range,
* returning -1 if the maximum value has already been reached.
......@@ -112,6 +205,18 @@ static int ssl_double_retransmit_timeout( mbedtls_ssl_context *ssl )
if( ssl->handshake->retransmit_timeout >= ssl->conf->hs_timeout_max )
return( -1 );
/* Implement the final paragraph of RFC 6347 section 4.1.1.1
* in the following way: after the initial transmission and a first
* retransmission, back off to a temporary estimated MTU of 508 bytes.
* This value is guaranteed to be deliverable (if not guaranteed to be
* delivered) of any compliant IPv4 (and IPv6) network, and should work
* on most non-IP stacks too. */
if( ssl->handshake->retransmit_timeout != ssl->conf->hs_timeout_min )
{
ssl->handshake->mtu = 508;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "mtu autoreduction to %d bytes", ssl->handshake->mtu ) );
}
new_timeout = 2 * ssl->handshake->retransmit_timeout;
/* Avoid arithmetic overflow and range overflow */
......@@ -145,14 +250,24 @@ static void ssl_reset_retransmit_timeout( mbedtls_ssl_context *ssl )
* } MaxFragmentLength;
* and we add 0 -> extension unused
*/
static unsigned int mfl_code_to_length[MBEDTLS_SSL_MAX_FRAG_LEN_INVALID] =
static unsigned int ssl_mfl_code_to_length( int mfl )
{
MBEDTLS_SSL_MAX_CONTENT_LEN, /* MBEDTLS_SSL_MAX_FRAG_LEN_NONE */
512, /* MBEDTLS_SSL_MAX_FRAG_LEN_512 */
1024, /* MBEDTLS_SSL_MAX_FRAG_LEN_1024 */
2048, /* MBEDTLS_SSL_MAX_FRAG_LEN_2048 */
4096, /* MBEDTLS_SSL_MAX_FRAG_LEN_4096 */
};
switch( mfl )
{
case MBEDTLS_SSL_MAX_FRAG_LEN_NONE:
return ( MBEDTLS_TLS_EXT_ADV_CONTENT_LEN );
case MBEDTLS_SSL_MAX_FRAG_LEN_512:
return 512;
case MBEDTLS_SSL_MAX_FRAG_LEN_1024:
return 1024;
case MBEDTLS_SSL_MAX_FRAG_LEN_2048:
return 2048;
case MBEDTLS_SSL_MAX_FRAG_LEN_4096:
return 4096;
default:
return ( MBEDTLS_TLS_EXT_ADV_CONTENT_LEN );
}
}
#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
#if defined(MBEDTLS_SSL_CLI_C)
......@@ -269,8 +384,8 @@ exit:
mbedtls_md5_free( &md5 );
mbedtls_sha1_free( &sha1 );
mbedtls_zeroize( padding, sizeof( padding ) );
mbedtls_zeroize( sha1sum, sizeof( sha1sum ) );
mbedtls_platform_zeroize( padding, sizeof( padding ) );
mbedtls_platform_zeroize( sha1sum, sizeof( sha1sum ) );
return( ret );
}
......@@ -367,8 +482,8 @@ static int tls1_prf( const unsigned char *secret, size_t slen,
mbedtls_md_free( &md_ctx );
mbedtls_zeroize( tmp, sizeof( tmp ) );
mbedtls_zeroize( h_i, sizeof( h_i ) );
mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
mbedtls_platform_zeroize( h_i, sizeof( h_i ) );
return( 0 );
}
......@@ -432,8 +547,8 @@ static int tls_prf_generic( mbedtls_md_type_t md_type,
mbedtls_md_free( &md_ctx );
mbedtls_zeroize( tmp, sizeof( tmp ) );
mbedtls_zeroize( h_i, sizeof( h_i ) );
mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
mbedtls_platform_zeroize( h_i, sizeof( h_i ) );
return( 0 );
}
......@@ -642,7 +757,8 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl )
return( ret );
}
mbedtls_zeroize( handshake->premaster, sizeof(handshake->premaster) );
mbedtls_platform_zeroize( handshake->premaster,
sizeof(handshake->premaster) );
}
else
MBEDTLS_SSL_DEBUG_MSG( 3, ( "no premaster (session resumed)" ) );
......@@ -653,7 +769,7 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl )
memcpy( tmp, handshake->randbytes, 64 );
memcpy( handshake->randbytes, tmp + 32, 32 );
memcpy( handshake->randbytes + 32, tmp, 32 );
mbedtls_zeroize( tmp, sizeof( tmp ) );
mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
/*
* SSLv3:
......@@ -681,7 +797,8 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl )
MBEDTLS_SSL_DEBUG_BUF( 4, "random bytes", handshake->randbytes, 64 );
MBEDTLS_SSL_DEBUG_BUF( 4, "key block", keyblk, 256 );
mbedtls_zeroize( handshake->randbytes, sizeof( handshake->randbytes ) );
mbedtls_platform_zeroize( handshake->randbytes,
sizeof( handshake->randbytes ) );
/*
* Determine the appropriate key, IV and MAC length.
......@@ -690,18 +807,32 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl )
transform->keylen = cipher_info->key_bitlen / 8;
if( cipher_info->mode == MBEDTLS_MODE_GCM ||
cipher_info->mode == MBEDTLS_MODE_CCM )
cipher_info->mode == MBEDTLS_MODE_CCM ||
cipher_info->mode == MBEDTLS_MODE_CHACHAPOLY )
{
size_t taglen, explicit_ivlen;
transform->maclen = 0;
mac_key_len = 0;
/* All modes haves 96-bit IVs;
* GCM and CCM has 4 implicit and 8 explicit bytes
* ChachaPoly has all 12 bytes implicit
*/
transform->ivlen = 12;
transform->fixed_ivlen = 4;
if( cipher_info->mode == MBEDTLS_MODE_CHACHAPOLY )
transform->fixed_ivlen = 12;
else
transform->fixed_ivlen = 4;
/* All modes have 128-bit tags, except CCM_8 (ciphersuite flag) */
taglen = transform->ciphersuite_info->flags &
MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16;
/* Minimum length is expicit IV + tag */
transform->minlen = transform->ivlen - transform->fixed_ivlen
+ ( transform->ciphersuite_info->flags &
MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16 );
/* Minimum length of encrypted record */
explicit_ivlen = transform->ivlen - transform->fixed_ivlen;
transform->minlen = explicit_ivlen + taglen;
}
else
{
......@@ -948,7 +1079,7 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl )
}
#endif /* MBEDTLS_CIPHER_MODE_CBC */
mbedtls_zeroize( keyblk, sizeof( keyblk ) );
mbedtls_platform_zeroize( keyblk, sizeof( keyblk ) );
#if defined(MBEDTLS_ZLIB_SUPPORT)
// Initialize compression
......@@ -958,11 +1089,11 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl )
if( ssl->compress_buf == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "Allocating compression buffer" ) );
ssl->compress_buf = mbedtls_calloc( 1, MBEDTLS_SSL_BUFFER_LEN );
ssl->compress_buf = mbedtls_calloc( 1, MBEDTLS_SSL_COMPRESS_BUFFER_LEN );
if( ssl->compress_buf == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed",
MBEDTLS_SSL_BUFFER_LEN ) );
MBEDTLS_SSL_COMPRESS_BUFFER_LEN ) );
return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
}
}
......@@ -1202,7 +1333,8 @@ int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exch
*(p++) = (unsigned char)( zlen );
p += zlen;
MBEDTLS_SSL_DEBUG_MPI( 3, "ECDH: z", &ssl->handshake->ecdh_ctx.z );
MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx,
MBEDTLS_DEBUG_ECDH_Z );
}
else
#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */
......@@ -1277,7 +1409,7 @@ static void ssl_mac( mbedtls_md_context_t *md_ctx,
#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) || \
( defined(MBEDTLS_CIPHER_MODE_CBC) && \
( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) ) )
( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) || defined(MBEDTLS_ARIA_C)) )
#define SSL_SOME_MODES_USE_MAC
#endif
......@@ -1323,14 +1455,6 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl )
MBEDTLS_SSL_DEBUG_BUF( 4, "before encrypt: output payload",
ssl->out_msg, ssl->out_msglen );
if( ssl->out_msglen > MBEDTLS_SSL_MAX_CONTENT_LEN )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "Record content %u too large, maximum %d",
(unsigned) ssl->out_msglen,
MBEDTLS_SSL_MAX_CONTENT_LEN ) );
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
/*
* Add MAC before if needed
*/
......@@ -1420,17 +1544,26 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl )
}
else
#endif /* MBEDTLS_ARC4_C || MBEDTLS_CIPHER_NULL_CIPHER */
#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C)
#if defined(MBEDTLS_GCM_C) || \
defined(MBEDTLS_CCM_C) || \
defined(MBEDTLS_CHACHAPOLY_C)
if( mode == MBEDTLS_MODE_GCM ||
mode == MBEDTLS_MODE_CCM )
mode == MBEDTLS_MODE_CCM ||
mode == MBEDTLS_MODE_CHACHAPOLY )
{
int ret;
size_t enc_msglen, olen;
unsigned char *enc_msg;
unsigned char add_data[13];
unsigned char taglen = ssl->transform_out->ciphersuite_info->flags &
unsigned char iv[12];
mbedtls_ssl_transform *transform = ssl->transform_out;
unsigned char taglen = transform->ciphersuite_info->flags &
MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16;
size_t explicit_ivlen = transform->ivlen - transform->fixed_ivlen;
/*
* Prepare additional authenticated data
*/
memcpy( add_data, ssl->out_ctr, 8 );
add_data[8] = ssl->out_msgtype;
mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver,
......@@ -1438,44 +1571,57 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl )
add_data[11] = ( ssl->out_msglen >> 8 ) & 0xFF;
add_data[12] = ssl->out_msglen & 0xFF;
MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD",
add_data, 13 );
MBEDTLS_SSL_DEBUG_BUF( 4, "additional data for AEAD", add_data, 13 );
/*
* Generate IV
*/
if( ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen != 8 )
if( transform->ivlen == 12 && transform->fixed_ivlen == 4 )
{
/* GCM and CCM: fixed || explicit (=seqnum) */
memcpy( iv, transform->iv_enc, transform->fixed_ivlen );
memcpy( iv + transform->fixed_ivlen, ssl->out_ctr, 8 );
memcpy( ssl->out_iv, ssl->out_ctr, 8 );
}
else if( transform->ivlen == 12 && transform->fixed_ivlen == 12 )
{
/* ChachaPoly: fixed XOR sequence number */
unsigned char i;
memcpy( iv, transform->iv_enc, transform->fixed_ivlen );
for( i = 0; i < 8; i++ )
iv[i+4] ^= ssl->out_ctr[i];
}
else
{
/* Reminder if we ever add an AEAD mode with a different size */
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
memcpy( ssl->transform_out->iv_enc + ssl->transform_out->fixed_ivlen,
ssl->out_ctr, 8 );
memcpy( ssl->out_iv, ssl->out_ctr, 8 );
MBEDTLS_SSL_DEBUG_BUF( 4, "IV used", ssl->out_iv,
ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen );
MBEDTLS_SSL_DEBUG_BUF( 4, "IV used (internal)",
iv, transform->ivlen );
MBEDTLS_SSL_DEBUG_BUF( 4, "IV used (transmitted)",
ssl->out_iv, explicit_ivlen );
/*
* Fix pointer positions and message length with added IV
* Fix message length with added IV
*/
enc_msg = ssl->out_msg;
enc_msglen = ssl->out_msglen;
ssl->out_msglen += ssl->transform_out->ivlen -
ssl->transform_out->fixed_ivlen;
ssl->out_msglen += explicit_ivlen;
MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, "
"including %d bytes of padding",
ssl->out_msglen, 0 ) );
"including 0 bytes of padding",
ssl->out_msglen ) );
/*
* Encrypt and authenticate
*/
if( ( ret = mbedtls_cipher_auth_encrypt( &ssl->transform_out->cipher_ctx_enc,
ssl->transform_out->iv_enc,
ssl->transform_out->ivlen,
if( ( ret = mbedtls_cipher_auth_encrypt( &transform->cipher_ctx_enc,
iv, transform->ivlen,
add_data, 13,
enc_msg, enc_msglen,
enc_msg, &olen,
......@@ -1499,7 +1645,7 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl )
else
#endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C */
#if defined(MBEDTLS_CIPHER_MODE_CBC) && \
( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) )
( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) || defined(MBEDTLS_ARIA_C) )
if( mode == MBEDTLS_MODE_CBC )
{
int ret;
......@@ -1619,7 +1765,7 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl )
}
else
#endif /* MBEDTLS_CIPHER_MODE_CBC &&
( MBEDTLS_AES_C || MBEDTLS_CAMELLIA_C ) */
( MBEDTLS_AES_C || MBEDTLS_CAMELLIA_C || MBEDTLS_ARIA_C ) */
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
......@@ -1639,7 +1785,6 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl )
static int ssl_decrypt_buf( mbedtls_ssl_context *ssl )
{
size_t i;
mbedtls_cipher_mode_t mode;
int auth_done = 0;
#if defined(SSL_SOME_MODES_USE_MAC)
......@@ -1689,20 +1834,27 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl )
}
else
#endif /* MBEDTLS_ARC4_C || MBEDTLS_CIPHER_NULL_CIPHER */
#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C)
#if defined(MBEDTLS_GCM_C) || \
defined(MBEDTLS_CCM_C) || \
defined(MBEDTLS_CHACHAPOLY_C)
if( mode == MBEDTLS_MODE_GCM ||
mode == MBEDTLS_MODE_CCM )
mode == MBEDTLS_MODE_CCM ||
mode == MBEDTLS_MODE_CHACHAPOLY )
{
int ret;
size_t dec_msglen, olen;
unsigned char *dec_msg;
unsigned char *dec_msg_result;
unsigned char add_data[13];
unsigned char taglen = ssl->transform_in->ciphersuite_info->flags &
unsigned char iv[12];
mbedtls_ssl_transform *transform = ssl->transform_in;
unsigned char taglen = transform->ciphersuite_info->flags &
MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16;
size_t explicit_iv_len = ssl->transform_in->ivlen -
ssl->transform_in->fixed_ivlen;
size_t explicit_iv_len = transform->ivlen - transform->fixed_ivlen;
/*
* Compute and update sizes
*/
if( ssl->in_msglen < explicit_iv_len + taglen )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < explicit_iv_len (%d) "
......@@ -1716,6 +1868,9 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl )
dec_msg_result = ssl->in_msg;
ssl->in_msglen = dec_msglen;
/*
* Prepare additional authenticated data
*/
memcpy( add_data, ssl->in_ctr, 8 );
add_data[8] = ssl->in_msgtype;
mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver,
......@@ -1723,23 +1878,43 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl )
add_data[11] = ( ssl->in_msglen >> 8 ) & 0xFF;
add_data[12] = ssl->in_msglen & 0xFF;
MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD",
add_data, 13 );
MBEDTLS_SSL_DEBUG_BUF( 4, "additional data for AEAD", add_data, 13 );
/*
* Prepare IV
*/
if( transform->ivlen == 12 && transform->fixed_ivlen == 4 )
{
/* GCM and CCM: fixed || explicit (transmitted) */
memcpy( iv, transform->iv_dec, transform->fixed_ivlen );
memcpy( iv + transform->fixed_ivlen, ssl->in_iv, 8 );
}
else if( transform->ivlen == 12 && transform->fixed_ivlen == 12 )
{
/* ChachaPoly: fixed XOR sequence number */
unsigned char i;
memcpy( iv, transform->iv_dec, transform->fixed_ivlen );
memcpy( ssl->transform_in->iv_dec + ssl->transform_in->fixed_ivlen,
ssl->in_iv,
ssl->transform_in->ivlen - ssl->transform_in->fixed_ivlen );
for( i = 0; i < 8; i++ )
iv[i+4] ^= ssl->in_ctr[i];
}
else
{
/* Reminder if we ever add an AEAD mode with a different size */
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
MBEDTLS_SSL_DEBUG_BUF( 4, "IV used", ssl->transform_in->iv_dec,
ssl->transform_in->ivlen );
MBEDTLS_SSL_DEBUG_BUF( 4, "IV used", iv, transform->ivlen );
MBEDTLS_SSL_DEBUG_BUF( 4, "TAG used", dec_msg + dec_msglen, taglen );
/*
* Decrypt and authenticate
*/
if( ( ret = mbedtls_cipher_auth_decrypt( &ssl->transform_in->cipher_ctx_dec,
ssl->transform_in->iv_dec,
ssl->transform_in->ivlen,
iv, transform->ivlen,
add_data, 13,
dec_msg, dec_msglen,
dec_msg_result, &olen,
......@@ -1763,7 +1938,7 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl )
else
#endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C */
#if defined(MBEDTLS_CIPHER_MODE_CBC) && \
( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) )
( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) || defined(MBEDTLS_ARIA_C) )
if( mode == MBEDTLS_MODE_CBC )
{
/*
......@@ -1857,6 +2032,7 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl )
*/
if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 )
{
unsigned char i;
dec_msglen -= ssl->transform_in->ivlen;
ssl->in_msglen -= ssl->transform_in->ivlen;
......@@ -1931,19 +2107,20 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl )
*/
size_t pad_count = 0, real_count = 1;
size_t padding_idx = ssl->in_msglen - padlen;
size_t i;
/*
* Padding is guaranteed to be incorrect if:
* 1. padlen > ssl->in_msglen
*
* 2. padding_idx > MBEDTLS_SSL_MAX_CONTENT_LEN +
* 2. padding_idx > MBEDTLS_SSL_IN_CONTENT_LEN +
* ssl->transform_in->maclen
*
* In both cases we reset padding_idx to a safe value (0) to
* prevent out-of-buffer reads.
*/
correct &= ( padlen <= ssl->in_msglen );
correct &= ( padding_idx <= MBEDTLS_SSL_MAX_CONTENT_LEN +
correct &= ( padding_idx <= MBEDTLS_SSL_IN_CONTENT_LEN +
ssl->transform_in->maclen );
padding_idx *= correct;
......@@ -1975,7 +2152,7 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl )
}
else
#endif /* MBEDTLS_CIPHER_MODE_CBC &&
( MBEDTLS_AES_C || MBEDTLS_CAMELLIA_C ) */
( MBEDTLS_AES_C || MBEDTLS_CAMELLIA_C || MBEDTLS_ARIA_C ) */
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
......@@ -2183,6 +2360,7 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl )
else
#endif
{
unsigned char i;
for( i = 8; i > ssl_ep_len( ssl ); i-- )
if( ++ssl->in_ctr[i - 1] != 0 )
break;
......@@ -2232,7 +2410,7 @@ static int ssl_compress_buf( mbedtls_ssl_context *ssl )
ssl->transform_out->ctx_deflate.next_in = msg_pre;
ssl->transform_out->ctx_deflate.avail_in = len_pre;
ssl->transform_out->ctx_deflate.next_out = msg_post;
ssl->transform_out->ctx_deflate.avail_out = MBEDTLS_SSL_BUFFER_LEN - bytes_written;
ssl->transform_out->ctx_deflate.avail_out = MBEDTLS_SSL_OUT_BUFFER_LEN - bytes_written;
ret = deflate( &ssl->transform_out->ctx_deflate, Z_SYNC_FLUSH );
if( ret != Z_OK )
......@@ -2241,7 +2419,7 @@ static int ssl_compress_buf( mbedtls_ssl_context *ssl )
return( MBEDTLS_ERR_SSL_COMPRESSION_FAILED );
}
ssl->out_msglen = MBEDTLS_SSL_BUFFER_LEN -
ssl->out_msglen = MBEDTLS_SSL_OUT_BUFFER_LEN -
ssl->transform_out->ctx_deflate.avail_out - bytes_written;
MBEDTLS_SSL_DEBUG_MSG( 3, ( "after compression: msglen = %d, ",
......@@ -2279,7 +2457,7 @@ static int ssl_decompress_buf( mbedtls_ssl_context *ssl )
ssl->transform_in->ctx_inflate.next_in = msg_pre;
ssl->transform_in->ctx_inflate.avail_in = len_pre;
ssl->transform_in->ctx_inflate.next_out = msg_post;
ssl->transform_in->ctx_inflate.avail_out = MBEDTLS_SSL_BUFFER_LEN -
ssl->transform_in->ctx_inflate.avail_out = MBEDTLS_SSL_IN_BUFFER_LEN -
header_bytes;
ret = inflate( &ssl->transform_in->ctx_inflate, Z_SYNC_FLUSH );
......@@ -2289,7 +2467,7 @@ static int ssl_decompress_buf( mbedtls_ssl_context *ssl )
return( MBEDTLS_ERR_SSL_COMPRESSION_FAILED );
}
ssl->in_msglen = MBEDTLS_SSL_BUFFER_LEN -
ssl->in_msglen = MBEDTLS_SSL_IN_BUFFER_LEN -
ssl->transform_in->ctx_inflate.avail_out - header_bytes;
MBEDTLS_SSL_DEBUG_MSG( 3, ( "after decompression: msglen = %d, ",
......@@ -2364,7 +2542,7 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
if( nb_want > MBEDTLS_SSL_BUFFER_LEN - (size_t)( ssl->in_hdr - ssl->in_buf ) )
if( nb_want > MBEDTLS_SSL_IN_BUFFER_LEN - (size_t)( ssl->in_hdr - ssl->in_buf ) )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "requesting more data than fits" ) );
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
......@@ -2428,7 +2606,7 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want )
}
/*
* A record can't be split accross datagrams. If we need to read but
* A record can't be split across datagrams. If we need to read but
* are not at the beginning of a new record, the caller did something
* wrong.
*/
......@@ -2444,10 +2622,13 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want )
* that will end up being dropped.
*/
if( ssl_check_timer( ssl ) != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "timer has expired" ) );
ret = MBEDTLS_ERR_SSL_TIMEOUT;
}
else
{
len = MBEDTLS_SSL_BUFFER_LEN - ( ssl->in_hdr - ssl->in_buf );
len = MBEDTLS_SSL_IN_BUFFER_LEN - ( ssl->in_hdr - ssl->in_buf );
if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER )
timeout = ssl->handshake->retransmit_timeout;
......@@ -2569,7 +2750,7 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want )
int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl )
{
int ret;
unsigned char *buf, i;
unsigned char *buf;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> flush output" ) );
......@@ -2592,8 +2773,7 @@ int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl )
MBEDTLS_SSL_DEBUG_MSG( 2, ( "message length: %d, out_left: %d",
mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen, ssl->out_left ) );
buf = ssl->out_hdr + mbedtls_ssl_hdr_len( ssl ) +
ssl->out_msglen - ssl->out_left;
buf = ssl->out_hdr - ssl->out_left;
ret = ssl->f_send( ssl->p_bio, buf, ssl->out_left );
MBEDTLS_SSL_DEBUG_RET( 2, "ssl->f_send", ret );
......@@ -2612,16 +2792,17 @@ int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl )
ssl->out_left -= ret;
}
for( i = 8; i > ssl_ep_len( ssl ); i-- )
if( ++ssl->out_ctr[i - 1] != 0 )
break;
/* The loop goes to its end iff the counter is wrapping */
if( i == ssl_ep_len( ssl ) )
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "outgoing message counter would wrap" ) );
return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING );
ssl->out_hdr = ssl->out_buf;
}
else
#endif
{
ssl->out_hdr = ssl->out_buf + 8;
}
ssl_update_out_pointers( ssl, ssl->transform_out );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= flush output" ) );
......@@ -2638,6 +2819,9 @@ int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl )
static int ssl_flight_append( mbedtls_ssl_context *ssl )
{
mbedtls_ssl_flight_item *msg;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_flight_append" ) );
MBEDTLS_SSL_DEBUG_BUF( 4, "message appended to flight",
ssl->out_msg, ssl->out_msglen );
/* Allocate space for current message */
if( ( msg = mbedtls_calloc( 1, sizeof( mbedtls_ssl_flight_item ) ) ) == NULL )
......@@ -2671,6 +2855,7 @@ static int ssl_flight_append( mbedtls_ssl_context *ssl )
cur->next = msg;
}
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= ssl_flight_append" ) );
return( 0 );
}
......@@ -2719,19 +2904,12 @@ static void ssl_swap_epochs( mbedtls_ssl_context *ssl )
ssl->handshake->alt_transform_out = tmp_transform;
/* Swap epoch + sequence_number */
memcpy( tmp_out_ctr, ssl->out_ctr, 8 );
memcpy( ssl->out_ctr, ssl->handshake->alt_out_ctr, 8 );
memcpy( tmp_out_ctr, ssl->cur_out_ctr, 8 );
memcpy( ssl->cur_out_ctr, ssl->handshake->alt_out_ctr, 8 );
memcpy( ssl->handshake->alt_out_ctr, tmp_out_ctr, 8 );
/* Adjust to the newly activated transform */
if( ssl->transform_out != NULL &&
ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 )
{
ssl->out_msg = ssl->out_iv + ssl->transform_out->ivlen -
ssl->transform_out->fixed_ivlen;
}
else
ssl->out_msg = ssl->out_iv;
ssl_update_out_pointers( ssl, ssl->transform_out );
#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL)
if( mbedtls_ssl_hw_record_activate != NULL )
......@@ -2747,20 +2925,38 @@ static void ssl_swap_epochs( mbedtls_ssl_context *ssl )
/*
* Retransmit the current flight of messages.
*/
int mbedtls_ssl_resend( mbedtls_ssl_context *ssl )
{
int ret = 0;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_resend" ) );
ret = mbedtls_ssl_flight_transmit( ssl );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_resend" ) );
return( ret );
}
/*
* Transmit or retransmit the current flight of messages.
*
* Need to remember the current message in case flush_output returns
* WANT_WRITE, causing us to exit this function and come back later.
* This function must be called until state is no longer SENDING.
*/
int mbedtls_ssl_resend( mbedtls_ssl_context *ssl )
int mbedtls_ssl_flight_transmit( mbedtls_ssl_context *ssl )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_resend" ) );
int ret;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_flight_transmit" ) );
if( ssl->handshake->retransmit_state != MBEDTLS_SSL_RETRANS_SENDING )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialise resending" ) );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialise flight transmission" ) );
ssl->handshake->cur_msg = ssl->handshake->flight;
ssl->handshake->cur_msg_p = ssl->handshake->flight->p + 12;
ssl_swap_epochs( ssl );
ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_SENDING;
......@@ -2768,33 +2964,129 @@ int mbedtls_ssl_resend( mbedtls_ssl_context *ssl )
while( ssl->handshake->cur_msg != NULL )
{
int ret;
mbedtls_ssl_flight_item *cur = ssl->handshake->cur_msg;
size_t max_frag_len;
const mbedtls_ssl_flight_item * const cur = ssl->handshake->cur_msg;
int const is_finished =
( cur->type == MBEDTLS_SSL_MSG_HANDSHAKE &&
cur->p[0] == MBEDTLS_SSL_HS_FINISHED );
uint8_t const force_flush = ssl->disable_datagram_packing == 1 ?
SSL_FORCE_FLUSH : SSL_DONT_FORCE_FLUSH;
/* Swap epochs before sending Finished: we can't do it after
* sending ChangeCipherSpec, in case write returns WANT_READ.
* Must be done before copying, may change out_msg pointer */
if( cur->type == MBEDTLS_SSL_MSG_HANDSHAKE &&
cur->p[0] == MBEDTLS_SSL_HS_FINISHED )
if( is_finished && ssl->handshake->cur_msg_p == ( cur->p + 12 ) )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "swap epochs to send finished message" ) );
ssl_swap_epochs( ssl );
}
memcpy( ssl->out_msg, cur->p, cur->len );
ssl->out_msglen = cur->len;
ssl->out_msgtype = cur->type;
ret = ssl_get_remaining_payload_in_datagram( ssl );
if( ret < 0 )
return( ret );
max_frag_len = (size_t) ret;
/* CCS is copied as is, while HS messages may need fragmentation */
if( cur->type == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC )
{
if( max_frag_len == 0 )
{
if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 )
return( ret );
continue;
}
memcpy( ssl->out_msg, cur->p, cur->len );
ssl->out_msglen = cur->len;
ssl->out_msgtype = cur->type;
/* Update position inside current message */
ssl->handshake->cur_msg_p += cur->len;
}
else
{
const unsigned char * const p = ssl->handshake->cur_msg_p;
const size_t hs_len = cur->len - 12;
const size_t frag_off = p - ( cur->p + 12 );
const size_t rem_len = hs_len - frag_off;
size_t cur_hs_frag_len, max_hs_frag_len;
if( ( max_frag_len < 12 ) || ( max_frag_len == 12 && hs_len != 0 ) )
{
if( is_finished )
ssl_swap_epochs( ssl );
if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 )
return( ret );
continue;
}
max_hs_frag_len = max_frag_len - 12;
cur_hs_frag_len = rem_len > max_hs_frag_len ?
max_hs_frag_len : rem_len;
if( frag_off == 0 && cur_hs_frag_len != hs_len )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "fragmenting handshake message (%u > %u)",
(unsigned) cur_hs_frag_len,
(unsigned) max_hs_frag_len ) );
}
/* Messages are stored with handshake headers as if not fragmented,
* copy beginning of headers then fill fragmentation fields.
* Handshake headers: type(1) len(3) seq(2) f_off(3) f_len(3) */
memcpy( ssl->out_msg, cur->p, 6 );
ssl->out_msg[6] = ( ( frag_off >> 16 ) & 0xff );
ssl->out_msg[7] = ( ( frag_off >> 8 ) & 0xff );
ssl->out_msg[8] = ( ( frag_off ) & 0xff );
ssl->handshake->cur_msg = cur->next;
ssl->out_msg[ 9] = ( ( cur_hs_frag_len >> 16 ) & 0xff );
ssl->out_msg[10] = ( ( cur_hs_frag_len >> 8 ) & 0xff );
ssl->out_msg[11] = ( ( cur_hs_frag_len ) & 0xff );
MBEDTLS_SSL_DEBUG_BUF( 3, "resent handshake message header", ssl->out_msg, 12 );
MBEDTLS_SSL_DEBUG_BUF( 3, "handshake header", ssl->out_msg, 12 );
/* Copy the handshake message content and set records fields */
memcpy( ssl->out_msg + 12, p, cur_hs_frag_len );
ssl->out_msglen = cur_hs_frag_len + 12;
ssl->out_msgtype = cur->type;
/* Update position inside current message */
ssl->handshake->cur_msg_p += cur_hs_frag_len;
}
/* If done with the current message move to the next one if any */
if( ssl->handshake->cur_msg_p >= cur->p + cur->len )
{
if( cur->next != NULL )
{
ssl->handshake->cur_msg = cur->next;
ssl->handshake->cur_msg_p = cur->next->p + 12;
}
else
{
ssl->handshake->cur_msg = NULL;
ssl->handshake->cur_msg_p = NULL;
}
}
if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
/* Actually send the message out */
if( ( ret = mbedtls_ssl_write_record( ssl, force_flush ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
return( ret );
}
}
if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 )
return( ret );
/* Update state and set timer */
if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER )
ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_FINISHED;
else
......@@ -2803,7 +3095,7 @@ int mbedtls_ssl_resend( mbedtls_ssl_context *ssl )
ssl_set_timer( ssl, ssl->handshake->retransmit_timeout );
}
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_resend" ) );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_flight_transmit" ) );
return( 0 );
}
......@@ -2821,6 +3113,12 @@ void mbedtls_ssl_recv_flight_completed( mbedtls_ssl_context *ssl )
/* The next incoming flight will start with this msg_seq */
ssl->handshake->in_flight_start_seq = ssl->handshake->in_msg_seq;
/* We don't want to remember CCS's across flight boundaries. */
ssl->handshake->buffering.seen_ccs = 0;
/* Clear future message buffering structure. */
ssl_buffering_free( ssl );
/* Cancel timer */
ssl_set_timer( ssl, 0 );
......@@ -2852,43 +3150,102 @@ void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl )
#endif /* MBEDTLS_SSL_PROTO_DTLS */
/*
* Record layer functions
* Handshake layer functions
*/
/*
* Write current record.
* Uses ssl->out_msgtype, ssl->out_msglen and bytes at ssl->out_msg.
* Write (DTLS: or queue) current handshake (including CCS) message.
*
* - fill in handshake headers
* - update handshake checksum
* - DTLS: save message for resending
* - then pass to the record layer
*
* DTLS: except for HelloRequest, messages are only queued, and will only be
* actually sent when calling flight_transmit() or resend().
*
* Inputs:
* - ssl->out_msglen: 4 + actual handshake message len
* (4 is the size of handshake headers for TLS)
* - ssl->out_msg[0]: the handshake type (ClientHello, ServerHello, etc)
* - ssl->out_msg + 4: the handshake message body
*
* Outputs, ie state before passing to flight_append() or write_record():
* - ssl->out_msglen: the length of the record contents
* (including handshake headers but excluding record headers)
* - ssl->out_msg: the record contents (handshake headers + content)
*/
int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl )
int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl )
{
int ret, done = 0, out_msg_type;
size_t len = ssl->out_msglen;
int ret;
const size_t hs_len = ssl->out_msglen - 4;
const unsigned char hs_type = ssl->out_msg[0];
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write record" ) );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write handshake message" ) );
/*
* Sanity checks
*/
if( ssl->out_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE &&
ssl->out_msgtype != MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC )
{
/* In SSLv3, the client might send a NoCertificate alert. */
#if defined(MBEDTLS_SSL_PROTO_SSL3) && defined(MBEDTLS_SSL_CLI_C)
if( ! ( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 &&
ssl->out_msgtype == MBEDTLS_SSL_MSG_ALERT &&
ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) )
#endif /* MBEDTLS_SSL_PROTO_SSL3 && MBEDTLS_SSL_SRV_C */
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
}
/* Whenever we send anything different from a
* HelloRequest we should be in a handshake - double check. */
if( ! ( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE &&
hs_type == MBEDTLS_SSL_HS_HELLO_REQUEST ) &&
ssl->handshake == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
ssl->handshake != NULL &&
ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING )
{
; /* Skip special handshake treatment when resending */
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
else
#endif
if( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE )
{
out_msg_type = ssl->out_msg[0];
if( out_msg_type != MBEDTLS_SSL_HS_HELLO_REQUEST &&
ssl->handshake == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
/* Double-check that we did not exceed the bounds
* of the outgoing record buffer.
* This should never fail as the various message
* writing functions must obey the bounds of the
* outgoing record buffer, but better be safe.
*
* Note: We deliberately do not check for the MTU or MFL here.
*/
if( ssl->out_msglen > MBEDTLS_SSL_OUT_CONTENT_LEN )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "Record too large: "
"size %u, maximum %u",
(unsigned) ssl->out_msglen,
(unsigned) MBEDTLS_SSL_OUT_CONTENT_LEN ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
ssl->out_msg[1] = (unsigned char)( ( len - 4 ) >> 16 );
ssl->out_msg[2] = (unsigned char)( ( len - 4 ) >> 8 );
ssl->out_msg[3] = (unsigned char)( ( len - 4 ) );
/*
* Fill handshake headers
*/
if( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE )
{
ssl->out_msg[1] = (unsigned char)( hs_len >> 16 );
ssl->out_msg[2] = (unsigned char)( hs_len >> 8 );
ssl->out_msg[3] = (unsigned char)( hs_len );
/*
* DTLS has additional fields in the Handshake layer,
......@@ -2901,21 +3258,20 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl )
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
{
/* Make room for the additional DTLS fields */
if( MBEDTLS_SSL_MAX_CONTENT_LEN - ssl->out_msglen < 8 )
if( MBEDTLS_SSL_OUT_CONTENT_LEN - ssl->out_msglen < 8 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "DTLS handshake message too large: "
"size %u, maximum %u",
(unsigned) ( ssl->in_hslen - 4 ),
(unsigned) ( MBEDTLS_SSL_MAX_CONTENT_LEN - 12 ) ) );
(unsigned) ( hs_len ),
(unsigned) ( MBEDTLS_SSL_OUT_CONTENT_LEN - 12 ) ) );
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
memmove( ssl->out_msg + 12, ssl->out_msg + 4, len - 4 );
memmove( ssl->out_msg + 12, ssl->out_msg + 4, hs_len );
ssl->out_msglen += 8;
len += 8;
/* Write message_seq and update it, except for HelloRequest */
if( out_msg_type != MBEDTLS_SSL_HS_HELLO_REQUEST )
if( hs_type != MBEDTLS_SSL_HS_HELLO_REQUEST )
{
ssl->out_msg[4] = ( ssl->handshake->out_msg_seq >> 8 ) & 0xFF;
ssl->out_msg[5] = ( ssl->handshake->out_msg_seq ) & 0xFF;
......@@ -2927,23 +3283,23 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl )
ssl->out_msg[5] = 0;
}
/* We don't fragment, so frag_offset = 0 and frag_len = len */
/* Handshake hashes are computed without fragmentation,
* so set frag_offset = 0 and frag_len = hs_len for now */
memset( ssl->out_msg + 6, 0x00, 3 );
memcpy( ssl->out_msg + 9, ssl->out_msg + 1, 3 );
}
#endif /* MBEDTLS_SSL_PROTO_DTLS */
if( out_msg_type != MBEDTLS_SSL_HS_HELLO_REQUEST )
ssl->handshake->update_checksum( ssl, ssl->out_msg, len );
/* Update running hashes of handshake messages seen */
if( hs_type != MBEDTLS_SSL_HS_HELLO_REQUEST )
ssl->handshake->update_checksum( ssl, ssl->out_msg, ssl->out_msglen );
}
/* Save handshake and CCS messages for resending */
/* Either send now, or just save to be sent (and resent) later */
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
ssl->handshake != NULL &&
ssl->handshake->retransmit_state != MBEDTLS_SSL_RETRANS_SENDING &&
( ssl->out_msgtype == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC ||
ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) )
! ( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE &&
hs_type == MBEDTLS_SSL_HS_HELLO_REQUEST ) )
{
if( ( ret = ssl_flight_append( ssl ) ) != 0 )
{
......@@ -2951,7 +3307,40 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl )
return( ret );
}
}
else
#endif
{
if( ( ret = mbedtls_ssl_write_record( ssl, SSL_FORCE_FLUSH ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_record", ret );
return( ret );
}
}
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write handshake message" ) );
return( 0 );
}
/*
* Record layer functions
*/
/*
* Write current record.
*
* Uses:
* - ssl->out_msgtype: type of the message (AppData, Handshake, Alert, CCS)
* - ssl->out_msglen: length of the record content (excl headers)
* - ssl->out_msg: record content
*/
int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush )
{
int ret, done = 0;
size_t len = ssl->out_msglen;
uint8_t flush = force_flush;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write record" ) );
#if defined(MBEDTLS_ZLIB_SUPPORT)
if( ssl->transform_out != NULL &&
......@@ -2985,10 +3374,14 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl )
#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */
if( !done )
{
unsigned i;
size_t protected_record_size;
ssl->out_hdr[0] = (unsigned char) ssl->out_msgtype;
mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver,
ssl->conf->transport, ssl->out_hdr + 1 );
memcpy( ssl->out_ctr, ssl->cur_out_ctr, 8 );
ssl->out_len[0] = (unsigned char)( len >> 8 );
ssl->out_len[1] = (unsigned char)( len );
......@@ -3005,21 +3398,79 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl )
ssl->out_len[1] = (unsigned char)( len );
}
ssl->out_left = mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen;
protected_record_size = len + mbedtls_ssl_hdr_len( ssl );
#if defined(MBEDTLS_SSL_PROTO_DTLS)
/* In case of DTLS, double-check that we don't exceed
* the remaining space in the datagram. */
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
{
ret = ssl_get_remaining_space_in_datagram( ssl );
if( ret < 0 )
return( ret );
if( protected_record_size > (size_t) ret )
{
/* Should never happen */
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
}
#endif /* MBEDTLS_SSL_PROTO_DTLS */
MBEDTLS_SSL_DEBUG_MSG( 3, ( "output record: msgtype = %d, "
"version = [%d:%d], msglen = %d",
ssl->out_hdr[0], ssl->out_hdr[1], ssl->out_hdr[2],
( ssl->out_len[0] << 8 ) | ssl->out_len[1] ) );
"version = [%d:%d], msglen = %d",
ssl->out_hdr[0], ssl->out_hdr[1],
ssl->out_hdr[2], len ) );
MBEDTLS_SSL_DEBUG_BUF( 4, "output record sent to network",
ssl->out_hdr, mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen );
}
ssl->out_hdr, protected_record_size );
if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flush_output", ret );
return( ret );
ssl->out_left += protected_record_size;
ssl->out_hdr += protected_record_size;
ssl_update_out_pointers( ssl, ssl->transform_out );
for( i = 8; i > ssl_ep_len( ssl ); i-- )
if( ++ssl->cur_out_ctr[i - 1] != 0 )
break;
/* The loop goes to its end iff the counter is wrapping */
if( i == ssl_ep_len( ssl ) )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "outgoing message counter would wrap" ) );
return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING );
}
}
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
flush == SSL_DONT_FORCE_FLUSH )
{
size_t remaining;
ret = ssl_get_remaining_payload_in_datagram( ssl );
if( ret < 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "ssl_get_remaining_payload_in_datagram",
ret );
return( ret );
}
remaining = (size_t) ret;
if( remaining == 0 )
{
flush = SSL_FORCE_FLUSH;
}
else
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Still %u bytes available in current datagram", (unsigned) remaining ) );
}
}
#endif /* MBEDTLS_SSL_PROTO_DTLS */
if( ( flush == SSL_FORCE_FLUSH ) &&
( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flush_output", ret );
return( ret );
}
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write record" ) );
......@@ -3028,6 +3479,52 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl )
}
#if defined(MBEDTLS_SSL_PROTO_DTLS)
static int ssl_hs_is_proper_fragment( mbedtls_ssl_context *ssl )
{
if( ssl->in_msglen < ssl->in_hslen ||
memcmp( ssl->in_msg + 6, "\0\0\0", 3 ) != 0 ||
memcmp( ssl->in_msg + 9, ssl->in_msg + 1, 3 ) != 0 )
{
return( 1 );
}
return( 0 );
}
static uint32_t ssl_get_hs_frag_len( mbedtls_ssl_context const *ssl )
{
return( ( ssl->in_msg[9] << 16 ) |
( ssl->in_msg[10] << 8 ) |
ssl->in_msg[11] );
}
static uint32_t ssl_get_hs_frag_off( mbedtls_ssl_context const *ssl )
{
return( ( ssl->in_msg[6] << 16 ) |
( ssl->in_msg[7] << 8 ) |
ssl->in_msg[8] );
}
static int ssl_check_hs_header( mbedtls_ssl_context const *ssl )
{
uint32_t msg_len, frag_off, frag_len;
msg_len = ssl_get_hs_total_len( ssl );
frag_off = ssl_get_hs_frag_off( ssl );
frag_len = ssl_get_hs_frag_len( ssl );
if( frag_off > msg_len )
return( -1 );
if( frag_len > msg_len - frag_off )
return( -1 );
if( frag_len + 12 > ssl->in_msglen )
return( -1 );
return( 0 );
}
/*
* Mark bits in bitmask (used for DTLS HS reassembly)
*/
......@@ -3089,162 +3586,29 @@ static int ssl_bitmask_check( unsigned char *mask, size_t len )
return( 0 );
}
/*
* Reassemble fragmented DTLS handshake messages.
*
* Use a temporary buffer for reassembly, divided in two parts:
* - the first holds the reassembled message (including handshake header),
* - the second holds a bitmask indicating which parts of the message
* (excluding headers) have been received so far.
*/
static int ssl_reassemble_dtls_handshake( mbedtls_ssl_context *ssl )
/* msg_len does not include the handshake header */
static size_t ssl_get_reassembly_buffer_size( size_t msg_len,
unsigned add_bitmap )
{
unsigned char *msg, *bitmask;
size_t frag_len, frag_off;
size_t msg_len = ssl->in_hslen - 12; /* Without headers */
size_t alloc_len;
if( ssl->handshake == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "not supported outside handshake (for now)" ) );
return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
}
/*
* For first fragment, check size and allocate buffer
*/
if( ssl->handshake->hs_msg == NULL )
{
size_t alloc_len;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialize reassembly, total length = %d",
msg_len ) );
if( ssl->in_hslen > MBEDTLS_SSL_MAX_CONTENT_LEN )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake message too large" ) );
return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
}
/* The bitmask needs one bit per byte of message excluding header */
alloc_len = 12 + msg_len + msg_len / 8 + ( msg_len % 8 != 0 );
ssl->handshake->hs_msg = mbedtls_calloc( 1, alloc_len );
if( ssl->handshake->hs_msg == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc failed (%d bytes)", alloc_len ) );
return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
}
/* Prepare final header: copy msg_type, length and message_seq,
* then add standardised fragment_offset and fragment_length */
memcpy( ssl->handshake->hs_msg, ssl->in_msg, 6 );
memset( ssl->handshake->hs_msg + 6, 0, 3 );
memcpy( ssl->handshake->hs_msg + 9,
ssl->handshake->hs_msg + 1, 3 );
}
else
{
/* Make sure msg_type and length are consistent */
if( memcmp( ssl->handshake->hs_msg, ssl->in_msg, 4 ) != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "fragment header mismatch" ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
}
msg = ssl->handshake->hs_msg + 12;
bitmask = msg + msg_len;
/*
* Check and copy current fragment
*/
frag_off = ( ssl->in_msg[6] << 16 ) |
( ssl->in_msg[7] << 8 ) |
ssl->in_msg[8];
frag_len = ( ssl->in_msg[9] << 16 ) |
( ssl->in_msg[10] << 8 ) |
ssl->in_msg[11];
if( frag_off + frag_len > msg_len )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid fragment offset/len: %d + %d > %d",
frag_off, frag_len, msg_len ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
if( frag_len + 12 > ssl->in_msglen )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid fragment length: %d + 12 > %d",
frag_len, ssl->in_msglen ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
MBEDTLS_SSL_DEBUG_MSG( 2, ( "adding fragment, offset = %d, length = %d",
frag_off, frag_len ) );
memcpy( msg + frag_off, ssl->in_msg + 12, frag_len );
ssl_bitmask_set( bitmask, frag_off, frag_len );
/*
* Do we have the complete message by now?
* If yes, finalize it, else ask to read the next record.
*/
if( ssl_bitmask_check( bitmask, msg_len ) != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "message is not complete yet" ) );
return( MBEDTLS_ERR_SSL_WANT_READ );
}
MBEDTLS_SSL_DEBUG_MSG( 2, ( "handshake message completed" ) );
if( frag_len + 12 < ssl->in_msglen )
{
/*
* We'got more handshake messages in the same record.
* This case is not handled now because no know implementation does
* that and it's hard to test, so we prefer to fail cleanly for now.
*/
MBEDTLS_SSL_DEBUG_MSG( 1, ( "last fragment not alone in its record" ) );
return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
}
if( ssl->in_left > ssl->next_record_offset )
{
/*
* We've got more data in the buffer after the current record,
* that we don't want to overwrite. Move it before writing the
* reassembled message, and adjust in_left and next_record_offset.
*/
unsigned char *cur_remain = ssl->in_hdr + ssl->next_record_offset;
unsigned char *new_remain = ssl->in_msg + ssl->in_hslen;
size_t remain_len = ssl->in_left - ssl->next_record_offset;
/* First compute and check new lengths */
ssl->next_record_offset = new_remain - ssl->in_hdr;
ssl->in_left = ssl->next_record_offset + remain_len;
if( ssl->in_left > MBEDTLS_SSL_BUFFER_LEN -
(size_t)( ssl->in_hdr - ssl->in_buf ) )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "reassembled message too large for buffer" ) );
return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
}
memmove( new_remain, cur_remain, remain_len );
}
alloc_len = 12; /* Handshake header */
alloc_len += msg_len; /* Content buffer */
memcpy( ssl->in_msg, ssl->handshake->hs_msg, ssl->in_hslen );
if( add_bitmap )
alloc_len += msg_len / 8 + ( msg_len % 8 != 0 ); /* Bitmap */
mbedtls_zeroize( ssl->handshake->hs_msg, ssl->in_hslen );
mbedtls_free( ssl->handshake->hs_msg );
ssl->handshake->hs_msg = NULL;
return( alloc_len );
}
MBEDTLS_SSL_DEBUG_BUF( 3, "reassembled handshake message",
ssl->in_msg, ssl->in_hslen );
#endif /* MBEDTLS_SSL_PROTO_DTLS */
return( 0 );
static uint32_t ssl_get_hs_total_len( mbedtls_ssl_context const *ssl )
{
return( ( ssl->in_msg[1] << 16 ) |
( ssl->in_msg[2] << 8 ) |
ssl->in_msg[3] );
}
#endif /* MBEDTLS_SSL_PROTO_DTLS */
int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl )
{
......@@ -3255,10 +3619,7 @@ int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl )
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
ssl->in_hslen = mbedtls_ssl_hs_hdr_len( ssl ) + (
( ssl->in_msg[1] << 16 ) |
( ssl->in_msg[2] << 8 ) |
ssl->in_msg[3] );
ssl->in_hslen = mbedtls_ssl_hs_hdr_len( ssl ) + ssl_get_hs_total_len( ssl );
MBEDTLS_SSL_DEBUG_MSG( 3, ( "handshake message: msglen ="
" %d, type = %d, hslen = %d",
......@@ -3270,10 +3631,26 @@ int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl )
int ret;
unsigned int recv_msg_seq = ( ssl->in_msg[4] << 8 ) | ssl->in_msg[5];
/* ssl->handshake is NULL when receiving ClientHello for renego */
if( ssl_check_hs_header( ssl ) != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid handshake header" ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
if( ssl->handshake != NULL &&
recv_msg_seq != ssl->handshake->in_msg_seq )
( ( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER &&
recv_msg_seq != ssl->handshake->in_msg_seq ) ||
( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER &&
ssl->in_msg[0] != MBEDTLS_SSL_HS_CLIENT_HELLO ) ) )
{
if( recv_msg_seq > ssl->handshake->in_msg_seq )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "received future handshake message of sequence number %u (next %u)",
recv_msg_seq,
ssl->handshake->in_msg_seq ) );
return( MBEDTLS_ERR_SSL_EARLY_MESSAGE );
}
/* Retransmit only on last message from previous flight, to avoid
* too many retransmissions.
* Besides, No sane server ever retransmits HelloVerifyRequest */
......@@ -3299,24 +3676,18 @@ int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl )
ssl->handshake->in_msg_seq ) );
}
return( MBEDTLS_ERR_SSL_WANT_READ );
return( MBEDTLS_ERR_SSL_CONTINUE_PROCESSING );
}
/* Wait until message completion to increment in_msg_seq */
/* Reassemble if current message is fragmented or reassembly is
* already in progress */
if( ssl->in_msglen < ssl->in_hslen ||
memcmp( ssl->in_msg + 6, "\0\0\0", 3 ) != 0 ||
memcmp( ssl->in_msg + 9, ssl->in_msg + 1, 3 ) != 0 ||
( ssl->handshake != NULL && ssl->handshake->hs_msg != NULL ) )
/* Message reassembly is handled alongside buffering of future
* messages; the commonality is that both handshake fragments and
* future messages cannot be forwarded immediately to the
* handshake logic layer. */
if( ssl_hs_is_proper_fragment( ssl ) == 1 )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "found fragmented DTLS handshake message" ) );
if( ( ret = ssl_reassemble_dtls_handshake( ssl ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "ssl_reassemble_dtls_handshake", ret );
return( ret );
}
return( MBEDTLS_ERR_SSL_EARLY_MESSAGE );
}
}
else
......@@ -3333,9 +3704,9 @@ int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl )
void mbedtls_ssl_update_handshake_status( mbedtls_ssl_context *ssl )
{
mbedtls_ssl_handshake_params * const hs = ssl->handshake;
if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER &&
ssl->handshake != NULL )
if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER && hs != NULL )
{
ssl->handshake->update_checksum( ssl, ssl->in_msg, ssl->in_hslen );
}
......@@ -3345,7 +3716,29 @@ void mbedtls_ssl_update_handshake_status( mbedtls_ssl_context *ssl )
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
ssl->handshake != NULL )
{
ssl->handshake->in_msg_seq++;
unsigned offset;
mbedtls_ssl_hs_buffer *hs_buf;
/* Increment handshake sequence number */
hs->in_msg_seq++;
/*
* Clear up handshake buffering and reassembly structure.
*/
/* Free first entry */
ssl_buffering_free_slot( ssl, 0 );
/* Shift all other entries */
for( offset = 0, hs_buf = &hs->buffering.hs[0];
offset + 1 < MBEDTLS_SSL_MAX_BUFFERED_HS;
offset++, hs_buf++ )
{
*hs_buf = *(hs_buf + 1);
}
/* Create a fresh last entry */
memset( hs_buf, 0, sizeof( mbedtls_ssl_hs_buffer ) );
}
#endif
}
......@@ -3598,7 +3991,7 @@ static int ssl_handle_possible_reconnect( mbedtls_ssl_context *ssl )
ssl->conf->p_cookie,
ssl->cli_id, ssl->cli_id_len,
ssl->in_buf, ssl->in_left,
ssl->out_buf, MBEDTLS_SSL_MAX_CONTENT_LEN, &len );
ssl->out_buf, MBEDTLS_SSL_OUT_CONTENT_LEN, &len );
MBEDTLS_SSL_DEBUG_RET( 2, "ssl_check_dtls_clihlo_cookie", ret );
......@@ -3695,88 +4088,30 @@ static int ssl_parse_record_header( mbedtls_ssl_context *ssl )
}
/* Check length against the size of our buffer */
if( ssl->in_msglen > MBEDTLS_SSL_BUFFER_LEN
if( ssl->in_msglen > MBEDTLS_SSL_IN_BUFFER_LEN
- (size_t)( ssl->in_msg - ssl->in_buf ) )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
/* Check length against bounds of the current transform and version */
if( ssl->transform_in == NULL )
{
if( ssl->in_msglen < 1 ||
ssl->in_msglen > MBEDTLS_SSL_MAX_CONTENT_LEN )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
}
else
{
if( ssl->in_msglen < ssl->transform_in->minlen )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
#if defined(MBEDTLS_SSL_PROTO_SSL3)
if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 &&
ssl->in_msglen > ssl->transform_in->minlen + MBEDTLS_SSL_MAX_CONTENT_LEN )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
defined(MBEDTLS_SSL_PROTO_TLS1_2)
/*
* TLS encrypted messages can have up to 256 bytes of padding
*/
if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 &&
ssl->in_msglen > ssl->transform_in->minlen +
MBEDTLS_SSL_MAX_CONTENT_LEN + 256 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
#endif
}
/*
* DTLS-related tests done last, because most of them may result in
* silently dropping the record (but not the whole datagram), and we only
* want to consider that after ensuring that the "basic" fields (type,
* version, length) are sane.
* DTLS-related tests.
* Check epoch before checking length constraint because
* the latter varies with the epoch. E.g., if a ChangeCipherSpec
* message gets duplicated before the corresponding Finished message,
* the second ChangeCipherSpec should be discarded because it belongs
* to an old epoch, but not because its length is shorter than
* the minimum record length for packets using the new record transform.
* Note that these two kinds of failures are handled differently,
* as an unexpected record is silently skipped but an invalid
* record leads to the entire datagram being dropped.
*/
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
{
unsigned int rec_epoch = ( ssl->in_ctr[0] << 8 ) | ssl->in_ctr[1];
/* Drop unexpected ChangeCipherSpec messages */
if( ssl->in_msgtype == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC &&
ssl->state != MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC &&
ssl->state != MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping unexpected ChangeCipherSpec" ) );
return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD );
}
/* Drop unexpected ApplicationData records,
* except at the beginning of renegotiations */
if( ssl->in_msgtype == MBEDTLS_SSL_MSG_APPLICATION_DATA &&
ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER
#if defined(MBEDTLS_SSL_RENEGOTIATION)
&& ! ( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS &&
ssl->state == MBEDTLS_SSL_SERVER_HELLO )
#endif
)
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping unexpected ApplicationData" ) );
return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD );
}
/* Check epoch (and sequence number) with DTLS */
if( rec_epoch != ssl->in_epoch )
{
......@@ -3804,7 +4139,16 @@ static int ssl_parse_record_header( mbedtls_ssl_context *ssl )
}
else
#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */
{
/* Consider buffering the record. */
if( rec_epoch == (unsigned int) ssl->in_epoch + 1 )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Consider record for buffering" ) );
return( MBEDTLS_ERR_SSL_EARLY_MESSAGE );
}
return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD );
}
}
#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
......@@ -3816,9 +4160,65 @@ static int ssl_parse_record_header( mbedtls_ssl_context *ssl )
return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD );
}
#endif
/* Drop unexpected ApplicationData records,
* except at the beginning of renegotiations */
if( ssl->in_msgtype == MBEDTLS_SSL_MSG_APPLICATION_DATA &&
ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER
#if defined(MBEDTLS_SSL_RENEGOTIATION)
&& ! ( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS &&
ssl->state == MBEDTLS_SSL_SERVER_HELLO )
#endif
)
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping unexpected ApplicationData" ) );
return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD );
}
}
#endif /* MBEDTLS_SSL_PROTO_DTLS */
/* Check length against bounds of the current transform and version */
if( ssl->transform_in == NULL )
{
if( ssl->in_msglen < 1 ||
ssl->in_msglen > MBEDTLS_SSL_IN_CONTENT_LEN )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
}
else
{
if( ssl->in_msglen < ssl->transform_in->minlen )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
#if defined(MBEDTLS_SSL_PROTO_SSL3)
if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 &&
ssl->in_msglen > ssl->transform_in->minlen + MBEDTLS_SSL_IN_CONTENT_LEN )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
defined(MBEDTLS_SSL_PROTO_TLS1_2)
/*
* TLS encrypted messages can have up to 256 bytes of padding
*/
if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 &&
ssl->in_msglen > ssl->transform_in->minlen +
MBEDTLS_SSL_IN_CONTENT_LEN + 256 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
#endif
}
return( 0 );
}
......@@ -3859,7 +4259,7 @@ static int ssl_prepare_record_content( mbedtls_ssl_context *ssl )
MBEDTLS_SSL_DEBUG_BUF( 4, "input payload after decrypt",
ssl->in_msg, ssl->in_msglen );
if( ssl->in_msglen > MBEDTLS_SSL_MAX_CONTENT_LEN )
if( ssl->in_msglen > MBEDTLS_SSL_IN_CONTENT_LEN )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
......@@ -3897,7 +4297,14 @@ static void ssl_handshake_wrapup_free_hs_transform( mbedtls_ssl_context *ssl );
* RFC 6347 4.1.2.7) and continue reading until a valid record is found.
*
*/
int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl )
/* Helper functions for mbedtls_ssl_read_record(). */
static int ssl_consume_current_message( mbedtls_ssl_context *ssl );
static int ssl_get_next_record( mbedtls_ssl_context *ssl );
static int ssl_record_is_in_progress( mbedtls_ssl_context *ssl );
int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl,
unsigned update_hs_digest )
{
int ret;
......@@ -3907,30 +4314,71 @@ int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl )
{
do {
if( ( ret = mbedtls_ssl_read_record_layer( ssl ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_read_record_layer" ), ret );
ret = ssl_consume_current_message( ssl );
if( ret != 0 )
return( ret );
if( ssl_record_is_in_progress( ssl ) == 0 )
{
#if defined(MBEDTLS_SSL_PROTO_DTLS)
int have_buffered = 0;
/* We only check for buffered messages if the
* current datagram is fully consumed. */
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
ssl_next_record_is_in_datagram( ssl ) == 0 )
{
if( ssl_load_buffered_message( ssl ) == 0 )
have_buffered = 1;
}
if( have_buffered == 0 )
#endif /* MBEDTLS_SSL_PROTO_DTLS */
{
ret = ssl_get_next_record( ssl );
if( ret == MBEDTLS_ERR_SSL_CONTINUE_PROCESSING )
continue;
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_get_next_record" ), ret );
return( ret );
}
}
}
ret = mbedtls_ssl_handle_message_type( ssl );
} while( MBEDTLS_ERR_SSL_NON_FATAL == ret );
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ret == MBEDTLS_ERR_SSL_EARLY_MESSAGE )
{
/* Buffer future message */
ret = ssl_buffer_message( ssl );
if( ret != 0 )
return( ret );
ret = MBEDTLS_ERR_SSL_CONTINUE_PROCESSING;
}
#endif /* MBEDTLS_SSL_PROTO_DTLS */
} while( MBEDTLS_ERR_SSL_NON_FATAL == ret ||
MBEDTLS_ERR_SSL_CONTINUE_PROCESSING == ret );
if( 0 != ret )
{
MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_read_record_layer" ), ret );
MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_handle_message_type" ), ret );
return( ret );
}
if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE )
if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE &&
update_hs_digest == 1 )
{
mbedtls_ssl_update_handshake_status( ssl );
}
}
else
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= reuse previously read message" ) );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "reuse previously read message" ) );
ssl->keep_current_message = 0;
}
......@@ -3939,13 +4387,350 @@ int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl )
return( 0 );
}
int mbedtls_ssl_read_record_layer( mbedtls_ssl_context *ssl )
#if defined(MBEDTLS_SSL_PROTO_DTLS)
static int ssl_next_record_is_in_datagram( mbedtls_ssl_context *ssl )
{
int ret;
if( ssl->in_left > ssl->next_record_offset )
return( 1 );
return( 0 );
}
static int ssl_load_buffered_message( mbedtls_ssl_context *ssl )
{
mbedtls_ssl_handshake_params * const hs = ssl->handshake;
mbedtls_ssl_hs_buffer * hs_buf;
int ret = 0;
if( hs == NULL )
return( -1 );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_load_buffered_messsage" ) );
if( ssl->state == MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC ||
ssl->state == MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC )
{
/* Check if we have seen a ChangeCipherSpec before.
* If yes, synthesize a CCS record. */
if( !hs->buffering.seen_ccs )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "CCS not seen in the current flight" ) );
ret = -1;
goto exit;
}
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Injecting buffered CCS message" ) );
ssl->in_msgtype = MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC;
ssl->in_msglen = 1;
ssl->in_msg[0] = 1;
/* As long as they are equal, the exact value doesn't matter. */
ssl->in_left = 0;
ssl->next_record_offset = 0;
hs->buffering.seen_ccs = 0;
goto exit;
}
#if defined(MBEDTLS_DEBUG_C)
/* Debug only */
{
unsigned offset;
for( offset = 1; offset < MBEDTLS_SSL_MAX_BUFFERED_HS; offset++ )
{
hs_buf = &hs->buffering.hs[offset];
if( hs_buf->is_valid == 1 )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Future message with sequence number %u %s buffered.",
hs->in_msg_seq + offset,
hs_buf->is_complete ? "fully" : "partially" ) );
}
}
}
#endif /* MBEDTLS_DEBUG_C */
/* Check if we have buffered and/or fully reassembled the
* next handshake message. */
hs_buf = &hs->buffering.hs[0];
if( ( hs_buf->is_valid == 1 ) && ( hs_buf->is_complete == 1 ) )
{
/* Synthesize a record containing the buffered HS message. */
size_t msg_len = ( hs_buf->data[1] << 16 ) |
( hs_buf->data[2] << 8 ) |
hs_buf->data[3];
/* Double-check that we haven't accidentally buffered
* a message that doesn't fit into the input buffer. */
if( msg_len + 12 > MBEDTLS_SSL_IN_CONTENT_LEN )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Next handshake message has been buffered - load" ) );
MBEDTLS_SSL_DEBUG_BUF( 3, "Buffered handshake message (incl. header)",
hs_buf->data, msg_len + 12 );
ssl->in_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE;
ssl->in_hslen = msg_len + 12;
ssl->in_msglen = msg_len + 12;
memcpy( ssl->in_msg, hs_buf->data, ssl->in_hslen );
ret = 0;
goto exit;
}
else
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Next handshake message %u not or only partially bufffered",
hs->in_msg_seq ) );
}
ret = -1;
exit:
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= ssl_load_buffered_message" ) );
return( ret );
}
static int ssl_buffer_make_space( mbedtls_ssl_context *ssl,
size_t desired )
{
int offset;
mbedtls_ssl_handshake_params * const hs = ssl->handshake;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Attempt to free buffered messages to have %u bytes available",
(unsigned) desired ) );
/* Get rid of future records epoch first, if such exist. */
ssl_free_buffered_record( ssl );
/* Check if we have enough space available now. */
if( desired <= ( MBEDTLS_SSL_DTLS_MAX_BUFFERING -
hs->buffering.total_bytes_buffered ) )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Enough space available after freeing future epoch record" ) );
return( 0 );
}
/* We don't have enough space to buffer the next expected handshake
* message. Remove buffers used for future messages to gain space,
* starting with the most distant one. */
for( offset = MBEDTLS_SSL_MAX_BUFFERED_HS - 1;
offset >= 0; offset-- )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Free buffering slot %d to make space for reassembly of next handshake message",
offset ) );
ssl_buffering_free_slot( ssl, (uint8_t) offset );
/* Check if we have enough space available now. */
if( desired <= ( MBEDTLS_SSL_DTLS_MAX_BUFFERING -
hs->buffering.total_bytes_buffered ) )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Enough space available after freeing buffered HS messages" ) );
return( 0 );
}
}
return( -1 );
}
static int ssl_buffer_message( mbedtls_ssl_context *ssl )
{
int ret = 0;
mbedtls_ssl_handshake_params * const hs = ssl->handshake;
if( hs == NULL )
return( 0 );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_buffer_message" ) );
switch( ssl->in_msgtype )
{
case MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC:
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Remember CCS message" ) );
hs->buffering.seen_ccs = 1;
break;
case MBEDTLS_SSL_MSG_HANDSHAKE:
{
unsigned recv_msg_seq_offset;
unsigned recv_msg_seq = ( ssl->in_msg[4] << 8 ) | ssl->in_msg[5];
mbedtls_ssl_hs_buffer *hs_buf;
size_t msg_len = ssl->in_hslen - 12;
/* We should never receive an old handshake
* message - double-check nonetheless. */
if( recv_msg_seq < ssl->handshake->in_msg_seq )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
recv_msg_seq_offset = recv_msg_seq - ssl->handshake->in_msg_seq;
if( recv_msg_seq_offset >= MBEDTLS_SSL_MAX_BUFFERED_HS )
{
/* Silently ignore -- message too far in the future */
MBEDTLS_SSL_DEBUG_MSG( 2,
( "Ignore future HS message with sequence number %u, "
"buffering window %u - %u",
recv_msg_seq, ssl->handshake->in_msg_seq,
ssl->handshake->in_msg_seq + MBEDTLS_SSL_MAX_BUFFERED_HS - 1 ) );
goto exit;
}
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffering HS message with sequence number %u, offset %u ",
recv_msg_seq, recv_msg_seq_offset ) );
hs_buf = &hs->buffering.hs[ recv_msg_seq_offset ];
/* Check if the buffering for this seq nr has already commenced. */
if( !hs_buf->is_valid )
{
size_t reassembly_buf_sz;
hs_buf->is_fragmented =
( ssl_hs_is_proper_fragment( ssl ) == 1 );
/* We copy the message back into the input buffer
* after reassembly, so check that it's not too large.
* This is an implementation-specific limitation
* and not one from the standard, hence it is not
* checked in ssl_check_hs_header(). */
if( msg_len + 12 > MBEDTLS_SSL_IN_CONTENT_LEN )
{
/* Ignore message */
goto exit;
}
/* Check if we have enough space to buffer the message. */
if( hs->buffering.total_bytes_buffered >
MBEDTLS_SSL_DTLS_MAX_BUFFERING )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
reassembly_buf_sz = ssl_get_reassembly_buffer_size( msg_len,
hs_buf->is_fragmented );
if( reassembly_buf_sz > ( MBEDTLS_SSL_DTLS_MAX_BUFFERING -
hs->buffering.total_bytes_buffered ) )
{
if( recv_msg_seq_offset > 0 )
{
/* If we can't buffer a future message because
* of space limitations -- ignore. */
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffering of future message of size %u would exceed the compile-time limit %u (already %u bytes buffered) -- ignore\n",
(unsigned) msg_len, MBEDTLS_SSL_DTLS_MAX_BUFFERING,
(unsigned) hs->buffering.total_bytes_buffered ) );
goto exit;
}
else
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffering of future message of size %u would exceed the compile-time limit %u (already %u bytes buffered) -- attempt to make space by freeing buffered future messages\n",
(unsigned) msg_len, MBEDTLS_SSL_DTLS_MAX_BUFFERING,
(unsigned) hs->buffering.total_bytes_buffered ) );
}
if( ssl_buffer_make_space( ssl, reassembly_buf_sz ) != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Reassembly of next message of size %u (%u with bitmap) would exceed the compile-time limit %u (already %u bytes buffered) -- fail\n",
(unsigned) msg_len,
(unsigned) reassembly_buf_sz,
MBEDTLS_SSL_DTLS_MAX_BUFFERING,
(unsigned) hs->buffering.total_bytes_buffered ) );
ret = MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL;
goto exit;
}
}
MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialize reassembly, total length = %d",
msg_len ) );
hs_buf->data = mbedtls_calloc( 1, reassembly_buf_sz );
if( hs_buf->data == NULL )
{
ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
goto exit;
}
hs_buf->data_len = reassembly_buf_sz;
/* Prepare final header: copy msg_type, length and message_seq,
* then add standardised fragment_offset and fragment_length */
memcpy( hs_buf->data, ssl->in_msg, 6 );
memset( hs_buf->data + 6, 0, 3 );
memcpy( hs_buf->data + 9, hs_buf->data + 1, 3 );
hs_buf->is_valid = 1;
hs->buffering.total_bytes_buffered += reassembly_buf_sz;
}
else
{
/* Make sure msg_type and length are consistent */
if( memcmp( hs_buf->data, ssl->in_msg, 4 ) != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "Fragment header mismatch - ignore" ) );
/* Ignore */
goto exit;
}
}
if( !hs_buf->is_complete )
{
size_t frag_len, frag_off;
unsigned char * const msg = hs_buf->data + 12;
/*
* Check and copy current fragment
*/
/* Validation of header fields already done in
* mbedtls_ssl_prepare_handshake_record(). */
frag_off = ssl_get_hs_frag_off( ssl );
frag_len = ssl_get_hs_frag_len( ssl );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "adding fragment, offset = %d, length = %d",
frag_off, frag_len ) );
memcpy( msg + frag_off, ssl->in_msg + 12, frag_len );
if( hs_buf->is_fragmented )
{
unsigned char * const bitmask = msg + msg_len;
ssl_bitmask_set( bitmask, frag_off, frag_len );
hs_buf->is_complete = ( ssl_bitmask_check( bitmask,
msg_len ) == 0 );
}
else
{
hs_buf->is_complete = 1;
}
MBEDTLS_SSL_DEBUG_MSG( 2, ( "message %scomplete",
hs_buf->is_complete ? "" : "not yet " ) );
}
break;
}
default:
/* We don't buffer other types of messages. */
break;
}
exit:
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= ssl_buffer_message" ) );
return( ret );
}
#endif /* MBEDTLS_SSL_PROTO_DTLS */
static int ssl_consume_current_message( mbedtls_ssl_context *ssl )
{
/*
* Step A
*
* Consume last content-layer message and potentially
* update in_msglen which keeps track of the contents'
* consumption state.
......@@ -3957,11 +4742,6 @@ int mbedtls_ssl_read_record_layer( mbedtls_ssl_context *ssl )
* (2) Alert messages:
* Consume whole record content, in_msglen = 0.
*
* NOTE: This needs to be fixed, since like for
* handshake messages it is allowed to have
* multiple alerts witin a single record.
* Internal reference IOTSSL-1321.
*
* (3) Change cipher spec:
* Consume whole record content, in_msglen = 0.
*
......@@ -3989,12 +4769,12 @@ int mbedtls_ssl_read_record_layer( mbedtls_ssl_context *ssl )
*/
/* Notes:
* (1) in_hslen is *NOT* necessarily the size of the
* (1) in_hslen is not necessarily the size of the
* current handshake content: If DTLS handshake
* fragmentation is used, that's the fragment
* size instead. Using the total handshake message
* size here is FAULTY and should be changed at
* some point. Internal reference IOTSSL-1414.
* size here is faulty and should be changed at
* some point.
* (2) While it doesn't seem to cause problems, one
* has to be very careful not to assume that in_hslen
* is always <= in_msglen in a sensible communication.
......@@ -4011,47 +4791,182 @@ int mbedtls_ssl_read_record_layer( mbedtls_ssl_context *ssl )
memmove( ssl->in_msg, ssl->in_msg + ssl->in_hslen,
ssl->in_msglen );
MBEDTLS_SSL_DEBUG_BUF( 4, "remaining content in record",
ssl->in_msg, ssl->in_msglen );
}
else
{
ssl->in_msglen = 0;
}
MBEDTLS_SSL_DEBUG_BUF( 4, "remaining content in record",
ssl->in_msg, ssl->in_msglen );
}
else
{
ssl->in_msglen = 0;
}
ssl->in_hslen = 0;
}
/* Case (4): Application data */
else if( ssl->in_offt != NULL )
{
return( 0 );
}
/* Everything else (CCS & Alerts) */
else
{
ssl->in_msglen = 0;
}
return( 0 );
}
static int ssl_record_is_in_progress( mbedtls_ssl_context *ssl )
{
if( ssl->in_msglen > 0 )
return( 1 );
return( 0 );
}
#if defined(MBEDTLS_SSL_PROTO_DTLS)
static void ssl_free_buffered_record( mbedtls_ssl_context *ssl )
{
mbedtls_ssl_handshake_params * const hs = ssl->handshake;
if( hs == NULL )
return;
if( hs->buffering.future_record.data != NULL )
{
hs->buffering.total_bytes_buffered -=
hs->buffering.future_record.len;
mbedtls_free( hs->buffering.future_record.data );
hs->buffering.future_record.data = NULL;
}
}
static int ssl_load_buffered_record( mbedtls_ssl_context *ssl )
{
mbedtls_ssl_handshake_params * const hs = ssl->handshake;
unsigned char * rec;
size_t rec_len;
unsigned rec_epoch;
ssl->in_hslen = 0;
if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM )
return( 0 );
if( hs == NULL )
return( 0 );
rec = hs->buffering.future_record.data;
rec_len = hs->buffering.future_record.len;
rec_epoch = hs->buffering.future_record.epoch;
if( rec == NULL )
return( 0 );
/* Only consider loading future records if the
* input buffer is empty. */
if( ssl_next_record_is_in_datagram( ssl ) == 1 )
return( 0 );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_load_buffered_record" ) );
if( rec_epoch != ssl->in_epoch )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffered record not from current epoch." ) );
goto exit;
}
/* Case (4): Application data */
else if( ssl->in_offt != NULL )
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Found buffered record from current epoch - load" ) );
/* Double-check that the record is not too large */
if( rec_len > MBEDTLS_SSL_IN_BUFFER_LEN -
(size_t)( ssl->in_hdr - ssl->in_buf ) )
{
return( 0 );
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
/* Everything else (CCS & Alerts) */
else
memcpy( ssl->in_hdr, rec, rec_len );
ssl->in_left = rec_len;
ssl->next_record_offset = 0;
ssl_free_buffered_record( ssl );
exit:
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= ssl_load_buffered_record" ) );
return( 0 );
}
static int ssl_buffer_future_record( mbedtls_ssl_context *ssl )
{
mbedtls_ssl_handshake_params * const hs = ssl->handshake;
size_t const rec_hdr_len = 13;
size_t const total_buf_sz = rec_hdr_len + ssl->in_msglen;
/* Don't buffer future records outside handshakes. */
if( hs == NULL )
return( 0 );
/* Only buffer handshake records (we are only interested
* in Finished messages). */
if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE )
return( 0 );
/* Don't buffer more than one future epoch record. */
if( hs->buffering.future_record.data != NULL )
return( 0 );
/* Don't buffer record if there's not enough buffering space remaining. */
if( total_buf_sz > ( MBEDTLS_SSL_DTLS_MAX_BUFFERING -
hs->buffering.total_bytes_buffered ) )
{
ssl->in_msglen = 0;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffering of future epoch record of size %u would exceed the compile-time limit %u (already %u bytes buffered) -- ignore\n",
(unsigned) total_buf_sz, MBEDTLS_SSL_DTLS_MAX_BUFFERING,
(unsigned) hs->buffering.total_bytes_buffered ) );
return( 0 );
}
/*
* Step B
*
* Fetch and decode new record if current one is fully consumed.
*
*/
/* Buffer record */
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffer record from epoch %u",
ssl->in_epoch + 1 ) );
MBEDTLS_SSL_DEBUG_BUF( 3, "Buffered record", ssl->in_hdr,
rec_hdr_len + ssl->in_msglen );
if( ssl->in_msglen > 0 )
/* ssl_parse_record_header() only considers records
* of the next epoch as candidates for buffering. */
hs->buffering.future_record.epoch = ssl->in_epoch + 1;
hs->buffering.future_record.len = total_buf_sz;
hs->buffering.future_record.data =
mbedtls_calloc( 1, hs->buffering.future_record.len );
if( hs->buffering.future_record.data == NULL )
{
/* There's something left to be processed in the current record. */
/* If we run out of RAM trying to buffer a
* record from the next epoch, just ignore. */
return( 0 );
}
/* Need to fetch a new record */
memcpy( hs->buffering.future_record.data, ssl->in_hdr, total_buf_sz );
#if defined(MBEDTLS_SSL_PROTO_DTLS)
read_record_header:
#endif
hs->buffering.total_bytes_buffered += total_buf_sz;
return( 0 );
}
#endif /* MBEDTLS_SSL_PROTO_DTLS */
static int ssl_get_next_record( mbedtls_ssl_context *ssl )
{
int ret;
/* Current record either fully processed or to be discarded. */
#if defined(MBEDTLS_SSL_PROTO_DTLS)
/* We might have buffered a future record; if so,
* and if the epoch matches now, load it.
* On success, this call will set ssl->in_left to
* the length of the buffered record, so that
* the calls to ssl_fetch_input() below will
* essentially be no-ops. */
ret = ssl_load_buffered_record( ssl );
if( ret != 0 )
return( ret );
#endif /* MBEDTLS_SSL_PROTO_DTLS */
if( ( ret = mbedtls_ssl_fetch_input( ssl, mbedtls_ssl_hdr_len( ssl ) ) ) != 0 )
{
......@@ -4065,6 +4980,16 @@ read_record_header:
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
ret != MBEDTLS_ERR_SSL_CLIENT_RECONNECT )
{
if( ret == MBEDTLS_ERR_SSL_EARLY_MESSAGE )
{
ret = ssl_buffer_future_record( ssl );
if( ret != 0 )
return( ret );
/* Fall through to handling of unexpected records */
ret = MBEDTLS_ERR_SSL_UNEXPECTED_RECORD;
}
if( ret == MBEDTLS_ERR_SSL_UNEXPECTED_RECORD )
{
/* Skip unexpected record (but not whole datagram) */
......@@ -4085,7 +5010,7 @@ read_record_header:
}
/* Get next record */
goto read_record_header;
return( MBEDTLS_ERR_SSL_CONTINUE_PROCESSING );
}
#endif
return( ret );
......@@ -4104,7 +5029,13 @@ read_record_header:
/* Done reading this record, get ready for the next one */
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
{
ssl->next_record_offset = ssl->in_msglen + mbedtls_ssl_hdr_len( ssl );
if( ssl->next_record_offset < ssl->in_left )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "more than one record within datagram" ) );
}
}
else
#endif
ssl->in_left = 0;
......@@ -4151,7 +5082,7 @@ read_record_header:
ssl->in_left = 0;
MBEDTLS_SSL_DEBUG_MSG( 1, ( "discarding invalid record (mac)" ) );
goto read_record_header;
return( MBEDTLS_ERR_SSL_CONTINUE_PROCESSING );
}
return( ret );
......@@ -4172,46 +5103,6 @@ read_record_header:
}
}
/*
* When we sent the last flight of the handshake, we MUST respond to a
* retransmit of the peer's previous flight with a retransmit. (In
* practice, only the Finished message will make it, other messages
* including CCS use the old transform so they're dropped as invalid.)
*
* If the record we received is not a handshake message, however, it
* means the peer received our last flight so we can clean up
* handshake info.
*
* This check needs to be done before prepare_handshake() due to an edge
* case: if the client immediately requests renegotiation, this
* finishes the current handshake first, avoiding the new ClientHello
* being mistaken for an ancient message in the current handshake.
*/
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
ssl->handshake != NULL &&
ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER )
{
if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE &&
ssl->in_msg[0] == MBEDTLS_SSL_HS_FINISHED )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "received retransmit of last flight" ) );
if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_resend", ret );
return( ret );
}
return( MBEDTLS_ERR_SSL_WANT_READ );
}
else
{
ssl_handshake_wrapup_free_hs_transform( ssl );
}
}
#endif
return( 0 );
}
......@@ -4230,6 +5121,39 @@ int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl )
}
}
if( ssl->in_msgtype == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC )
{
if( ssl->in_msglen != 1 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid CCS message, len: %d",
ssl->in_msglen ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
if( ssl->in_msg[0] != 1 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid CCS message, content: %02x",
ssl->in_msg[0] ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
ssl->state != MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC &&
ssl->state != MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC )
{
if( ssl->handshake == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping ChangeCipherSpec outside handshake" ) );
return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD );
}
MBEDTLS_SSL_DEBUG_MSG( 1, ( "received out-of-order ChangeCipherSpec - remember" ) );
return( MBEDTLS_ERR_SSL_EARLY_MESSAGE );
}
#endif
}
if( ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT )
{
if( ssl->in_msglen != 2 )
......@@ -4266,7 +5190,7 @@ int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl )
if( ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_WARNING &&
ssl->in_msg[1] == MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "is a SSLv3 no_cert" ) );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "is a SSLv3 no renegotiation alert" ) );
/* Will be handled when trying to parse ServerHello */
return( 0 );
}
......@@ -4288,6 +5212,15 @@ int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl )
return MBEDTLS_ERR_SSL_NON_FATAL;
}
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
ssl->handshake != NULL &&
ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER )
{
ssl_handshake_wrapup_free_hs_transform( ssl );
}
#endif
return( 0 );
}
......@@ -4322,7 +5255,7 @@ int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl,
ssl->out_msg[0] = level;
ssl->out_msg[1] = message;
if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
if( ( ret = mbedtls_ssl_write_record( ssl, SSL_FORCE_FLUSH ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
return( ret );
......@@ -4462,10 +5395,10 @@ int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl )
while( crt != NULL )
{
n = crt->raw.len;
if( n > MBEDTLS_SSL_MAX_CONTENT_LEN - 3 - i )
if( n > MBEDTLS_SSL_OUT_CONTENT_LEN - 3 - i )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "certificate too large, %d > %d",
i + 3 + n, MBEDTLS_SSL_MAX_CONTENT_LEN ) );
i + 3 + n, MBEDTLS_SSL_OUT_CONTENT_LEN ) );
return( MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE );
}
......@@ -4491,9 +5424,9 @@ write_msg:
ssl->state++;
if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret );
return( ret );
}
......@@ -4502,60 +5435,16 @@ write_msg:
return( ret );
}
int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
/*
* 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 )
{
int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
int ret;
size_t i, n;
const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info;
int authmode = ssl->conf->authmode;
uint8_t alert;
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 );
}
#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 defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
if( ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET )
authmode = ssl->handshake->sni_authmode;
#endif
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( ( ret = mbedtls_ssl_read_record( ssl ) ) != 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 );
}
ssl->state++;
#if defined(MBEDTLS_SSL_SRV_C)
#if defined(MBEDTLS_SSL_PROTO_SSL3)
/*
......@@ -4575,10 +5464,7 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
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;
if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL )
return( 0 );
else
return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE );
return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE );
}
}
#endif /* MBEDTLS_SSL_PROTO_SSL3 */
......@@ -4599,10 +5485,7 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
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;
if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL )
return( 0 );
else
return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE );
return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE );
}
}
#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \
......@@ -4752,6 +5635,94 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
}
#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */
return( 0 );
}
int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
{
int ret;
const mbedtls_ssl_ciphersuite_t * const 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;
#else
const int authmode = ssl->conf->authmode;
#endif
void *rs_ctx = NULL;
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 );
}
#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 )
{
mbedtls_x509_crt *ca_chain;
......@@ -4773,19 +5744,24 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
/*
* Main check: verify certificate
*/
ret = mbedtls_x509_crt_verify_with_profile(
ret = mbedtls_x509_crt_verify_restartable(
ssl->session_negotiate->peer_cert,
ca_chain, ca_crl,
ssl->conf->cert_profile,
ssl->hostname,
&ssl->session_negotiate->verify_result,
ssl->conf->f_vrfy, ssl->conf->p_vrfy );
ssl->conf->f_vrfy, ssl->conf->p_vrfy, rs_ctx );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret );
}
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
return( MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS );
#endif
/*
* Secondary checks: always done, but change 'ret' only if it was 0
*/
......@@ -4838,6 +5814,8 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
if( ret != 0 )
{
uint8_t alert;
/* The certificate may have been rejected for several reasons.
Pick one and send the corresponding alert. Which alert to send
may be a subject of debate in some cases. */
......@@ -4880,6 +5858,8 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
#endif /* MBEDTLS_DEBUG_C */
}
ssl->state++;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) );
return( ret );
......@@ -4904,9 +5884,9 @@ int mbedtls_ssl_write_change_cipher_spec( mbedtls_ssl_context *ssl )
ssl->state++;
if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret );
return( ret );
}
......@@ -4921,7 +5901,7 @@ int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl )
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse change cipher spec" ) );
if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 )
if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
return( ret );
......@@ -4935,13 +5915,8 @@ int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl )
return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
}
if( ssl->in_msglen != 1 || ssl->in_msg[0] != 1 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad change cipher spec message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
return( MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC );
}
/* CCS records are only accepted if they have length 1 and content '1',
* so we don't need to check this here. */
/*
* Switch to our negotiated transform and session parameters for inbound
......@@ -4971,16 +5946,7 @@ int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl )
#endif /* MBEDTLS_SSL_PROTO_DTLS */
memset( ssl->in_ctr, 0, 8 );
/*
* Set the in_msg pointer to the correct location based on IV length
*/
if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 )
{
ssl->in_msg = ssl->in_iv + ssl->transform_negotiate->ivlen -
ssl->transform_negotiate->fixed_ivlen;
}
else
ssl->in_msg = ssl->in_iv;
ssl_update_in_pointers( ssl, ssl->transform_negotiate );
#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL)
if( mbedtls_ssl_hw_record_activate != NULL )
......@@ -5171,9 +6137,9 @@ static void ssl_calc_finished_ssl(
mbedtls_md5_free( &md5 );
mbedtls_sha1_free( &sha1 );
mbedtls_zeroize( padbuf, sizeof( padbuf ) );
mbedtls_zeroize( md5sum, sizeof( md5sum ) );
mbedtls_zeroize( sha1sum, sizeof( sha1sum ) );
mbedtls_platform_zeroize( padbuf, sizeof( padbuf ) );
mbedtls_platform_zeroize( md5sum, sizeof( md5sum ) );
mbedtls_platform_zeroize( sha1sum, sizeof( sha1sum ) );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) );
}
......@@ -5232,7 +6198,7 @@ static void ssl_calc_finished_tls(
mbedtls_md5_free( &md5 );
mbedtls_sha1_free( &sha1 );
mbedtls_zeroize( padbuf, sizeof( padbuf ) );
mbedtls_platform_zeroize( padbuf, sizeof( padbuf ) );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) );
}
......@@ -5282,7 +6248,7 @@ static void ssl_calc_finished_tls_sha256(
mbedtls_sha256_free( &sha256 );
mbedtls_zeroize( padbuf, sizeof( padbuf ) );
mbedtls_platform_zeroize( padbuf, sizeof( padbuf ) );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) );
}
......@@ -5331,7 +6297,7 @@ static void ssl_calc_finished_tls_sha384(
mbedtls_sha512_free( &sha512 );
mbedtls_zeroize( padbuf, sizeof( padbuf ) );
mbedtls_platform_zeroize( padbuf, sizeof( padbuf ) );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) );
}
......@@ -5345,7 +6311,7 @@ static void ssl_handshake_wrapup_free_hs_transform( mbedtls_ssl_context *ssl )
/*
* Free our handshake params
*/
mbedtls_ssl_handshake_free( ssl->handshake );
mbedtls_ssl_handshake_free( ssl );
mbedtls_free( ssl->handshake );
ssl->handshake = NULL;
......@@ -5431,16 +6397,7 @@ int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl )
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write finished" ) );
/*
* Set the out_msg pointer to the correct location based on IV length
*/
if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 )
{
ssl->out_msg = ssl->out_iv + ssl->transform_negotiate->ivlen -
ssl->transform_negotiate->fixed_ivlen;
}
else
ssl->out_msg = ssl->out_iv;
ssl_update_out_pointers( ssl, ssl->transform_negotiate );
ssl->handshake->calc_finished( ssl, ssl->out_msg + 4, ssl->conf->endpoint );
......@@ -5492,14 +6449,14 @@ int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl )
/* Remember current epoch settings for resending */
ssl->handshake->alt_transform_out = ssl->transform_out;
memcpy( ssl->handshake->alt_out_ctr, ssl->out_ctr, 8 );
memcpy( ssl->handshake->alt_out_ctr, ssl->cur_out_ctr, 8 );
/* Set sequence_number to zero */
memset( ssl->out_ctr + 2, 0, 6 );
memset( ssl->cur_out_ctr + 2, 0, 6 );
/* Increment epoch */
for( i = 2; i > 0; i-- )
if( ++ssl->out_ctr[i - 1] != 0 )
if( ++ssl->cur_out_ctr[i - 1] != 0 )
break;
/* The loop goes to its end iff the counter is wrapping */
......@@ -5511,7 +6468,7 @@ int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl )
}
else
#endif /* MBEDTLS_SSL_PROTO_DTLS */
memset( ssl->out_ctr, 0, 8 );
memset( ssl->cur_out_ctr, 0, 8 );
ssl->transform_out = ssl->transform_negotiate;
ssl->session_out = ssl->session_negotiate;
......@@ -5532,11 +6489,20 @@ int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl )
mbedtls_ssl_send_flight_completed( ssl );
#endif
if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret );
return( ret );
}
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret );
return( ret );
}
#endif
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write finished" ) );
......@@ -5559,7 +6525,7 @@ int mbedtls_ssl_parse_finished( mbedtls_ssl_context *ssl )
ssl->handshake->calc_finished( ssl, buf, ssl->conf->endpoint ^ 1 );
if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 )
if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
return( ret );
......@@ -5671,6 +6637,10 @@ static void ssl_handshake_params_init( mbedtls_ssl_handshake_params *handshake )
#endif
#endif
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
mbedtls_x509_crt_restart_init( &handshake->ecrs_ctx );
#endif
#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
handshake->sni_authmode = MBEDTLS_SSL_VERIFY_UNSET;
#endif
......@@ -5700,7 +6670,7 @@ static int ssl_handshake_init( mbedtls_ssl_context *ssl )
if( ssl->session_negotiate )
mbedtls_ssl_session_free( ssl->session_negotiate );
if( ssl->handshake )
mbedtls_ssl_handshake_free( ssl->handshake );
mbedtls_ssl_handshake_free( ssl );
/*
* Either the pointers are now NULL or cleared properly and can be freed.
......@@ -5790,6 +6760,78 @@ static int ssl_cookie_check_dummy( void *ctx,
}
#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY && MBEDTLS_SSL_SRV_C */
/* Once ssl->out_hdr as the address of the beginning of the
* next outgoing record is set, deduce the other pointers.
*
* Note: For TLS, we save the implicit record sequence number
* (entering MAC computation) in the 8 bytes before ssl->out_hdr,
* and the caller has to make sure there's space for this.
*/
static void ssl_update_out_pointers( mbedtls_ssl_context *ssl,
mbedtls_ssl_transform *transform )
{
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
{
ssl->out_ctr = ssl->out_hdr + 3;
ssl->out_len = ssl->out_hdr + 11;
ssl->out_iv = ssl->out_hdr + 13;
}
else
#endif
{
ssl->out_ctr = ssl->out_hdr - 8;
ssl->out_len = ssl->out_hdr + 3;
ssl->out_iv = ssl->out_hdr + 5;
}
/* Adjust out_msg to make space for explicit IV, if used. */
if( transform != NULL &&
ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 )
{
ssl->out_msg = ssl->out_iv + transform->ivlen - transform->fixed_ivlen;
}
else
ssl->out_msg = ssl->out_iv;
}
/* Once ssl->in_hdr as the address of the beginning of the
* next incoming record is set, deduce the other pointers.
*
* Note: For TLS, we save the implicit record sequence number
* (entering MAC computation) in the 8 bytes before ssl->in_hdr,
* and the caller has to make sure there's space for this.
*/
static void ssl_update_in_pointers( mbedtls_ssl_context *ssl,
mbedtls_ssl_transform *transform )
{
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
{
ssl->in_ctr = ssl->in_hdr + 3;
ssl->in_len = ssl->in_hdr + 11;
ssl->in_iv = ssl->in_hdr + 13;
}
else
#endif
{
ssl->in_ctr = ssl->in_hdr - 8;
ssl->in_len = ssl->in_hdr + 3;
ssl->in_iv = ssl->in_hdr + 5;
}
/* Offset in_msg from in_iv to allow space for explicit IV, if used. */
if( transform != NULL &&
ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 )
{
ssl->in_msg = ssl->in_iv + transform->ivlen - transform->fixed_ivlen;
}
else
ssl->in_msg = ssl->in_iv;
}
/*
* Initialize an SSL context
*/
......@@ -5801,57 +6843,59 @@ void mbedtls_ssl_init( mbedtls_ssl_context *ssl )
/*
* Setup an SSL context
*/
static void ssl_reset_in_out_pointers( mbedtls_ssl_context *ssl )
{
/* Set the incoming and outgoing record pointers. */
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
{
ssl->out_hdr = ssl->out_buf;
ssl->in_hdr = ssl->in_buf;
}
else
#endif /* MBEDTLS_SSL_PROTO_DTLS */
{
ssl->out_hdr = ssl->out_buf + 8;
ssl->in_hdr = ssl->in_buf + 8;
}
/* Derive other internal pointers. */
ssl_update_out_pointers( ssl, NULL /* no transform enabled */ );
ssl_update_in_pointers ( ssl, NULL /* no transform enabled */ );
}
int mbedtls_ssl_setup( mbedtls_ssl_context *ssl,
const mbedtls_ssl_config *conf )
{
int ret;
const size_t len = MBEDTLS_SSL_BUFFER_LEN;
ssl->conf = conf;
/*
* Prepare base structures
*/
ssl->in_buf = NULL;
/* Set to NULL in case of an error condition */
ssl->out_buf = NULL;
if( ( ssl-> in_buf = mbedtls_calloc( 1, len ) ) == NULL ||
( ssl->out_buf = mbedtls_calloc( 1, len ) ) == NULL )
ssl->in_buf = mbedtls_calloc( 1, MBEDTLS_SSL_IN_BUFFER_LEN );
if( ssl->in_buf == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", len ) );
MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", MBEDTLS_SSL_IN_BUFFER_LEN) );
ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
goto error;
}
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
ssl->out_buf = mbedtls_calloc( 1, MBEDTLS_SSL_OUT_BUFFER_LEN );
if( ssl->out_buf == NULL )
{
ssl->out_hdr = ssl->out_buf;
ssl->out_ctr = ssl->out_buf + 3;
ssl->out_len = ssl->out_buf + 11;
ssl->out_iv = ssl->out_buf + 13;
ssl->out_msg = ssl->out_buf + 13;
ssl->in_hdr = ssl->in_buf;
ssl->in_ctr = ssl->in_buf + 3;
ssl->in_len = ssl->in_buf + 11;
ssl->in_iv = ssl->in_buf + 13;
ssl->in_msg = ssl->in_buf + 13;
MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", MBEDTLS_SSL_OUT_BUFFER_LEN) );
ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
goto error;
}
else
#endif
{
ssl->out_ctr = ssl->out_buf;
ssl->out_hdr = ssl->out_buf + 8;
ssl->out_len = ssl->out_buf + 11;
ssl->out_iv = ssl->out_buf + 13;
ssl->out_msg = ssl->out_buf + 13;
ssl->in_ctr = ssl->in_buf;
ssl->in_hdr = ssl->in_buf + 8;
ssl->in_len = ssl->in_buf + 11;
ssl->in_iv = ssl->in_buf + 13;
ssl->in_msg = ssl->in_buf + 13;
}
ssl_reset_in_out_pointers( ssl );
if( ( ret = ssl_handshake_init( ssl ) ) != 0 )
goto error;
......@@ -5893,6 +6937,11 @@ static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial )
{
int ret;
#if !defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) || \
!defined(MBEDTLS_SSL_SRV_C)
((void) partial);
#endif
ssl->state = MBEDTLS_SSL_HELLO_REQUEST;
/* Cancel any possibly running timer */
......@@ -5909,12 +6958,10 @@ static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial )
ssl->secure_renegotiation = MBEDTLS_SSL_LEGACY_RENEGOTIATION;
ssl->in_offt = NULL;
ssl_reset_in_out_pointers( ssl );
ssl->in_msg = ssl->in_buf + 13;
ssl->in_msgtype = 0;
ssl->in_msglen = 0;
if( partial == 0 )
ssl->in_left = 0;
#if defined(MBEDTLS_SSL_PROTO_DTLS)
ssl->next_record_offset = 0;
ssl->in_epoch = 0;
......@@ -5928,7 +6975,6 @@ static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial )
ssl->keep_current_message = 0;
ssl->out_msg = ssl->out_buf + 13;
ssl->out_msgtype = 0;
ssl->out_msglen = 0;
ssl->out_left = 0;
......@@ -5937,16 +6983,23 @@ static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial )
ssl->split_done = 0;
#endif
memset( ssl->cur_out_ctr, 0, sizeof( ssl->cur_out_ctr ) );
ssl->transform_in = NULL;
ssl->transform_out = NULL;
ssl->session_in = NULL;
ssl->session_out = NULL;
memset( ssl->out_buf, 0, MBEDTLS_SSL_BUFFER_LEN );
memset( ssl->out_buf, 0, MBEDTLS_SSL_OUT_BUFFER_LEN );
#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C)
if( partial == 0 )
memset( ssl->in_buf, 0, MBEDTLS_SSL_BUFFER_LEN );
#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */
{
ssl->in_left = 0;
memset( ssl->in_buf, 0, MBEDTLS_SSL_IN_BUFFER_LEN );
}
#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL)
if( mbedtls_ssl_hw_record_reset != NULL )
......@@ -5979,7 +7032,9 @@ static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial )
#endif
#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C)
#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE)
if( partial == 0 )
#endif
{
mbedtls_free( ssl->cli_id );
ssl->cli_id = NULL;
......@@ -6030,7 +7085,15 @@ void mbedtls_ssl_conf_dtls_badmac_limit( mbedtls_ssl_config *conf, unsigned limi
#endif
#if defined(MBEDTLS_SSL_PROTO_DTLS)
void mbedtls_ssl_conf_handshake_timeout( mbedtls_ssl_config *conf, uint32_t min, uint32_t max )
void mbedtls_ssl_set_datagram_packing( mbedtls_ssl_context *ssl,
unsigned allow_packing )
{
ssl->disable_datagram_packing = !allow_packing;
}
void mbedtls_ssl_conf_handshake_timeout( mbedtls_ssl_config *conf,
uint32_t min, uint32_t max )
{
conf->hs_timeout_min = min;
conf->hs_timeout_max = max;
......@@ -6080,6 +7143,13 @@ void mbedtls_ssl_set_bio( mbedtls_ssl_context *ssl,
ssl->f_recv_timeout = f_recv_timeout;
}
#if defined(MBEDTLS_SSL_PROTO_DTLS)
void mbedtls_ssl_set_mtu( mbedtls_ssl_context *ssl, uint16_t mtu )
{
ssl->mtu = mtu;
}
#endif
void mbedtls_ssl_conf_read_timeout( mbedtls_ssl_config *conf, uint32_t timeout )
{
conf->read_timeout = timeout;
......@@ -6271,14 +7341,14 @@ int mbedtls_ssl_conf_psk( mbedtls_ssl_config *conf,
/* Identity len will be encoded on two bytes */
if( ( psk_identity_len >> 16 ) != 0 ||
psk_identity_len > MBEDTLS_SSL_MAX_CONTENT_LEN )
psk_identity_len > MBEDTLS_SSL_OUT_CONTENT_LEN )
{
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
if( conf->psk != NULL )
{
mbedtls_zeroize( conf->psk, conf->psk_len );
mbedtls_platform_zeroize( conf->psk, conf->psk_len );
mbedtls_free( conf->psk );
conf->psk = NULL;
......@@ -6321,7 +7391,8 @@ int mbedtls_ssl_set_hs_psk( mbedtls_ssl_context *ssl,
if( ssl->handshake->psk != NULL )
{
mbedtls_zeroize( ssl->handshake->psk, ssl->handshake->psk_len );
mbedtls_platform_zeroize( ssl->handshake->psk,
ssl->handshake->psk_len );
mbedtls_free( ssl->handshake->psk );
ssl->handshake->psk_len = 0;
}
......@@ -6451,7 +7522,7 @@ int mbedtls_ssl_set_hostname( mbedtls_ssl_context *ssl, const char *hostname )
if( ssl->hostname != NULL )
{
mbedtls_zeroize( ssl->hostname, strlen( ssl->hostname ) );
mbedtls_platform_zeroize( ssl->hostname, strlen( ssl->hostname ) );
mbedtls_free( ssl->hostname );
}
......@@ -6571,7 +7642,7 @@ void mbedtls_ssl_conf_arc4_support( mbedtls_ssl_config *conf, char arc4 )
int mbedtls_ssl_conf_max_frag_len( mbedtls_ssl_config *conf, unsigned char mfl_code )
{
if( mfl_code >= MBEDTLS_SSL_MAX_FRAG_LEN_INVALID ||
mfl_code_to_length[mfl_code] > MBEDTLS_SSL_MAX_CONTENT_LEN )
ssl_mfl_code_to_length( mfl_code ) > MBEDTLS_TLS_EXT_ADV_CONTENT_LEN )
{
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
......@@ -6650,6 +7721,43 @@ void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf,
}
#endif
#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
void mbedtls_ssl_conf_async_private_cb(
mbedtls_ssl_config *conf,
mbedtls_ssl_async_sign_t *f_async_sign,
mbedtls_ssl_async_decrypt_t *f_async_decrypt,
mbedtls_ssl_async_resume_t *f_async_resume,
mbedtls_ssl_async_cancel_t *f_async_cancel,
void *async_config_data )
{
conf->f_async_sign_start = f_async_sign;
conf->f_async_decrypt_start = f_async_decrypt;
conf->f_async_resume = f_async_resume;
conf->f_async_cancel = f_async_cancel;
conf->p_async_config_data = async_config_data;
}
void *mbedtls_ssl_conf_get_async_config_data( const mbedtls_ssl_config *conf )
{
return( conf->p_async_config_data );
}
void *mbedtls_ssl_get_async_operation_data( const mbedtls_ssl_context *ssl )
{
if( ssl->handshake == NULL )
return( NULL );
else
return( ssl->handshake->user_async_ctx );
}
void mbedtls_ssl_set_async_operation_data( mbedtls_ssl_context *ssl,
void *ctx )
{
if( ssl->handshake != NULL )
ssl->handshake->user_async_ctx = ctx;
}
#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
/*
* SSL get accessors
*/
......@@ -6658,6 +7766,61 @@ size_t mbedtls_ssl_get_bytes_avail( const mbedtls_ssl_context *ssl )
return( ssl->in_offt == NULL ? 0 : ssl->in_msglen );
}
int mbedtls_ssl_check_pending( const mbedtls_ssl_context *ssl )
{
/*
* Case A: We're currently holding back
* a message for further processing.
*/
if( ssl->keep_current_message == 1 )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "ssl_check_pending: record held back for processing" ) );
return( 1 );
}
/*
* Case B: Further records are pending in the current datagram.
*/
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
ssl->in_left > ssl->next_record_offset )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "ssl_check_pending: more records within current datagram" ) );
return( 1 );
}
#endif /* MBEDTLS_SSL_PROTO_DTLS */
/*
* Case C: A handshake message is being processed.
*/
if( ssl->in_hslen > 0 && ssl->in_hslen < ssl->in_msglen )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "ssl_check_pending: more handshake messages within current record" ) );
return( 1 );
}
/*
* Case D: An application data message is being processed
*/
if( ssl->in_offt != NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "ssl_check_pending: application data record is being processed" ) );
return( 1 );
}
/*
* In all other cases, the rest of the message can be dropped.
* As in ssl_get_next_record, this needs to be adapted if
* we implement support for multiple alerts in single records.
*/
MBEDTLS_SSL_DEBUG_MSG( 3, ( "ssl_check_pending: nothing pending" ) );
return( 0 );
}
uint32_t mbedtls_ssl_get_verify_result( const mbedtls_ssl_context *ssl )
{
if( ssl->session != NULL )
......@@ -6733,6 +7896,7 @@ int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl )
{
case MBEDTLS_MODE_GCM:
case MBEDTLS_MODE_CCM:
case MBEDTLS_MODE_CHACHAPOLY:
case MBEDTLS_MODE_STREAM:
transform_expansion = transform->minlen;
break;
......@@ -6775,21 +7939,91 @@ size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl )
/*
* Assume mfl_code is correct since it was checked when set
*/
max_len = mfl_code_to_length[ssl->conf->mfl_code];
max_len = ssl_mfl_code_to_length( ssl->conf->mfl_code );
/*
* Check if a smaller max length was negotiated
*/
/* Check if a smaller max length was negotiated */
if( ssl->session_out != NULL &&
mfl_code_to_length[ssl->session_out->mfl_code] < max_len )
ssl_mfl_code_to_length( ssl->session_out->mfl_code ) < max_len )
{
max_len = ssl_mfl_code_to_length( ssl->session_out->mfl_code );
}
/* During a handshake, use the value being negotiated */
if( ssl->session_negotiate != NULL &&
ssl_mfl_code_to_length( ssl->session_negotiate->mfl_code ) < max_len )
{
max_len = mfl_code_to_length[ssl->session_out->mfl_code];
max_len = ssl_mfl_code_to_length( ssl->session_negotiate->mfl_code );
}
return max_len;
return( max_len );
}
#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
#if defined(MBEDTLS_SSL_PROTO_DTLS)
static size_t ssl_get_current_mtu( const mbedtls_ssl_context *ssl )
{
/* Return unlimited mtu for client hello messages to avoid fragmentation. */
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT &&
( ssl->state == MBEDTLS_SSL_CLIENT_HELLO ||
ssl->state == MBEDTLS_SSL_SERVER_HELLO ) )
return ( 0 );
if( ssl->handshake == NULL || ssl->handshake->mtu == 0 )
return( ssl->mtu );
if( ssl->mtu == 0 )
return( ssl->handshake->mtu );
return( ssl->mtu < ssl->handshake->mtu ?
ssl->mtu : ssl->handshake->mtu );
}
#endif /* MBEDTLS_SSL_PROTO_DTLS */
int mbedtls_ssl_get_max_out_record_payload( const mbedtls_ssl_context *ssl )
{
size_t max_len = MBEDTLS_SSL_OUT_CONTENT_LEN;
#if !defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) && \
!defined(MBEDTLS_SSL_PROTO_DTLS)
(void) ssl;
#endif
#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
const size_t mfl = mbedtls_ssl_get_max_frag_len( ssl );
if( max_len > mfl )
max_len = mfl;
#endif
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl_get_current_mtu( ssl ) != 0 )
{
const size_t mtu = ssl_get_current_mtu( ssl );
const int ret = mbedtls_ssl_get_record_expansion( ssl );
const size_t overhead = (size_t) ret;
if( ret < 0 )
return( ret );
if( mtu <= overhead )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "MTU too low for record expansion" ) );
return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
}
if( max_len > mtu - overhead )
max_len = mtu - overhead;
}
#endif /* MBEDTLS_SSL_PROTO_DTLS */
#if !defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) && \
!defined(MBEDTLS_SSL_PROTO_DTLS)
((void) ssl);
#endif
return( (int) max_len );
}
#if defined(MBEDTLS_X509_CRT_PARSE_C)
const mbedtls_x509_crt *mbedtls_ssl_get_peer_cert( const mbedtls_ssl_context *ssl )
{
......@@ -6877,9 +8111,9 @@ static int ssl_write_hello_request( mbedtls_ssl_context *ssl )
ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE;
ssl->out_msg[0] = MBEDTLS_SSL_HS_HELLO_REQUEST;
if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret );
return( ret );
}
......@@ -7009,7 +8243,7 @@ static int ssl_check_ctr_renegotiate( mbedtls_ssl_context *ssl )
in_ctr_cmp = memcmp( ssl->in_ctr + ep_len,
ssl->conf->renego_period + ep_len, 8 - ep_len );
out_ctr_cmp = memcmp( ssl->out_ctr + ep_len,
out_ctr_cmp = memcmp( ssl->cur_out_ctr + ep_len,
ssl->conf->renego_period + ep_len, 8 - ep_len );
if( in_ctr_cmp <= 0 && out_ctr_cmp <= 0 )
......@@ -7044,7 +8278,7 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len )
if( ssl->handshake != NULL &&
ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING )
{
if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 )
if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 )
return( ret );
}
}
......@@ -7083,7 +8317,8 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len )
}
}
if( ssl->in_offt == NULL )
/* Loop as long as no application data record is available */
while( ssl->in_offt == NULL )
{
/* Start timer if not already running */
if( ssl->f_get_timer != NULL &&
......@@ -7092,7 +8327,7 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len )
ssl_set_timer( ssl, ssl->conf->read_timeout );
}
if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 )
if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
{
if( ret == MBEDTLS_ERR_SSL_CONN_EOF )
return( 0 );
......@@ -7107,7 +8342,7 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len )
/*
* OpenSSL sends empty messages to randomize the IV
*/
if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 )
if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
{
if( ret == MBEDTLS_ERR_SSL_CONN_EOF )
return( 0 );
......@@ -7137,7 +8372,9 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len )
/* With DTLS, drop the packet (probably from last handshake) */
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
return( MBEDTLS_ERR_SSL_WANT_READ );
{
continue;
}
#endif
return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
}
......@@ -7152,7 +8389,9 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len )
/* With DTLS, drop the packet (probably from last handshake) */
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
return( MBEDTLS_ERR_SSL_WANT_READ );
{
continue;
}
#endif
return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
}
......@@ -7225,7 +8464,25 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len )
}
}
return( MBEDTLS_ERR_SSL_WANT_READ );
/* At this point, we don't know whether the renegotiation has been
* completed or not. The cases to consider are the following:
* 1) The renegotiation is complete. In this case, no new record
* has been read yet.
* 2) The renegotiation is incomplete because the client received
* an application data record while awaiting the ServerHello.
* 3) The renegotiation is incomplete because the client received
* a non-handshake, non-application data message while awaiting
* the ServerHello.
* In each of these case, looping will be the proper action:
* - For 1), the next iteration will read a new record and check
* if it's application data.
* - For 2), the loop condition isn't satisfied as application data
* is present, hence continue is the same as break
* - For 3), the loop condition is satisfied and read_record
* will re-deliver the message that was held back by the client
* when expecting the ServerHello.
*/
continue;
}
#if defined(MBEDTLS_SSL_RENEGOTIATION)
else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING )
......@@ -7318,12 +8575,15 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len )
static int ssl_write_real( mbedtls_ssl_context *ssl,
const unsigned char *buf, size_t len )
{
int ret;
#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
size_t max_len = mbedtls_ssl_get_max_frag_len( ssl );
#else
size_t max_len = MBEDTLS_SSL_MAX_CONTENT_LEN;
#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
int ret = mbedtls_ssl_get_max_out_record_payload( ssl );
const size_t max_len = (size_t) ret;
if( ret < 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_get_max_out_record_payload", ret );
return( ret );
}
if( len > max_len )
{
#if defined(MBEDTLS_SSL_PROTO_DTLS)
......@@ -7364,7 +8624,7 @@ static int ssl_write_real( mbedtls_ssl_context *ssl,
ssl->out_msgtype = MBEDTLS_SSL_MSG_APPLICATION_DATA;
memcpy( ssl->out_msg, buf, len );
if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
if( ( ret = mbedtls_ssl_write_record( ssl, SSL_FORCE_FLUSH ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
return( ret );
......@@ -7499,7 +8759,7 @@ void mbedtls_ssl_transform_free( mbedtls_ssl_transform *transform )
mbedtls_md_free( &transform->md_ctx_enc );
mbedtls_md_free( &transform->md_ctx_dec );
mbedtls_zeroize( transform, sizeof( mbedtls_ssl_transform ) );
mbedtls_platform_zeroize( transform, sizeof( mbedtls_ssl_transform ) );
}
#if defined(MBEDTLS_X509_CRT_PARSE_C)
......@@ -7516,11 +8776,57 @@ static void ssl_key_cert_free( mbedtls_ssl_key_cert *key_cert )
}
#endif /* MBEDTLS_X509_CRT_PARSE_C */
void mbedtls_ssl_handshake_free( mbedtls_ssl_handshake_params *handshake )
#if defined(MBEDTLS_SSL_PROTO_DTLS)
static void ssl_buffering_free( mbedtls_ssl_context *ssl )
{
unsigned offset;
mbedtls_ssl_handshake_params * const hs = ssl->handshake;
if( hs == NULL )
return;
ssl_free_buffered_record( ssl );
for( offset = 0; offset < MBEDTLS_SSL_MAX_BUFFERED_HS; offset++ )
ssl_buffering_free_slot( ssl, offset );
}
static void ssl_buffering_free_slot( mbedtls_ssl_context *ssl,
uint8_t slot )
{
mbedtls_ssl_handshake_params * const hs = ssl->handshake;
mbedtls_ssl_hs_buffer * const hs_buf = &hs->buffering.hs[slot];
if( slot >= MBEDTLS_SSL_MAX_BUFFERED_HS )
return;
if( hs_buf->is_valid == 1 )
{
hs->buffering.total_bytes_buffered -= hs_buf->data_len;
mbedtls_platform_zeroize( hs_buf->data, hs_buf->data_len );
mbedtls_free( hs_buf->data );
memset( hs_buf, 0, sizeof( mbedtls_ssl_hs_buffer ) );
}
}
#endif /* MBEDTLS_SSL_PROTO_DTLS */
void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl )
{
mbedtls_ssl_handshake_params *handshake = ssl->handshake;
if( handshake == NULL )
return;
#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
if( ssl->conf->f_async_cancel != NULL && handshake->async_in_progress != 0 )
{
ssl->conf->f_async_cancel( ssl );
handshake->async_in_progress = 0;
}
#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \
defined(MBEDTLS_SSL_PROTO_TLS1_1)
mbedtls_md5_free( &handshake->fin_md5 );
......@@ -7559,7 +8865,7 @@ void mbedtls_ssl_handshake_free( mbedtls_ssl_handshake_params *handshake )
#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
if( handshake->psk != NULL )
{
mbedtls_zeroize( handshake->psk, handshake->psk_len );
mbedtls_platform_zeroize( handshake->psk, handshake->psk_len );
mbedtls_free( handshake->psk );
}
#endif
......@@ -7583,13 +8889,18 @@ void mbedtls_ssl_handshake_free( mbedtls_ssl_handshake_params *handshake )
}
#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_SERVER_NAME_INDICATION */
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
mbedtls_x509_crt_restart_free( &handshake->ecrs_ctx );
#endif
#if defined(MBEDTLS_SSL_PROTO_DTLS)
mbedtls_free( handshake->verify_cookie );
mbedtls_free( handshake->hs_msg );
ssl_flight_free( handshake->flight );
ssl_buffering_free( ssl );
#endif
mbedtls_zeroize( handshake, sizeof( mbedtls_ssl_handshake_params ) );
mbedtls_platform_zeroize( handshake,
sizeof( mbedtls_ssl_handshake_params ) );
}
void mbedtls_ssl_session_free( mbedtls_ssl_session *session )
......@@ -7609,7 +8920,7 @@ void mbedtls_ssl_session_free( mbedtls_ssl_session *session )
mbedtls_free( session->ticket );
#endif
mbedtls_zeroize( session, sizeof( mbedtls_ssl_session ) );
mbedtls_platform_zeroize( session, sizeof( mbedtls_ssl_session ) );
}
/*
......@@ -7624,20 +8935,20 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl )
if( ssl->out_buf != NULL )
{
mbedtls_zeroize( ssl->out_buf, MBEDTLS_SSL_BUFFER_LEN );
mbedtls_platform_zeroize( ssl->out_buf, MBEDTLS_SSL_OUT_BUFFER_LEN );
mbedtls_free( ssl->out_buf );
}
if( ssl->in_buf != NULL )
{
mbedtls_zeroize( ssl->in_buf, MBEDTLS_SSL_BUFFER_LEN );
mbedtls_platform_zeroize( ssl->in_buf, MBEDTLS_SSL_IN_BUFFER_LEN );
mbedtls_free( ssl->in_buf );
}
#if defined(MBEDTLS_ZLIB_SUPPORT)
if( ssl->compress_buf != NULL )
{
mbedtls_zeroize( ssl->compress_buf, MBEDTLS_SSL_BUFFER_LEN );
mbedtls_platform_zeroize( ssl->compress_buf, MBEDTLS_SSL_COMPRESS_BUFFER_LEN );
mbedtls_free( ssl->compress_buf );
}
#endif
......@@ -7650,7 +8961,7 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl )
if( ssl->handshake )
{
mbedtls_ssl_handshake_free( ssl->handshake );
mbedtls_ssl_handshake_free( ssl );
mbedtls_ssl_transform_free( ssl->transform_negotiate );
mbedtls_ssl_session_free( ssl->session_negotiate );
......@@ -7668,7 +8979,7 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl )
#if defined(MBEDTLS_X509_CRT_PARSE_C)
if( ssl->hostname != NULL )
{
mbedtls_zeroize( ssl->hostname, strlen( ssl->hostname ) );
mbedtls_platform_zeroize( ssl->hostname, strlen( ssl->hostname ) );
mbedtls_free( ssl->hostname );
}
#endif
......@@ -7688,7 +8999,7 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl )
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= free" ) );
/* Actually clear after last debug message */
mbedtls_zeroize( ssl, sizeof( mbedtls_ssl_context ) );
mbedtls_platform_zeroize( ssl, sizeof( mbedtls_ssl_context ) );
}
/*
......@@ -7732,8 +9043,12 @@ static int ssl_preset_suiteb_hashes[] = {
#if defined(MBEDTLS_ECP_C)
static mbedtls_ecp_group_id ssl_preset_suiteb_curves[] = {
#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED)
MBEDTLS_ECP_DP_SECP256R1,
#endif
#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED)
MBEDTLS_ECP_DP_SECP384R1,
#endif
MBEDTLS_ECP_DP_NONE
};
#endif
......@@ -7915,11 +9230,17 @@ void mbedtls_ssl_config_free( mbedtls_ssl_config *conf )
#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
if( conf->psk != NULL )
{
mbedtls_zeroize( conf->psk, conf->psk_len );
mbedtls_zeroize( conf->psk_identity, conf->psk_identity_len );
mbedtls_platform_zeroize( conf->psk, conf->psk_len );
mbedtls_free( conf->psk );
mbedtls_free( conf->psk_identity );
conf->psk = NULL;
conf->psk_len = 0;
}
if( conf->psk_identity != NULL )
{
mbedtls_platform_zeroize( conf->psk_identity, conf->psk_identity_len );
mbedtls_free( conf->psk_identity );
conf->psk_identity = NULL;
conf->psk_identity_len = 0;
}
#endif
......@@ -7928,7 +9249,7 @@ void mbedtls_ssl_config_free( mbedtls_ssl_config *conf )
ssl_key_cert_free( conf->key_cert );
#endif
mbedtls_zeroize( conf, sizeof( mbedtls_ssl_config ) );
mbedtls_platform_zeroize( conf, sizeof( mbedtls_ssl_config ) );
}
#if defined(MBEDTLS_PK_C) && \
......@@ -8411,13 +9732,14 @@ exit:
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
defined(MBEDTLS_SSL_PROTO_TLS1_2)
int mbedtls_ssl_get_key_exchange_md_tls1_2( mbedtls_ssl_context *ssl,
unsigned char *output,
unsigned char *data, size_t data_len,
mbedtls_md_type_t md_alg )
unsigned char *hash, size_t *hashlen,
unsigned char *data, size_t data_len,
mbedtls_md_type_t md_alg )
{
int ret = 0;
mbedtls_md_context_t ctx;
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg );
*hashlen = mbedtls_md_get_size( md_info );
mbedtls_md_init( &ctx );
......@@ -8448,7 +9770,7 @@ int mbedtls_ssl_get_key_exchange_md_tls1_2( mbedtls_ssl_context *ssl,
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_update", ret );
goto exit;
}
if( ( ret = mbedtls_md_finish( &ctx, output ) ) != 0 )
if( ( ret = mbedtls_md_finish( &ctx, hash ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_finish", ret );
goto exit;
......
......@@ -19,6 +19,14 @@
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* Ensure gmtime_r is available even with -std=c99; must be defined before
* config.h, which pulls in glibc's features.h. Harmless on other platforms.
*/
#if !defined(_POSIX_C_SOURCE)
#define _POSIX_C_SOURCE 200112L
#endif
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
......@@ -29,6 +37,36 @@
#include "mbedtls/threading.h"
#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT)
#if !defined(_WIN32) && (defined(unix) || \
defined(__unix) || defined(__unix__) || (defined(__APPLE__) && \
defined(__MACH__)))
#include <unistd.h>
#endif /* !_WIN32 && (unix || __unix || __unix__ ||
* (__APPLE__ && __MACH__)) */
#if !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \
( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \
_POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) )
/*
* This is a convenience shorthand macro to avoid checking the long
* preprocessor conditions above. Ideally, we could expose this macro in
* platform_util.h and simply use it in platform_util.c, threading.c and
* threading.h. However, this macro is not part of the Mbed TLS public API, so
* we keep it private by only defining it in this file
*/
#if ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) )
#define THREADING_USE_GMTIME
#endif /* ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) ) */
#endif /* !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \
( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \
_POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) */
#endif /* MBEDTLS_HAVE_TIME_DATE && !MBEDTLS_PLATFORM_GMTIME_R_ALT */
#if defined(MBEDTLS_THREADING_PTHREAD)
static void threading_mutex_init_pthread( mbedtls_threading_mutex_t *mutex )
{
......@@ -114,7 +152,7 @@ void mbedtls_threading_set_alt( void (*mutex_init)( mbedtls_threading_mutex_t *
#if defined(MBEDTLS_FS_IO)
mbedtls_mutex_init( &mbedtls_threading_readdir_mutex );
#endif
#if defined(MBEDTLS_HAVE_TIME_DATE)
#if defined(THREADING_USE_GMTIME)
mbedtls_mutex_init( &mbedtls_threading_gmtime_mutex );
#endif
}
......@@ -127,7 +165,7 @@ void mbedtls_threading_free_alt( void )
#if defined(MBEDTLS_FS_IO)
mbedtls_mutex_free( &mbedtls_threading_readdir_mutex );
#endif
#if defined(MBEDTLS_HAVE_TIME_DATE)
#if defined(THREADING_USE_GMTIME)
mbedtls_mutex_free( &mbedtls_threading_gmtime_mutex );
#endif
}
......@@ -142,7 +180,7 @@ void mbedtls_threading_free_alt( void )
#if defined(MBEDTLS_FS_IO)
mbedtls_threading_mutex_t mbedtls_threading_readdir_mutex MUTEX_INIT;
#endif
#if defined(MBEDTLS_HAVE_TIME_DATE)
#if defined(THREADING_USE_GMTIME)
mbedtls_threading_mutex_t mbedtls_threading_gmtime_mutex MUTEX_INIT;
#endif
......
......@@ -39,7 +39,8 @@
#if !defined(MBEDTLS_TIMING_ALT)
#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \
!defined(__APPLE__) && !defined(_WIN32)
!defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \
!defined(__HAIKU__)
#error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in config.h"
#endif
......@@ -50,7 +51,6 @@
#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
#include <windows.h>
#include <winbase.h>
#include <process.h>
struct _hr_time
......
......@@ -30,7 +30,7 @@
#include "mbedtls/version.h"
#include <string.h>
unsigned int mbedtls_version_get_number()
unsigned int mbedtls_version_get_number( void )
{
return( MBEDTLS_VERSION_NUMBER );
}
......
......@@ -39,6 +39,9 @@ static const char *features[] = {
#if defined(MBEDTLS_NO_UDBL_DIVISION)
"MBEDTLS_NO_UDBL_DIVISION",
#endif /* MBEDTLS_NO_UDBL_DIVISION */
#if defined(MBEDTLS_NO_64BIT_MULTIPLICATION)
"MBEDTLS_NO_64BIT_MULTIPLICATION",
#endif /* MBEDTLS_NO_64BIT_MULTIPLICATION */
#if defined(MBEDTLS_HAVE_SSE2)
"MBEDTLS_HAVE_SSE2",
#endif /* MBEDTLS_HAVE_SSE2 */
......@@ -81,6 +84,12 @@ static const char *features[] = {
#if defined(MBEDTLS_DEPRECATED_REMOVED)
"MBEDTLS_DEPRECATED_REMOVED",
#endif /* MBEDTLS_DEPRECATED_REMOVED */
#if defined(MBEDTLS_CHECK_PARAMS)
"MBEDTLS_CHECK_PARAMS",
#endif /* MBEDTLS_CHECK_PARAMS */
#if defined(MBEDTLS_CHECK_PARAMS_ASSERT)
"MBEDTLS_CHECK_PARAMS_ASSERT",
#endif /* MBEDTLS_CHECK_PARAMS_ASSERT */
#if defined(MBEDTLS_TIMING_ALT)
"MBEDTLS_TIMING_ALT",
#endif /* MBEDTLS_TIMING_ALT */
......@@ -90,6 +99,9 @@ static const char *features[] = {
#if defined(MBEDTLS_ARC4_ALT)
"MBEDTLS_ARC4_ALT",
#endif /* MBEDTLS_ARC4_ALT */
#if defined(MBEDTLS_ARIA_ALT)
"MBEDTLS_ARIA_ALT",
#endif /* MBEDTLS_ARIA_ALT */
#if defined(MBEDTLS_BLOWFISH_ALT)
"MBEDTLS_BLOWFISH_ALT",
#endif /* MBEDTLS_BLOWFISH_ALT */
......@@ -99,6 +111,12 @@ static const char *features[] = {
#if defined(MBEDTLS_CCM_ALT)
"MBEDTLS_CCM_ALT",
#endif /* MBEDTLS_CCM_ALT */
#if defined(MBEDTLS_CHACHA20_ALT)
"MBEDTLS_CHACHA20_ALT",
#endif /* MBEDTLS_CHACHA20_ALT */
#if defined(MBEDTLS_CHACHAPOLY_ALT)
"MBEDTLS_CHACHAPOLY_ALT",
#endif /* MBEDTLS_CHACHAPOLY_ALT */
#if defined(MBEDTLS_CMAC_ALT)
"MBEDTLS_CMAC_ALT",
#endif /* MBEDTLS_CMAC_ALT */
......@@ -114,6 +132,9 @@ static const char *features[] = {
#if defined(MBEDTLS_GCM_ALT)
"MBEDTLS_GCM_ALT",
#endif /* MBEDTLS_GCM_ALT */
#if defined(MBEDTLS_NIST_KW_ALT)
"MBEDTLS_NIST_KW_ALT",
#endif /* MBEDTLS_NIST_KW_ALT */
#if defined(MBEDTLS_MD2_ALT)
"MBEDTLS_MD2_ALT",
#endif /* MBEDTLS_MD2_ALT */
......@@ -123,6 +144,9 @@ static const char *features[] = {
#if defined(MBEDTLS_MD5_ALT)
"MBEDTLS_MD5_ALT",
#endif /* MBEDTLS_MD5_ALT */
#if defined(MBEDTLS_POLY1305_ALT)
"MBEDTLS_POLY1305_ALT",
#endif /* MBEDTLS_POLY1305_ALT */
#if defined(MBEDTLS_RIPEMD160_ALT)
"MBEDTLS_RIPEMD160_ALT",
#endif /* MBEDTLS_RIPEMD160_ALT */
......@@ -237,6 +261,9 @@ static const char *features[] = {
#if defined(MBEDTLS_AES_ROM_TABLES)
"MBEDTLS_AES_ROM_TABLES",
#endif /* MBEDTLS_AES_ROM_TABLES */
#if defined(MBEDTLS_AES_FEWER_TABLES)
"MBEDTLS_AES_FEWER_TABLES",
#endif /* MBEDTLS_AES_FEWER_TABLES */
#if defined(MBEDTLS_CAMELLIA_SMALL_MEMORY)
"MBEDTLS_CAMELLIA_SMALL_MEMORY",
#endif /* MBEDTLS_CAMELLIA_SMALL_MEMORY */
......@@ -249,6 +276,12 @@ static const char *features[] = {
#if defined(MBEDTLS_CIPHER_MODE_CTR)
"MBEDTLS_CIPHER_MODE_CTR",
#endif /* MBEDTLS_CIPHER_MODE_CTR */
#if defined(MBEDTLS_CIPHER_MODE_OFB)
"MBEDTLS_CIPHER_MODE_OFB",
#endif /* MBEDTLS_CIPHER_MODE_OFB */
#if defined(MBEDTLS_CIPHER_MODE_XTS)
"MBEDTLS_CIPHER_MODE_XTS",
#endif /* MBEDTLS_CIPHER_MODE_XTS */
#if defined(MBEDTLS_CIPHER_NULL_CIPHER)
"MBEDTLS_CIPHER_NULL_CIPHER",
#endif /* MBEDTLS_CIPHER_NULL_CIPHER */
......@@ -264,12 +297,18 @@ static const char *features[] = {
#if defined(MBEDTLS_CIPHER_PADDING_ZEROS)
"MBEDTLS_CIPHER_PADDING_ZEROS",
#endif /* MBEDTLS_CIPHER_PADDING_ZEROS */
#if defined(MBEDTLS_CTR_DRBG_USE_128_BIT_KEY)
"MBEDTLS_CTR_DRBG_USE_128_BIT_KEY",
#endif /* MBEDTLS_CTR_DRBG_USE_128_BIT_KEY */
#if defined(MBEDTLS_ENABLE_WEAK_CIPHERSUITES)
"MBEDTLS_ENABLE_WEAK_CIPHERSUITES",
#endif /* MBEDTLS_ENABLE_WEAK_CIPHERSUITES */
#if defined(MBEDTLS_REMOVE_ARC4_CIPHERSUITES)
"MBEDTLS_REMOVE_ARC4_CIPHERSUITES",
#endif /* MBEDTLS_REMOVE_ARC4_CIPHERSUITES */
#if defined(MBEDTLS_REMOVE_3DES_CIPHERSUITES)
"MBEDTLS_REMOVE_3DES_CIPHERSUITES",
#endif /* MBEDTLS_REMOVE_3DES_CIPHERSUITES */
#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED)
"MBEDTLS_ECP_DP_SECP192R1_ENABLED",
#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */
......@@ -306,9 +345,15 @@ static const char *features[] = {
#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED)
"MBEDTLS_ECP_DP_CURVE25519_ENABLED",
#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */
#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED)
"MBEDTLS_ECP_DP_CURVE448_ENABLED",
#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */
#if defined(MBEDTLS_ECP_NIST_OPTIM)
"MBEDTLS_ECP_NIST_OPTIM",
#endif /* MBEDTLS_ECP_NIST_OPTIM */
#if defined(MBEDTLS_ECP_RESTARTABLE)
"MBEDTLS_ECP_RESTARTABLE",
#endif /* MBEDTLS_ECP_RESTARTABLE */
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
"MBEDTLS_ECDSA_DETERMINISTIC",
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
......@@ -396,6 +441,9 @@ static const char *features[] = {
#if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES)
"MBEDTLS_SSL_ALL_ALERT_MESSAGES",
#endif /* MBEDTLS_SSL_ALL_ALERT_MESSAGES */
#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
"MBEDTLS_SSL_ASYNC_PRIVATE",
#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
#if defined(MBEDTLS_SSL_DEBUG_ALL)
"MBEDTLS_SSL_DEBUG_ALL",
#endif /* MBEDTLS_SSL_DEBUG_ALL */
......@@ -525,12 +573,21 @@ static const char *features[] = {
#if defined(MBEDTLS_CAMELLIA_C)
"MBEDTLS_CAMELLIA_C",
#endif /* MBEDTLS_CAMELLIA_C */
#if defined(MBEDTLS_ARIA_C)
"MBEDTLS_ARIA_C",
#endif /* MBEDTLS_ARIA_C */
#if defined(MBEDTLS_CCM_C)
"MBEDTLS_CCM_C",
#endif /* MBEDTLS_CCM_C */
#if defined(MBEDTLS_CERTS_C)
"MBEDTLS_CERTS_C",
#endif /* MBEDTLS_CERTS_C */
#if defined(MBEDTLS_CHACHA20_C)
"MBEDTLS_CHACHA20_C",
#endif /* MBEDTLS_CHACHA20_C */
#if defined(MBEDTLS_CHACHAPOLY_C)
"MBEDTLS_CHACHAPOLY_C",
#endif /* MBEDTLS_CHACHAPOLY_C */
#if defined(MBEDTLS_CIPHER_C)
"MBEDTLS_CIPHER_C",
#endif /* MBEDTLS_CIPHER_C */
......@@ -573,9 +630,15 @@ static const char *features[] = {
#if defined(MBEDTLS_HAVEGE_C)
"MBEDTLS_HAVEGE_C",
#endif /* MBEDTLS_HAVEGE_C */
#if defined(MBEDTLS_HKDF_C)
"MBEDTLS_HKDF_C",
#endif /* MBEDTLS_HKDF_C */
#if defined(MBEDTLS_HMAC_DRBG_C)
"MBEDTLS_HMAC_DRBG_C",
#endif /* MBEDTLS_HMAC_DRBG_C */
#if defined(MBEDTLS_NIST_KW_C)
"MBEDTLS_NIST_KW_C",
#endif /* MBEDTLS_NIST_KW_C */
#if defined(MBEDTLS_MD_C)
"MBEDTLS_MD_C",
#endif /* MBEDTLS_MD_C */
......@@ -627,6 +690,9 @@ static const char *features[] = {
#if defined(MBEDTLS_PLATFORM_C)
"MBEDTLS_PLATFORM_C",
#endif /* MBEDTLS_PLATFORM_C */
#if defined(MBEDTLS_POLY1305_C)
"MBEDTLS_POLY1305_C",
#endif /* MBEDTLS_POLY1305_C */
#if defined(MBEDTLS_RIPEMD160_C)
"MBEDTLS_RIPEMD160_C",
#endif /* MBEDTLS_RIPEMD160_C */
......
......@@ -59,19 +59,23 @@
#define mbedtls_snprintf snprintf
#endif
#if defined(MBEDTLS_HAVE_TIME)
#include "mbedtls/platform_time.h"
#endif
#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
#include <windows.h>
#else
#if defined(MBEDTLS_HAVE_TIME_DATE)
#include "mbedtls/platform_util.h"
#include <time.h>
#endif
#define CHECK(code) if( ( ret = code ) != 0 ){ return( ret ); }
#define CHECK_RANGE(min, max, val) if( val < min || val > max ){ return( ret ); }
#define CHECK(code) if( ( ret = ( code ) ) != 0 ){ return( ret ); }
#define CHECK_RANGE(min, max, val) \
do \
{ \
if( ( val ) < ( min ) || ( val ) > ( max ) ) \
{ \
return( ret ); \
} \
} while( 0 )
/*
* CertificateSerialNumber ::= INTEGER
......@@ -119,7 +123,7 @@ int mbedtls_x509_get_alg_null( unsigned char **p, const unsigned char *end,
}
/*
* Parse an algorithm identifier with (optional) paramaters
* Parse an algorithm identifier with (optional) parameters
*/
int mbedtls_x509_get_alg( unsigned char **p, const unsigned char *end,
mbedtls_x509_buf *alg, mbedtls_x509_buf *params )
......@@ -357,6 +361,8 @@ static int x509_get_attr_type_value( unsigned char **p,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
return( MBEDTLS_ERR_X509_INVALID_NAME + ret );
end = *p + len;
if( ( end - *p ) < 1 )
return( MBEDTLS_ERR_X509_INVALID_NAME +
MBEDTLS_ERR_ASN1_OUT_OF_DATA );
......@@ -390,6 +396,12 @@ static int x509_get_attr_type_value( unsigned char **p,
val->p = *p;
*p += val->len;
if( *p != end )
{
return( MBEDTLS_ERR_X509_INVALID_NAME +
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
}
cur->next = NULL;
return( 0 );
......@@ -696,30 +708,25 @@ int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x50
* be either manually updated or extensions should be parsed!)
*/
int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end,
mbedtls_x509_buf *ext, int tag )
mbedtls_x509_buf *ext, int tag )
{
int ret;
size_t len;
if( *p == end )
return( 0 );
ext->tag = **p;
if( ( ret = mbedtls_asn1_get_tag( p, end, &ext->len,
MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | tag ) ) != 0 )
return( ret );
/* Extension structure use EXPLICIT tagging. That is, the actual
* `Extensions` structure is wrapped by a tag-length pair using
* the respective context-specific tag. */
ret = mbedtls_asn1_get_tag( p, end, &ext->len,
MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | tag );
if( ret != 0 )
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
ext->p = *p;
end = *p + ext->len;
ext->tag = MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | tag;
ext->p = *p;
end = *p + ext->len;
/*
* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
*
* Extension ::= SEQUENCE {
* extnID OBJECT IDENTIFIER,
* critical BOOLEAN DEFAULT FALSE,
* extnValue OCTET STRING }
*/
if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
......@@ -894,36 +901,14 @@ int mbedtls_x509_key_size_helper( char *buf, size_t buf_size, const char *name )
* Set the time structure to the current time.
* Return 0 on success, non-zero on failure.
*/
#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
static int x509_get_current_time( mbedtls_x509_time *now )
{
SYSTEMTIME st;
GetSystemTime( &st );
now->year = st.wYear;
now->mon = st.wMonth;
now->day = st.wDay;
now->hour = st.wHour;
now->min = st.wMinute;
now->sec = st.wSecond;
return( 0 );
}
#else
static int x509_get_current_time( mbedtls_x509_time *now )
{
struct tm *lt;
struct tm *lt, tm_buf;
mbedtls_time_t tt;
int ret = 0;
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_lock( &mbedtls_threading_gmtime_mutex ) != 0 )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
#endif
tt = mbedtls_time( NULL );
lt = gmtime( &tt );
lt = mbedtls_platform_gmtime_r( &tt, &tm_buf );
if( lt == NULL )
ret = -1;
......@@ -937,14 +922,8 @@ static int x509_get_current_time( mbedtls_x509_time *now )
now->sec = lt->tm_sec;
}
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_unlock( &mbedtls_threading_gmtime_mutex ) != 0 )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
#endif
return( ret );
}
#endif /* _WIN32 && !EFIX64 && !EFI32 */
/*
* Return 0 if before <= after, 1 otherwise
......@@ -1032,8 +1011,8 @@ int mbedtls_x509_time_is_future( const mbedtls_x509_time *from )
*/
int mbedtls_x509_self_test( int verbose )
{
int ret = 0;
#if defined(MBEDTLS_CERTS_C) && defined(MBEDTLS_SHA256_C)
int ret;
uint32_t flags;
mbedtls_x509_crt cacert;
mbedtls_x509_crt clicert;
......@@ -1041,6 +1020,7 @@ int mbedtls_x509_self_test( int verbose )
if( verbose != 0 )
mbedtls_printf( " X.509 certificate load: " );
mbedtls_x509_crt_init( &cacert );
mbedtls_x509_crt_init( &clicert );
ret = mbedtls_x509_crt_parse( &clicert, (const unsigned char *) mbedtls_test_cli_crt,
......@@ -1050,11 +1030,9 @@ int mbedtls_x509_self_test( int verbose )
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( ret );
goto cleanup;
}
mbedtls_x509_crt_init( &cacert );
ret = mbedtls_x509_crt_parse( &cacert, (const unsigned char *) mbedtls_test_ca_crt,
mbedtls_test_ca_crt_len );
if( ret != 0 )
......@@ -1062,7 +1040,7 @@ int mbedtls_x509_self_test( int verbose )
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( ret );
goto cleanup;
}
if( verbose != 0 )
......@@ -1074,20 +1052,19 @@ int mbedtls_x509_self_test( int verbose )
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( ret );
goto cleanup;
}
if( verbose != 0 )
mbedtls_printf( "passed\n\n");
cleanup:
mbedtls_x509_crt_free( &cacert );
mbedtls_x509_crt_free( &clicert );
return( 0 );
#else
((void) verbose);
return( 0 );
#endif /* MBEDTLS_CERTS_C && MBEDTLS_SHA1_C */
return( ret );
}
#endif /* MBEDTLS_SELF_TEST */
......
......@@ -33,48 +33,84 @@
#include <string.h>
/* Structure linking OIDs for X.509 DN AttributeTypes to their
* string representations and default string encodings used by Mbed TLS. */
typedef struct {
const char *name;
size_t name_len;
const char*oid;
const char *name; /* String representation of AttributeType, e.g.
* "CN" or "emailAddress". */
size_t name_len; /* Length of 'name', without trailing 0 byte. */
const char *oid; /* String representation of OID of AttributeType,
* as per RFC 5280, Appendix A.1. */
int default_tag; /* The default character encoding used for the
* given attribute type, e.g.
* MBEDTLS_ASN1_UTF8_STRING for UTF-8. */
} x509_attr_descriptor_t;
#define ADD_STRLEN( s ) s, sizeof( s ) - 1
/* X.509 DN attributes from RFC 5280, Appendix A.1. */
static const x509_attr_descriptor_t x509_attrs[] =
{
{ ADD_STRLEN( "CN" ), MBEDTLS_OID_AT_CN },
{ ADD_STRLEN( "commonName" ), MBEDTLS_OID_AT_CN },
{ ADD_STRLEN( "C" ), MBEDTLS_OID_AT_COUNTRY },
{ ADD_STRLEN( "countryName" ), MBEDTLS_OID_AT_COUNTRY },
{ ADD_STRLEN( "O" ), MBEDTLS_OID_AT_ORGANIZATION },
{ ADD_STRLEN( "organizationName" ), MBEDTLS_OID_AT_ORGANIZATION },
{ ADD_STRLEN( "L" ), MBEDTLS_OID_AT_LOCALITY },
{ ADD_STRLEN( "locality" ), MBEDTLS_OID_AT_LOCALITY },
{ ADD_STRLEN( "R" ), MBEDTLS_OID_PKCS9_EMAIL },
{ ADD_STRLEN( "OU" ), MBEDTLS_OID_AT_ORG_UNIT },
{ ADD_STRLEN( "organizationalUnitName" ), MBEDTLS_OID_AT_ORG_UNIT },
{ ADD_STRLEN( "ST" ), MBEDTLS_OID_AT_STATE },
{ ADD_STRLEN( "stateOrProvinceName" ), MBEDTLS_OID_AT_STATE },
{ ADD_STRLEN( "emailAddress" ), MBEDTLS_OID_PKCS9_EMAIL },
{ ADD_STRLEN( "serialNumber" ), MBEDTLS_OID_AT_SERIAL_NUMBER },
{ ADD_STRLEN( "postalAddress" ), MBEDTLS_OID_AT_POSTAL_ADDRESS },
{ ADD_STRLEN( "postalCode" ), MBEDTLS_OID_AT_POSTAL_CODE },
{ ADD_STRLEN( "dnQualifier" ), MBEDTLS_OID_AT_DN_QUALIFIER },
{ ADD_STRLEN( "title" ), MBEDTLS_OID_AT_TITLE },
{ ADD_STRLEN( "surName" ), MBEDTLS_OID_AT_SUR_NAME },
{ ADD_STRLEN( "SN" ), MBEDTLS_OID_AT_SUR_NAME },
{ ADD_STRLEN( "givenName" ), MBEDTLS_OID_AT_GIVEN_NAME },
{ ADD_STRLEN( "GN" ), MBEDTLS_OID_AT_GIVEN_NAME },
{ ADD_STRLEN( "initials" ), MBEDTLS_OID_AT_INITIALS },
{ ADD_STRLEN( "pseudonym" ), MBEDTLS_OID_AT_PSEUDONYM },
{ ADD_STRLEN( "generationQualifier" ), MBEDTLS_OID_AT_GENERATION_QUALIFIER },
{ ADD_STRLEN( "domainComponent" ), MBEDTLS_OID_DOMAIN_COMPONENT },
{ ADD_STRLEN( "DC" ), MBEDTLS_OID_DOMAIN_COMPONENT },
{ NULL, 0, NULL }
{ ADD_STRLEN( "CN" ),
MBEDTLS_OID_AT_CN, MBEDTLS_ASN1_UTF8_STRING },
{ ADD_STRLEN( "commonName" ),
MBEDTLS_OID_AT_CN, MBEDTLS_ASN1_UTF8_STRING },
{ ADD_STRLEN( "C" ),
MBEDTLS_OID_AT_COUNTRY, MBEDTLS_ASN1_PRINTABLE_STRING },
{ ADD_STRLEN( "countryName" ),
MBEDTLS_OID_AT_COUNTRY, MBEDTLS_ASN1_PRINTABLE_STRING },
{ ADD_STRLEN( "O" ),
MBEDTLS_OID_AT_ORGANIZATION, MBEDTLS_ASN1_UTF8_STRING },
{ ADD_STRLEN( "organizationName" ),
MBEDTLS_OID_AT_ORGANIZATION, MBEDTLS_ASN1_UTF8_STRING },
{ ADD_STRLEN( "L" ),
MBEDTLS_OID_AT_LOCALITY, MBEDTLS_ASN1_UTF8_STRING },
{ ADD_STRLEN( "locality" ),
MBEDTLS_OID_AT_LOCALITY, MBEDTLS_ASN1_UTF8_STRING },
{ ADD_STRLEN( "R" ),
MBEDTLS_OID_PKCS9_EMAIL, MBEDTLS_ASN1_IA5_STRING },
{ ADD_STRLEN( "OU" ),
MBEDTLS_OID_AT_ORG_UNIT, MBEDTLS_ASN1_UTF8_STRING },
{ ADD_STRLEN( "organizationalUnitName" ),
MBEDTLS_OID_AT_ORG_UNIT, MBEDTLS_ASN1_UTF8_STRING },
{ ADD_STRLEN( "ST" ),
MBEDTLS_OID_AT_STATE, MBEDTLS_ASN1_UTF8_STRING },
{ ADD_STRLEN( "stateOrProvinceName" ),
MBEDTLS_OID_AT_STATE, MBEDTLS_ASN1_UTF8_STRING },
{ ADD_STRLEN( "emailAddress" ),
MBEDTLS_OID_PKCS9_EMAIL, MBEDTLS_ASN1_IA5_STRING },
{ ADD_STRLEN( "serialNumber" ),
MBEDTLS_OID_AT_SERIAL_NUMBER, MBEDTLS_ASN1_PRINTABLE_STRING },
{ ADD_STRLEN( "postalAddress" ),
MBEDTLS_OID_AT_POSTAL_ADDRESS, MBEDTLS_ASN1_PRINTABLE_STRING },
{ ADD_STRLEN( "postalCode" ),
MBEDTLS_OID_AT_POSTAL_CODE, MBEDTLS_ASN1_PRINTABLE_STRING },
{ ADD_STRLEN( "dnQualifier" ),
MBEDTLS_OID_AT_DN_QUALIFIER, MBEDTLS_ASN1_PRINTABLE_STRING },
{ ADD_STRLEN( "title" ),
MBEDTLS_OID_AT_TITLE, MBEDTLS_ASN1_UTF8_STRING },
{ ADD_STRLEN( "surName" ),
MBEDTLS_OID_AT_SUR_NAME, MBEDTLS_ASN1_UTF8_STRING },
{ ADD_STRLEN( "SN" ),
MBEDTLS_OID_AT_SUR_NAME, MBEDTLS_ASN1_UTF8_STRING },
{ ADD_STRLEN( "givenName" ),
MBEDTLS_OID_AT_GIVEN_NAME, MBEDTLS_ASN1_UTF8_STRING },
{ ADD_STRLEN( "GN" ),
MBEDTLS_OID_AT_GIVEN_NAME, MBEDTLS_ASN1_UTF8_STRING },
{ ADD_STRLEN( "initials" ),
MBEDTLS_OID_AT_INITIALS, MBEDTLS_ASN1_UTF8_STRING },
{ ADD_STRLEN( "pseudonym" ),
MBEDTLS_OID_AT_PSEUDONYM, MBEDTLS_ASN1_UTF8_STRING },
{ ADD_STRLEN( "generationQualifier" ),
MBEDTLS_OID_AT_GENERATION_QUALIFIER, MBEDTLS_ASN1_UTF8_STRING },
{ ADD_STRLEN( "domainComponent" ),
MBEDTLS_OID_DOMAIN_COMPONENT, MBEDTLS_ASN1_IA5_STRING },
{ ADD_STRLEN( "DC" ),
MBEDTLS_OID_DOMAIN_COMPONENT, MBEDTLS_ASN1_IA5_STRING },
{ NULL, 0, NULL, MBEDTLS_ASN1_NULL }
};
static const char *x509_at_oid_from_name( const char *name, size_t name_len )
static const x509_attr_descriptor_t *x509_attr_descr_from_name( const char *name, size_t name_len )
{
const x509_attr_descriptor_t *cur;
......@@ -83,7 +119,10 @@ static const char *x509_at_oid_from_name( const char *name, size_t name_len )
strncmp( cur->name, name, name_len ) == 0 )
break;
return( cur->oid );
if ( cur->name == NULL )
return( NULL );
return( cur );
}
int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *name )
......@@ -92,6 +131,7 @@ int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *na
const char *s = name, *c = s;
const char *end = s + strlen( s );
const char *oid = NULL;
const x509_attr_descriptor_t* attr_descr = NULL;
int in_tag = 1;
char data[MBEDTLS_X509_MAX_DN_NAME_SIZE];
char *d = data;
......@@ -103,12 +143,13 @@ int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *na
{
if( in_tag && *c == '=' )
{
if( ( oid = x509_at_oid_from_name( s, c - s ) ) == NULL )
if( ( attr_descr = x509_attr_descr_from_name( s, c - s ) ) == NULL )
{
ret = MBEDTLS_ERR_X509_UNKNOWN_OID;
goto exit;
}
oid = attr_descr->oid;
s = c + 1;
in_tag = 0;
d = data;
......@@ -127,13 +168,19 @@ int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *na
}
else if( !in_tag && ( *c == ',' || c == end ) )
{
if( mbedtls_asn1_store_named_data( head, oid, strlen( oid ),
(unsigned char *) data,
d - data ) == NULL )
mbedtls_asn1_named_data* cur =
mbedtls_asn1_store_named_data( head, oid, strlen( oid ),
(unsigned char *) data,
d - data );
if(cur == NULL )
{
return( MBEDTLS_ERR_X509_ALLOC_FAILED );
}
// set tagType
cur->val.tag = attr_descr->default_tag;
while( c < end && *(c + 1) == ' ' )
c++;
......@@ -192,46 +239,40 @@ int mbedtls_x509_set_extension( mbedtls_asn1_named_data **head, const char *oid,
*
* AttributeValue ::= ANY DEFINED BY AttributeType
*/
static int x509_write_name( unsigned char **p, unsigned char *start,
const char *oid, size_t oid_len,
const unsigned char *name, size_t name_len )
static int x509_write_name( unsigned char **p, unsigned char *start, mbedtls_asn1_named_data* cur_name)
{
int ret;
size_t len = 0;
// Write PrintableString for all except MBEDTLS_OID_PKCS9_EMAIL
//
if( MBEDTLS_OID_SIZE( MBEDTLS_OID_PKCS9_EMAIL ) == oid_len &&
memcmp( oid, MBEDTLS_OID_PKCS9_EMAIL, oid_len ) == 0 )
{
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_ia5_string( p, start,
(const char *) name,
name_len ) );
}
else
{
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_printable_string( p, start,
(const char *) name,
name_len ) );
}
const char *oid = (const char*)cur_name->oid.p;
size_t oid_len = cur_name->oid.len;
const unsigned char *name = cur_name->val.p;
size_t name_len = cur_name->val.len;
// Write correct string tag and value
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tagged_string( p, start,
cur_name->val.tag,
(const char *) name,
name_len ) );
// Write OID
//
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid,
oid_len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start,
MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start,
MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SET ) );
return( (int) len );
}
int mbedtls_x509_write_names( unsigned char **p, unsigned char *start,
mbedtls_asn1_named_data *first )
mbedtls_asn1_named_data *first )
{
int ret;
size_t len = 0;
......@@ -239,9 +280,7 @@ int mbedtls_x509_write_names( unsigned char **p, unsigned char *start,
while( cur != NULL )
{
MBEDTLS_ASN1_CHK_ADD( len, x509_write_name( p, start, (char *) cur->oid.p,
cur->oid.len,
cur->val.p, cur->val.len ) );
MBEDTLS_ASN1_CHK_ADD( len, x509_write_name( p, start, cur ) );
cur = cur->next;
}
......
......@@ -39,6 +39,7 @@
#include "mbedtls/x509_crl.h"
#include "mbedtls/oid.h"
#include "mbedtls/platform_util.h"
#include <string.h>
......@@ -66,11 +67,6 @@
#include <stdio.h>
#endif
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
/*
* Version ::= INTEGER { v1(0), v2(1) }
*/
......@@ -107,17 +103,17 @@ static int x509_get_crl_ext( unsigned char **p,
{
int ret;
if( *p == end )
return( 0 );
/*
* crlExtensions [0] EXPLICIT Extensions OPTIONAL
* -- if present, version MUST be v2
*/
if( ( ret = mbedtls_x509_get_ext( p, end, ext, 0 ) ) != 0 )
{
if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
return( 0 );
return( ret );
}
end = ext->p + ext->len;
while( *p < end )
{
......@@ -616,7 +612,7 @@ int mbedtls_x509_crl_parse_file( mbedtls_x509_crl *chain, const char *path )
ret = mbedtls_x509_crl_parse( chain, buf, n );
mbedtls_zeroize( buf, n );
mbedtls_platform_zeroize( buf, n );
mbedtls_free( buf );
return( ret );
......@@ -737,7 +733,7 @@ void mbedtls_x509_crl_free( mbedtls_x509_crl *crl )
{
name_prv = name_cur;
name_cur = name_cur->next;
mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) );
mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) );
mbedtls_free( name_prv );
}
......@@ -746,13 +742,14 @@ void mbedtls_x509_crl_free( mbedtls_x509_crl *crl )
{
entry_prv = entry_cur;
entry_cur = entry_cur->next;
mbedtls_zeroize( entry_prv, sizeof( mbedtls_x509_crl_entry ) );
mbedtls_platform_zeroize( entry_prv,
sizeof( mbedtls_x509_crl_entry ) );
mbedtls_free( entry_prv );
}
if( crl_cur->raw.p != NULL )
{
mbedtls_zeroize( crl_cur->raw.p, crl_cur->raw.len );
mbedtls_platform_zeroize( crl_cur->raw.p, crl_cur->raw.len );
mbedtls_free( crl_cur->raw.p );
}
......@@ -766,7 +763,7 @@ void mbedtls_x509_crl_free( mbedtls_x509_crl *crl )
crl_prv = crl_cur;
crl_cur = crl_cur->next;
mbedtls_zeroize( crl_prv, sizeof( mbedtls_x509_crl ) );
mbedtls_platform_zeroize( crl_prv, sizeof( mbedtls_x509_crl ) );
if( crl_prv != crl )
mbedtls_free( crl_prv );
}
......
......@@ -27,6 +27,8 @@
*
* http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf
* http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
*
* [SIRO] https://cabforum.org/wp-content/uploads/Chunghwatelecom201503cabforumV4.pdf
*/
#if !defined(MBEDTLS_CONFIG_FILE)
......@@ -39,6 +41,7 @@
#include "mbedtls/x509_crt.h"
#include "mbedtls/oid.h"
#include "mbedtls/platform_util.h"
#include <string.h>
......@@ -75,10 +78,18 @@
#endif /* !_WIN32 || EFIX64 || EFI32 */
#endif
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
/*
* Item in a verification chain: cert and flags for it
*/
typedef struct {
mbedtls_x509_crt *crt;
uint32_t flags;
} x509_crt_verify_chain_item;
/*
* Max size of verification chain: end-entity + intermediates + trusted root
*/
#define X509_MAX_VERIFY_CHAIN_SIZE ( MBEDTLS_X509_MAX_INTERMEDIATE_CA + 2 )
/*
* Default profile
......@@ -147,7 +158,7 @@ const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb =
/*
* Check md_alg against profile
* Return 0 if md_alg acceptable for this profile, -1 otherwise
* Return 0 if md_alg is acceptable for this profile, -1 otherwise
*/
static int x509_profile_check_md_alg( const mbedtls_x509_crt_profile *profile,
mbedtls_md_type_t md_alg )
......@@ -163,7 +174,7 @@ static int x509_profile_check_md_alg( const mbedtls_x509_crt_profile *profile,
/*
* Check pk_alg against profile
* Return 0 if pk_alg acceptable for this profile, -1 otherwise
* Return 0 if pk_alg is acceptable for this profile, -1 otherwise
*/
static int x509_profile_check_pk_alg( const mbedtls_x509_crt_profile *profile,
mbedtls_pk_type_t pk_alg )
......@@ -179,12 +190,13 @@ static int x509_profile_check_pk_alg( const mbedtls_x509_crt_profile *profile,
/*
* Check key against profile
* Return 0 if pk_alg acceptable for this profile, -1 otherwise
* Return 0 if pk is acceptable for this profile, -1 otherwise
*/
static int x509_profile_check_key( const mbedtls_x509_crt_profile *profile,
mbedtls_pk_type_t pk_alg,
const mbedtls_pk_context *pk )
{
const mbedtls_pk_type_t pk_alg = mbedtls_pk_get_type( pk );
#if defined(MBEDTLS_RSA_C)
if( pk_alg == MBEDTLS_PK_RSA || pk_alg == MBEDTLS_PK_RSASSA_PSS )
{
......@@ -200,7 +212,7 @@ static int x509_profile_check_key( const mbedtls_x509_crt_profile *profile,
pk_alg == MBEDTLS_PK_ECKEY ||
pk_alg == MBEDTLS_PK_ECKEY_DH )
{
mbedtls_ecp_group_id gid = mbedtls_pk_ec( *pk )->grp.id;
const mbedtls_ecp_group_id gid = mbedtls_pk_ec( *pk )->grp.id;
if( gid == MBEDTLS_ECP_DP_NONE )
return( -1 );
......@@ -215,6 +227,153 @@ static int x509_profile_check_key( const mbedtls_x509_crt_profile *profile,
return( -1 );
}
/*
* Like memcmp, but case-insensitive and always returns -1 if different
*/
static int x509_memcasecmp( const void *s1, const void *s2, size_t len )
{
size_t i;
unsigned char diff;
const unsigned char *n1 = s1, *n2 = s2;
for( i = 0; i < len; i++ )
{
diff = n1[i] ^ n2[i];
if( diff == 0 )
continue;
if( diff == 32 &&
( ( n1[i] >= 'a' && n1[i] <= 'z' ) ||
( n1[i] >= 'A' && n1[i] <= 'Z' ) ) )
{
continue;
}
return( -1 );
}
return( 0 );
}
/*
* Return 0 if name matches wildcard, -1 otherwise
*/
static int x509_check_wildcard( const char *cn, const mbedtls_x509_buf *name )
{
size_t i;
size_t cn_idx = 0, cn_len = strlen( cn );
/* We can't have a match if there is no wildcard to match */
if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' )
return( -1 );
for( i = 0; i < cn_len; ++i )
{
if( cn[i] == '.' )
{
cn_idx = i;
break;
}
}
if( cn_idx == 0 )
return( -1 );
if( cn_len - cn_idx == name->len - 1 &&
x509_memcasecmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 )
{
return( 0 );
}
return( -1 );
}
/*
* Compare two X.509 strings, case-insensitive, and allowing for some encoding
* variations (but not all).
*
* Return 0 if equal, -1 otherwise.
*/
static int x509_string_cmp( const mbedtls_x509_buf *a, const mbedtls_x509_buf *b )
{
if( a->tag == b->tag &&
a->len == b->len &&
memcmp( a->p, b->p, b->len ) == 0 )
{
return( 0 );
}
if( ( a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) &&
( b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) &&
a->len == b->len &&
x509_memcasecmp( a->p, b->p, b->len ) == 0 )
{
return( 0 );
}
return( -1 );
}
/*
* Compare two X.509 Names (aka rdnSequence).
*
* See RFC 5280 section 7.1, though we don't implement the whole algorithm:
* we sometimes return unequal when the full algorithm would return equal,
* but never the other way. (In particular, we don't do Unicode normalisation
* or space folding.)
*
* Return 0 if equal, -1 otherwise.
*/
static int x509_name_cmp( const mbedtls_x509_name *a, const mbedtls_x509_name *b )
{
/* Avoid recursion, it might not be optimised by the compiler */
while( a != NULL || b != NULL )
{
if( a == NULL || b == NULL )
return( -1 );
/* type */
if( a->oid.tag != b->oid.tag ||
a->oid.len != b->oid.len ||
memcmp( a->oid.p, b->oid.p, b->oid.len ) != 0 )
{
return( -1 );
}
/* value */
if( x509_string_cmp( &a->val, &b->val ) != 0 )
return( -1 );
/* structure of the list of sets */
if( a->next_merged != b->next_merged )
return( -1 );
a = a->next;
b = b->next;
}
/* a == NULL == b */
return( 0 );
}
/*
* Reset (init or clear) a verify_chain
*/
static void x509_crt_verify_chain_reset(
mbedtls_x509_crt_verify_chain *ver_chain )
{
size_t i;
for( i = 0; i < MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE; i++ )
{
ver_chain->items[i].crt = NULL;
ver_chain->items[i].flags = (uint32_t) -1;
}
ver_chain->len = 0;
}
/*
* Version ::= INTEGER { v1(0), v2(1), v3(2) }
*/
......@@ -234,7 +393,7 @@ static int x509_get_version( unsigned char **p,
return( 0 );
}
return( ret );
return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret );
}
end = *p + len;
......@@ -301,7 +460,7 @@ static int x509_get_uid( unsigned char **p,
if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
return( 0 );
return( ret );
return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret );
}
uid->p = *p;
......@@ -540,14 +699,13 @@ static int x509_get_crt_ext( unsigned char **p,
size_t len;
unsigned char *end_ext_data, *end_ext_octet;
if( ( ret = mbedtls_x509_get_ext( p, end, &crt->v3_ext, 3 ) ) != 0 )
{
if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
return( 0 );
if( *p == end )
return( 0 );
if( ( ret = mbedtls_x509_get_ext( p, end, &crt->v3_ext, 3 ) ) != 0 )
return( ret );
}
end = crt->v3_ext.p + crt->v3_ext.len;
while( *p < end )
{
/*
......@@ -1104,7 +1262,7 @@ int mbedtls_x509_crt_parse_file( mbedtls_x509_crt *chain, const char *path )
ret = mbedtls_x509_crt_parse( chain, buf, n );
mbedtls_zeroize( buf, n );
mbedtls_platform_zeroize( buf, n );
mbedtls_free( buf );
return( ret );
......@@ -1280,7 +1438,7 @@ static int x509_info_subject_alt_name( char **buf, size_t *size,
}
#define CERT_TYPE(type,name) \
if( ns_cert_type & type ) \
if( ns_cert_type & (type) ) \
PRINT_ITEM( name );
static int x509_info_cert_type( char **buf, size_t *size,
......@@ -1307,7 +1465,7 @@ static int x509_info_cert_type( char **buf, size_t *size,
}
#define KEY_USAGE(code,name) \
if( key_usage & code ) \
if( key_usage & (code) ) \
PRINT_ITEM( name );
static int x509_info_key_usage( char **buf, size_t *size,
......@@ -1364,204 +1522,75 @@ static int x509_info_ext_key_usage( char **buf, size_t *size,
}
/*
* Like memcmp, but case-insensitive and always returns -1 if different
* Return an informational string about the certificate.
*/
static int x509_memcasecmp( const void *s1, const void *s2, size_t len )
#define BEFORE_COLON 18
#define BC "18"
int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix,
const mbedtls_x509_crt *crt )
{
size_t i;
unsigned char diff;
const unsigned char *n1 = s1, *n2 = s2;
int ret;
size_t n;
char *p;
char key_size_str[BEFORE_COLON];
for( i = 0; i < len; i++ )
p = buf;
n = size;
if( NULL == crt )
{
diff = n1[i] ^ n2[i];
ret = mbedtls_snprintf( p, n, "\nCertificate is uninitialised!\n" );
MBEDTLS_X509_SAFE_SNPRINTF;
if( diff == 0 )
continue;
return( (int) ( size - n ) );
}
if( diff == 32 &&
( ( n1[i] >= 'a' && n1[i] <= 'z' ) ||
( n1[i] >= 'A' && n1[i] <= 'Z' ) ) )
{
continue;
}
ret = mbedtls_snprintf( p, n, "%scert. version : %d\n",
prefix, crt->version );
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_snprintf( p, n, "%sserial number : ",
prefix );
MBEDTLS_X509_SAFE_SNPRINTF;
return( -1 );
}
ret = mbedtls_x509_serial_gets( p, n, &crt->serial );
MBEDTLS_X509_SAFE_SNPRINTF;
return( 0 );
}
ret = mbedtls_snprintf( p, n, "\n%sissuer name : ", prefix );
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_x509_dn_gets( p, n, &crt->issuer );
MBEDTLS_X509_SAFE_SNPRINTF;
/*
* Return 0 if name matches wildcard, -1 otherwise
*/
static int x509_check_wildcard( const char *cn, mbedtls_x509_buf *name )
{
size_t i;
size_t cn_idx = 0, cn_len = strlen( cn );
ret = mbedtls_snprintf( p, n, "\n%ssubject name : ", prefix );
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_x509_dn_gets( p, n, &crt->subject );
MBEDTLS_X509_SAFE_SNPRINTF;
if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' )
return( 0 );
ret = mbedtls_snprintf( p, n, "\n%sissued on : " \
"%04d-%02d-%02d %02d:%02d:%02d", prefix,
crt->valid_from.year, crt->valid_from.mon,
crt->valid_from.day, crt->valid_from.hour,
crt->valid_from.min, crt->valid_from.sec );
MBEDTLS_X509_SAFE_SNPRINTF;
for( i = 0; i < cn_len; ++i )
{
if( cn[i] == '.' )
{
cn_idx = i;
break;
}
}
ret = mbedtls_snprintf( p, n, "\n%sexpires on : " \
"%04d-%02d-%02d %02d:%02d:%02d", prefix,
crt->valid_to.year, crt->valid_to.mon,
crt->valid_to.day, crt->valid_to.hour,
crt->valid_to.min, crt->valid_to.sec );
MBEDTLS_X509_SAFE_SNPRINTF;
if( cn_idx == 0 )
return( -1 );
ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix );
MBEDTLS_X509_SAFE_SNPRINTF;
if( cn_len - cn_idx == name->len - 1 &&
x509_memcasecmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 )
ret = mbedtls_x509_sig_alg_gets( p, n, &crt->sig_oid, crt->sig_pk,
crt->sig_md, crt->sig_opts );
MBEDTLS_X509_SAFE_SNPRINTF;
/* Key size */
if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON,
mbedtls_pk_get_name( &crt->pk ) ) ) != 0 )
{
return( 0 );
}
return( -1 );
}
/*
* Compare two X.509 strings, case-insensitive, and allowing for some encoding
* variations (but not all).
*
* Return 0 if equal, -1 otherwise.
*/
static int x509_string_cmp( const mbedtls_x509_buf *a, const mbedtls_x509_buf *b )
{
if( a->tag == b->tag &&
a->len == b->len &&
memcmp( a->p, b->p, b->len ) == 0 )
{
return( 0 );
}
if( ( a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) &&
( b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) &&
a->len == b->len &&
x509_memcasecmp( a->p, b->p, b->len ) == 0 )
{
return( 0 );
}
return( -1 );
}
/*
* Compare two X.509 Names (aka rdnSequence).
*
* See RFC 5280 section 7.1, though we don't implement the whole algorithm:
* we sometimes return unequal when the full algorithm would return equal,
* but never the other way. (In particular, we don't do Unicode normalisation
* or space folding.)
*
* Return 0 if equal, -1 otherwise.
*/
static int x509_name_cmp( const mbedtls_x509_name *a, const mbedtls_x509_name *b )
{
/* Avoid recursion, it might not be optimised by the compiler */
while( a != NULL || b != NULL )
{
if( a == NULL || b == NULL )
return( -1 );
/* type */
if( a->oid.tag != b->oid.tag ||
a->oid.len != b->oid.len ||
memcmp( a->oid.p, b->oid.p, b->oid.len ) != 0 )
{
return( -1 );
}
/* value */
if( x509_string_cmp( &a->val, &b->val ) != 0 )
return( -1 );
/* structure of the list of sets */
if( a->next_merged != b->next_merged )
return( -1 );
a = a->next;
b = b->next;
}
/* a == NULL == b */
return( 0 );
}
/*
* Return an informational string about the certificate.
*/
#define BEFORE_COLON 18
#define BC "18"
int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix,
const mbedtls_x509_crt *crt )
{
int ret;
size_t n;
char *p;
char key_size_str[BEFORE_COLON];
p = buf;
n = size;
if( NULL == crt )
{
ret = mbedtls_snprintf( p, n, "\nCertificate is uninitialised!\n" );
MBEDTLS_X509_SAFE_SNPRINTF;
return( (int) ( size - n ) );
}
ret = mbedtls_snprintf( p, n, "%scert. version : %d\n",
prefix, crt->version );
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_snprintf( p, n, "%sserial number : ",
prefix );
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_x509_serial_gets( p, n, &crt->serial );
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_snprintf( p, n, "\n%sissuer name : ", prefix );
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_x509_dn_gets( p, n, &crt->issuer );
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_snprintf( p, n, "\n%ssubject name : ", prefix );
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_x509_dn_gets( p, n, &crt->subject );
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_snprintf( p, n, "\n%sissued on : " \
"%04d-%02d-%02d %02d:%02d:%02d", prefix,
crt->valid_from.year, crt->valid_from.mon,
crt->valid_from.day, crt->valid_from.hour,
crt->valid_from.min, crt->valid_from.sec );
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_snprintf( p, n, "\n%sexpires on : " \
"%04d-%02d-%02d %02d:%02d:%02d", prefix,
crt->valid_to.year, crt->valid_to.mon,
crt->valid_to.day, crt->valid_to.hour,
crt->valid_to.min, crt->valid_to.sec );
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix );
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_x509_sig_alg_gets( p, n, &crt->sig_oid, crt->sig_pk,
crt->sig_md, crt->sig_opts );
MBEDTLS_X509_SAFE_SNPRINTF;
/* Key size */
if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON,
mbedtls_pk_get_name( &crt->pk ) ) ) != 0 )
{
return( ret );
return( ret );
}
ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: %d bits", prefix, key_size_str,
......@@ -1819,7 +1848,7 @@ static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca,
break;
}
if( x509_profile_check_key( profile, crl_list->sig_pk, &ca->pk ) != 0 )
if( x509_profile_check_key( profile, &ca->pk ) != 0 )
flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
if( mbedtls_pk_verify_ext( crl_list->sig_pk, crl_list->sig_opts, &ca->pk,
......@@ -1855,16 +1884,52 @@ static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca,
}
#endif /* MBEDTLS_X509_CRL_PARSE_C */
/*
* Check the signature of a certificate by its parent
*/
static int x509_crt_check_signature( const mbedtls_x509_crt *child,
mbedtls_x509_crt *parent,
mbedtls_x509_crt_restart_ctx *rs_ctx )
{
const mbedtls_md_info_t *md_info;
unsigned char hash[MBEDTLS_MD_MAX_SIZE];
md_info = mbedtls_md_info_from_type( child->sig_md );
if( mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ) != 0 )
{
/* Note: this can't happen except after an internal error */
return( -1 );
}
/* Skip expensive computation on obvious mismatch */
if( ! mbedtls_pk_can_do( &parent->pk, child->sig_pk ) )
return( -1 );
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && child->sig_pk == MBEDTLS_PK_ECDSA )
{
return( mbedtls_pk_verify_restartable( &parent->pk,
child->sig_md, hash, mbedtls_md_get_size( md_info ),
child->sig.p, child->sig.len, &rs_ctx->pk ) );
}
#else
(void) rs_ctx;
#endif
return( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &parent->pk,
child->sig_md, hash, mbedtls_md_get_size( md_info ),
child->sig.p, child->sig.len ) );
}
/*
* Check if 'parent' is a suitable parent (signing CA) for 'child'.
* Return 0 if yes, -1 if not.
*
* top means parent is a locally-trusted certificate
* bottom means child is the end entity cert
*/
static int x509_crt_check_parent( const mbedtls_x509_crt *child,
const mbedtls_x509_crt *parent,
int top, int bottom )
int top )
{
int need_ca_bit;
......@@ -1879,14 +1944,6 @@ static int x509_crt_check_parent( const mbedtls_x509_crt *child,
if( top && parent->version < 3 )
need_ca_bit = 0;
/* Exception: self-signed end-entity certs that are locally trusted. */
if( top && bottom &&
child->raw.len == parent->raw.len &&
memcmp( child->raw.p, parent->raw.p, child->raw.len ) == 0 )
{
need_ca_bit = 0;
}
if( need_ca_bit && ! parent->ca_istrue )
return( -1 );
......@@ -1902,301 +1959,538 @@ static int x509_crt_check_parent( const mbedtls_x509_crt *child,
}
/*
* Verify a certificate with no parent inside the chain
* (either the parent is a trusted root, or there is no parent)
* Find a suitable parent for child in candidates, or return NULL.
*
* Here suitable is defined as:
* 1. subject name matches child's issuer
* 2. if necessary, the CA bit is set and key usage allows signing certs
* 3. for trusted roots, the signature is correct
* (for intermediates, the signature is checked and the result reported)
* 4. pathlen constraints are satisfied
*
* If there's a suitable candidate which is also time-valid, return the first
* such. Otherwise, return the first suitable candidate (or NULL if there is
* none).
*
* See comments for mbedtls_x509_crt_verify_with_profile()
* (also for notation used below)
* The rationale for this rule is that someone could have a list of trusted
* roots with two versions on the same root with different validity periods.
* (At least one user reported having such a list and wanted it to just work.)
* The reason we don't just require time-validity is that generally there is
* only one version, and if it's expired we want the flags to state that
* rather than NOT_TRUSTED, as would be the case if we required it here.
*
* This function is called in two cases:
* - child was found to have a parent in trusted roots, in which case we're
* called with trust_ca pointing directly to that parent (not the full list)
* - this is cases 1, 2 and 3 of the comment on verify_with_profile()
* - case 1 is special as child and trust_ca point to copies of the same
* certificate then
* - child was found to have no parent either in the chain or in trusted CAs
* - this is cases 4 and 5 of the comment on verify_with_profile()
* The rationale for rule 3 (signature for trusted roots) is that users might
* have two versions of the same CA with different keys in their list, and the
* way we select the correct one is by checking the signature (as we don't
* rely on key identifier extensions). (This is one way users might choose to
* handle key rollover, another relies on self-issued certs, see [SIRO].)
*
* For historical reasons, the function currently does not assume that
* trust_ca points directly to the right root in the first case, and it
* doesn't know in which case it starts, so it always starts by searching for
* a parent in trust_ca.
* Arguments:
* - [in] child: certificate for which we're looking for a parent
* - [in] candidates: chained list of potential parents
* - [out] r_parent: parent found (or NULL)
* - [out] r_signature_is_good: 1 if child signature by parent is valid, or 0
* - [in] top: 1 if candidates consists of trusted roots, ie we're at the top
* of the chain, 0 otherwise
* - [in] path_cnt: number of intermediates seen so far
* - [in] self_cnt: number of self-signed intermediates seen so far
* (will never be greater than path_cnt)
* - [in-out] rs_ctx: context for restarting operations
*
* Return value:
* - 0 on success
* - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise
*/
static int x509_crt_verify_top(
mbedtls_x509_crt *child, mbedtls_x509_crt *trust_ca,
mbedtls_x509_crl *ca_crl,
const mbedtls_x509_crt_profile *profile,
int path_cnt, int self_cnt, uint32_t *flags,
int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
void *p_vrfy )
static int x509_crt_find_parent_in(
mbedtls_x509_crt *child,
mbedtls_x509_crt *candidates,
mbedtls_x509_crt **r_parent,
int *r_signature_is_good,
int top,
unsigned path_cnt,
unsigned self_cnt,
mbedtls_x509_crt_restart_ctx *rs_ctx )
{
int ret;
uint32_t ca_flags = 0;
int check_path_cnt;
unsigned char hash[MBEDTLS_MD_MAX_SIZE];
const mbedtls_md_info_t *md_info;
mbedtls_x509_crt *future_past_ca = NULL;
if( mbedtls_x509_time_is_past( &child->valid_to ) )
*flags |= MBEDTLS_X509_BADCERT_EXPIRED;
if( mbedtls_x509_time_is_future( &child->valid_from ) )
*flags |= MBEDTLS_X509_BADCERT_FUTURE;
mbedtls_x509_crt *parent, *fallback_parent;
int signature_is_good, fallback_signature_is_good;
if( x509_profile_check_md_alg( profile, child->sig_md ) != 0 )
*flags |= MBEDTLS_X509_BADCERT_BAD_MD;
if( x509_profile_check_pk_alg( profile, child->sig_pk ) != 0 )
*flags |= MBEDTLS_X509_BADCERT_BAD_PK;
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
/* did we have something in progress? */
if( rs_ctx != NULL && rs_ctx->parent != NULL )
{
/* restore saved state */
parent = rs_ctx->parent;
fallback_parent = rs_ctx->fallback_parent;
fallback_signature_is_good = rs_ctx->fallback_signature_is_good;
/*
* Child is the top of the chain. Check against the trust_ca list.
*/
*flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED;
/* clear saved state */
rs_ctx->parent = NULL;
rs_ctx->fallback_parent = NULL;
rs_ctx->fallback_signature_is_good = 0;
md_info = mbedtls_md_info_from_type( child->sig_md );
if( mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ) != 0 )
{
/* Note: this can't happen except after an internal error */
/* Cannot check signature, no need to try any CA */
trust_ca = NULL;
/* resume where we left */
goto check_signature;
}
#endif
fallback_parent = NULL;
fallback_signature_is_good = 0;
for( /* trust_ca */ ; trust_ca != NULL; trust_ca = trust_ca->next )
for( parent = candidates; parent != NULL; parent = parent->next )
{
if( x509_crt_check_parent( child, trust_ca, 1, path_cnt == 0 ) != 0 )
/* basic parenting skills (name, CA bit, key usage) */
if( x509_crt_check_parent( child, parent, top ) != 0 )
continue;
check_path_cnt = path_cnt + 1;
/*
* Reduce check_path_cnt to check against if top of the chain is
* the same as the trusted CA
*/
if( child->subject_raw.len == trust_ca->subject_raw.len &&
memcmp( child->subject_raw.p, trust_ca->subject_raw.p,
child->subject_raw.len ) == 0 )
/* +1 because stored max_pathlen is 1 higher that the actual value */
if( parent->max_pathlen > 0 &&
(size_t) parent->max_pathlen < 1 + path_cnt - self_cnt )
{
check_path_cnt--;
continue;
}
/* Self signed certificates do not count towards the limit */
if( trust_ca->max_pathlen > 0 &&
trust_ca->max_pathlen < check_path_cnt - self_cnt )
/* Signature */
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
check_signature:
#endif
ret = x509_crt_check_signature( child, parent, rs_ctx );
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
{
continue;
/* save state */
rs_ctx->parent = parent;
rs_ctx->fallback_parent = fallback_parent;
rs_ctx->fallback_signature_is_good = fallback_signature_is_good;
return( ret );
}
#else
(void) ret;
#endif
if( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &trust_ca->pk,
child->sig_md, hash, mbedtls_md_get_size( md_info ),
child->sig.p, child->sig.len ) != 0 )
{
signature_is_good = ret == 0;
if( top && ! signature_is_good )
continue;
}
if( mbedtls_x509_time_is_past( &trust_ca->valid_to ) ||
mbedtls_x509_time_is_future( &trust_ca->valid_from ) )
/* optional time check */
if( mbedtls_x509_time_is_past( &parent->valid_to ) ||
mbedtls_x509_time_is_future( &parent->valid_from ) )
{
if ( future_past_ca == NULL )
future_past_ca = trust_ca;
if( fallback_parent == NULL )
{
fallback_parent = parent;
fallback_signature_is_good = signature_is_good;
}
continue;
}
*r_parent = parent;
*r_signature_is_good = signature_is_good;
break;
}
if( trust_ca != NULL || ( trust_ca = future_past_ca ) != NULL )
if( parent == NULL )
{
/*
* Top of chain is signed by a trusted CA
*/
*flags &= ~MBEDTLS_X509_BADCERT_NOT_TRUSTED;
if( x509_profile_check_key( profile, child->sig_pk, &trust_ca->pk ) != 0 )
*flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
*r_parent = fallback_parent;
*r_signature_is_good = fallback_signature_is_good;
}
/*
* If top of chain is not the same as the trusted CA send a verify request
* to the callback for any issues with validity and CRL presence for the
* trusted CA certificate.
*/
if( trust_ca != NULL &&
( child->subject_raw.len != trust_ca->subject_raw.len ||
memcmp( child->subject_raw.p, trust_ca->subject_raw.p,
child->subject_raw.len ) != 0 ) )
return( 0 );
}
/*
* Find a parent in trusted CAs or the provided chain, or return NULL.
*
* Searches in trusted CAs first, and return the first suitable parent found
* (see find_parent_in() for definition of suitable).
*
* Arguments:
* - [in] child: certificate for which we're looking for a parent, followed
* by a chain of possible intermediates
* - [in] trust_ca: list of locally trusted certificates
* - [out] parent: parent found (or NULL)
* - [out] parent_is_trusted: 1 if returned `parent` is trusted, or 0
* - [out] signature_is_good: 1 if child signature by parent is valid, or 0
* - [in] path_cnt: number of links in the chain so far (EE -> ... -> child)
* - [in] self_cnt: number of self-signed certs in the chain so far
* (will always be no greater than path_cnt)
* - [in-out] rs_ctx: context for restarting operations
*
* Return value:
* - 0 on success
* - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise
*/
static int x509_crt_find_parent(
mbedtls_x509_crt *child,
mbedtls_x509_crt *trust_ca,
mbedtls_x509_crt **parent,
int *parent_is_trusted,
int *signature_is_good,
unsigned path_cnt,
unsigned self_cnt,
mbedtls_x509_crt_restart_ctx *rs_ctx )
{
int ret;
mbedtls_x509_crt *search_list;
*parent_is_trusted = 1;
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
/* restore then clear saved state if we have some stored */
if( rs_ctx != NULL && rs_ctx->parent_is_trusted != -1 )
{
#if defined(MBEDTLS_X509_CRL_PARSE_C)
/* Check trusted CA's CRL for the chain's top crt */
*flags |= x509_crt_verifycrl( child, trust_ca, ca_crl, profile );
#else
((void) ca_crl);
*parent_is_trusted = rs_ctx->parent_is_trusted;
rs_ctx->parent_is_trusted = -1;
}
#endif
if( mbedtls_x509_time_is_past( &trust_ca->valid_to ) )
ca_flags |= MBEDTLS_X509_BADCERT_EXPIRED;
while( 1 ) {
search_list = *parent_is_trusted ? trust_ca : child->next;
if( mbedtls_x509_time_is_future( &trust_ca->valid_from ) )
ca_flags |= MBEDTLS_X509_BADCERT_FUTURE;
ret = x509_crt_find_parent_in( child, search_list,
parent, signature_is_good,
*parent_is_trusted,
path_cnt, self_cnt, rs_ctx );
if( NULL != f_vrfy )
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
{
if( ( ret = f_vrfy( p_vrfy, trust_ca, path_cnt + 1,
&ca_flags ) ) != 0 )
{
return( ret );
}
/* save state */
rs_ctx->parent_is_trusted = *parent_is_trusted;
return( ret );
}
#else
(void) ret;
#endif
/* stop here if found or already in second iteration */
if( *parent != NULL || *parent_is_trusted == 0 )
break;
/* prepare second iteration */
*parent_is_trusted = 0;
}
/* Call callback on top cert */
if( NULL != f_vrfy )
/* extra precaution against mistakes in the caller */
if( *parent == NULL )
{
if( ( ret = f_vrfy( p_vrfy, child, path_cnt, flags ) ) != 0 )
return( ret );
*parent_is_trusted = 0;
*signature_is_good = 0;
}
*flags |= ca_flags;
return( 0 );
}
/*
* Verify a certificate with a parent inside the chain
* Check if an end-entity certificate is locally trusted
*
* See comments for mbedtls_x509_crt_verify_with_profile()
* Currently we require such certificates to be self-signed (actually only
* check for self-issued as self-signatures are not checked)
*/
static int x509_crt_verify_child(
mbedtls_x509_crt *child, mbedtls_x509_crt *parent,
mbedtls_x509_crt *trust_ca, mbedtls_x509_crl *ca_crl,
const mbedtls_x509_crt_profile *profile,
int path_cnt, int self_cnt, uint32_t *flags,
int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
void *p_vrfy )
static int x509_crt_check_ee_locally_trusted(
mbedtls_x509_crt *crt,
mbedtls_x509_crt *trust_ca )
{
int ret;
uint32_t parent_flags = 0;
unsigned char hash[MBEDTLS_MD_MAX_SIZE];
mbedtls_x509_crt *grandparent;
const mbedtls_md_info_t *md_info;
mbedtls_x509_crt *cur;
/* Counting intermediate self signed certificates */
if( ( path_cnt != 0 ) && x509_name_cmp( &child->issuer, &child->subject ) == 0 )
self_cnt++;
/* must be self-issued */
if( x509_name_cmp( &crt->issuer, &crt->subject ) != 0 )
return( -1 );
/* path_cnt is 0 for the first intermediate CA */
if( 1 + path_cnt > MBEDTLS_X509_MAX_INTERMEDIATE_CA )
/* look for an exact match with trusted cert */
for( cur = trust_ca; cur != NULL; cur = cur->next )
{
/* return immediately as the goal is to avoid unbounded recursion */
return( MBEDTLS_ERR_X509_FATAL_ERROR );
if( crt->raw.len == cur->raw.len &&
memcmp( crt->raw.p, cur->raw.p, crt->raw.len ) == 0 )
{
return( 0 );
}
}
if( mbedtls_x509_time_is_past( &child->valid_to ) )
*flags |= MBEDTLS_X509_BADCERT_EXPIRED;
/* too bad */
return( -1 );
}
if( mbedtls_x509_time_is_future( &child->valid_from ) )
*flags |= MBEDTLS_X509_BADCERT_FUTURE;
/*
* Build and verify a certificate chain
*
* Given a peer-provided list of certificates EE, C1, ..., Cn and
* a list of trusted certs R1, ... Rp, try to build and verify a chain
* EE, Ci1, ... Ciq [, Rj]
* such that every cert in the chain is a child of the next one,
* jumping to a trusted root as early as possible.
*
* Verify that chain and return it with flags for all issues found.
*
* Special cases:
* - EE == Rj -> return a one-element list containing it
* - EE, Ci1, ..., Ciq cannot be continued with a trusted root
* -> return that chain with NOT_TRUSTED set on Ciq
*
* Tests for (aspects of) this function should include at least:
* - trusted EE
* - EE -> trusted root
* - EE -> intermediate CA -> trusted root
* - if relevant: EE untrusted
* - if relevant: EE -> intermediate, untrusted
* with the aspect under test checked at each relevant level (EE, int, root).
* For some aspects longer chains are required, but usually length 2 is
* enough (but length 1 is not in general).
*
* Arguments:
* - [in] crt: the cert list EE, C1, ..., Cn
* - [in] trust_ca: the trusted list R1, ..., Rp
* - [in] ca_crl, profile: as in verify_with_profile()
* - [out] ver_chain: the built and verified chain
* Only valid when return value is 0, may contain garbage otherwise!
* Restart note: need not be the same when calling again to resume.
* - [in-out] rs_ctx: context for restarting operations
*
* Return value:
* - non-zero if the chain could not be fully built and examined
* - 0 is the chain was successfully built and examined,
* even if it was found to be invalid
*/
static int x509_crt_verify_chain(
mbedtls_x509_crt *crt,
mbedtls_x509_crt *trust_ca,
mbedtls_x509_crl *ca_crl,
const mbedtls_x509_crt_profile *profile,
mbedtls_x509_crt_verify_chain *ver_chain,
mbedtls_x509_crt_restart_ctx *rs_ctx )
{
/* Don't initialize any of those variables here, so that the compiler can
* catch potential issues with jumping ahead when restarting */
int ret;
uint32_t *flags;
mbedtls_x509_crt_verify_chain_item *cur;
mbedtls_x509_crt *child;
mbedtls_x509_crt *parent;
int parent_is_trusted;
int child_is_trusted;
int signature_is_good;
unsigned self_cnt;
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
/* resume if we had an operation in progress */
if( rs_ctx != NULL && rs_ctx->in_progress == x509_crt_rs_find_parent )
{
/* restore saved state */
*ver_chain = rs_ctx->ver_chain; /* struct copy */
self_cnt = rs_ctx->self_cnt;
/* restore derived state */
cur = &ver_chain->items[ver_chain->len - 1];
child = cur->crt;
flags = &cur->flags;
goto find_parent;
}
#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
child = crt;
self_cnt = 0;
parent_is_trusted = 0;
child_is_trusted = 0;
while( 1 ) {
/* Add certificate to the verification chain */
cur = &ver_chain->items[ver_chain->len];
cur->crt = child;
cur->flags = 0;
ver_chain->len++;
flags = &cur->flags;
/* Check time-validity (all certificates) */
if( mbedtls_x509_time_is_past( &child->valid_to ) )
*flags |= MBEDTLS_X509_BADCERT_EXPIRED;
if( mbedtls_x509_time_is_future( &child->valid_from ) )
*flags |= MBEDTLS_X509_BADCERT_FUTURE;
/* Stop here for trusted roots (but not for trusted EE certs) */
if( child_is_trusted )
return( 0 );
if( x509_profile_check_md_alg( profile, child->sig_md ) != 0 )
*flags |= MBEDTLS_X509_BADCERT_BAD_MD;
/* Check signature algorithm: MD & PK algs */
if( x509_profile_check_md_alg( profile, child->sig_md ) != 0 )
*flags |= MBEDTLS_X509_BADCERT_BAD_MD;
if( x509_profile_check_pk_alg( profile, child->sig_pk ) != 0 )
*flags |= MBEDTLS_X509_BADCERT_BAD_PK;
if( x509_profile_check_pk_alg( profile, child->sig_pk ) != 0 )
*flags |= MBEDTLS_X509_BADCERT_BAD_PK;
md_info = mbedtls_md_info_from_type( child->sig_md );
if( mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ) != 0 )
{
/* Note: this can't happen except after an internal error */
*flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED;
}
else
{
if( x509_profile_check_key( profile, child->sig_pk, &parent->pk ) != 0 )
*flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
/* Special case: EE certs that are locally trusted */
if( ver_chain->len == 1 &&
x509_crt_check_ee_locally_trusted( child, trust_ca ) == 0 )
{
return( 0 );
}
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
find_parent:
#endif
/* Look for a parent in trusted CAs or up the chain */
ret = x509_crt_find_parent( child, trust_ca, &parent,
&parent_is_trusted, &signature_is_good,
ver_chain->len - 1, self_cnt, rs_ctx );
if( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &parent->pk,
child->sig_md, hash, mbedtls_md_get_size( md_info ),
child->sig.p, child->sig.len ) != 0 )
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
{
/* save state */
rs_ctx->in_progress = x509_crt_rs_find_parent;
rs_ctx->self_cnt = self_cnt;
rs_ctx->ver_chain = *ver_chain; /* struct copy */
return( ret );
}
#else
(void) ret;
#endif
/* No parent? We're done here */
if( parent == NULL )
{
*flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED;
return( 0 );
}
/* Count intermediate self-issued (not necessarily self-signed) certs.
* These can occur with some strategies for key rollover, see [SIRO],
* and should be excluded from max_pathlen checks. */
if( ver_chain->len != 1 &&
x509_name_cmp( &child->issuer, &child->subject ) == 0 )
{
self_cnt++;
}
}
/* path_cnt is 0 for the first intermediate CA,
* and if parent is trusted it's not an intermediate CA */
if( ! parent_is_trusted &&
ver_chain->len > MBEDTLS_X509_MAX_INTERMEDIATE_CA )
{
/* return immediately to avoid overflow the chain array */
return( MBEDTLS_ERR_X509_FATAL_ERROR );
}
/* signature was checked while searching parent */
if( ! signature_is_good )
*flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED;
/* check size of signing key */
if( x509_profile_check_key( profile, &parent->pk ) != 0 )
*flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
#if defined(MBEDTLS_X509_CRL_PARSE_C)
/* Check trusted CA's CRL for the given crt */
*flags |= x509_crt_verifycrl(child, parent, ca_crl, profile );
/* Check trusted CA's CRL for the given crt */
*flags |= x509_crt_verifycrl( child, parent, ca_crl, profile );
#else
(void) ca_crl;
#endif
/* Look for a grandparent in trusted CAs */
for( grandparent = trust_ca;
grandparent != NULL;
grandparent = grandparent->next )
/* prepare for next iteration */
child = parent;
parent = NULL;
child_is_trusted = parent_is_trusted;
signature_is_good = 0;
}
}
/*
* Check for CN match
*/
static int x509_crt_check_cn( const mbedtls_x509_buf *name,
const char *cn, size_t cn_len )
{
/* try exact match */
if( name->len == cn_len &&
x509_memcasecmp( cn, name->p, cn_len ) == 0 )
{
if( x509_crt_check_parent( parent, grandparent,
0, path_cnt == 0 ) == 0 )
break;
return( 0 );
}
if( grandparent != NULL )
/* try wildcard match */
if( x509_check_wildcard( cn, name ) == 0 )
{
ret = x509_crt_verify_top( parent, grandparent, ca_crl, profile,
path_cnt + 1, self_cnt, &parent_flags, f_vrfy, p_vrfy );
if( ret != 0 )
return( ret );
return( 0 );
}
else
return( -1 );
}
/*
* Verify the requested CN - only call this if cn is not NULL!
*/
static void x509_crt_verify_name( const mbedtls_x509_crt *crt,
const char *cn,
uint32_t *flags )
{
const mbedtls_x509_name *name;
const mbedtls_x509_sequence *cur;
size_t cn_len = strlen( cn );
if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME )
{
/* Look for a grandparent upwards the chain */
for( grandparent = parent->next;
grandparent != NULL;
grandparent = grandparent->next )
for( cur = &crt->subject_alt_names; cur != NULL; cur = cur->next )
{
/* +2 because the current step is not yet accounted for
* and because max_pathlen is one higher than it should be.
* Also self signed certificates do not count to the limit. */
if( grandparent->max_pathlen > 0 &&
grandparent->max_pathlen < 2 + path_cnt - self_cnt )
{
continue;
}
if( x509_crt_check_parent( parent, grandparent,
0, path_cnt == 0 ) == 0 )
if( x509_crt_check_cn( &cur->buf, cn, cn_len ) == 0 )
break;
}
/* Is our parent part of the chain or at the top? */
if( grandparent != NULL )
{
ret = x509_crt_verify_child( parent, grandparent, trust_ca, ca_crl,
profile, path_cnt + 1, self_cnt, &parent_flags,
f_vrfy, p_vrfy );
if( ret != 0 )
return( ret );
}
else
if( cur == NULL )
*flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH;
}
else
{
for( name = &crt->subject; name != NULL; name = name->next )
{
ret = x509_crt_verify_top( parent, trust_ca, ca_crl, profile,
path_cnt + 1, self_cnt, &parent_flags,
f_vrfy, p_vrfy );
if( ret != 0 )
return( ret );
if( MBEDTLS_OID_CMP( MBEDTLS_OID_AT_CN, &name->oid ) == 0 &&
x509_crt_check_cn( &name->val, cn, cn_len ) == 0 )
{
break;
}
}
if( name == NULL )
*flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH;
}
}
/* child is verified to be a child of the parent, call verify callback */
if( NULL != f_vrfy )
if( ( ret = f_vrfy( p_vrfy, child, path_cnt, flags ) ) != 0 )
return( ret );
/*
* Merge the flags for all certs in the chain, after calling callback
*/
static int x509_crt_merge_flags_with_cb(
uint32_t *flags,
const mbedtls_x509_crt_verify_chain *ver_chain,
int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
void *p_vrfy )
{
int ret;
unsigned i;
uint32_t cur_flags;
const mbedtls_x509_crt_verify_chain_item *cur;
*flags |= parent_flags;
for( i = ver_chain->len; i != 0; --i )
{
cur = &ver_chain->items[i-1];
cur_flags = cur->flags;
if( NULL != f_vrfy )
if( ( ret = f_vrfy( p_vrfy, cur->crt, (int) i-1, &cur_flags ) ) != 0 )
return( ret );
*flags |= cur_flags;
}
return( 0 );
}
/*
* Verify the certificate validity
* Verify the certificate validity (default profile, not restartable)
*/
int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt,
mbedtls_x509_crt *trust_ca,
......@@ -2205,41 +2499,13 @@ int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt,
int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
void *p_vrfy )
{
return( mbedtls_x509_crt_verify_with_profile( crt, trust_ca, ca_crl,
&mbedtls_x509_crt_profile_default, cn, flags, f_vrfy, p_vrfy ) );
return( mbedtls_x509_crt_verify_restartable( crt, trust_ca, ca_crl,
&mbedtls_x509_crt_profile_default, cn, flags,
f_vrfy, p_vrfy, NULL ) );
}
/*
* Verify the certificate validity, with profile
*
* The chain building/verification is spread accross 4 functions:
* - this one
* - x509_crt_verify_child()
* - x509_crt_verify_top()
* - x509_crt_check_parent()
*
* There are five main cases to consider. Let's introduce some notation:
* - E means the end-entity certificate
* - I an intermediate CA
* - R the trusted root CA this chain anchors to
* - T the list of trusted roots (R and possible some others)
*
* The main cases with the calling sequence of the crt_verify_xxx() are:
* 1. E = R (explicitly trusted EE cert)
* verify(E, T) -> verify_top(E, R)
* 2. E -> R (EE signed by trusted root)
* verify(E, T) -> verify_top(E, R)
* 3. E -> I -> R (EE signed by intermediate signed by trusted root)
* verify(E, T) -> verify_child(E, I, T) -> verify_top(I, R)
* (plus variant with multiple intermediates)
* 4. E -> I (EE signed by intermediate that's not trusted)
* verify(E, T) -> verify_child(E, I, T) -> verify_top(I, T)
* (plus variant with multiple intermediates)
* 5. E (EE not trusted)
* verify(E, T) -> verify_top(E, T)
*
* Note: this notation and case numbering is also used in x509_crt_verify_top()
* Verify the certificate validity (user-chosen profile, not restartable)
*/
int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt,
mbedtls_x509_crt *trust_ca,
......@@ -2249,15 +2515,37 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt,
int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
void *p_vrfy )
{
size_t cn_len;
return( mbedtls_x509_crt_verify_restartable( crt, trust_ca, ca_crl,
profile, cn, flags, f_vrfy, p_vrfy, NULL ) );
}
/*
* Verify the certificate validity, with profile, restartable version
*
* This function:
* - checks the requested CN (if any)
* - checks the type and size of the EE cert's key,
* as that isn't done as part of chain building/verification currently
* - builds and verifies the chain
* - then calls the callback and merges the flags
*/
int mbedtls_x509_crt_verify_restartable( mbedtls_x509_crt *crt,
mbedtls_x509_crt *trust_ca,
mbedtls_x509_crl *ca_crl,
const mbedtls_x509_crt_profile *profile,
const char *cn, uint32_t *flags,
int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
void *p_vrfy,
mbedtls_x509_crt_restart_ctx *rs_ctx )
{
int ret;
int pathlen = 0, selfsigned = 0;
mbedtls_x509_crt *parent;
mbedtls_x509_name *name;
mbedtls_x509_sequence *cur = NULL;
mbedtls_pk_type_t pk_type;
mbedtls_x509_crt_verify_chain ver_chain;
uint32_t ee_flags;
*flags = 0;
ee_flags = 0;
x509_crt_verify_chain_reset( &ver_chain );
if( profile == NULL )
{
......@@ -2265,106 +2553,38 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt,
goto exit;
}
/* check name if requested */
if( cn != NULL )
{
name = &crt->subject;
cn_len = strlen( cn );
if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME )
{
cur = &crt->subject_alt_names;
while( cur != NULL )
{
if( cur->buf.len == cn_len &&
x509_memcasecmp( cn, cur->buf.p, cn_len ) == 0 )
break;
if( cur->buf.len > 2 &&
memcmp( cur->buf.p, "*.", 2 ) == 0 &&
x509_check_wildcard( cn, &cur->buf ) == 0 )
{
break;
}
cur = cur->next;
}
if( cur == NULL )
*flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH;
}
else
{
while( name != NULL )
{
if( MBEDTLS_OID_CMP( MBEDTLS_OID_AT_CN, &name->oid ) == 0 )
{
if( name->val.len == cn_len &&
x509_memcasecmp( name->val.p, cn, cn_len ) == 0 )
break;
if( name->val.len > 2 &&
memcmp( name->val.p, "*.", 2 ) == 0 &&
x509_check_wildcard( cn, &name->val ) == 0 )
break;
}
name = name->next;
}
if( name == NULL )
*flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH;
}
}
x509_crt_verify_name( crt, cn, &ee_flags );
/* Check the type and size of the key */
pk_type = mbedtls_pk_get_type( &crt->pk );
if( x509_profile_check_pk_alg( profile, pk_type ) != 0 )
*flags |= MBEDTLS_X509_BADCERT_BAD_PK;
ee_flags |= MBEDTLS_X509_BADCERT_BAD_PK;
if( x509_profile_check_key( profile, pk_type, &crt->pk ) != 0 )
*flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
if( x509_profile_check_key( profile, &crt->pk ) != 0 )
ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
/* Look for a parent in trusted CAs */
for( parent = trust_ca; parent != NULL; parent = parent->next )
{
if( x509_crt_check_parent( crt, parent, 0, pathlen == 0 ) == 0 )
break;
}
/* Check the chain */
ret = x509_crt_verify_chain( crt, trust_ca, ca_crl, profile,
&ver_chain, rs_ctx );
if( parent != NULL )
{
ret = x509_crt_verify_top( crt, parent, ca_crl, profile,
pathlen, selfsigned, flags, f_vrfy, p_vrfy );
if( ret != 0 )
goto exit;
}
else
{
/* Look for a parent upwards the chain */
for( parent = crt->next; parent != NULL; parent = parent->next )
if( x509_crt_check_parent( crt, parent, 0, pathlen == 0 ) == 0 )
break;
if( ret != 0 )
goto exit;
/* Are we part of the chain or at the top? */
if( parent != NULL )
{
ret = x509_crt_verify_child( crt, parent, trust_ca, ca_crl, profile,
pathlen, selfsigned, flags, f_vrfy, p_vrfy );
if( ret != 0 )
goto exit;
}
else
{
ret = x509_crt_verify_top( crt, trust_ca, ca_crl, profile,
pathlen, selfsigned, flags, f_vrfy, p_vrfy );
if( ret != 0 )
goto exit;
}
}
/* Merge end-entity flags */
ver_chain.items[0].flags |= ee_flags;
/* Build final flags, calling callback on the way if any */
ret = x509_crt_merge_flags_with_cb( flags, &ver_chain, f_vrfy, p_vrfy );
exit:
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx != NULL && ret != MBEDTLS_ERR_ECP_IN_PROGRESS )
mbedtls_x509_crt_restart_free( rs_ctx );
#endif
/* prevent misuse of the vrfy callback - VERIFY_FAILED would be ignored by
* the SSL module for authmode optional, but non-zero return from the
* callback means a fatal error so it shouldn't be ignored */
......@@ -2419,7 +2639,7 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt )
{
name_prv = name_cur;
name_cur = name_cur->next;
mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) );
mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) );
mbedtls_free( name_prv );
}
......@@ -2428,7 +2648,7 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt )
{
name_prv = name_cur;
name_cur = name_cur->next;
mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) );
mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) );
mbedtls_free( name_prv );
}
......@@ -2437,7 +2657,8 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt )
{
seq_prv = seq_cur;
seq_cur = seq_cur->next;
mbedtls_zeroize( seq_prv, sizeof( mbedtls_x509_sequence ) );
mbedtls_platform_zeroize( seq_prv,
sizeof( mbedtls_x509_sequence ) );
mbedtls_free( seq_prv );
}
......@@ -2446,13 +2667,14 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt )
{
seq_prv = seq_cur;
seq_cur = seq_cur->next;
mbedtls_zeroize( seq_prv, sizeof( mbedtls_x509_sequence ) );
mbedtls_platform_zeroize( seq_prv,
sizeof( mbedtls_x509_sequence ) );
mbedtls_free( seq_prv );
}
if( cert_cur->raw.p != NULL )
{
mbedtls_zeroize( cert_cur->raw.p, cert_cur->raw.len );
mbedtls_platform_zeroize( cert_cur->raw.p, cert_cur->raw.len );
mbedtls_free( cert_cur->raw.p );
}
......@@ -2466,11 +2688,43 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt )
cert_prv = cert_cur;
cert_cur = cert_cur->next;
mbedtls_zeroize( cert_prv, sizeof( mbedtls_x509_crt ) );
mbedtls_platform_zeroize( cert_prv, sizeof( mbedtls_x509_crt ) );
if( cert_prv != crt )
mbedtls_free( cert_prv );
}
while( cert_cur != NULL );
}
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
/*
* Initialize a restart context
*/
void mbedtls_x509_crt_restart_init( mbedtls_x509_crt_restart_ctx *ctx )
{
mbedtls_pk_restart_init( &ctx->pk );
ctx->parent = NULL;
ctx->fallback_parent = NULL;
ctx->fallback_signature_is_good = 0;
ctx->parent_is_trusted = -1;
ctx->in_progress = x509_crt_rs_none;
ctx->self_cnt = 0;
x509_crt_verify_chain_reset( &ctx->ver_chain );
}
/*
* Free the components of a restart context
*/
void mbedtls_x509_crt_restart_free( mbedtls_x509_crt_restart_ctx *ctx )
{
if( ctx == NULL )
return;
mbedtls_pk_restart_free( &ctx->pk );
mbedtls_x509_crt_restart_init( ctx );
}
#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
#endif /* MBEDTLS_X509_CRT_PARSE_C */
......@@ -39,6 +39,7 @@
#include "mbedtls/x509_csr.h"
#include "mbedtls/oid.h"
#include "mbedtls/platform_util.h"
#include <string.h>
......@@ -60,11 +61,6 @@
#include <stdio.h>
#endif
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
/*
* Version ::= INTEGER { v1(0) }
*/
......@@ -283,15 +279,24 @@ int mbedtls_x509_csr_parse( mbedtls_x509_csr *csr, const unsigned char *buf, siz
{
mbedtls_pem_init( &pem );
ret = mbedtls_pem_read_buffer( &pem,
"-----BEGIN CERTIFICATE REQUEST-----",
"-----END CERTIFICATE REQUEST-----",
buf, NULL, 0, &use_len );
"-----BEGIN CERTIFICATE REQUEST-----",
"-----END CERTIFICATE REQUEST-----",
buf, NULL, 0, &use_len );
if( ret == MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
{
ret = mbedtls_pem_read_buffer( &pem,
"-----BEGIN NEW CERTIFICATE REQUEST-----",
"-----END NEW CERTIFICATE REQUEST-----",
buf, NULL, 0, &use_len );
}
if( ret == 0 )
{
/*
* Was PEM encoded, parse the result
*/
ret = mbedtls_x509_csr_parse_der( csr, pem.buf, pem.buflen );
}
mbedtls_pem_free( &pem );
if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
......@@ -316,7 +321,7 @@ int mbedtls_x509_csr_parse_file( mbedtls_x509_csr *csr, const char *path )
ret = mbedtls_x509_csr_parse( csr, buf, n );
mbedtls_zeroize( buf, n );
mbedtls_platform_zeroize( buf, n );
mbedtls_free( buf );
return( ret );
......@@ -398,17 +403,17 @@ void mbedtls_x509_csr_free( mbedtls_x509_csr *csr )
{
name_prv = name_cur;
name_cur = name_cur->next;
mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) );
mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) );
mbedtls_free( name_prv );
}
if( csr->raw.p != NULL )
{
mbedtls_zeroize( csr->raw.p, csr->raw.len );
mbedtls_platform_zeroize( csr->raw.p, csr->raw.len );
mbedtls_free( csr->raw.p );
}
mbedtls_zeroize( csr, sizeof( mbedtls_x509_csr ) );
mbedtls_platform_zeroize( csr, sizeof( mbedtls_x509_csr ) );
}
#endif /* MBEDTLS_X509_CSR_PARSE_C */
......@@ -37,6 +37,7 @@
#include "mbedtls/oid.h"
#include "mbedtls/asn1write.h"
#include "mbedtls/sha1.h"
#include "mbedtls/platform_util.h"
#include <string.h>
......@@ -44,10 +45,15 @@
#include "mbedtls/pem.h"
#endif /* MBEDTLS_PEM_WRITE_C */
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
/*
* For the currently used signature algorithms the buffer to store any signature
* must be at least of size MAX(MBEDTLS_ECDSA_MAX_LEN, MBEDTLS_MPI_MAX_SIZE)
*/
#if MBEDTLS_ECDSA_MAX_LEN > MBEDTLS_MPI_MAX_SIZE
#define SIGNATURE_MAX_SIZE MBEDTLS_ECDSA_MAX_LEN
#else
#define SIGNATURE_MAX_SIZE MBEDTLS_MPI_MAX_SIZE
#endif
void mbedtls_x509write_crt_init( mbedtls_x509write_cert *ctx )
{
......@@ -65,7 +71,7 @@ void mbedtls_x509write_crt_free( mbedtls_x509write_cert *ctx )
mbedtls_asn1_free_named_data_list( &ctx->issuer );
mbedtls_asn1_free_named_data_list( &ctx->extensions );
mbedtls_zeroize( ctx, sizeof( mbedtls_x509write_cert ) );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_x509write_cert ) );
}
void mbedtls_x509write_crt_set_version( mbedtls_x509write_cert *ctx, int version )
......@@ -222,26 +228,51 @@ int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert *
}
#endif /* MBEDTLS_SHA1_C */
static size_t crt_get_unused_bits_for_named_bitstring( unsigned char bitstring,
size_t bit_offset )
{
size_t unused_bits;
/* Count the unused bits removing trailing 0s */
for( unused_bits = bit_offset; unused_bits < 8; unused_bits++ )
if( ( ( bitstring >> unused_bits ) & 0x1 ) != 0 )
break;
return( unused_bits );
}
int mbedtls_x509write_crt_set_key_usage( mbedtls_x509write_cert *ctx,
unsigned int key_usage )
{
unsigned char buf[4], ku;
unsigned char *c;
int ret;
/* We currently only support 7 bits, from 0x80 to 0x02 */
if( ( key_usage & ~0xfe ) != 0 )
size_t unused_bits;
const unsigned int allowed_bits = MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
MBEDTLS_X509_KU_NON_REPUDIATION |
MBEDTLS_X509_KU_KEY_ENCIPHERMENT |
MBEDTLS_X509_KU_DATA_ENCIPHERMENT |
MBEDTLS_X509_KU_KEY_AGREEMENT |
MBEDTLS_X509_KU_KEY_CERT_SIGN |
MBEDTLS_X509_KU_CRL_SIGN;
/* Check that nothing other than the allowed flags is set */
if( ( key_usage & ~allowed_bits ) != 0 )
return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE );
c = buf + 4;
ku = (unsigned char) key_usage;
ku = (unsigned char)key_usage;
unused_bits = crt_get_unused_bits_for_named_bitstring( ku, 1 );
ret = mbedtls_asn1_write_bitstring( &c, buf, &ku, 8 - unused_bits );
if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ku, 7 ) ) != 4 )
if( ret < 0 )
return( ret );
else if( ret < 3 || ret > 4 )
return( MBEDTLS_ERR_X509_INVALID_FORMAT );
ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_KEY_USAGE,
MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ),
1, buf, 4 );
1, c, (size_t)ret );
if( ret != 0 )
return( ret );
......@@ -253,16 +284,22 @@ int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx,
{
unsigned char buf[4];
unsigned char *c;
size_t unused_bits;
int ret;
c = buf + 4;
if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 )
unused_bits = crt_get_unused_bits_for_named_bitstring( ns_cert_type, 0 );
ret = mbedtls_asn1_write_bitstring( &c,
buf,
&ns_cert_type,
8 - unused_bits );
if( ret < 3 || ret > 4 )
return( ret );
ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE,
MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ),
0, buf, 4 );
0, c, (size_t)ret );
if( ret != 0 )
return( ret );
......@@ -307,7 +344,7 @@ int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf,
size_t sig_oid_len = 0;
unsigned char *c, *c2;
unsigned char hash[64];
unsigned char sig[MBEDTLS_MPI_MAX_SIZE];
unsigned char sig[SIGNATURE_MAX_SIZE];
unsigned char tmp_buf[2048];
size_t sub_len = 0, pub_len = 0, sig_and_oid_len = 0, sig_len;
size_t len = 0;
......
......@@ -35,6 +35,7 @@
#include "mbedtls/x509_csr.h"
#include "mbedtls/oid.h"
#include "mbedtls/asn1write.h"
#include "mbedtls/platform_util.h"
#include <string.h>
#include <stdlib.h>
......@@ -43,10 +44,15 @@
#include "mbedtls/pem.h"
#endif
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
/*
* For the currently used signature algorithms the buffer to store any signature
* must be at least of size MAX(MBEDTLS_ECDSA_MAX_LEN, MBEDTLS_MPI_MAX_SIZE)
*/
#if MBEDTLS_ECDSA_MAX_LEN > MBEDTLS_MPI_MAX_SIZE
#define SIGNATURE_MAX_SIZE MBEDTLS_ECDSA_MAX_LEN
#else
#define SIGNATURE_MAX_SIZE MBEDTLS_MPI_MAX_SIZE
#endif
void mbedtls_x509write_csr_init( mbedtls_x509write_csr *ctx )
{
......@@ -58,7 +64,7 @@ void mbedtls_x509write_csr_free( mbedtls_x509write_csr *ctx )
mbedtls_asn1_free_named_data_list( &ctx->subject );
mbedtls_asn1_free_named_data_list( &ctx->extensions );
mbedtls_zeroize( ctx, sizeof( mbedtls_x509write_csr ) );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_x509write_csr ) );
}
void mbedtls_x509write_csr_set_md_alg( mbedtls_x509write_csr *ctx, mbedtls_md_type_t md_alg )
......@@ -85,20 +91,39 @@ int mbedtls_x509write_csr_set_extension( mbedtls_x509write_csr *ctx,
0, val, val_len );
}
static size_t csr_get_unused_bits_for_named_bitstring( unsigned char bitstring,
size_t bit_offset )
{
size_t unused_bits;
/* Count the unused bits removing trailing 0s */
for( unused_bits = bit_offset; unused_bits < 8; unused_bits++ )
if( ( ( bitstring >> unused_bits ) & 0x1 ) != 0 )
break;
return( unused_bits );
}
int mbedtls_x509write_csr_set_key_usage( mbedtls_x509write_csr *ctx, unsigned char key_usage )
{
unsigned char buf[4];
unsigned char *c;
size_t unused_bits;
int ret;
c = buf + 4;
if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &key_usage, 7 ) ) != 4 )
unused_bits = csr_get_unused_bits_for_named_bitstring( key_usage, 0 );
ret = mbedtls_asn1_write_bitstring( &c, buf, &key_usage, 8 - unused_bits );
if( ret < 0 )
return( ret );
else if( ret < 3 || ret > 4 )
return( MBEDTLS_ERR_X509_INVALID_FORMAT );
ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_KEY_USAGE,
MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ),
buf, 4 );
c, (size_t)ret );
if( ret != 0 )
return( ret );
......@@ -110,16 +135,25 @@ int mbedtls_x509write_csr_set_ns_cert_type( mbedtls_x509write_csr *ctx,
{
unsigned char buf[4];
unsigned char *c;
size_t unused_bits;
int ret;
c = buf + 4;
if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 )
unused_bits = csr_get_unused_bits_for_named_bitstring( ns_cert_type, 0 );
ret = mbedtls_asn1_write_bitstring( &c,
buf,
&ns_cert_type,
8 - unused_bits );
if( ret < 0 )
return( ret );
else if( ret < 3 || ret > 4 )
return( ret );
ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE,
MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ),
buf, 4 );
c, (size_t)ret );
if( ret != 0 )
return( ret );
......@@ -135,7 +169,7 @@ int mbedtls_x509write_csr_der( mbedtls_x509write_csr *ctx, unsigned char *buf, s
size_t sig_oid_len = 0;
unsigned char *c, *c2;
unsigned char hash[64];
unsigned char sig[MBEDTLS_MPI_MAX_SIZE];
unsigned char sig[SIGNATURE_MAX_SIZE];
unsigned char tmp_buf[2048];
size_t pub_len = 0, sig_and_oid_len = 0, sig_len;
size_t len = 0;
......
......@@ -28,6 +28,7 @@
#if defined(MBEDTLS_XTEA_C)
#include "mbedtls/xtea.h"
#include "mbedtls/platform_util.h"
#include <string.h>
......@@ -42,11 +43,6 @@
#if !defined(MBEDTLS_XTEA_ALT)
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
/*
* 32-bit integer manipulation macros (big endian)
*/
......@@ -80,7 +76,7 @@ void mbedtls_xtea_free( mbedtls_xtea_context *ctx )
if( ctx == NULL )
return;
mbedtls_zeroize( ctx, sizeof( mbedtls_xtea_context ) );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_xtea_context ) );
}
/*
......
#include <stdlib.h>
void *mbedtls_calloc(size_t n, size_t sz) { return calloc(n, sz); }
void mbedtls_free(void *p) { free(p); }
......@@ -47,19 +47,6 @@
*/
static int net_prepare( void )
{
#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \
!defined(EFI32)
WSADATA wsaData;
if( wsa_init_done == 0 )
{
if( WSAStartup( MAKEWORD(2,0), &wsaData ) != 0 )
return( MBEDTLS_ERR_NET_SOCKET_FAILED );
wsa_init_done = 1;
}
#else
#endif
return( 0 );
}
......@@ -169,18 +156,6 @@ int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char
}
#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \
!defined(EFI32)
/*
* Check if the requested operation would be blocking on a non-blocking socket
* and thus 'failed' with a negative return value.
*/
static int net_would_block( const mbedtls_net_context *ctx )
{
((void) ctx);
return( WSAGetLastError() == WSAEWOULDBLOCK );
}
#else
/*
* Check if the requested operation would be blocking on a non-blocking socket
* and thus 'failed' with a negative return value.
......@@ -189,25 +164,8 @@ static int net_would_block( const mbedtls_net_context *ctx )
*/
static int net_would_block( const mbedtls_net_context *ctx )
{
/*
* Never return 'WOULD BLOCK' on a non-blocking socket
*/
// if( ( fcntl( ctx->fd, F_GETFL, 0) & O_NONBLOCK ) != O_NONBLOCK )
// return( 0 );
// switch( errno )
// {
//#if defined EAGAIN
// case EAGAIN:
//#endif
//#if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN
// case EWOULDBLOCK:
//#endif
// return( 1 );
// }
return( 0 );
}
#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */
/*
* Accept a connection from a remote client
......@@ -256,44 +214,12 @@ int mbedtls_net_accept( mbedtls_net_context *bind_ctx,
*/
int mbedtls_net_set_block( mbedtls_net_context *ctx )
{
#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \
!defined(EFI32)
u_long n = 0;
return( ioctlsocket( ctx->fd, FIONBIO, &n ) );
#else
return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL, 0 ) & ~O_NONBLOCK ) );
#endif
}
int mbedtls_net_set_nonblock( mbedtls_net_context *ctx )
{
#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \
!defined(EFI32)
u_long n = 1;
return( ioctlsocket( ctx->fd, FIONBIO, &n ) );
#else
return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL, 0 ) | O_NONBLOCK ) );
#endif
}
/*
* Portable usleep helper
*/
void mbedtls_net_usleep( unsigned long usec )
{
//#if defined(_WIN32)
// Sleep( ( usec + 999 ) / 1000 );
//#else
// struct timeval tv;
// tv.tv_sec = usec / 1000000;
//#if defined(__unix__) || defined(__unix) || \
// ( defined(__APPLE__) && defined(__MACH__) )
// tv.tv_usec = (suseconds_t) usec % 1000000;
//#else
// tv.tv_usec = usec % 1000000;
//#endif
// select( 0, NULL, NULL, NULL, &tv );
//#endif
}
/*
......@@ -315,18 +241,6 @@ int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len )
if( net_would_block( ctx ) != 0 )
return( MBEDTLS_ERR_SSL_WANT_READ );
//#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \
// !defined(EFI32)
// if( WSAGetLastError() == WSAECONNRESET )
// return( MBEDTLS_ERR_NET_CONN_RESET );
//#else
// if( errno == EPIPE || errno == ECONNRESET )
// return( MBEDTLS_ERR_NET_CONN_RESET );
//
// if( errno == EINTR )
// return( MBEDTLS_ERR_SSL_WANT_READ );
//#endif
return( MBEDTLS_ERR_NET_RECV_FAILED );
}
// os_printf("mbedtls_net_recv get %d\n", ret);
......@@ -350,32 +264,6 @@ int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, size_t len,
if( fd < 0 )
return( MBEDTLS_ERR_NET_INVALID_CONTEXT );
// FD_ZERO( &read_fds );
// FD_SET( fd, &read_fds );
//
// tv.tv_sec = timeout / 1000;
// tv.tv_usec = ( timeout % 1000 ) * 1000;
//
// ret = select( fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv );
//
// /* Zero fds ready means we timed out */
// if( ret == 0 )
// return( MBEDTLS_ERR_SSL_TIMEOUT );
//
// if( ret < 0 )
// {
//#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \
// !defined(EFI32)
// if( WSAGetLastError() == WSAEINTR )
// return( MBEDTLS_ERR_SSL_WANT_READ );
//#else
// if( errno == EINTR )
// return( MBEDTLS_ERR_SSL_WANT_READ );
//#endif
//
// return( MBEDTLS_ERR_NET_RECV_FAILED );
// }
/* This call will not block */
return( mbedtls_net_recv( ctx, buf, len ) );
}
......@@ -398,20 +286,6 @@ int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len )
{
if( net_would_block( ctx ) != 0 )
return( MBEDTLS_ERR_SSL_WANT_WRITE );
//#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \
// !defined(EFI32)
// if( WSAGetLastError() == WSAECONNRESET )
// return( MBEDTLS_ERR_NET_CONN_RESET );
//#else
// if( errno == EPIPE || errno == ECONNRESET )
// return( MBEDTLS_ERR_NET_CONN_RESET );
//
// if( errno == EINTR )
// return( MBEDTLS_ERR_SSL_WANT_WRITE );
//#endif
//
// return( MBEDTLS_ERR_NET_SEND_FAILED );
}
// os_printf("mbedtls_net_send write %d\n", ret);
if (ret == 0)
......
......@@ -10,7 +10,6 @@ The following encryption/decryption algorithms/modes are supported:
- `"AES-CBC"` for 128-bit AES in CBC mode
The following hash algorithms are supported:
- MD2 (not available by default, has to be explicitly enabled in `app/include/user_config.h`)
- MD5
- SHA1
- SHA256, SHA384, SHA512 (unless disabled in `app/include/user_config.h`)
......
......@@ -10,7 +10,7 @@
NodeMCU includes the open-source version of [mbed TLS library](https://tls.mbed.org/).
With the NodeMCU default configuration it supports **TLS** 1.1 and 1.2 with
With the NodeMCU default configuration it supports **TLS** 1.2 with
most common features supported. Specifically, it provides:
- ciphers: AES, Camellia
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment