diff --git a/ChangeLog b/ChangeLog index ddba5c0eb..d8d67982a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,14 +3,37 @@ mbed TLS ChangeLog (Sorted per branch, date) = mbed TLS 1.3.14 released 2015-10-xx Security - * Added fix for CVE-2015-xxxxx to prevent heap corruption due to buffer - overflow of the hostname or session ticket. (Found by Guido Vranken) + * Added fix for CVE-2015-5291 to prevent heap corruption due to buffer + overflow of the hostname or session ticket. Found by Guido Vranken, + Intelworks. + * Fix stack buffer overflow in pkcs12 decryption (used by + mbedtls_pk_parse_key(file)() when the password is > 129 bytes. Found by + Guido Vranken, Intelworks. Not triggerable remotely. + * Fix potential buffer overflow in mbedtls_mpi_read_string(). + Found by Guido Vranken, Intelworks. Not exploitable remotely in the context + of TLS, but might be in other uses. On 32 bit machines, requires reading a + string of close to or larger than 1GB to exploit; on 64 bit machines, would + require reading a string of close to or larger than 2^62 bytes. + * Fix potential random memory allocation in mbedtls_pem_read_buffer() + on crafted PEM input data. Found and fix provided by Guido Vranken, + Intelworks. Not triggerable remotely in TLS. Triggerable remotely if you + accept PEM data from an untrusted source. + * Fix potential double-free if ssl_set_psk() is called repeatedly on + the same ssl_context object and some memory allocations fail. Found by + Guido Vranken, Intelworks. Can not be forced remotely. + * Fix possible heap buffer overflow in base64_encode() when the input + buffer is 512MB or larger on 32-bit platforms. Found by Guido Vranken, + Intelworks. Found by Guido Vranken. Not trigerrable remotely in TLS. + * Fix potential heap buffer overflow in servers that perform client + authentication against a crafted CA cert. Cannot be triggered remotely + unless you allow third parties to pick trust CAs for client auth. Found by + Guido Vranken, Intelworks. Changes * Added checking of hostname length in ssl_set_hostname() to ensure domain names are compliant with RFC 1035. -= mbed TLS 1.3.13 reladsed 2015-09-17 += mbed TLS 1.3.13 released 2015-09-17 Security * Fix possible client-side NULL pointer dereference (read) when the client diff --git a/include/polarssl/base64.h b/include/polarssl/base64.h index 0f1e8549b..bdd0c4106 100644 --- a/include/polarssl/base64.h +++ b/include/polarssl/base64.h @@ -44,6 +44,8 @@ extern "C" { * \return 0 if successful, or POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL. * *dlen is always updated to reflect the amount * of data that has (or would have) been written. + * If that length cannot be represented, then no data is + * written to the buffer and *dlen is set to SIZE_T_MAX. * * \note Call this function with *dlen = 0 to obtain the * required buffer size in *dlen diff --git a/library/base64.c b/library/base64.c index ac922a474..7de87e51c 100644 --- a/library/base64.c +++ b/library/base64.c @@ -75,6 +75,8 @@ static const unsigned char base64_dec_map[128] = 49, 50, 51, 127, 127, 127, 127, 127 }; +#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */ + /* * Encode a buffer into base64 format */ @@ -91,15 +93,16 @@ int base64_encode( unsigned char *dst, size_t *dlen, return( 0 ); } - n = ( slen << 3 ) / 6; + n = slen / 3 + ( slen % 3 != 0 ); - switch( ( slen << 3 ) - ( n * 6 ) ) + if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 ) { - case 2: n += 3; break; - case 4: n += 2; break; - default: break; + *dlen = BASE64_SIZE_T_MAX; + return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL ); } + n *= 4; + if( *dlen < n + 1 ) { *dlen = n + 1; @@ -190,7 +193,10 @@ int base64_decode( unsigned char *dst, size_t *dlen, } if( n == 0 ) + { + *dlen = 0; return( 0 ); + } n = ( ( n * 6 ) + 7 ) >> 3; n -= j; diff --git a/library/bignum.c b/library/bignum.c index f479bc9ed..c97f16d36 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -59,11 +59,14 @@ static void polarssl_zeroize( void *v, size_t n ) { #define biL (ciL << 3) /* bits in limb */ #define biH (ciL << 2) /* half limb size */ +#define MPI_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */ + /* * Convert between bits/chars and number of limbs + * Divide first in order to avoid potential overflows */ -#define BITS_TO_LIMBS(i) (((i) + biL - 1) / biL) -#define CHARS_TO_LIMBS(i) (((i) + ciL - 1) / ciL) +#define BITS_TO_LIMBS(i) ( (i) / biL + ( (i) % biL != 0 ) ) +#define CHARS_TO_LIMBS(i) ( (i) / ciL + ( (i) % ciL != 0 ) ) /* * Initialize one MPI @@ -414,6 +417,9 @@ int mpi_read_string( mpi *X, int radix, const char *s ) if( radix == 16 ) { + if( slen > MPI_SIZE_T_MAX >> 2 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + n = BITS_TO_LIMBS( slen << 2 ); MPI_CHK( mpi_grow( X, n ) ); diff --git a/library/pem.c b/library/pem.c index 5060484cc..054fcffb8 100644 --- a/library/pem.c +++ b/library/pem.c @@ -317,6 +317,9 @@ int pem_read_buffer( pem_context *ctx, const char *header, const char *footer, ( POLARSSL_AES_C || POLARSSL_DES_C ) */ } + if( s1 == s2 ) + return( POLARSSL_ERR_PEM_INVALID_DATA ); + len = 0; ret = base64_decode( NULL, &len, s1, s2 - s1 ); diff --git a/library/pkcs12.c b/library/pkcs12.c index f84fd52cd..dff01a778 100644 --- a/library/pkcs12.c +++ b/library/pkcs12.c @@ -87,6 +87,8 @@ static int pkcs12_parse_pbe_params( asn1_buf *params, return( 0 ); } +#define PKCS12_MAX_PWDLEN 128 + static int pkcs12_pbe_derive_key_iv( asn1_buf *pbe_params, md_type_t md_type, const unsigned char *pwd, size_t pwdlen, unsigned char *key, size_t keylen, @@ -95,7 +97,10 @@ static int pkcs12_pbe_derive_key_iv( asn1_buf *pbe_params, md_type_t md_type, int ret, iterations; asn1_buf salt; size_t i; - unsigned char unipwd[258]; + unsigned char unipwd[PKCS12_MAX_PWDLEN * 2 + 2]; + + if( pwdlen > PKCS12_MAX_PWDLEN ) + return( POLARSSL_ERR_PKCS12_BAD_INPUT_DATA ); memset( &salt, 0, sizeof(asn1_buf) ); memset( &unipwd, 0, sizeof(unipwd) ); @@ -126,6 +131,8 @@ static int pkcs12_pbe_derive_key_iv( asn1_buf *pbe_params, md_type_t md_type, return( 0 ); } +#undef PKCS12_MAX_PWDLEN + int pkcs12_pbe_sha1_rc4_128( asn1_buf *pbe_params, int mode, const unsigned char *pwd, size_t pwdlen, const unsigned char *data, size_t len, diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 379a3abea..82fa2d46e 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2300,6 +2300,7 @@ static int ssl_write_certificate_request( ssl_context *ssl ) size_t ct_len, sa_len; /* including length bytes */ unsigned char *buf, *p; const x509_crt *crt; + const unsigned char * const end = ssl->out_msg + SSL_MAX_CONTENT_LEN; SSL_DEBUG_MSG( 2, ( "=> write certificate request" ) ); @@ -2406,10 +2407,14 @@ static int ssl_write_certificate_request( ssl_context *ssl ) total_dn_size = 0; while( crt != NULL && crt->version != 0 ) { - if( p - buf > 4096 ) - break; - dn_size = crt->subject_raw.len; + + if( end < p || (size_t)( end - p ) < 2 + dn_size ) + { + SSL_DEBUG_MSG( 1, ( "skipping CAs: buffer too short" ) ); + break; + } + *p++ = (unsigned char)( dn_size >> 8 ); *p++ = (unsigned char)( dn_size ); memcpy( p, crt->subject_raw.p, dn_size ); diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 0a7fee19f..7fc9d9908 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -4064,7 +4064,9 @@ int ssl_set_psk( ssl_context *ssl, const unsigned char *psk, size_t psk_len, ( ssl->psk_identity = polarssl_malloc( psk_identity_len ) ) == NULL ) { polarssl_free( ssl->psk ); + polarssl_free( ssl->psk_identity ); ssl->psk = NULL; + ssl->psk_identity = NULL; return( POLARSSL_ERR_SSL_MALLOC_FAILED ); }