diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h index 324612a243..a0d4694949 100644 --- a/include/mbedtls/pk.h +++ b/include/mbedtls/pk.h @@ -923,7 +923,8 @@ int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n ); * change or be removed at any time without notice. * * \note Only ECDSA keys are supported so far. Signing with the - * specified hash is the only allowed use of that key. + * specified hash & ECDH key agreement derivation operation + * are the only allowed use of that key. * * \param pk Input: the EC key to import to a PSA key. * Output: a PK context wrapping that PSA key. diff --git a/library/pk.c b/library/pk.c index 7f4d5fe949..3b42799c7d 100644 --- a/library/pk.c +++ b/library/pk.c @@ -735,8 +735,10 @@ int mbedtls_pk_wrap_as_opaque( mbedtls_pk_context *pk, /* prepare the key attributes */ psa_set_key_type( &attributes, key_type ); psa_set_key_bits( &attributes, bits ); - psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN_HASH ); + psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN_HASH | + PSA_KEY_USAGE_DERIVE); psa_set_key_algorithm( &attributes, PSA_ALG_ECDSA(hash_alg) ); + psa_set_key_enrollment_algorithm( &attributes, PSA_ALG_ECDH ); /* import private key into PSA */ if( PSA_SUCCESS != psa_import_key( &attributes, d, d_len, key ) ) diff --git a/library/ssl_misc.h b/library/ssl_misc.h index 193f310c30..254627f5ce 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -644,8 +644,9 @@ struct mbedtls_ssl_handshake_params #if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3) psa_key_type_t ecdh_psa_type; - uint16_t ecdh_bits; + size_t ecdh_bits; mbedtls_svc_key_id_t ecdh_psa_privkey; + uint8_t ecdh_psa_privkey_is_external; unsigned char ecdh_psa_peerkey[MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH]; size_t ecdh_psa_peerkey_len; #endif /* MBEDTLS_USE_PSA_CRYPTO || MBEDTLS_SSL_PROTO_TLS1_3 */ diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 94cb77621b..32b9799429 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -3204,7 +3204,8 @@ void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ) #if defined(MBEDTLS_ECDH_C) && \ ( defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3) ) - psa_destroy_key( handshake->ecdh_psa_privkey ); + if( handshake->ecdh_psa_privkey_is_external == 0 ) + psa_destroy_key( handshake->ecdh_psa_privkey ); #endif /* MBEDTLS_ECDH_C && MBEDTLS_USE_PSA_CRYPTO */ #if defined(MBEDTLS_SSL_PROTO_TLS1_3) diff --git a/library/ssl_tls12_client.c b/library/ssl_tls12_client.c index 734d3a2e97..7771d38c1d 100644 --- a/library/ssl_tls12_client.c +++ b/library/ssl_tls12_client.c @@ -1861,9 +1861,7 @@ static int ssl_parse_server_ecdh_params_psa( mbedtls_ssl_context *ssl, { return( MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE ); } - if( ecdh_bits > 0xffff ) - return( MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER ); - handshake->ecdh_bits = (uint16_t) ecdh_bits; + handshake->ecdh_bits = ecdh_bits; /* Keep a copy of the peer's public key */ ecpoint_len = *(*p)++; diff --git a/library/ssl_tls12_server.c b/library/ssl_tls12_server.c index 486632ee8e..9ecfdd20a1 100644 --- a/library/ssl_tls12_server.c +++ b/library/ssl_tls12_server.c @@ -2848,7 +2848,102 @@ static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) } #endif /* MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED */ -#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ +#if defined(MBEDTLS_USE_PSA_CRYPTO) && \ + ( defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) ) +static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + unsigned char buf[ + PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS)]; + psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; + size_t ecdh_bits = 0; + size_t key_len; + mbedtls_pk_context *pk; + mbedtls_ecp_keypair *key; + + pk = mbedtls_ssl_own_key( ssl ); + + if( pk == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + switch( mbedtls_pk_get_type( pk ) ) + { + case MBEDTLS_PK_OPAQUE: + if( ! mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) ) + return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH ); + + ssl->handshake->ecdh_psa_privkey = + *( (mbedtls_svc_key_id_t*) pk->pk_ctx ); + + /* Key should not be destroyed in the TLS library */ + ssl->handshake->ecdh_psa_privkey_is_external = 1; + + status = psa_get_key_attributes( ssl->handshake->ecdh_psa_privkey, + &key_attributes ); + if( status != PSA_SUCCESS) + { + ssl->handshake->ecdh_psa_privkey = MBEDTLS_SVC_KEY_ID_INIT; + return( psa_ssl_status_to_mbedtls( status ) ); + } + + ssl->handshake->ecdh_psa_type = psa_get_key_type( &key_attributes ); + ssl->handshake->ecdh_bits = psa_get_key_bits( &key_attributes ); + + psa_reset_key_attributes( &key_attributes ); + + ret = 0; + break; + case MBEDTLS_PK_ECKEY: + case MBEDTLS_PK_ECKEY_DH: + case MBEDTLS_PK_ECDSA: + key = mbedtls_pk_ec( *pk ); + if( key == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* Convert EC group to PSA key type. */ + if( ( ssl->handshake->ecdh_psa_type = + mbedtls_ecc_group_to_psa( key->grp.id, + &ecdh_bits ) ) == 0 ) + { + return( MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE ); + } + + ssl->handshake->ecdh_bits = ecdh_bits; + + key_attributes = psa_key_attributes_init(); + psa_set_key_usage_flags( &key_attributes, PSA_KEY_USAGE_DERIVE ); + psa_set_key_algorithm( &key_attributes, PSA_ALG_ECDH ); + psa_set_key_type( &key_attributes, + PSA_KEY_TYPE_ECC_KEY_PAIR( ssl->handshake->ecdh_psa_type ) ); + psa_set_key_bits( &key_attributes, ssl->handshake->ecdh_bits ); + + key_len = PSA_BITS_TO_BYTES( key->grp.pbits ); + ret = mbedtls_ecp_write_key( key, buf, key_len ); + if( ret != 0 ) + goto cleanup; + + status = psa_import_key( &key_attributes, buf, key_len, + &ssl->handshake->ecdh_psa_privkey ); + if( status != PSA_SUCCESS ) + { + ret = psa_ssl_status_to_mbedtls( status ); + goto cleanup; + } + + ret = 0; + break; + default: + ret = MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH; + } + +cleanup: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + + return( ret ); +} +#elif defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl ) { @@ -3085,12 +3180,12 @@ curve_matching_done: handshake->ecdh_psa_type = mbedtls_psa_parse_tls_ecc_group( (*curve)->tls_id, &ecdh_bits ); - if( handshake->ecdh_psa_type == 0 || ecdh_bits > 0xffff ) + if( handshake->ecdh_psa_type == 0 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "Invalid ecc group parse." ) ); return( MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER ); } - handshake->ecdh_bits = (uint16_t) ecdh_bits; + handshake->ecdh_bits = ecdh_bits; key_attributes = psa_key_attributes_init(); psa_set_key_usage_flags( &key_attributes, PSA_KEY_USAGE_DERIVE ); @@ -3832,9 +3927,13 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl ) #endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */ #if defined(MBEDTLS_USE_PSA_CRYPTO) && \ ( defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ - defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) ) + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) ) if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA || - ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ) + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA ) { size_t data_len = (size_t)( *p++ ); size_t buf_len = (size_t)( end - p ); @@ -3872,25 +3971,31 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl ) { ret = psa_ssl_status_to_mbedtls( status ); MBEDTLS_SSL_DEBUG_RET( 1, "psa_raw_key_agreement", ret ); - (void) psa_destroy_key( handshake->ecdh_psa_privkey ); + if( handshake->ecdh_psa_privkey_is_external == 0 ) + (void) psa_destroy_key( handshake->ecdh_psa_privkey ); handshake->ecdh_psa_privkey = MBEDTLS_SVC_KEY_ID_INIT; return( ret ); } - status = psa_destroy_key( handshake->ecdh_psa_privkey ); - - if( status != PSA_SUCCESS ) + if( handshake->ecdh_psa_privkey_is_external == 0 ) { - ret = psa_ssl_status_to_mbedtls( status ); - MBEDTLS_SSL_DEBUG_RET( 1, "psa_destroy_key", ret ); - return( ret ); + status = psa_destroy_key( handshake->ecdh_psa_privkey ); + + if( status != PSA_SUCCESS ) + { + ret = psa_ssl_status_to_mbedtls( status ); + MBEDTLS_SSL_DEBUG_RET( 1, "psa_destroy_key", ret ); + return( ret ); + } } handshake->ecdh_psa_privkey = MBEDTLS_SVC_KEY_ID_INIT; } else #endif /* MBEDTLS_USE_PSA_CRYPTO && ( MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || - MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED ) */ + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED ) */ #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index a9b9b03c10..8e1112df2f 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -229,9 +229,7 @@ static int ssl_tls13_generate_and_write_ecdh_key_exchange( mbedtls_psa_parse_tls_ecc_group( named_group, &ecdh_bits ) ) == 0 ) return( MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE ); - if( ecdh_bits > 0xffff ) - return( MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER ); - ssl->handshake->ecdh_bits = (uint16_t) ecdh_bits; + ssl->handshake->ecdh_bits = ecdh_bits; key_attributes = psa_key_attributes_init(); psa_set_key_usage_flags( &key_attributes, PSA_KEY_USAGE_DERIVE ); diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 71a3904c2d..70dac3fc0b 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -1583,6 +1583,24 @@ run_test "Opaque key for server authentication" \ -S "error" \ -C "error" +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2 +requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_enabled MBEDTLS_X509_CRT_PARSE_C +requires_config_enabled MBEDTLS_ECDSA_C +requires_config_enabled MBEDTLS_SHA256_C +run_test "Opaque key for server authentication (ECDH-)" \ + "$P_SRV force_version=tls12 auth_mode=required key_opaque=1\ + crt_file=data_files/server5.ku-ka.crt\ + key_file=data_files/server5.key" \ + "$P_CLI" \ + 0 \ + -c "Verifying peer X.509 certificate... ok" \ + -c "Ciphersuite is TLS-ECDH-" \ + -s "key types: Opaque, none" \ + -s "Ciphersuite is TLS-ECDH-" \ + -S "error" \ + -C "error" + # Test using an opaque private key for client/server authentication requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2 requires_config_enabled MBEDTLS_USE_PSA_CRYPTO