diff --git a/include/polarssl/config.h b/include/polarssl/config.h index 1ed203c738..1a68f2a621 100644 --- a/include/polarssl/config.h +++ b/include/polarssl/config.h @@ -813,6 +813,20 @@ */ #define POLARSSL_SSL_TRUNCATED_HMAC +/** + * \def POLARSSL_SSL_SET_CURVES + * + * Enable ssl_set_curves(). + * + * This is disabled by default since it breaks binary compatibility with the + * 1.3.x line. If you choose to enable it, you will need to rebuild your + * application against the new header files, relinking will not be enough. + * It will be enabled by default, or no longer an option, in the 1.4 branch. + * + * Uncomment to make ssl_set_curves() available. + */ +//#define POLARSSL_SSL_SET_CURVES + /** * \def POLARSSL_THREADING_ALT * diff --git a/include/polarssl/ecp.h b/include/polarssl/ecp.h index 1635b702f3..b35b0d1d04 100644 --- a/include/polarssl/ecp.h +++ b/include/polarssl/ecp.h @@ -222,12 +222,22 @@ ecp_keypair; #define POLARSSL_ECP_TLS_NAMED_CURVE 3 /**< ECCurveType's named_curve */ /** - * \brief Return the list of supported curves with associated info + * \brief Get the list of supported curves in order of preferrence + * (full information) * * \return A statically allocated array, the last entry is 0. */ const ecp_curve_info *ecp_curve_list( void ); +/** + * \brief Get the list of supported curves in order of preferrence + * (grp_id only) + * + * \return A statically allocated array, + * terminated with POLARSSL_ECP_DP_NONE. + */ +const ecp_group_id *ecp_grp_id_list( void ); + /** * \brief Get curve information from an internal group identifier * diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h index 1bda2b3959..d610052c98 100644 --- a/include/polarssl/ssl.h +++ b/include/polarssl/ssl.h @@ -83,6 +83,12 @@ #define POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED #endif +#if defined(POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED) +#define POLARSSL_KEY_EXCHANGE__SOME__ECDHE_ENABLED +#endif + #if defined(_MSC_VER) && !defined(inline) #define inline _inline #else @@ -721,6 +727,9 @@ struct _ssl_context int disable_renegotiation; /*!< enable/disable renegotiation */ int allow_legacy_renegotiation; /*!< allow legacy renegotiation */ const int *ciphersuite_list[4]; /*!< allowed ciphersuites / version */ +#if defined(POLARSSL_SSL_SET_CURVES) + const ecp_group_id *curve_list; /*!< allowed curves */ +#endif #if defined(POLARSSL_SSL_TRUNCATED_HMAC) int trunc_hmac; /*!< negotiate truncated hmac? */ #endif @@ -1149,6 +1158,28 @@ int ssl_set_dh_param( ssl_context *ssl, const char *dhm_P, const char *dhm_G ); int ssl_set_dh_param_ctx( ssl_context *ssl, dhm_context *dhm_ctx ); #endif +#if defined(POLARSSL_SSL_SET_CURVES) +/** + * \brief Set the allowed curves in order of preference. + * (Default: all defined curves.) + * + * On server: this only affects selection of the ECDHE curve; + * the curves used for ECDH and ECDSA are determined by the + * list of available certificates instead. + * + * On client: this affects the list of curves offered for any + * use. The server can override our preference order. + * + * Both sides: limits the set of curves used by peer to the + * listed curves for any use (ECDH(E), certificates). + * + * \param ssl SSL context + * \param curves Ordered list of allowed curves, + * terminated by POLARSSL_ECP_DP_NONE. + */ +void ssl_set_curves( ssl_context *ssl, const ecp_group_id *curves ); +#endif + #if defined(POLARSSL_SSL_SERVER_NAME_INDICATION) /** * \brief Set hostname for ServerName TLS extension @@ -1561,6 +1592,10 @@ pk_type_t ssl_pk_alg_from_sig( unsigned char sig ); md_type_t ssl_md_alg_from_hash( unsigned char hash ); +#if defined(POLARSSL_SSL_SET_CURVES) +int ssl_curve_is_acceptable( const ssl_context *ssl, ecp_group_id grp_id ); +#endif + #if defined(POLARSSL_X509_CRT_PARSE_C) static inline pk_context *ssl_own_key( ssl_context *ssl ) { diff --git a/library/debug.c b/library/debug.c index 371cbf95cf..4e674e1e2c 100644 --- a/library/debug.c +++ b/library/debug.c @@ -149,10 +149,6 @@ void debug_print_ecp( const ssl_context *ssl, int level, snprintf( str, maxlen, "%s(Y)", text ); str[maxlen] = '\0'; debug_print_mpi( ssl, level, file, line, str, &X->Y ); - - snprintf( str, maxlen, "%s(Z)", text ); - str[maxlen] = '\0'; - debug_print_mpi( ssl, level, file, line, str, &X->Z ); } #endif /* POLARSSL_ECP_C */ diff --git a/library/ecp.c b/library/ecp.c index a27d30e2a0..ad6e5f586f 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -114,45 +114,50 @@ typedef enum * - TLS NamedCurve ID (RFC 4492 sec. 5.1.1, RFC 7071 sec. 2) * - size in bits * - readable name + * + * Curves are listed in order: largest curves first, and for a given size, + * fastest curves first. This provides the default order for the SSL module. */ -static const ecp_curve_info ecp_supported_curves[] = +static const ecp_curve_info ecp_supported_curves[POLARSSL_ECP_DP_MAX] = { -#if defined(POLARSSL_ECP_DP_BP512R1_ENABLED) - { POLARSSL_ECP_DP_BP512R1, 28, 512, "brainpoolP512r1" }, -#endif -#if defined(POLARSSL_ECP_DP_BP384R1_ENABLED) - { POLARSSL_ECP_DP_BP384R1, 27, 384, "brainpoolP384r1" }, -#endif -#if defined(POLARSSL_ECP_DP_BP256R1_ENABLED) - { POLARSSL_ECP_DP_BP256R1, 26, 256, "brainpoolP256r1" }, -#endif #if defined(POLARSSL_ECP_DP_SECP521R1_ENABLED) { POLARSSL_ECP_DP_SECP521R1, 25, 521, "secp521r1" }, #endif +#if defined(POLARSSL_ECP_DP_BP512R1_ENABLED) + { POLARSSL_ECP_DP_BP512R1, 28, 512, "brainpoolP512r1" }, +#endif #if defined(POLARSSL_ECP_DP_SECP384R1_ENABLED) { POLARSSL_ECP_DP_SECP384R1, 24, 384, "secp384r1" }, #endif +#if defined(POLARSSL_ECP_DP_BP384R1_ENABLED) + { POLARSSL_ECP_DP_BP384R1, 27, 384, "brainpoolP384r1" }, +#endif #if defined(POLARSSL_ECP_DP_SECP256R1_ENABLED) { POLARSSL_ECP_DP_SECP256R1, 23, 256, "secp256r1" }, #endif -#if defined(POLARSSL_ECP_DP_SECP224R1_ENABLED) - { POLARSSL_ECP_DP_SECP224R1, 21, 224, "secp224r1" }, -#endif -#if defined(POLARSSL_ECP_DP_SECP192R1_ENABLED) - { POLARSSL_ECP_DP_SECP192R1, 19, 192, "secp192r1" }, -#endif #if defined(POLARSSL_ECP_DP_SECP256K1_ENABLED) { POLARSSL_ECP_DP_SECP256K1, 22, 256, "secp256k1" }, #endif +#if defined(POLARSSL_ECP_DP_BP256R1_ENABLED) + { POLARSSL_ECP_DP_BP256R1, 26, 256, "brainpoolP256r1" }, +#endif +#if defined(POLARSSL_ECP_DP_SECP224R1_ENABLED) + { POLARSSL_ECP_DP_SECP224R1, 21, 224, "secp224r1" }, +#endif #if defined(POLARSSL_ECP_DP_SECP224K1_ENABLED) { POLARSSL_ECP_DP_SECP224K1, 20, 224, "secp224k1" }, #endif +#if defined(POLARSSL_ECP_DP_SECP192R1_ENABLED) + { POLARSSL_ECP_DP_SECP192R1, 19, 192, "secp192r1" }, +#endif #if defined(POLARSSL_ECP_DP_SECP192K1_ENABLED) { POLARSSL_ECP_DP_SECP192K1, 18, 192, "secp192k1" }, #endif { POLARSSL_ECP_DP_NONE, 0, 0, NULL }, }; +static ecp_group_id ecp_supported_grp_id[POLARSSL_ECP_DP_MAX]; + /* * List of supported curves and associated info */ @@ -162,7 +167,33 @@ const ecp_curve_info *ecp_curve_list( void ) } /* - * Get the curve info for the internal identifer + * List of supported curves, group ID only + */ +const ecp_group_id *ecp_grp_id_list( void ) +{ + static int init_done = 0; + + if( ! init_done ) + { + size_t i = 0; + const ecp_curve_info *curve_info; + + for( curve_info = ecp_curve_list(); + curve_info->grp_id != POLARSSL_ECP_DP_NONE; + curve_info++ ) + { + ecp_supported_grp_id[i++] = curve_info->grp_id; + } + ecp_supported_grp_id[i] = POLARSSL_ECP_DP_NONE; + + init_done = 1; + } + + return ecp_supported_grp_id; +} + +/* + * Get the curve info for the internal identifier */ const ecp_curve_info *ecp_curve_info_from_grp_id( ecp_group_id grp_id ) { diff --git a/library/ssl_cli.c b/library/ssl_cli.c index 62df857473..bdd2d9502c 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -233,19 +233,26 @@ static void ssl_write_supported_elliptic_curves_ext( ssl_context *ssl, unsigned char *p = buf; unsigned char *elliptic_curve_list = p + 6; size_t elliptic_curve_len = 0; - const ecp_curve_info *curve; - ((void) ssl); + const ecp_curve_info *info; +#if defined(POLARSSL_SSL_SET_CURVES) + const ecp_group_id *grp_id; +#endif *olen = 0; SSL_DEBUG_MSG( 3, ( "client hello, adding supported_elliptic_curves extension" ) ); - for( curve = ecp_curve_list(); - curve->grp_id != POLARSSL_ECP_DP_NONE; - curve++ ) +#if defined(POLARSSL_SSL_SET_CURVES) + for( grp_id = ssl->curve_list; *grp_id != POLARSSL_ECP_DP_NONE; grp_id++ ) { - elliptic_curve_list[elliptic_curve_len++] = curve->tls_id >> 8; - elliptic_curve_list[elliptic_curve_len++] = curve->tls_id & 0xFF; + info = ecp_curve_info_from_grp_id( *grp_id ); +#else + for( info = ecp_curve_list(); info->grp_id != POLARSSL_ECP_DP_NONE; info++ ) + { +#endif + + elliptic_curve_list[elliptic_curve_len++] = info->tls_id >> 8; + elliptic_curve_list[elliptic_curve_len++] = info->tls_id & 0xFF; } if( elliptic_curve_len == 0 ) @@ -1118,15 +1125,25 @@ static int ssl_parse_server_dh_params( ssl_context *ssl, unsigned char **p, defined(POLARSSL_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) static int ssl_check_server_ecdh_params( const ssl_context *ssl ) { - SSL_DEBUG_MSG( 2, ( "ECDH curve size: %d", - (int) ssl->handshake->ecdh_ctx.grp.nbits ) ); + const ecp_curve_info *curve_info; - if( ssl->handshake->ecdh_ctx.grp.nbits < 163 || - ssl->handshake->ecdh_ctx.grp.nbits > 521 ) + curve_info = ecp_curve_info_from_grp_id( ssl->handshake->ecdh_ctx.grp.id ); + if( curve_info == NULL ) { + SSL_DEBUG_MSG( 1, ( "Should never happen" ) ); return( -1 ); } + SSL_DEBUG_MSG( 2, ( "ECDH curve: %s", curve_info->name ) ); + +#if defined(POLARSSL_SSL_ECP_SET_CURVES) + if( ! ssl_curve_is_acceptable( ssl, ssl->handshake->ecdh_ctx.grp.id ) ) +#else + if( ssl->handshake->ecdh_ctx.grp.nbits < 163 || + ssl->handshake->ecdh_ctx.grp.nbits > 521 ) +#endif + return( -1 ); + SSL_DEBUG_ECP( 3, "ECDH: Qp", &ssl->handshake->ecdh_ctx.Qp ); return( 0 ); @@ -1160,7 +1177,7 @@ static int ssl_parse_server_ecdh_params( ssl_context *ssl, if( ssl_check_server_ecdh_params( ssl ) != 0 ) { - SSL_DEBUG_MSG( 1, ( "bad server key exchange message (ECDH length)" ) ); + SSL_DEBUG_MSG( 1, ( "bad server key exchange message (ECDHE curve)" ) ); return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); } @@ -1348,7 +1365,7 @@ static int ssl_get_ecdh_params_from_cert( ssl_context *ssl ) if( ssl_check_server_ecdh_params( ssl ) != 0 ) { - SSL_DEBUG_MSG( 1, ( "bad server certificate (ECDH length)" ) ); + SSL_DEBUG_MSG( 1, ( "bad server certificate (ECDH curve)" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE ); } @@ -1390,7 +1407,11 @@ static int ssl_parse_server_key_exchange( ssl_context *ssl ) if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_ECDH_RSA || ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_ECDH_ECDSA ) { - ssl_get_ecdh_params_from_cert( ssl ); + if( ( ret = ssl_get_ecdh_params_from_cert( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_get_ecdh_params_from_cert", ret ); + return( ret ); + } SSL_DEBUG_MSG( 2, ( "<= skip parse server key exchange" ) ); ssl->state++; diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 0abded139b..e045fdc98d 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -536,7 +536,7 @@ static int ssl_parse_supported_elliptic_curves( ssl_context *ssl, return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } - /* Don't allow our peer to make use allocated too much memory, + /* Don't allow our peer to make us allocate too much memory, * and leave room for a final 0 */ our_size = list_size / 2 + 1; if( our_size > POLARSSL_ECP_DP_MAX ) @@ -2092,10 +2092,7 @@ static int ssl_write_server_key_exchange( ssl_context *ssl ) #endif /* POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED || POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED */ -#if defined(POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ - defined(POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ - defined(POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED) - +#if defined(POLARSSL_KEY_EXCHANGE__SOME__ECDHE_ENABLED) if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_ECDHE_RSA || ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA || ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_ECDHE_PSK ) @@ -2108,16 +2105,36 @@ static int ssl_write_server_key_exchange( ssl_context *ssl ) * ECPoint public; * } ServerECDHParams; */ + const ecp_curve_info **curve; +#if defined(POLARSSL_SSL_SET_CURVES) + const ecp_group_id *gid; + + /* Match our preference list against the offered curves */ + for( gid = ssl->curve_list; *gid != POLARSSL_ECP_DP_NONE; gid++ ) + for( curve = ssl->handshake->curves; *curve != NULL; curve++ ) + if( (*curve)->grp_id == *gid ) + goto curve_matching_done; + +curve_matching_done: +#else + curve = ssl->handshake->curves; +#endif + + if( *curve == NULL ) + { + SSL_DEBUG_MSG( 1, ( "no matching curve for ECDHE" ) ); + return( POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN ); + } + + SSL_DEBUG_MSG( 2, ( "ECDHE curve: %s", (*curve)->name ) ); + if( ( ret = ecp_use_known_dp( &ssl->handshake->ecdh_ctx.grp, - ssl->handshake->curves[0]->grp_id ) ) != 0 ) + (*curve)->grp_id ) ) != 0 ) { SSL_DEBUG_RET( 1, "ecp_use_known_dp", ret ); return( ret ); } - SSL_DEBUG_MSG( 2, ( "ECDH curve size: %d", - (int) ssl->handshake->ecdh_ctx.grp.nbits ) ); - if( ( ret = ecdh_make_params( &ssl->handshake->ecdh_ctx, &len, p, SSL_MAX_CONTENT_LEN - n, ssl->f_rng, ssl->p_rng ) ) != 0 ) @@ -2134,9 +2151,7 @@ static int ssl_write_server_key_exchange( ssl_context *ssl ) SSL_DEBUG_ECP( 3, "ECDH: Q ", &ssl->handshake->ecdh_ctx.Q ); } -#endif /* POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED || - POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED || - POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ +#endif /* POLARSSL_KEY_EXCHANGE__SOME__ECDHE_ENABLED */ #if defined(POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ defined(POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ @@ -2601,10 +2616,6 @@ static int ssl_parse_client_key_exchange( ssl_context *ssl ) SSL_DEBUG_ECP( 3, "ECDH: Qp ", &ssl->handshake->ecdh_ctx.Qp ); - SSL_DEBUG_MSG( 0, ( "ECDH: id %d", ssl->handshake->ecdh_ctx.grp.id ) ); - SSL_DEBUG_ECP( 0, "ECDH: Q ", &ssl->handshake->ecdh_ctx.Q ); - SSL_DEBUG_MPI( 0, "ECDH: d ", &ssl->handshake->ecdh_ctx.d ); - if( ( ret = ecdh_calc_secret( &ssl->handshake->ecdh_ctx, &ssl->handshake->pmslen, ssl->handshake->premaster, diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 36378ef1bd..a5205836c2 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -2664,7 +2664,23 @@ int ssl_parse_certificate( ssl_context *ssl ) ssl->f_vrfy, ssl->p_vrfy ); if( ret != 0 ) + { SSL_DEBUG_RET( 1, "x509_verify_cert", ret ); + } +#if defined(POLARSSL_SSL_SET_CURVES) + else + { + pk_context *pk = &ssl->session_negotiate->peer_cert->pk; + + /* If certificate uses an EC key, make sure the curve is OK */ + if( pk_can_do( pk, POLARSSL_PK_ECKEY ) && + ! ssl_curve_is_acceptable( ssl, pk_ec( *pk )->grp.id ) ) + { + SSL_DEBUG_MSG( 1, ( "bad server certificate (EC key curve)" ) ); + ret = POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE; + } + } +#endif if( ssl->authmode != SSL_VERIFY_REQUIRED ) ret = 0; @@ -3384,6 +3400,10 @@ int ssl_init( ssl_context *ssl ) ssl->ticket_lifetime = SSL_DEFAULT_TICKET_LIFETIME; #endif +#if defined(POLARSSL_SSL_SET_CURVES) + ssl->curve_list = ecp_grp_id_list( ); +#endif + if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) return( ret ); @@ -3796,6 +3816,16 @@ int ssl_set_dh_param_ctx( ssl_context *ssl, dhm_context *dhm_ctx ) } #endif /* POLARSSL_DHM_C */ +#if defined(POLARSSL_SSL_SET_CURVES) +/* + * Set the allowed elliptic curves + */ +void ssl_set_curves( ssl_context *ssl, const ecp_group_id *curve_list ) +{ + ssl->curve_list = curve_list; +} +#endif + #if defined(POLARSSL_SSL_SERVER_NAME_INDICATION) int ssl_set_hostname( ssl_context *ssl, const char *hostname ) { @@ -4610,3 +4640,20 @@ md_type_t ssl_md_alg_from_hash( unsigned char hash ) } #endif + +#if defined(POLARSSL_SSL_SET_CURVES) +/* + * Check is a curve proposed by the peer is in our list. + * Return 1 if we're willing to use it, 0 otherwise. + */ +int ssl_curve_is_acceptable( const ssl_context *ssl, ecp_group_id grp_id ) +{ + const ecp_group_id *gid; + + for( gid = ssl->curve_list; *gid != POLARSSL_ECP_DP_NONE; gid++ ) + if( *gid == grp_id ) + return( 1 ); + + return( 0 ); +} +#endif diff --git a/programs/test/benchmark.c b/programs/test/benchmark.c index b1974fed1f..56baa58fe1 100644 --- a/programs/test/benchmark.c +++ b/programs/test/benchmark.c @@ -50,6 +50,7 @@ #include "polarssl/dhm.h" #include "polarssl/ecdsa.h" #include "polarssl/ecdh.h" +#include "polarssl/error.h" #if defined _MSC_VER && !defined snprintf #define snprintf _snprintf @@ -57,7 +58,7 @@ #define BUFSIZE 1024 #define HEADER_FORMAT " %-24s : " -#define TITLE_LEN 15 +#define TITLE_LEN 25 #if !defined(POLARSSL_TIMING_C) int main( int argc, char *argv[] ) @@ -132,7 +133,10 @@ do { \ } \ \ if( ret != 0 ) \ - printf( "FAILED\n" ); \ + { \ + polarssl_strerror( ret, ( char * )tmp, sizeof( tmp ) ); \ + printf( "FAILED: %s\n", tmp ); \ + } \ else \ printf( "%9lu " TYPE "/s\n", i / 3 ); \ } while( 0 )