diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h index f357b4624..144c85256 100644 --- a/include/polarssl/ssl.h +++ b/include/polarssl/ssl.h @@ -490,7 +490,7 @@ struct _ssl_handshake_params ecdh_context ecdh_ctx; /*!< ECDH key exchange */ #endif #if defined(POLARSSL_ECDH_C) || defined(POLARSSL_ECDSA_C) - int ec_curve; /*!< Selected elliptic curve */ + const ecp_curve_info **curves; /*!< Supported elliptic curves */ #endif #if defined(POLARSSL_X509_CRT_PARSE_C) ssl_key_cert *key_cert; /*!< Own key/cert in use */ diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 9c90268c1..df7709bd4 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -501,9 +501,9 @@ static int ssl_parse_supported_elliptic_curves( ssl_context *ssl, const unsigned char *buf, size_t len ) { - size_t list_size; + size_t list_size, our_size; const unsigned char *p; - const ecp_curve_info *curve_info; + const ecp_curve_info *curve_info, **curves; list_size = ( ( buf[0] << 8 ) | ( buf[1] ) ); if( list_size + 2 != len || @@ -513,15 +513,27 @@ 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, + * and leave room for a final 0 */ + our_size = list_size / 2 + 1; + if( our_size > POLARSSL_ECP_DP_MAX ) + our_size = POLARSSL_ECP_DP_MAX; + + if( ( curves = polarssl_malloc( our_size * sizeof( *curves ) ) ) == NULL ) + return( POLARSSL_ERR_SSL_MALLOC_FAILED ); + + memset( curves, 0, our_size * sizeof( *curves ) ); + ssl->handshake->curves = curves; + p = buf + 2; - while( list_size > 0 ) + while( list_size > 0 && our_size > 1 ) { curve_info = ecp_curve_info_from_tls_id( ( p[0] << 8 ) | p[1] ); if( curve_info != NULL ) { - ssl->handshake->ec_curve = curve_info->grp_id; - return( 0 ); + *curves++ = curve_info; + our_size--; } list_size -= 2; @@ -875,6 +887,62 @@ have_ciphersuite_v2: } #endif /* POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO */ +#if defined(POLARSSL_X509_CRT_PARSE_C) +#if defined(POLARSSL_ECDSA_C) +static int ssl_key_matches_curves( pk_context *pk, + const ecp_curve_info **curves ) +{ + const ecp_curve_info **crv = curves; + ecp_group_id grp_id = pk_ec( *pk )->grp.id; + + while( *crv != NULL ) + { + if( (*crv)->grp_id == grp_id ) + return( 1 ); + crv++; + } + + return( 0 ); +} +#endif /* POLARSSL_ECDSA_C */ + +/* + * Try picking a certificate for this ciphersuite, + * return 0 on success and -1 on failure. + */ +static int ssl_pick_cert( ssl_context *ssl, + const ssl_ciphersuite_t * ciphersuite_info ) +{ + ssl_key_cert *cur; + pk_type_t pk_alg = ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info ); + + if( pk_alg == POLARSSL_PK_NONE ) + return( 0 ); + + for( cur = ssl->key_cert; cur != NULL; cur = cur->next ) + { + if( ! pk_can_do( cur->key, pk_alg ) ) + continue; + +#if defined(POLARSSL_ECDSA_C) + if( pk_alg == POLARSSL_PK_ECDSA ) + { + if( ssl_key_matches_curves( cur->key, ssl->handshake->curves ) ) + break; + } + else +#endif + break; + } + + if( cur == NULL ) + return( -1 ); + + ssl->handshake->key_cert = cur; + return( 0 ); +} +#endif /* POLARSSL_X509_CRT_PARSE_C */ + static int ssl_parse_client_hello( ssl_context *ssl ) { int ret; @@ -888,9 +956,6 @@ static int ssl_parse_client_hello( ssl_context *ssl ) int handshake_failure = 0; const int *ciphersuites; const ssl_ciphersuite_t *ciphersuite_info; -#if defined(POLARSSL_PK_C) - pk_type_t pk_alg; -#endif SSL_DEBUG_MSG( 2, ( "=> parse client hello" ) ); @@ -1298,7 +1363,7 @@ static int ssl_parse_client_hello( ssl_context *ssl ) #if defined(POLARSSL_ECDH_C) || defined(POLARSSL_ECDSA_C) if( ssl_ciphersuite_uses_ec( ciphersuite_info ) && - ssl->handshake->ec_curve == 0 ) + ssl->handshake->curves[0] == NULL ) continue; #endif @@ -1310,24 +1375,8 @@ static int ssl_parse_client_hello( ssl_context *ssl ) * - try the next ciphersuite if we don't * This must be done last since we modify the key_cert list. */ - pk_alg = ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info ); - if( pk_alg != POLARSSL_PK_NONE ) - { - ssl_key_cert *good = NULL; - ssl_key_cert *cur = ssl->key_cert; - - while( cur != NULL && good == NULL ) - { - if( pk_can_do( cur->key, pk_alg ) ) - good = cur; - cur = cur->next; - } - - if( good == NULL ) - continue; - else - ssl->handshake->key_cert = good; - } + if( ssl_pick_cert( ssl, ciphersuite_info ) != 0 ) + continue; #endif goto have_ciphersuite; @@ -1928,7 +1977,7 @@ static int ssl_write_server_key_exchange( ssl_context *ssl ) * } ServerECDHParams; */ if( ( ret = ecp_use_known_dp( &ssl->handshake->ecdh_ctx.grp, - ssl->handshake->ec_curve ) ) != 0 ) + ssl->handshake->curves[0]->grp_id ) ) != 0 ) { SSL_DEBUG_RET( 1, "ecp_use_known_dp", ret ); return( ret ); diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 5ab4a5cbe..cafdcf092 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -4145,6 +4145,10 @@ void ssl_handshake_free( ssl_handshake_params *handshake ) ecdh_free( &handshake->ecdh_ctx ); #endif +#if defined(POLARSSL_ECDH_C) || defined(POLARSSL_ECDSA_C) + polarssl_free( handshake->curves ); +#endif + memset( handshake, 0, sizeof( ssl_handshake_params ) ); }