diff --git a/library/ssl_tls13_invasive.h b/library/ssl_tls13_invasive.h index aa35784010..a025dbee3d 100644 --- a/library/ssl_tls13_invasive.h +++ b/library/ssl_tls13_invasive.h @@ -28,6 +28,37 @@ #if defined(MBEDTLS_PSA_CRYPTO_C) +/** + * \brief Take the input keying material \p ikm and extract from it a + * fixed-length pseudorandom key \p prk. + * + * \param alg The HMAC algorithm to use + * (\c #PSA_ALG_HMAC( PSA_ALG_XXX ) value such that + * PSA_ALG_XXX is a hash algorithm and + * #PSA_ALG_IS_HMAC(\p alg) is true). + * \param salt An optional salt value (a non-secret random value); + * if the salt is not provided, a string of all zeros + * of the length of the hash provided by \p alg is used + * as the salt. + * \param salt_len The length in bytes of the optional \p salt. + * \param ikm The input keying material. + * \param ikm_len The length in bytes of \p ikm. + * \param[out] prk A pseudorandom key of \p prk_len bytes. + * \param prk_size Size of the \p prk buffer in bytes. + * \param[out] prk_len On success, the length in bytes of the + * pseudorandom key in \p prk. + * + * \return 0 on success. + * \return #PSA_ERROR_INVALID_ARGUMENT when the parameters are invalid. + * \return An PSA_ERROR_* error for errors returned from the underlying + * PSA layer. + */ +psa_status_t mbedtls_psa_hkdf_extract( psa_algorithm_t alg, + const unsigned char *salt, size_t salt_len, + const unsigned char *ikm, size_t ikm_len, + unsigned char *prk, size_t prk_size, + size_t *prk_len ); + /** * \brief Expand the supplied \p prk into several additional pseudorandom * keys, which is the output of the HKDF. diff --git a/library/ssl_tls13_keys.c b/library/ssl_tls13_keys.c index 10b3b7e1a7..a5af5900ba 100644 --- a/library/ssl_tls13_keys.c +++ b/library/ssl_tls13_keys.c @@ -138,6 +138,59 @@ static void ssl_tls13_hkdf_encode_label( #if defined( MBEDTLS_TEST_HOOKS ) +MBEDTLS_STATIC_TESTABLE +psa_status_t mbedtls_psa_hkdf_extract( psa_algorithm_t alg, + const unsigned char *salt, size_t salt_len, + const unsigned char *ikm, size_t ikm_len, + unsigned char *prk, size_t prk_size, + size_t *prk_len ) +{ + unsigned char null_salt[PSA_MAC_MAX_SIZE] = { '\0' }; + mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t destroy_status = PSA_ERROR_CORRUPTION_DETECTED; + + if( salt == NULL || salt_len == 0 ) + { + size_t hash_len; + + if( salt_len != 0 ) + { + return( PSA_ERROR_INVALID_ARGUMENT ); + } + + hash_len = PSA_HASH_LENGTH( alg ); + + if( hash_len == 0 ) + { + return( PSA_ERROR_INVALID_ARGUMENT ); + } + + /* salt_len <= sizeof( salt ) because + PSA_HASH_LENGTH( alg ) <= PSA_MAC_MAX_SIZE. */ + salt = null_salt; + salt_len = hash_len; + } + + psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN_MESSAGE ); + psa_set_key_algorithm( &attributes, alg ); + psa_set_key_type( &attributes, PSA_KEY_TYPE_HMAC ); + + status = psa_import_key( &attributes, salt, salt_len, &key ); + if( status != PSA_SUCCESS ) + { + goto cleanup; + } + + status = psa_mac_compute( key, alg, ikm, ikm_len, prk, prk_size, prk_len ); + +cleanup: + destroy_status = psa_destroy_key( key ); + + return( ( status == PSA_SUCCESS ) ? destroy_status : status ); +} + MBEDTLS_STATIC_TESTABLE psa_status_t mbedtls_psa_hkdf_expand( psa_algorithm_t alg, const unsigned char *prk, size_t prk_len, diff --git a/tests/suites/test_suite_hkdf.function b/tests/suites/test_suite_hkdf.function index feb17174e5..1ad6f3d4f3 100644 --- a/tests/suites/test_suite_hkdf.function +++ b/tests/suites/test_suite_hkdf.function @@ -30,71 +30,57 @@ void test_hkdf( int md_alg, data_t *ikm, data_t *salt, data_t *info, /* END_CASE */ /* BEGIN_CASE */ -void test_hkdf_extract( int md_alg, char *hex_ikm_string, - char *hex_salt_string, char *hex_prk_string ) +void test_hkdf_extract( int md_alg, + data_t *ikm, + data_t *salt, + data_t *prk ) { int ret; - unsigned char *ikm = NULL; - unsigned char *salt = NULL; - unsigned char *prk = NULL; unsigned char *output_prk = NULL; - size_t ikm_len, salt_len, prk_len, output_prk_len; + size_t output_prk_len; const mbedtls_md_info_t *md = mbedtls_md_info_from_type( md_alg ); TEST_ASSERT( md != NULL ); output_prk_len = mbedtls_md_get_size( md ); - output_prk = mbedtls_calloc( 1, output_prk_len ); + ASSERT_ALLOC( output_prk, output_prk_len ); - ikm = mbedtls_test_unhexify_alloc( hex_ikm_string, &ikm_len ); - salt = mbedtls_test_unhexify_alloc( hex_salt_string, &salt_len ); - prk = mbedtls_test_unhexify_alloc( hex_prk_string, &prk_len ); - - ret = mbedtls_hkdf_extract( md, salt, salt_len, ikm, ikm_len, output_prk ); + ret = mbedtls_hkdf_extract( md, salt->x, salt->len, + ikm->x, ikm->len, output_prk ); TEST_ASSERT( ret == 0 ); - ASSERT_COMPARE( output_prk, output_prk_len, prk, prk_len ); + ASSERT_COMPARE( output_prk, output_prk_len, prk->x, prk->len ); exit: - mbedtls_free(ikm); - mbedtls_free(salt); - mbedtls_free(prk); mbedtls_free(output_prk); } /* END_CASE */ /* BEGIN_CASE */ -void test_hkdf_expand( int md_alg, char *hex_info_string, - char *hex_prk_string, char *hex_okm_string ) +void test_hkdf_expand( int md_alg, + data_t *info, + data_t *prk, + data_t *okm ) { enum { OKM_LEN = 1024 }; int ret; - unsigned char *info = NULL; - unsigned char *prk = NULL; - unsigned char *okm = NULL; unsigned char *output_okm = NULL; - size_t info_len, prk_len, okm_len; const mbedtls_md_info_t *md = mbedtls_md_info_from_type( md_alg ); TEST_ASSERT( md != NULL ); ASSERT_ALLOC( output_okm, OKM_LEN ); - prk = mbedtls_test_unhexify_alloc( hex_prk_string, &prk_len ); - info = mbedtls_test_unhexify_alloc( hex_info_string, &info_len ); - okm = mbedtls_test_unhexify_alloc( hex_okm_string, &okm_len ); - TEST_ASSERT( prk_len == mbedtls_md_get_size( md ) ); - TEST_ASSERT( okm_len < OKM_LEN ); + TEST_ASSERT( prk->len == mbedtls_md_get_size( md ) ); + TEST_ASSERT( okm->len < OKM_LEN ); - ret = mbedtls_hkdf_expand( md, prk, prk_len, info, info_len, + ret = mbedtls_hkdf_expand( md, prk->x, prk->len, + info->x, info->len, output_okm, OKM_LEN ); TEST_ASSERT( ret == 0 ); - ASSERT_COMPARE( output_okm, okm_len, okm, okm_len ); + ASSERT_COMPARE( output_okm, okm->len, okm->x, okm->len ); exit: - mbedtls_free(info); - mbedtls_free(prk); - mbedtls_free(okm); mbedtls_free(output_okm); } /* END_CASE */ @@ -113,7 +99,7 @@ void test_hkdf_extract_ret( int hash_len, int ret ) fake_md_info.type = MBEDTLS_MD_NONE; fake_md_info.size = hash_len; - prk = mbedtls_calloc( MBEDTLS_MD_MAX_SIZE, 1 ); + ASSERT_ALLOC( prk, MBEDTLS_MD_MAX_SIZE); salt_len = 0; ikm_len = 0; diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index eb1b8f44e8..0c6e3133ef 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -4392,6 +4392,37 @@ SSL TLS 1.3 Key schedule: Secret evolution #3 # Handshake secret to Master Secret ssl_tls13_key_evolution:MBEDTLS_MD_SHA256:"fb9fc80689b3a5d02c33243bf69a1b1b20705588a794304a6e7120155edf149a":"":"7f2882bb9b9a46265941653e9c2f19067118151e21d12e57a7b6aca1f8150c8d" +SSL TLS 1.3 Key schedule: HKDF RFC5869 Test Vector #1 Extract +depends_on:PSA_WANT_ALG_SHA_256 +psa_hkdf_extract:PSA_ALG_HMAC(PSA_ALG_SHA_256):"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":"000102030405060708090a0b0c":"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5" + +SSL TLS 1.3 Key schedule: HKDF RFC5869 Test Vector #2 Extract +depends_on:PSA_WANT_ALG_SHA_256 +psa_hkdf_extract:PSA_ALG_HMAC(PSA_ALG_SHA_256):"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f":"606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf":"06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244" + +SSL TLS 1.3 Key schedule: HKDF RFC5869 Test Vector #3 Extract +depends_on:PSA_WANT_ALG_SHA_256 +psa_hkdf_extract:PSA_ALG_HMAC(PSA_ALG_SHA_256):"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":"":"19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04" + +SSL TLS 1.3 Key schedule: HKDF RFC5869 Test Vector #4 Extract +depends_on:PSA_WANT_ALG_SHA_1 +psa_hkdf_extract:PSA_ALG_HMAC(PSA_ALG_SHA_1):"0b0b0b0b0b0b0b0b0b0b0b":"000102030405060708090a0b0c":"9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243" + +SSL TLS 1.3 Key schedule: HKDF RFC5869 Test Vector #5 Extract +depends_on:PSA_WANT_ALG_SHA_1 +psa_hkdf_extract:PSA_ALG_HMAC(PSA_ALG_SHA_1):"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f":"606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf":"8adae09a2a307059478d309b26c4115a224cfaf6" + +SSL TLS 1.3 Key schedule: HKDF RFC5869 Test Vector #6 Extract +depends_on:PSA_WANT_ALG_SHA_1 +psa_hkdf_extract:PSA_ALG_HMAC(PSA_ALG_SHA_1):"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":"":"da8c8a73c7fa77288ec6f5e7c297786aa0d32d01" + +SSL TLS 1.3 Key schedule: HKDF RFC5869 Test Vector #7 Extract +depends_on:PSA_WANT_ALG_SHA_1 +psa_hkdf_extract:PSA_ALG_HMAC(PSA_ALG_SHA_1):"0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c":"":"2adccada18779e7c2077ad2eb19d3f3e731385dd" + +SSL TLS 1.3 Key schedule: HKDF extract fails with wrong hash alg +psa_hkdf_extract_ret:0:PSA_ERROR_INVALID_ARGUMENT + SSL TLS 1.3 Key schedule: HKDF RFC5869 Test Vector #1 Expand depends_on:PSA_WANT_ALG_SHA_256 psa_hkdf_expand:PSA_ALG_HMAC(PSA_ALG_SHA_256):"f0f1f2f3f4f5f6f7f8f9":"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5":"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865" diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 67f4d6ec1f..855cfc77a7 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -3886,35 +3886,84 @@ exit: /* END_CASE */ /* BEGIN_CASE depends_on:MBEDTLS_TEST_HOOKS:MBEDTLS_SSL_PROTO_TLS1_3 */ -void psa_hkdf_expand( int alg, char *hex_info_string, - char *hex_prk_string, char *hex_okm_string ) +void psa_hkdf_extract( int alg, + data_t *ikm, + data_t *salt, + data_t *prk ) +{ + unsigned char *output_prk = NULL; + size_t output_prk_size, output_prk_len; + + PSA_INIT( ); + + output_prk_size = PSA_HASH_LENGTH( alg ); + ASSERT_ALLOC( output_prk, output_prk_size ); + + PSA_ASSERT( mbedtls_psa_hkdf_extract( alg, salt->x, salt->len, + ikm->x, ikm->len, + output_prk, output_prk_size, + &output_prk_len ) ); + + ASSERT_COMPARE( output_prk, output_prk_len, prk->x, prk->len ); + +exit: + mbedtls_free( output_prk ); + + PSA_DONE( ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_TEST_HOOKS:MBEDTLS_SSL_PROTO_TLS1_3 */ +void psa_hkdf_extract_ret( int alg, int ret ) +{ + int output_ret; + unsigned char *salt = NULL; + unsigned char *ikm = NULL; + unsigned char *prk = NULL; + size_t salt_len, ikm_len, prk_len; + + PSA_INIT( ); + + ASSERT_ALLOC( prk, PSA_MAC_MAX_SIZE); + salt_len = 0; + ikm_len = 0; + prk_len = 0; + + output_ret = mbedtls_psa_hkdf_extract( alg, salt, salt_len, + ikm, ikm_len, + prk, PSA_MAC_MAX_SIZE, &prk_len ); + TEST_ASSERT( output_ret == ret ); + TEST_ASSERT( prk_len == 0 ); + +exit: + mbedtls_free( prk ); + + PSA_DONE( ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_TEST_HOOKS:MBEDTLS_SSL_PROTO_TLS1_3 */ +void psa_hkdf_expand( int alg, + data_t *info, + data_t *prk, + data_t *okm ) { enum { OKM_LEN = 1024 }; - unsigned char *info = NULL; - unsigned char *prk = NULL; - unsigned char *okm = NULL; unsigned char *output_okm = NULL; - size_t info_len, prk_len, okm_len; PSA_INIT( ); ASSERT_ALLOC( output_okm, OKM_LEN ); + TEST_ASSERT( prk->len == PSA_HASH_LENGTH( alg ) ); + TEST_ASSERT( okm->len < OKM_LEN ); - prk = mbedtls_test_unhexify_alloc( hex_prk_string, &prk_len ); - info = mbedtls_test_unhexify_alloc( hex_info_string, &info_len ); - okm = mbedtls_test_unhexify_alloc( hex_okm_string, &okm_len ); - TEST_ASSERT( prk_len == PSA_HASH_LENGTH( alg ) ); - TEST_ASSERT( okm_len < OKM_LEN ); - - PSA_ASSERT( mbedtls_psa_hkdf_expand( alg, prk, prk_len, info, info_len, + PSA_ASSERT( mbedtls_psa_hkdf_expand( alg, prk->x, prk->len, + info->x, info->len, output_okm, OKM_LEN ) ); - ASSERT_COMPARE( output_okm, okm_len, okm, okm_len ); + ASSERT_COMPARE( output_okm, okm->len, okm->x, okm->len ); exit: - mbedtls_free( info ); - mbedtls_free( prk ); - mbedtls_free( okm ); mbedtls_free( output_okm ); PSA_DONE( );