Merge remote-tracking branch 'hanno/mpi_read_file_underflow_backport-1.3' into mbedtls-1.3
* hanno/mpi_read_file_underflow_backport-1.3:
Fix potential stack underflow in mpi_read_file.
diff --git a/ChangeLog b/ChangeLog
index cedfc18..8449329 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,11 +1,38 @@
mbed TLS ChangeLog (Sorted per branch, date)
-= mbed TLS x.x.x branch released xxxx-xx-xx
+= mbed TLS 1.3.x branch released xxxx-xx-xx
+
+Security
+ * Add exponent blinding to RSA private operations as a countermeasure
+ against side-channel attacks like the cache attack described in
+ https://arxiv.org/abs/1702.08719v2.
+ Found and fix proposed by Michael Schwarz, Samuel Weiser, Daniel Gruss,
+ Clémentine Maurice and Stefan Mangard.
Bugfix
+ * Fix insufficient support for signature-hash-algorithm extension,
+ resulting in compatibility problems with Chrome. Found by hfloyrd. #823
+ * Wipe stack buffers in RSA private key operations
+ (rsa_rsaes_pkcs1_v15_decrypt(), rsa_rsaes_oaep_decrypt).
+ Found by Laurent Simon.
+ * Accept empty trusted CA chain in authentication mode
+ SSL_VERIFY_OPTIONAL. Fixes #864. Found by jethrogb.
+ * Fix implementation of ssl_parse_certificate
+ to not annihilate fatal errors in authentication mode
+ SSL_VERIFY_OPTIONAL and to reflect bad EC curves
+ within verification result.
+ * Fix modular inversion function on invalid modulus 1.
+ Found by blaufish. Fixes #641.
+ * Fix incorrect sign computation in modular exponentiation
+ when dealing with negative MPI. Found by Guido Vranken.
* Fix potential stack underflow in mpi_read_file.
Found by Guido Vranken.
+Changes
+ * Clarify ECDSA documentation and improve the sample code to avoid
+ misunderstandings and potentially dangerous use of the API. Pointed out
+ by Jean-Philippe Aumasson.
+
= mbed TLS 1.3.19 branch released 2017-03-08
Security
diff --git a/include/polarssl/bignum.h b/include/polarssl/bignum.h
index 3b55151..c11db96 100644
--- a/include/polarssl/bignum.h
+++ b/include/polarssl/bignum.h
@@ -699,6 +699,8 @@
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ * POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is <= 1,
+ * POLARSSL_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N.
*/
int mpi_gcd( mpi *G, const mpi *A, const mpi *B );
diff --git a/include/polarssl/ecdsa.h b/include/polarssl/ecdsa.h
index 5eb83d9..47b644e 100644
--- a/include/polarssl/ecdsa.h
+++ b/include/polarssl/ecdsa.h
@@ -26,6 +26,23 @@
#include "ecp.h"
#include "md.h"
+/*
+ * RFC 4492 page 20:
+ *
+ * Ecdsa-Sig-Value ::= SEQUENCE {
+ * r INTEGER,
+ * s INTEGER
+ * }
+ *
+ * Size is at most
+ * 1 (tag) + 1 (len) + 1 (initial 0) + ECP_MAX_BYTES for each of r and s,
+ * twice that + 1 (tag) + 2 (len) for the sequence
+ * (assuming ECP_MAX_BYTES is less than 126 for r and s,
+ * and less than 124 (total len <= 255) for the sequence)
+ *
+ */
+/** Maximum size of an ECDSA signature in bytes */
+#define POLARSSL_ECDSA_MAX_LEN ( 3 + 2 * ( 3 + POLARSSL_ECP_MAX_BYTES ) )
/**
* \brief ECDSA context structure
@@ -58,6 +75,10 @@
* \param f_rng RNG function
* \param p_rng RNG parameter
*
+ * \note If the bitlength of the message hash is larger than the
+ * bitlength of the group order, then the hash is truncated as
+ * prescribed by SEC1 4.1.3 step 5.
+ *
* \return 0 if successful,
* or a POLARSSL_ERR_ECP_XXX or POLARSSL_MPI_XXX error code
*/
@@ -78,6 +99,10 @@
* \param blen Length of buf
* \param md_alg MD algorithm used to hash the message
*
+ * \note If the bitlength of the message hash is larger than the
+ * bitlength of the group order, then the hash is truncated as
+ * prescribed by SEC1 4.1.3 step 5.
+ *
* \return 0 if successful,
* or a POLARSSL_ERR_ECP_XXX or POLARSSL_MPI_XXX error code
*/
@@ -96,6 +121,10 @@
* \param r First integer of the signature
* \param s Second integer of the signature
*
+ * \note If the bitlength of the message hash is larger than the
+ * bitlength of the group order, then the hash is truncated as
+ * prescribed by SEC1 4.1.4 step 3.
+ *
* \return 0 if successful,
* POLARSSL_ERR_ECP_BAD_INPUT_DATA if signature is invalid
* or a POLARSSL_ERR_ECP_XXX or POLARSSL_MPI_XXX error code
@@ -121,6 +150,10 @@
* size of the curve used, plus 7 (eg. 71 bytes if a 256-bit
* curve is used).
*
+ * \note If the bitlength of the message hash is larger than the
+ * bitlength of the group order, then the hash is truncated as
+ * prescribed by SEC1 4.1.3 step 5.
+ *
* \return 0 if successful,
* or a POLARSSL_ERR_ECP, POLARSSL_ERR_MPI or
* POLARSSL_ERR_ASN1 error code
@@ -168,6 +201,10 @@
* \param sig Signature to read and verify
* \param slen Size of sig
*
+ * \note If the bitlength of the message hash is larger than the
+ * bitlength of the group order, then the hash is truncated as
+ * prescribed by SEC1 4.1.4 step 3.
+ *
* \return 0 if successful,
* POLARSSL_ERR_ECP_BAD_INPUT_DATA if signature is invalid,
* POLARSSL_ERR_ECP_SIG_LEN_MISTMATCH if the signature is
diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h
index c7cd541..74b1317 100644
--- a/include/polarssl/ssl.h
+++ b/include/polarssl/ssl.h
@@ -539,6 +539,7 @@
typedef struct _ssl_context ssl_context;
typedef struct _ssl_transform ssl_transform;
typedef struct _ssl_handshake_params ssl_handshake_params;
+typedef struct _ssl_sig_hash_set_t ssl_sig_hash_set_t;
#if defined(POLARSSL_SSL_SESSION_TICKETS)
typedef struct _ssl_ticket_keys ssl_ticket_keys;
#endif
@@ -625,6 +626,24 @@
#endif
};
+#if defined(POLARSSL_SSL_PROTO_TLS1_2) && \
+ defined(POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED)
+/*
+ * Abstraction for a grid of allowed signature-hash-algorithm pairs.
+ */
+struct _ssl_sig_hash_set_t
+{
+ /* At the moment, we only need to remember a single suitable
+ * hash algorithm per signature algorithm. As long as that's
+ * the case - and we don't need a general lookup function -
+ * we can implement the sig-hash-set as a map from signatures
+ * to hash algorithms. */
+ md_type_t rsa;
+ md_type_t ecdsa;
+};
+#endif /* POLARSSL_SSL_PROTO_TLS1_2) &&
+ POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED */
+
/*
* This structure contains the parameters only needed during handshake.
*/
@@ -633,7 +652,10 @@
/*
* Handshake specific crypto variables
*/
- int sig_alg; /*!< Hash algorithm for signature */
+#if defined(POLARSSL_SSL_PROTO_TLS1_2) && \
+ defined(POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED)
+ ssl_sig_hash_set_t hash_algs; /*!< Set of suitable sig-hash pairs */
+#endif
int cert_type; /*!< Requested cert type */
int verify_sig_alg; /*!< Signature algorithm for verify */
#if defined(POLARSSL_DHM_C)
@@ -1957,15 +1979,40 @@
#if defined(POLARSSL_PK_C)
unsigned char ssl_sig_from_pk( pk_context *pk );
+unsigned char ssl_sig_from_pk_alg( pk_type_t type );
pk_type_t ssl_pk_alg_from_sig( unsigned char sig );
#endif
md_type_t ssl_md_alg_from_hash( unsigned char hash );
+unsigned char ssl_hash_from_md_alg( md_type_t md );
#if defined(POLARSSL_SSL_SET_CURVES)
int ssl_curve_is_acceptable( const ssl_context *ssl, ecp_group_id grp_id );
#endif
+#if defined(POLARSSL_SSL_PROTO_TLS1_2) && \
+ defined(POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED)
+
+/* Find an entry in a signature-hash set matching a given hash algorithm. */
+md_type_t ssl_sig_hash_set_find( ssl_sig_hash_set_t *set,
+ pk_type_t sig_alg );
+/* Add a signature-hash-pair to a signature-hash set */
+void ssl_sig_hash_set_add( ssl_sig_hash_set_t *set,
+ pk_type_t sig_alg,
+ md_type_t md_alg );
+/* Allow exactly one hash algorithm for each signature. */
+void ssl_sig_hash_set_const_hash( ssl_sig_hash_set_t *set,
+ md_type_t md_alg );
+
+/* Setup an empty signature-hash set */
+static inline void ssl_sig_hash_set_init( ssl_sig_hash_set_t *set )
+{
+ ssl_sig_hash_set_const_hash( set, POLARSSL_MD_NONE );
+}
+
+#endif /* POLARSSL_SSL_PROTO_TLS1_2) &&
+ POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED */
+
#if defined(POLARSSL_X509_CRT_PARSE_C)
static inline pk_context *ssl_own_key( ssl_context *ssl )
{
@@ -1980,6 +2027,12 @@
}
/*
+ * Check if a hash proposed by the peer is in our list.
+ * Return 0 if we're willing to use it, -1 otherwise.
+ */
+int ssl_check_sig_hash( md_type_t md );
+
+/*
* Check usage of a certificate wrt extensions:
* keyUsage, extendedKeyUsage (later), and nSCertType (later).
*
diff --git a/include/polarssl/ssl_ciphersuites.h b/include/polarssl/ssl_ciphersuites.h
index f0519ca..2666b3b 100644
--- a/include/polarssl/ssl_ciphersuites.h
+++ b/include/polarssl/ssl_ciphersuites.h
@@ -290,6 +290,7 @@
#if defined(POLARSSL_PK_C)
pk_type_t ssl_get_ciphersuite_sig_pk_alg( const ssl_ciphersuite_t *info );
+pk_type_t ssl_get_ciphersuite_sig_alg( const ssl_ciphersuite_t *info );
#endif
int ssl_ciphersuite_uses_ec( const ssl_ciphersuite_t *info );
diff --git a/include/polarssl/x509.h b/include/polarssl/x509.h
index cd01539..adaacff 100644
--- a/include/polarssl/x509.h
+++ b/include/polarssl/x509.h
@@ -97,6 +97,8 @@
#define BADCERT_KEY_USAGE 0x0800 /**< Usage does not match the keyUsage extension. */
#define BADCERT_EXT_KEY_USAGE 0x1000 /**< Usage does not match the extendedKeyUsage extension. */
#define BADCERT_NS_CERT_TYPE 0x2000 /**< Usage does not match the nsCertType extension. */
+#define BADCERT_BAD_KEY 0x10000 /**< Bad key (e.g. unsupported elliptic curve in use) */
+
/* \} name */
/* \} addtogroup x509_module */
diff --git a/library/bignum.c b/library/bignum.c
index 5873b66..4829d91 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -1788,7 +1788,7 @@
*/
mpi_montred( X, N, mm, &T );
- if( neg )
+ if( neg && E->n != 0 && ( E->p[0] & 1 ) != 0 )
{
X->s = -1;
MPI_CHK( mpi_add_mpi( X, N, X ) );
@@ -1891,7 +1891,7 @@
int ret;
mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
- if( mpi_cmp_int( N, 0 ) <= 0 )
+ if( mpi_cmp_int( N, 1 ) <= 0 )
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
mpi_init( &TA ); mpi_init( &TU ); mpi_init( &U1 ); mpi_init( &U2 );
diff --git a/library/rsa.c b/library/rsa.c
index 79726c1..1cdf0d6 100644
--- a/library/rsa.c
+++ b/library/rsa.c
@@ -24,6 +24,11 @@
*
* http://theory.lcs.mit.edu/~rivest/rsapaper.pdf
* http://www.cacr.math.uwaterloo.ca/hac/about/chap8.pdf
+ * [3] Malware Guard Extension: Using SGX to Conceal Cache Attacks
+ * Michael Schwarz, Samuel Weiser, Daniel Gruss, Clémentine Maurice and
+ * Stefan Mangard
+ * https://arxiv.org/abs/1702.08719v2
+ *
*/
#if !defined(POLARSSL_CONFIG_FILE)
@@ -56,6 +61,11 @@
#define polarssl_free free
#endif
+/* Implementation that should never be optimized out by the compiler */
+static void polarssl_zeroize( void *v, size_t n ) {
+ volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0;
+}
+
/*
* Initialize an RSA context
*/
@@ -351,6 +361,27 @@
}
/*
+ * Exponent blinding supposed to prevent side-channel attacks using multiple
+ * traces of measurements to recover the RSA key. The more collisions are there,
+ * the more bits of the key can be recovered. See [3].
+ *
+ * Collecting n collisions with m bit long blinding value requires 2^(m-m/n)
+ * observations on avarage.
+ *
+ * For example with 28 byte blinding to achieve 2 collisions the adversary has
+ * to make 2^112 observations on avarage.
+ *
+ * (With the currently (as of 2017 April) known best algorithms breaking 2048
+ * bit RSA requires approximately as much time as trying out 2^112 random keys.
+ * Thus in this sense with 28 byte blinding the security is not reduced by
+ * side-channel attacks like the one in [3])
+ *
+ * This countermeasure does not help if the key recovery is possible with a
+ * single trace.
+ */
+#define RSA_EXPONENT_BLINDING 28
+
+/*
* Do an RSA private key operation
*/
int rsa_private( rsa_context *ctx,
@@ -362,8 +393,28 @@
int ret;
size_t olen;
mpi T, T1, T2;
+ mpi P1, Q1, R;
+#if defined(POLARSSL_RSA_NO_CRT)
+ mpi D_blind;
+ mpi *D = &ctx->D;
+#else
+ mpi DP_blind, DQ_blind;
+ mpi *DP = &ctx->DP;
+ mpi *DQ = &ctx->DQ;
+#endif
mpi_init( &T ); mpi_init( &T1 ); mpi_init( &T2 );
+ mpi_init( &P1 ); mpi_init( &Q1 ); mpi_init( &R );
+
+ if( f_rng != NULL )
+ {
+#if defined(POLARSSL_RSA_NO_CRT)
+ mpi_init( &D_blind );
+#else
+ mpi_init( &DP_blind );
+ mpi_init( &DQ_blind );
+#endif
+ }
#if defined(POLARSSL_THREADING_C)
if( ( ret = polarssl_mutex_lock( &ctx->mutex ) ) != 0 )
@@ -386,19 +437,60 @@
MPI_CHK( rsa_prepare_blinding( ctx, f_rng, p_rng ) );
MPI_CHK( mpi_mul_mpi( &T, &T, &ctx->Vi ) );
MPI_CHK( mpi_mod_mpi( &T, &T, &ctx->N ) );
+
+ /*
+ * Exponent blinding
+ */
+ MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) );
+ MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) );
+
+#if defined(POLARSSL_RSA_NO_CRT)
+ /*
+ * D_blind = ( P - 1 ) * ( Q - 1 ) * R + D
+ */
+ MPI_CHK( mpi_fill_random( &R, RSA_EXPONENT_BLINDING,
+ f_rng, p_rng ) );
+ MPI_CHK( mpi_mul_mpi( &D_blind, &P1, &Q1 ) );
+ MPI_CHK( mpi_mul_mpi( &D_blind, &D_blind, &R ) );
+ MPI_CHK( mpi_add_mpi( &D_blind, &D_blind, &ctx->D ) );
+
+ D = &D_blind;
+#else
+ /*
+ * DP_blind = ( P - 1 ) * R + DP
+ */
+ MPI_CHK( mpi_fill_random( &R, RSA_EXPONENT_BLINDING,
+ f_rng, p_rng ) );
+ MPI_CHK( mpi_mul_mpi( &DP_blind, &P1, &R ) );
+ MPI_CHK( mpi_add_mpi( &DP_blind, &DP_blind,
+ &ctx->DP ) );
+
+ DP = &DP_blind;
+
+ /*
+ * DQ_blind = ( Q - 1 ) * R + DQ
+ */
+ MPI_CHK( mpi_fill_random( &R, RSA_EXPONENT_BLINDING,
+ f_rng, p_rng ) );
+ MPI_CHK( mpi_mul_mpi( &DQ_blind, &Q1, &R ) );
+ MPI_CHK( mpi_add_mpi( &DQ_blind, &DQ_blind,
+ &ctx->DQ ) );
+
+ DQ = &DQ_blind;
+#endif /* POLARSSL_RSA_NO_CRT */
}
#if defined(POLARSSL_RSA_NO_CRT)
- MPI_CHK( mpi_exp_mod( &T, &T, &ctx->D, &ctx->N, &ctx->RN ) );
+ MPI_CHK( mpi_exp_mod( &T, &T, D, &ctx->N, &ctx->RN ) );
#else
/*
- * faster decryption using the CRT
+ * Faster decryption using the CRT
*
* T1 = input ^ dP mod P
* T2 = input ^ dQ mod Q
*/
- MPI_CHK( mpi_exp_mod( &T1, &T, &ctx->DP, &ctx->P, &ctx->RP ) );
- MPI_CHK( mpi_exp_mod( &T2, &T, &ctx->DQ, &ctx->Q, &ctx->RQ ) );
+ MPI_CHK( mpi_exp_mod( &T1, &T, DP, &ctx->P, &ctx->RP ) );
+ MPI_CHK( mpi_exp_mod( &T2, &T, DQ, &ctx->Q, &ctx->RQ ) );
/*
* T = (T1 - T2) * (Q^-1 mod P) mod P
@@ -434,6 +526,17 @@
#endif
mpi_free( &T ); mpi_free( &T1 ); mpi_free( &T2 );
+ mpi_free( &P1 ); mpi_free( &Q1 ); mpi_free( &R );
+
+ if( f_rng != NULL )
+ {
+#if defined(POLARSSL_RSA_NO_CRT)
+ mpi_free( &D_blind );
+#else
+ mpi_free( &DP_blind );
+ mpi_free( &DQ_blind );
+#endif
+ }
if( ret != 0 )
return( POLARSSL_ERR_RSA_PRIVATE_FAILED + ret );
@@ -487,6 +590,8 @@
dlen -= use_len;
}
+
+ polarssl_zeroize( mask, sizeof( mask ) );
}
#endif /* POLARSSL_PKCS1_V21 */
@@ -720,7 +825,7 @@
: rsa_private( ctx, f_rng, p_rng, input, buf );
if( ret != 0 )
- return( ret );
+ goto cleanup;
/*
* Unmask data and generate lHash
@@ -785,15 +890,26 @@
* the different error conditions.
*/
if( bad != 0 )
- return( POLARSSL_ERR_RSA_INVALID_PADDING );
+ {
+ ret = POLARSSL_ERR_RSA_INVALID_PADDING;
+ goto cleanup;
+ }
if( ilen - ( p - buf ) > output_max_len )
- return( POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE );
+ {
+ ret = POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE;
+ goto cleanup;
+ }
*olen = ilen - (p - buf);
memcpy( output, p, *olen );
+ ret = 0;
- return( 0 );
+cleanup:
+ polarssl_zeroize( buf, sizeof( buf ) );
+ polarssl_zeroize( lhash, sizeof( lhash ) );
+
+ return( ret );
}
#endif /* POLARSSL_PKCS1_V21 */
@@ -827,7 +943,7 @@
: rsa_private( ctx, f_rng, p_rng, input, buf );
if( ret != 0 )
- return( ret );
+ goto cleanup;
p = buf;
bad = 0;
@@ -872,15 +988,25 @@
bad |= ( pad_count < 8 );
if( bad )
- return( POLARSSL_ERR_RSA_INVALID_PADDING );
+ {
+ ret = POLARSSL_ERR_RSA_INVALID_PADDING;
+ goto cleanup;
+ }
if( ilen - ( p - buf ) > output_max_len )
- return( POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE );
+ {
+ ret = POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE;
+ goto cleanup;
+ }
*olen = ilen - (p - buf);
memcpy( output, p, *olen );
+ ret = 0;
- return( 0 );
+cleanup:
+ polarssl_zeroize( buf, sizeof( buf ) );
+
+ return( ret );
}
#endif /* POLARSSL_PKCS1_V15 */
@@ -985,6 +1111,7 @@
if( ( ret = md_init_ctx( &md_ctx, md_info ) ) != 0 )
{
md_free( &md_ctx );
+ /* No need to zeroize salt: we didn't use it. */
return( ret );
}
@@ -995,6 +1122,7 @@
md_update( &md_ctx, hash, hashlen );
md_update( &md_ctx, salt, slen );
md_finish( &md_ctx, p );
+ polarssl_zeroize( salt, sizeof( salt ) );
// Compensate for boundary condition when applying mask
//
diff --git a/library/ssl_ciphersuites.c b/library/ssl_ciphersuites.c
index 0fee1e6..8204731 100644
--- a/library/ssl_ciphersuites.c
+++ b/library/ssl_ciphersuites.c
@@ -1803,6 +1803,24 @@
return( POLARSSL_PK_NONE );
}
}
+
+pk_type_t ssl_get_ciphersuite_sig_alg( const ssl_ciphersuite_t *info )
+{
+ switch( info->key_exchange )
+ {
+ case POLARSSL_KEY_EXCHANGE_RSA:
+ case POLARSSL_KEY_EXCHANGE_DHE_RSA:
+ case POLARSSL_KEY_EXCHANGE_ECDHE_RSA:
+ return( POLARSSL_PK_RSA );
+
+ case POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA:
+ return( POLARSSL_PK_ECDSA );
+
+ default:
+ return( POLARSSL_PK_NONE );
+ }
+}
+
#endif /* POLARSSL_PK_C */
#if defined(POLARSSL_ECDH_C) || defined(POLARSSL_ECDSA_C)
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index 90d5ac7..8ad990b 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -467,6 +467,18 @@
#if defined(POLARSSL_SSL_PROTO_TLS1_2) && \
defined(POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED)
+/*
+ * Status of the implementation of signature-algorithms extension:
+ *
+ * Currently, we are only considering the signature-algorithm extension
+ * to pick a ciphersuite which allows us to send the ServerKeyExchange
+ * message with a signature-hash combination that the user allows.
+ *
+ * We do *not* check whether all certificates in our certificate
+ * chain are signed with an allowed signature-hash pair.
+ * This needs to be done at a later stage.
+ *
+ */
static int ssl_parse_signature_algorithms_ext( ssl_context *ssl,
const unsigned char *buf,
size_t len )
@@ -474,8 +486,9 @@
size_t sig_alg_list_size;
const unsigned char *p;
const unsigned char *end = buf + len;
- const int *md_cur;
+ md_type_t md_cur;
+ pk_type_t sig_cur;
sig_alg_list_size = ( ( buf[0] << 8 ) | ( buf[1] ) );
if( sig_alg_list_size + 2 != len ||
@@ -485,35 +498,48 @@
return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
}
- /*
- * For now, ignore the SignatureAlgorithm part and rely on offered
- * ciphersuites only for that part. To be fixed later.
+ /* Currently we only guarantee signing the ServerKeyExchange message according
+ * to the constraints specified in this extension (see above), so it suffices
+ * to remember only one suitable hash for each possible signature algorithm.
*
- * So, just look at the HashAlgorithm part.
+ * This will change when we also consider certificate signatures,
+ * in which case we will need to remember the whole signature-hash
+ * pair list from the extension.
*/
- for( md_cur = md_list(); *md_cur != POLARSSL_MD_NONE; md_cur++ ) {
-#if !defined(POLARSSL_SSL_ENABLE_MD5_SIGNATURES)
- /* Skip MD5 */
- if( *md_cur == POLARSSL_MD_MD5 )
- continue;
-#endif
- for( p = buf + 2; p < end; p += 2 ) {
- if( *md_cur == (int) ssl_md_alg_from_hash( p[0] ) ) {
- ssl->handshake->sig_alg = p[0];
- goto have_sig_alg;
- }
+ for( p = buf + 2; p < end; p += 2 ) {
+
+ /* Silently ignore unknown signature or hash algorithms. */
+
+ if( (sig_cur = ssl_pk_alg_from_sig( p[1] ) ) == POLARSSL_PK_NONE )
+ {
+ SSL_DEBUG_MSG( 3, ( "client hello v3, signature_algorithm ext: unknown sig alg encoding %d",
+ p[1] ) );
+ continue;
+ }
+
+ /* Check if we support the hash the user proposes */
+ md_cur = ssl_md_alg_from_hash( p[0] );
+ if( md_cur == POLARSSL_MD_NONE )
+ {
+ SSL_DEBUG_MSG( 3, ( "client hello v3, signature_algorithm ext: "
+ "unknown hash alg encoding %d", p[0] ) );
+ continue;
+ }
+
+ if( ssl_check_sig_hash( md_cur ) == 0 )
+ {
+ ssl_sig_hash_set_add( &ssl->handshake->hash_algs, sig_cur, md_cur );
+ SSL_DEBUG_MSG( 3, ( "client hello v3, signature_algorithm ext: match sig %d and hash %d",
+ sig_cur, md_cur ) );
+ }
+ else
+ {
+ SSL_DEBUG_MSG( 3, ( "client hello v3, signature_algorithm ext: hash alg %d not supported",
+ md_cur ) );
}
}
- /* Some key echanges do not need signatures at all */
- SSL_DEBUG_MSG( 3, ( "no signature_algorithm in common" ) );
- return( 0 );
-
-have_sig_alg:
- SSL_DEBUG_MSG( 3, ( "client hello v3, signature_algorithm ext: %d",
- ssl->handshake->sig_alg ) );
-
return( 0 );
}
#endif /* POLARSSL_SSL_PROTO_TLS1_2 &&
@@ -932,6 +958,11 @@
{
const ssl_ciphersuite_t *suite_info;
+#if defined(POLARSSL_SSL_PROTO_TLS1_2) && \
+ defined(POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED)
+ pk_type_t sig_type;
+#endif
+
suite_info = ssl_ciphersuite_from_id( suite_id );
if( suite_info == NULL )
{
@@ -979,6 +1010,26 @@
}
#endif
+#if defined(POLARSSL_SSL_PROTO_TLS1_2) && \
+ defined(POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED)
+ /* If the ciphersuite requires signing, check whether
+ * a suitable hash algorithm is present. */
+ if( ssl->minor_ver == SSL_MINOR_VERSION_3 )
+ {
+ sig_type = ssl_get_ciphersuite_sig_alg( suite_info );
+ if( sig_type != POLARSSL_PK_NONE &&
+ ssl_sig_hash_set_find( &ssl->handshake->hash_algs, sig_type ) == POLARSSL_MD_NONE )
+ {
+ SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: no suitable hash algorithm "
+ "for signature algorithm %d", sig_type ) );
+ return( 0 );
+ }
+ }
+
+#endif /* POLARSSL_SSL_PROTO_TLS1_2 &&
+ POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED */
+
+
#if defined(POLARSSL_X509_CRT_PARSE_C)
/*
* Final check: if ciphersuite requires us to have a
@@ -1287,6 +1338,15 @@
const int *ciphersuites;
const ssl_ciphersuite_t *ciphersuite_info;
+ /* If there is no signature-algorithm extension present,
+ * we need to fall back to the default values for allowed
+ * signature-hash pairs. */
+#if defined(POLARSSL_SSL_PROTO_TLS1_2) && \
+ defined(POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED)
+ int sig_hash_alg_ext_present = 0;
+#endif /* POLARSSL_SSL_PROTO_TLS1_2 &&
+ POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED */
+
SSL_DEBUG_MSG( 2, ( "=> parse client hello" ) );
#if defined(POLARSSL_SSL_RENEGOTIATION)
@@ -1621,6 +1681,8 @@
ret = ssl_parse_signature_algorithms_ext( ssl, ext + 4, ext_size );
if( ret != 0 )
return( ret );
+
+ sig_hash_alg_ext_present = 1;
break;
#endif /* POLARSSL_SSL_PROTO_TLS1_2 &&
POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED */
@@ -1764,6 +1826,27 @@
return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
}
+
+#if defined(POLARSSL_SSL_PROTO_TLS1_2) && \
+ defined(POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED)
+
+ /*
+ * Try to fall back to default hash SHA1 if the client
+ * hasn't provided any preferred signature-hash combinations.
+ */
+ if( sig_hash_alg_ext_present == 0 )
+ {
+ md_type_t md_default = POLARSSL_MD_SHA1;
+
+ if( ssl_check_sig_hash( md_default ) != 0 )
+ md_default = POLARSSL_MD_NONE;
+
+ ssl_sig_hash_set_const_hash( &ssl->handshake->hash_algs, md_default );
+ }
+
+#endif /* POLARSSL_SSL_PROTO_TLS1_2 &&
+ POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED */
+
/*
* Search for a matching ciphersuite
* (At the end because we need information from the EC-based extensions
@@ -1821,6 +1904,28 @@
ssl->in_left = 0;
ssl->state++;
+ /* Debugging-only output for testsuite */
+#if defined(POLARSSL_DEBUG_C) && \
+ defined(POLARSSL_SSL_PROTO_TLS1_2) && \
+ defined(POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED)
+ if( ssl->minor_ver == SSL_MINOR_VERSION_3 )
+ {
+ pk_type_t sig_alg = ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info );
+ if( sig_alg != POLARSSL_PK_NONE )
+ {
+ md_type_t md_alg = ssl_sig_hash_set_find( &ssl->handshake->hash_algs,
+ sig_alg );
+ SSL_DEBUG_MSG( 3, ( "client hello v3, signature_algorithm ext: %d",
+ ssl_hash_from_md_alg( md_alg ) ) );
+ }
+ else
+ {
+ SSL_DEBUG_MSG( 3, ( "no hash algorithm for signature algorithm %d - should not happen",
+ sig_alg ) );
+ }
+ }
+#endif
+
SSL_DEBUG_MSG( 2, ( "<= parse client hello" ) );
return( 0 );
@@ -2665,17 +2770,25 @@
size_t signature_len = 0;
unsigned int hashlen = 0;
unsigned char hash[64];
- md_type_t md_alg = POLARSSL_MD_NONE;
/*
- * Choose hash algorithm. NONE means MD5 + SHA1 here.
+ * Choose hash algorithm:
+ * - For TLS 1.2, obey signature-hash-algorithm extension to choose appropriate hash.
+ * - For SSL3, TLS1.0, TLS1.1 and ECDHE_ECDSA, use SHA1 (RFC 4492, Sec. 5.4)
+ * - Otherwise, use MD5 + SHA1 (RFC 4346, Sec. 7.4.3)
*/
+
+ md_type_t md_alg;
+
#if defined(POLARSSL_SSL_PROTO_TLS1_2)
+ pk_type_t sig_alg = ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info );
if( ssl->minor_ver == SSL_MINOR_VERSION_3 )
{
- md_alg = ssl_md_alg_from_hash( ssl->handshake->sig_alg );
+ /* For TLS 1.2, obey signature-hash-algorithm extension
+ * (RFC 5246, Sec. 7.4.1.4.1). */
- if( md_alg == POLARSSL_MD_NONE )
+ if( sig_alg == POLARSSL_PK_NONE ||
+ ( md_alg = ssl_sig_hash_set_find( &ssl->handshake->hash_algs, sig_alg ) ) == POLARSSL_MD_NONE )
{
SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( POLARSSL_ERR_SSL_INTERNAL_ERROR );
@@ -2696,6 +2809,8 @@
md_alg = POLARSSL_MD_NONE;
}
+ SSL_DEBUG_MSG( 3, ( "pick hash algorithm %d for signing", md_alg ) );
+
/*
* Compute the hash to be signed
*/
@@ -2794,8 +2909,8 @@
#if defined(POLARSSL_SSL_PROTO_TLS1_2)
if( ssl->minor_ver == SSL_MINOR_VERSION_3 )
{
- *(p++) = ssl->handshake->sig_alg;
- *(p++) = ssl_sig_from_pk( ssl_own_key( ssl ) );
+ *(p++) = ssl_hash_from_md_alg( md_alg );
+ *(p++) = ssl_sig_from_pk_alg( sig_alg );
n += 2;
}
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 8604997..5779229 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -2841,12 +2841,6 @@
if( ssl->authmode != SSL_VERIFY_NONE )
{
- if( ssl->ca_chain == NULL )
- {
- SSL_DEBUG_MSG( 1, ( "got no CA chain" ) );
- return( POLARSSL_ERR_SSL_CA_CHAIN_REQUIRED );
- }
-
/*
* Main check: verify certificate
*/
@@ -2872,6 +2866,8 @@
if( pk_can_do( pk, POLARSSL_PK_ECKEY ) &&
! ssl_curve_is_acceptable( ssl, pk_ec( *pk )->grp.id ) )
{
+ ssl->session_negotiate->verify_result |= BADCERT_BAD_KEY;
+
SSL_DEBUG_MSG( 1, ( "bad certificate (EC key curve)" ) );
if( ret == 0 )
ret = POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE;
@@ -2889,8 +2885,36 @@
ret = POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE;
}
- if( ssl->authmode != SSL_VERIFY_REQUIRED )
+ /* x509_crt_verify_with_profile is supposed to report a
+ * verification failure through POLARSSL_ERR_X509_CERT_VERIFY_FAILED,
+ * with details encoded in the verification flags. All other kinds
+ * of error codes, including those from the user provided f_vrfy
+ * functions, are treated as fatal and lead to a failure of
+ * ssl_parse_certificate even if verification was optional. */
+ if( ssl->authmode == SSL_VERIFY_OPTIONAL &&
+ ( ret == POLARSSL_ERR_X509_CERT_VERIFY_FAILED ||
+ ret == POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE ) )
+ {
ret = 0;
+ }
+
+ if( ssl->ca_chain == NULL && ssl->authmode == SSL_VERIFY_REQUIRED )
+ {
+ SSL_DEBUG_MSG( 1, ( "got no CA chain" ) );
+ ret = POLARSSL_ERR_SSL_CA_CHAIN_REQUIRED;
+ }
+
+#if defined(POLARSSL_DEBUG_C)
+ if( ssl->session_negotiate->verify_result != 0 )
+ {
+ SSL_DEBUG_MSG( 3, ( "! Certificate verification flags %x",
+ ssl->session_negotiate->verify_result ) );
+ }
+ else
+ {
+ SSL_DEBUG_MSG( 3, ( "Certificate verification flags clear" ) );
+ }
+#endif /* POLARSSL_DEBUG_C */
}
SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) );
@@ -3526,7 +3550,11 @@
#endif /* POLARSSL_SSL_PROTO_TLS1_2 */
handshake->update_checksum = ssl_update_checksum_start;
- handshake->sig_alg = SSL_HASH_SHA1;
+
+#if defined(POLARSSL_SSL_PROTO_TLS1_2) && \
+ defined(POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED)
+ ssl_sig_hash_set_init( &handshake->hash_algs );
+#endif
#if defined(POLARSSL_DHM_C)
dhm_init( &handshake->dhm_ctx );
@@ -5166,6 +5194,19 @@
return( SSL_SIG_ANON );
}
+unsigned char ssl_sig_from_pk_alg( pk_type_t type )
+{
+ switch( type ) {
+ case POLARSSL_PK_RSA:
+ return( SSL_SIG_RSA );
+ case POLARSSL_PK_ECDSA:
+ case POLARSSL_PK_ECKEY:
+ return( SSL_SIG_ECDSA );
+ default:
+ return( SSL_SIG_ANON );
+ }
+}
+
pk_type_t ssl_pk_alg_from_sig( unsigned char sig )
{
switch( sig )
@@ -5184,6 +5225,57 @@
}
#endif /* POLARSSL_PK_C */
+#if defined(POLARSSL_SSL_PROTO_TLS1_2) && \
+ defined(POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED)
+
+/* Find an entry in a signature-hash set matching a given hash algorithm. */
+md_type_t ssl_sig_hash_set_find( ssl_sig_hash_set_t *set,
+ pk_type_t sig_alg )
+{
+ switch( sig_alg )
+ {
+ case POLARSSL_PK_RSA:
+ return( set->rsa );
+ case POLARSSL_PK_ECDSA:
+ return( set->ecdsa );
+ default:
+ return( POLARSSL_MD_NONE );
+ }
+}
+
+/* Add a signature-hash-pair to a signature-hash set */
+void ssl_sig_hash_set_add( ssl_sig_hash_set_t *set,
+ pk_type_t sig_alg,
+ md_type_t md_alg )
+{
+ switch( sig_alg )
+ {
+ case POLARSSL_PK_RSA:
+ if( set->rsa == POLARSSL_MD_NONE )
+ set->rsa = md_alg;
+ break;
+
+ case POLARSSL_PK_ECDSA:
+ if( set->ecdsa == POLARSSL_MD_NONE )
+ set->ecdsa = md_alg;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Allow exactly one hash algorithm for each signature. */
+void ssl_sig_hash_set_const_hash( ssl_sig_hash_set_t *set,
+ md_type_t md_alg )
+{
+ set->rsa = md_alg;
+ set->ecdsa = md_alg;
+}
+
+#endif /* POLARSSL_SSL_PROTO_TLS1_2) &&
+ POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED */
+
/*
* Convert between SSL_HASH_XXX and POLARSSL_MD_XXX
*/
@@ -5216,6 +5308,38 @@
}
}
+/*
+ * Convert from POLARSSL_MD_XXX to SSL_HASH_XXX
+ */
+unsigned char ssl_hash_from_md_alg( md_type_t md )
+{
+ switch( md )
+ {
+#if defined(POLARSSL_MD5_C)
+ case POLARSSL_MD_MD5:
+ return( SSL_HASH_MD5 );
+#endif
+#if defined(POLARSSL_SHA1_C)
+ case POLARSSL_MD_SHA1:
+ return( SSL_HASH_SHA1 );
+#endif
+#if defined(POLARSSL_SHA256_C)
+ case POLARSSL_MD_SHA224:
+ return( SSL_HASH_SHA224 );
+ case POLARSSL_MD_SHA256:
+ return( SSL_HASH_SHA256 );
+#endif
+#if defined(POLARSSL_SHA512_C)
+ case POLARSSL_MD_SHA384:
+ return( SSL_HASH_SHA384 );
+ case POLARSSL_MD_SHA512:
+ return( SSL_HASH_SHA512 );
+#endif
+ default:
+ return( SSL_HASH_NONE );
+ }
+}
+
#if defined(POLARSSL_SSL_SET_CURVES)
/*
* Check is a curve proposed by the peer is in our list.
@@ -5233,6 +5357,30 @@
}
#endif /* POLARSSL_SSL_SET_CURVES */
+#if defined(POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED)
+/*
+ * Check if a hash proposed by the peer is in our list.
+ * Return 0 if we're willing to use it, -1 otherwise.
+ */
+int ssl_check_sig_hash( md_type_t md )
+{
+ const int *cur;
+
+ for( cur = md_list(); *cur != POLARSSL_MD_NONE; cur++ )
+ {
+#if !defined(POLARSSL_SSL_ENABLE_MD5_SIGNATURES)
+ /* Skip MD5 */
+ if( *cur == POLARSSL_MD_MD5 )
+ continue;
+#endif
+ if( *cur == (int) md )
+ return( 0 );
+ }
+
+ return( -1 );
+}
+#endif /* POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED */
+
#if defined(POLARSSL_X509_CRT_PARSE_C)
int ssl_check_cert_usage( const x509_crt *cert,
const ssl_ciphersuite_t *ciphersuite,
diff --git a/library/x509_crt.c b/library/x509_crt.c
index a3517f6..16a29b5 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -1403,6 +1403,7 @@
{ BADCERT_KEY_USAGE, "Usage does not match the keyUsage extension" },
{ BADCERT_EXT_KEY_USAGE, "Usage does not match the extendedKeyUsage extension" },
{ BADCERT_NS_CERT_TYPE, "Usage does not match the nsCertType extension" },
+ { BADCERT_BAD_KEY, "The certificate uses an invalid key (e.g. unsupported elliptic curve)" },
{ 0, NULL }
};
diff --git a/programs/pkey/ecdsa.c b/programs/pkey/ecdsa.c
index aa8eafb..1411e42 100644
--- a/programs/pkey/ecdsa.c
+++ b/programs/pkey/ecdsa.c
@@ -38,6 +38,7 @@
#include "polarssl/entropy.h"
#include "polarssl/ctr_drbg.h"
#include "polarssl/ecdsa.h"
+#include "polarssl/sha256.h"
#include <string.h>
#endif
@@ -102,16 +103,20 @@
ecdsa_context ctx_sign, ctx_verify;
entropy_context entropy;
ctr_drbg_context ctr_drbg;
- unsigned char hash[] = "This should be the hash of a message.";
- unsigned char sig[512];
+ sha256_context sha256_ctx;
+ unsigned char message[100];
+ unsigned char hash[32];
+ unsigned char sig[POLARSSL_ECDSA_MAX_LEN];
size_t sig_len;
const char *pers = "ecdsa";
((void) argv);
ecdsa_init( &ctx_sign );
ecdsa_init( &ctx_verify );
+ sha256_init( &sha256_ctx );
- memset(sig, 0, sizeof( sig ) );
+ memset( sig, 0, sizeof( sig ) );
+ memset( message, 0x25, sizeof( message ) );
ret = 1;
if( argc != 1 )
@@ -155,9 +160,24 @@
dump_pubkey( " + Public key: ", &ctx_sign );
/*
- * Sign some message hash
+ * Compute message hash
*/
polarssl_printf( " . Signing message..." );
+ polarssl_printf( " . Computing message hash..." );
+ fflush( stdout );
+
+ sha256_starts( &sha256_ctx, 0 );
+ sha256_update( &sha256_ctx, message, sizeof( message ) );
+ sha256_finish( &sha256_ctx, hash );
+
+ polarssl_printf( " ok\n" );
+
+ dump_buf( " + Hash: ", hash, sizeof( hash ) );
+
+ /*
+ * Sign message hash
+ */
+ polarssl_printf( " . Signing message hash..." );
fflush( stdout );
if( ( ret = ecdsa_write_signature( &ctx_sign,
@@ -170,7 +190,6 @@
}
polarssl_printf( " ok (signature length = %u)\n", (unsigned int) sig_len );
- dump_buf( " + Hash: ", hash, sizeof hash );
dump_buf( " + Signature: ", sig, sig_len );
/*
@@ -233,6 +252,7 @@
ecdsa_free( &ctx_sign );
ctr_drbg_free( &ctr_drbg );
entropy_free( &entropy );
+ sha256_free( &sha256_ctx );
return( ret );
}
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index cdadf59..e302244 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -92,6 +92,7 @@
#define DFL_RECO_DELAY 0
#define DFL_TICKETS SSL_SESSION_TICKETS_ENABLED
#define DFL_ALPN_STRING NULL
+#define DFL_CURVES NULL
#define DFL_FALLBACK -1
#define DFL_EXTENDED_MS -1
#define DFL_ETM -1
@@ -169,6 +170,17 @@
#define USAGE_ALPN ""
#endif /* POLARSSL_SSL_ALPN */
+#if defined(POLARSSL_SSL_SET_CURVES)
+#define USAGE_CURVES \
+ " curves=a,b,c,d default: \"default\" (library default)\n" \
+ " example: \"secp521r1,brainpoolP512r1\"\n" \
+ " - use \"none\" for empty list\n" \
+ " - see ecp_curve_list()\n" \
+ " for acceptable curve names\n"
+#else
+#define USAGE_CURVES ""
+#endif /* POLARSSL_SSL_SET_CURVES */
+
#if defined(POLARSSL_SSL_FALLBACK_SCSV)
#define USAGE_FALLBACK \
" fallback=0/1 default: (library default: off)\n"
@@ -226,6 +238,7 @@
USAGE_MAX_FRAG_LEN \
USAGE_TRUNC_HMAC \
USAGE_ALPN \
+ USAGE_CURVES \
USAGE_FALLBACK \
USAGE_EMS \
USAGE_ETM \
@@ -285,6 +298,7 @@
int reconnect; /* attempt to resume session */
int reco_delay; /* delay in seconds before resuming session */
int tickets; /* enable / disable session tickets */
+ const char *curves; /* list of supported elliptic curves */
const char *alpn_string; /* ALPN supported protocols */
int fallback; /* is this a fallback connection? */
int extended_ms; /* negotiate extended master secret? */
@@ -373,6 +387,11 @@
#if defined(POLARSSL_SSL_ALPN)
const char *alpn_list[10];
#endif
+#if defined(POLARSSL_SSL_SET_CURVES)
+ ecp_group_id curve_list[20];
+ const ecp_curve_info *curve_cur;
+#endif
+
const char *pers = "ssl_client2";
entropy_context entropy;
@@ -453,6 +472,7 @@
opt.reco_delay = DFL_RECO_DELAY;
opt.tickets = DFL_TICKETS;
opt.alpn_string = DFL_ALPN_STRING;
+ opt.curves = DFL_CURVES;
opt.fallback = DFL_FALLBACK;
opt.extended_ms = DFL_EXTENDED_MS;
opt.etm = DFL_ETM;
@@ -584,6 +604,8 @@
default: goto usage;
}
}
+ else if( strcmp( p, "curves" ) == 0 )
+ opt.curves = q;
else if( strcmp( p, "etm" ) == 0 )
{
switch( atoi( q ) )
@@ -775,6 +797,64 @@
}
#endif /* POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED */
+#if defined(POLARSSL_SSL_SET_CURVES)
+ if( opt.curves != NULL )
+ {
+ p = (char *) opt.curves;
+ i = 0;
+
+ if( strcmp( p, "none" ) == 0 )
+ {
+ curve_list[0] = POLARSSL_ECP_DP_NONE;
+ }
+ else if( strcmp( p, "default" ) != 0 )
+ {
+ /* Leave room for a final NULL in curve list */
+ while( i < (int) ( sizeof( curve_list ) / sizeof( *curve_list ) ) - 1
+ && *p != '\0' )
+ {
+ q = p;
+
+ /* Terminate the current string */
+ while( *p != ',' && *p != '\0' )
+ p++;
+ if( *p == ',' )
+ *p++ = '\0';
+
+ if( ( curve_cur = ecp_curve_info_from_name( q ) ) != NULL )
+ {
+ curve_list[i++] = curve_cur->grp_id;
+ }
+ else
+ {
+ polarssl_printf( "unknown curve %s\n", q );
+ polarssl_printf( "supported curves: " );
+ for( curve_cur = ecp_curve_list();
+ curve_cur->grp_id != POLARSSL_ECP_DP_NONE;
+ curve_cur++ )
+ {
+ polarssl_printf( "%s ", curve_cur->name );
+ }
+ polarssl_printf( "\n" );
+ goto exit;
+ }
+ }
+
+ polarssl_printf( "Number of curves: %d\n", i );
+
+ if( i == (int) ( sizeof( curve_list ) / sizeof( *curve_list ) ) - 1
+ && *p != '\0' )
+ {
+ polarssl_printf( "curves list too long, maximum %zu",
+ (size_t) ( sizeof( curve_list ) / sizeof( *curve_list ) - 1 ) );
+ goto exit;
+ }
+
+ curve_list[i] = POLARSSL_ECP_DP_NONE;
+ }
+ }
+#endif /* POLARSSL_SSL_SET_CURVES */
+
#if defined(POLARSSL_SSL_ALPN)
if( opt.alpn_string != NULL )
{
@@ -996,6 +1076,14 @@
}
#endif
+#if defined(POLARSSL_SSL_SET_CURVES)
+ if( opt.curves != NULL &&
+ strcmp( opt.curves, "default" ) != 0 )
+ {
+ ssl_set_curves( &ssl, curve_list );
+ }
+#endif
+
ssl_set_rng( &ssl, ctr_drbg_random, &ctr_drbg );
ssl_set_dbg( &ssl, my_debug, stdout );
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 095fabd..95438f9 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -106,6 +106,7 @@
#define DFL_CACHE_TIMEOUT -1
#define DFL_SNI NULL
#define DFL_ALPN_STRING NULL
+#define DFL_CURVES NULL
#define DFL_DHM_FILE NULL
#define DFL_EXTENDED_MS -1
#define DFL_ETM -1
@@ -215,6 +216,17 @@
#define USAGE_ALPN ""
#endif /* POLARSSL_SSL_ALPN */
+#if defined(POLARSSL_SSL_SET_CURVES)
+#define USAGE_CURVES \
+ " curves=a,b,c,d default: \"default\" (library default)\n" \
+ " example: \"secp521r1,brainpoolP512r1\"\n" \
+ " - use \"none\" for empty list\n" \
+ " - see ecp_curve_list()\n" \
+ " for acceptable curve names\n"
+#else
+#define USAGE_CURVES ""
+#endif /* POLARSSL_SSL_SET_CURVES */
+
#if defined(POLARSSL_SSL_EXTENDED_MASTER_SECRET)
#define USAGE_EMS \
" extended_ms=0/1 default: (library default: on)\n"
@@ -263,6 +275,7 @@
USAGE_MAX_FRAG_LEN \
USAGE_TRUNC_HMAC \
USAGE_ALPN \
+ USAGE_CURVES \
USAGE_EMS \
USAGE_ETM \
"\n" \
@@ -327,6 +340,7 @@
int cache_max; /* max number of session cache entries */
int cache_timeout; /* expiration delay of session cache entries */
char *sni; /* string describing sni information */
+ const char *curves; /* list of supported elliptic curves */
const char *alpn_string; /* ALPN supported protocols */
const char *dhm_file; /* the file with the DH parameters */
int extended_ms; /* allow negotiation of extended MS? */
@@ -685,6 +699,10 @@
#if defined(POLARSSL_SSL_ALPN)
const char *alpn_list[10];
#endif
+#if defined(POLARSSL_SSL_SET_CURVES)
+ ecp_group_id curve_list[20];
+ const ecp_curve_info *curve_cur;
+#endif
#if defined(POLARSSL_MEMORY_BUFFER_ALLOC_C)
unsigned char alloc_buf[100000];
#endif
@@ -780,6 +798,7 @@
opt.cache_timeout = DFL_CACHE_TIMEOUT;
opt.sni = DFL_SNI;
opt.alpn_string = DFL_ALPN_STRING;
+ opt.curves = DFL_CURVES;
opt.dhm_file = DFL_DHM_FILE;
opt.extended_ms = DFL_EXTENDED_MS;
opt.etm = DFL_ETM;
@@ -987,6 +1006,8 @@
default: goto usage;
}
}
+ else if( strcmp( p, "curves" ) == 0 )
+ opt.curves = q;
else if( strcmp( p, "etm" ) == 0 )
{
switch( atoi( q ) )
@@ -1118,6 +1139,64 @@
}
#endif /* POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED */
+#if defined(POLARSSL_SSL_SET_CURVES)
+ if( opt.curves != NULL )
+ {
+ p = (char *) opt.curves;
+ i = 0;
+
+ if( strcmp( p, "none" ) == 0 )
+ {
+ curve_list[0] = POLARSSL_ECP_DP_NONE;
+ }
+ else if( strcmp( p, "default" ) != 0 )
+ {
+ /* Leave room for a final NULL in curve list */
+ while( i < (int) ( sizeof( curve_list ) / sizeof( *curve_list ) ) - 1
+ && *p != '\0' )
+ {
+ q = p;
+
+ /* Terminate the current string */
+ while( *p != ',' && *p != '\0' )
+ p++;
+ if( *p == ',' )
+ *p++ = '\0';
+
+ if( ( curve_cur = ecp_curve_info_from_name( q ) ) != NULL )
+ {
+ curve_list[i++] = curve_cur->grp_id;
+ }
+ else
+ {
+ polarssl_printf( "unknown curve %s\n", q );
+ polarssl_printf( "supported curves: " );
+ for( curve_cur = ecp_curve_list();
+ curve_cur->grp_id != POLARSSL_ECP_DP_NONE;
+ curve_cur++ )
+ {
+ polarssl_printf( "%s ", curve_cur->name );
+ }
+ polarssl_printf( "\n" );
+ goto exit;
+ }
+ }
+
+ polarssl_printf( "Number of curves: %d\n", i );
+
+ if( i == (int) ( sizeof( curve_list ) / sizeof( *curve_list ) ) - 1
+ && *p != '\0' )
+ {
+ polarssl_printf( "curves list too long, maximum %zu",
+ (size_t) ( sizeof( curve_list ) / sizeof( *curve_list ) - 1 ) );
+ goto exit;
+ }
+
+ curve_list[i] = POLARSSL_ECP_DP_NONE;
+ }
+ }
+#endif /* POLARSSL_SSL_SET_CURVES */
+
#if defined(POLARSSL_SSL_ALPN)
if( opt.alpn_string != NULL )
{
@@ -1397,6 +1476,14 @@
}
#endif
+#if defined(POLARSSL_SSL_SET_CURVES)
+ if( opt.curves != NULL &&
+ strcmp( opt.curves, "default" ) != 0 )
+ {
+ ssl_set_curves( &ssl, curve_list );
+ }
+#endif
+
ssl_set_rng( &ssl, ctr_drbg_random, &ctr_drbg );
ssl_set_dbg( &ssl, my_debug, stdout );
diff --git a/tests/scripts/tcp_client.pl b/tests/scripts/tcp_client.pl
new file mode 100755
index 0000000..11cbf1b
--- /dev/null
+++ b/tests/scripts/tcp_client.pl
@@ -0,0 +1,86 @@
+#!/usr/bin/env perl
+
+# A simple TCP client that sends some data and expects a response.
+# Usage: tcp_client.pl HOSTNAME PORT DATA1 RESPONSE1
+# DATA: hex-encoded data to send to the server
+# RESPONSE: regexp that must match the server's response
+
+use warnings;
+use strict;
+use IO::Socket::INET;
+
+# Pack hex digits into a binary string, ignoring whitespace.
+sub parse_hex {
+ my ($hex) = @_;
+ $hex =~ s/\s+//g;
+ return pack('H*', $hex);
+}
+
+## Open a TCP connection to the specified host and port.
+sub open_connection {
+ my ($host, $port) = @_;
+ my $socket = IO::Socket::INET->new(PeerAddr => $host,
+ PeerPort => $port,
+ Proto => 'tcp',
+ Timeout => 1);
+ die "Cannot connect to $host:$port: $!" unless $socket;
+ return $socket;
+}
+
+## Close the TCP connection.
+sub close_connection {
+ my ($connection) = @_;
+ $connection->shutdown(2);
+ # Ignore shutdown failures (at least for now)
+ return 1;
+}
+
+## Write the given data, expressed as hexadecimal
+sub write_data {
+ my ($connection, $hexdata) = @_;
+ my $data = parse_hex($hexdata);
+ my $total_sent = 0;
+ while ($total_sent < length($data)) {
+ my $sent = $connection->send($data, 0);
+ if (!defined $sent) {
+ die "Unable to send data: $!";
+ }
+ $total_sent += $sent;
+ }
+ return 1;
+}
+
+## Read a response and check it against an expected prefix
+sub read_response {
+ my ($connection, $expected_hex) = @_;
+ my $expected_data = parse_hex($expected_hex);
+ my $start_offset = 0;
+ while ($start_offset < length($expected_data)) {
+ my $actual_data;
+ my $ok = $connection->recv($actual_data, length($expected_data));
+ if (!defined $ok) {
+ die "Unable to receive data: $!";
+ }
+ if (($actual_data ^ substr($expected_data, $start_offset)) =~ /[^\000]/) {
+ printf STDERR ("Received \\x%02x instead of \\x%02x at offset %d\n",
+ ord(substr($actual_data, $-[0], 1)),
+ ord(substr($expected_data, $start_offset + $-[0], 1)),
+ $start_offset + $-[0]);
+ return 0;
+ }
+ $start_offset += length($actual_data);
+ }
+ return 1;
+}
+
+if (@ARGV != 4) {
+ print STDERR "Usage: $0 HOSTNAME PORT DATA1 RESPONSE1\n";
+ exit(3);
+}
+my ($host, $port, $data1, $response1) = @ARGV;
+my $connection = open_connection($host, $port);
+write_data($connection, $data1);
+if (!read_response($connection, $response1)) {
+ exit(1);
+}
+close_connection($connection);
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index a018f64..6e19646 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -16,11 +16,13 @@
: ${OPENSSL_CMD:=openssl} # OPENSSL would conflict with the build system
: ${GNUTLS_CLI:=gnutls-cli}
: ${GNUTLS_SERV:=gnutls-serv}
+: ${PERL:=perl}
O_SRV="$OPENSSL_CMD s_server -www -cert data_files/server5.crt -key data_files/server5.key -dhparam data_files/dhparams.pem"
O_CLI="echo 'GET / HTTP/1.0' | $OPENSSL_CMD s_client"
G_SRV="$GNUTLS_SERV --x509certfile data_files/server5.crt --x509keyfile data_files/server5.key"
G_CLI="echo 'GET / HTTP/1.0' | $GNUTLS_CLI --x509cafile data_files/test-ca_cat12.crt"
+TCP_CLIENT="$PERL scripts/tcp_client.pl"
TESTS=0
FAILS=0
@@ -761,6 +763,37 @@
-s "received FALLBACK_SCSV" \
-S "inapropriate fallback"
+## ClientHello generated with
+## "openssl s_client -CAfile tests/data_files/test-ca.crt -tls1_1 -connect localhost:4433 -cipher ..."
+## then manually twiddling the ciphersuite list.
+## The ClientHello content is spelled out below as a hex string as
+## "prefix ciphersuite1 ciphersuite2 ciphersuite3 ciphersuite4 suffix".
+## The expected response is an inappropriate_fallback alert.
+requires_openssl_with_fallback_scsv
+run_test "Fallback SCSV: beginning of list" \
+ "$P_SRV debug_level=2" \
+ "$TCP_CLIENT localhost $PORT '160301003e0100003a03022aafb94308dc22ca1086c65acc00e414384d76b61ecab37df1633b1ae1034dbe000008 5600 0031 0032 0033 0100000900230000000f000101' '15030200020256'" \
+ 0 \
+ -s "received FALLBACK_SCSV" \
+ -s "inapropriate fallback"
+
+requires_openssl_with_fallback_scsv
+run_test "Fallback SCSV: end of list" \
+ "$P_SRV debug_level=2" \
+ "$TCP_CLIENT localhost $PORT '160301003e0100003a03022aafb94308dc22ca1086c65acc00e414384d76b61ecab37df1633b1ae1034dbe000008 0031 0032 0033 5600 0100000900230000000f000101' '15030200020256'" \
+ 0 \
+ -s "received FALLBACK_SCSV" \
+ -s "inapropriate fallback"
+
+## Here the expected response is a valid ServerHello prefix, up to the random.
+requires_openssl_with_fallback_scsv
+run_test "Fallback SCSV: not in list" \
+ "$P_SRV debug_level=2" \
+ "$TCP_CLIENT localhost $PORT '160301003e0100003a03022aafb94308dc22ca1086c65acc00e414384d76b61ecab37df1633b1ae1034dbe000008 0056 0031 0032 0033 0100000900230000000f000101' '16030200300200002c0302'" \
+ 0 \
+ -S "received FALLBACK_SCSV" \
+ -S "inapropriate fallback"
+
# Tests for CBC 1/n-1 record splitting
run_test "CBC Record splitting: TLS 1.2, no splitting" \
@@ -1399,6 +1432,54 @@
-C "! ssl_handshake returned" \
-C "X509 - Certificate verification failed"
+run_test "Authentication: server goodcert, client optional, no trusted CA" \
+ "$P_SRV" \
+ "$P_CLI debug_level=3 auth_mode=optional ca_file=none ca_path=none" \
+ 0 \
+ -c "x509_verify_cert() returned" \
+ -c "! The certificate is not correctly signed by the trusted CA" \
+ -c "! Certificate verification flags"\
+ -C "! ssl_handshake returned" \
+ -C "X509 - Certificate verification failed" \
+ -C "SSL - No CA Chain is set, but required to operate"
+
+run_test "Authentication: server goodcert, client required, no trusted CA" \
+ "$P_SRV" \
+ "$P_CLI debug_level=3 auth_mode=required ca_file=none ca_path=none" \
+ 1 \
+ -c "x509_verify_cert() returned" \
+ -c "! The certificate is not correctly signed by the trusted CA" \
+ -c "! Certificate verification flags"\
+ -c "! ssl_handshake returned" \
+ -c "SSL - No CA Chain is set, but required to operate"
+
+# The purpose of the next two tests is to test the client's behaviour when receiving a server
+# certificate with an unsupported elliptic curve. This should usually not happen because
+# the client informs the server about the supported curves - it does, though, in the
+# corner case of a static ECDH suite, because the server doesn't check the curve on that
+# occasion (to be fixed). If that bug's fixed, the test needs to be altered to use a
+# different means to have the server ignoring the client's supported curve list.
+
+requires_config_enabled POLARSSL_SSL_SET_CURVES
+run_test "Authentication: server ECDH p256v1, client required, p256v1 unsupported" \
+ "$P_SRV debug_level=1 key_file=data_files/server5.key \
+ crt_file=data_files/server5.ku-ka.crt" \
+ "$P_CLI debug_level=3 auth_mode=required curves=secp521r1" \
+ 1 \
+ -c "bad certificate (EC key curve)"\
+ -c "! Certificate verification flags"\
+ -C "bad server certificate (ECDH curve)" # Expect failure at earlier verification stage
+
+requires_config_enabled POLARSSL_SSL_SET_CURVES
+run_test "Authentication: server ECDH p256v1, client optional, p256v1 unsupported" \
+ "$P_SRV debug_level=1 key_file=data_files/server5.key \
+ crt_file=data_files/server5.ku-ka.crt" \
+ "$P_CLI debug_level=3 auth_mode=optional curves=secp521r1" \
+ 1 \
+ -c "bad certificate (EC key curve)"\
+ -c "! Certificate verification flags"\
+ -c "bad server certificate (ECDH curve)" # Expect failure only at ECDH params check
+
run_test "Authentication: server badcert, client none" \
"$P_SRV crt_file=data_files/server5-badsign.crt \
key_file=data_files/server5.key" \
@@ -2387,7 +2468,7 @@
# A test for extensions in SSLv3
-requires_config_enabled MBEDTLS_SSL_PROTO_SSL3
+requires_config_enabled POLARSSL_SSL_PROTO_SSL3
run_test "SSLv3 with extensions, server side" \
"$P_SRV min_version=ssl3 debug_level=3" \
"$P_CLI force_version=ssl3 tickets=1 max_frag_len=4096 alpn=abc,1234" \
diff --git a/tests/suites/test_suite_mpi.data b/tests/suites/test_suite_mpi.data
index 81fc73f..52cbd7e 100644
--- a/tests/suites/test_suite_mpi.data
+++ b/tests/suites/test_suite_mpi.data
@@ -521,7 +521,7 @@
mpi_exp_mod:10:"433019240910377478217373572959560109819648647016096560523769010881172869083338285573756574557395862965095016483867813043663981946477698466501451832407592327356331263124555137732393938242285782144928753919588632679050799198937132922145084847":10:"5781538327977828897150909166778407659250458379645823062042492461576758526757490910073628008613977550546382774775570888130029763571528699574717583228939535960234464230882573615930384979100379102915657483866755371559811718767760594919456971354184113721":10:"583137007797276923956891216216022144052044091311388601652961409557516421612874571554415606746479105795833145583959622117418531166391184939066520869800857530421873250114773204354963864729386957427276448683092491947566992077136553066273207777134303397724679138833126700957":10:"":10:"114597449276684355144920670007147953232659436380163461553186940113929777196018164149703566472936578890991049344459204199888254907113495794730452699842273939581048142004834330369483813876618772578869083248061616444392091693787039636316845512292127097865026290173004860736":0
Test mpi_exp_mod (Negative base)
-mpi_exp_mod:10:"-10000000000":10:"10000000000":10:"99999":10:"":10:"99998":0
+mpi_exp_mod:10:"-10000000000":10:"10000000000":10:"99999":10:"":10:"1":0
Test mpi_exp_mod (Negative base)
mpi_exp_mod:16:"-9f13012cd92aa72fb86ac8879d2fde4f7fd661aaae43a00971f081cc60ca277059d5c37e89652e2af2585d281d66ef6a9d38a117e9608e9e7574cd142dc55278838a2161dd56db9470d4c1da2d5df15a908ee2eb886aaa890f23be16de59386663a12f1afbb325431a3e835e3fd89b98b96a6f77382f458ef9a37e1f84a03045c8676ab55291a94c2228ea15448ee96b626b998":16:"40a54d1b9e86789f06d9607fb158672d64867665c73ee9abb545fc7a785634b354c7bae5b962ce8040cf45f2c1f3d3659b2ee5ede17534c8fc2ec85c815e8df1fe7048d12c90ee31b88a68a081f17f0d8ce5f4030521e9400083bcea73a429031d4ca7949c2000d597088e0c39a6014d8bf962b73bb2e8083bd0390a4e00b9b3":16:"eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3":16:"":16:"21acc7199e1b90f9b4844ffe12c19f00ec548c5d32b21c647d48b6015d8eb9ec9db05b4f3d44db4227a2b5659c1a7cceb9d5fa8fa60376047953ce7397d90aaeb7465e14e820734f84aa52ad0fc66701bcbb991d57715806a11531268e1e83dd48288c72b424a6287e9ce4e5cc4db0dd67614aecc23b0124a5776d36e5c89483":0
@@ -550,6 +550,9 @@
Base test mpi_inv_mod #4
mpi_inv_mod:10:"2":10:"4":10:"0":POLARSSL_ERR_MPI_NOT_ACCEPTABLE
+Base test mbedtls_mpi_inv_mod #5
+mpi_inv_mod:10:"3":10:"1":10:"0":POLARSSL_ERR_MPI_BAD_INPUT_DATA
+
Test mpi_inv_mod #1
mpi_inv_mod:16:"aa4df5cb14b4c31237f98bd1faf527c283c2d0f3eec89718664ba33f9762907c":16:"fffbbd660b94412ae61ead9c2906a344116e316a256fd387874c6c675b1d587d":16:"8d6a5c1d7adeae3e94b9bcd2c47e0d46e778bc8804a2cc25c02d775dc3d05b0c":0