From a96f8d7da6e985f1a31b5983e6a4882e11c971d7 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Fri, 21 Aug 2026 15:39:50 -0700 Subject: [PATCH] Fix TLS 1.2 PRF KDFs to pass a MAC algorithm id to wc_PRF_TLS --- src/psa_key_derivation.c | 30 ++++++++++++-- test/psa_server/psa_api_test.c | 75 +++++++++++++++++++++++++++++++++- 2 files changed, 99 insertions(+), 6 deletions(-) diff --git a/src/psa_key_derivation.c b/src/psa_key_derivation.c index d119b1c..4dc83fc 100644 --- a/src/psa_key_derivation.c +++ b/src/psa_key_derivation.c @@ -222,6 +222,24 @@ static int wolfpsa_hash_type_from_alg(psa_algorithm_t alg) } } +#if defined(WOLFSSL_HAVE_PRF) && !defined(NO_HMAC) +/* wc_PRF_TLS wants a wc_MACAlgorithm id and promotes ids below sha256_mac to + * SHA-256, so only map SHA-256/384/512; others return no_mac (caller rejects). */ +static int wolfpsa_prf_mac_from_alg(psa_algorithm_t alg) +{ + switch (wolfpsa_hash_type_from_alg(alg)) { + case WC_HASH_TYPE_SHA256: + return sha256_mac; + case WC_HASH_TYPE_SHA384: + return sha384_mac; + case WC_HASH_TYPE_SHA512: + return sha512_mac; + default: + return no_mac; + } +} +#endif + static psa_status_t wolfpsa_kdf_require_output(wolfpsa_kdf_ctx_t *ctx, size_t output_length) { @@ -962,9 +980,10 @@ static psa_status_t wolfpsa_kdf_tls12_prf(wolfpsa_kdf_ctx_t *ctx, return PSA_ERROR_NOT_SUPPORTED; #else int hash_type = wolfpsa_hash_type_from_alg(ctx->alg); + int prf_mac = wolfpsa_prf_mac_from_alg(ctx->alg); int ret; - if (hash_type == WC_HASH_TYPE_NONE) { + if (hash_type == WC_HASH_TYPE_NONE || prf_mac == no_mac) { return PSA_ERROR_NOT_SUPPORTED; } if ((wolfpsa_check_word32_length(output_length) != PSA_SUCCESS) || @@ -977,7 +996,8 @@ static psa_status_t wolfpsa_kdf_tls12_prf(wolfpsa_kdf_ctx_t *ctx, ctx->secret, (word32)ctx->secret_length, ctx->label, (word32)ctx->label_length, ctx->seed, (word32)ctx->seed_length, - 1, hash_type, NULL, wolfPSA_GetDefaultDevID()); + 1, prf_mac, NULL, + wolfPSA_GetDefaultDevID()); if (ret != 0) { return wc_error_to_psa_status(ret); } @@ -996,6 +1016,7 @@ static psa_status_t wolfpsa_kdf_tls12_psk_to_ms(wolfpsa_kdf_ctx_t *ctx, return PSA_ERROR_NOT_SUPPORTED; #else int hash_type = wolfpsa_hash_type_from_alg(ctx->alg); + int prf_mac = wolfpsa_prf_mac_from_alg(ctx->alg); size_t other_secret_length; const uint8_t *other_secret; uint8_t *premaster = NULL; @@ -1003,7 +1024,7 @@ static psa_status_t wolfpsa_kdf_tls12_psk_to_ms(wolfpsa_kdf_ctx_t *ctx, psa_status_t status; int ret; - if (hash_type == WC_HASH_TYPE_NONE) { + if (hash_type == WC_HASH_TYPE_NONE || prf_mac == no_mac) { return PSA_ERROR_NOT_SUPPORTED; } if ((ctx->steps_set & WOLFPSA_KDF_STEP_OTHER_SECRET) == 0) { @@ -1043,7 +1064,8 @@ static psa_status_t wolfpsa_kdf_tls12_psk_to_ms(wolfpsa_kdf_ctx_t *ctx, premaster, (word32)premaster_len, (const byte *)"master secret", 13u, ctx->seed, (word32)ctx->seed_length, - 1, hash_type, NULL, wolfPSA_GetDefaultDevID()); + 1, prf_mac, NULL, + wolfPSA_GetDefaultDevID()); if (ret != 0) { status = wc_error_to_psa_status(ret); } diff --git a/test/psa_server/psa_api_test.c b/test/psa_server/psa_api_test.c index 70a0bc5..76b236c 100644 --- a/test/psa_server/psa_api_test.c +++ b/test/psa_server/psa_api_test.c @@ -7835,7 +7835,7 @@ static int test_kdf_tls12_psk_to_ms_rfc4279_order(void) premaster, (word32)sizeof(premaster), (const byte*)"master secret", 13u, seed, (word32)seed_len, - 1, WC_HASH_TYPE_SHA256, NULL, INVALID_DEVID); + 1, sha256_mac, NULL, INVALID_DEVID); if (ret != 0) { printf("FAIL: wc_PRF_TLS(TLS12_PSK_TO_MS reference) (%d)\n", ret); return TEST_FAIL; @@ -7905,7 +7905,7 @@ static int test_kdf_tls12_psk_to_ms_plain_psk_optional_other_secret(void) premaster, (word32)sizeof(premaster), (const byte*)"master secret", 13u, seed, (word32)seed_len, - 1, WC_HASH_TYPE_SHA256, NULL, INVALID_DEVID); + 1, sha256_mac, NULL, INVALID_DEVID); if (ret != 0) { printf("FAIL: wc_PRF_TLS(TLS12_PSK_TO_MS plain PSK reference) (%d)\n", ret); return TEST_FAIL; @@ -8671,6 +8671,72 @@ static int test_hkdf_extract_truncated_output(void) return TEST_OK; } +static int test_tls12_prf(void) +{ + /* PSA_ALG_TLS12_PRF output must match a direct wc_PRF_TLS reference using + * the correct MAC-algorithm id (sha256_mac). Regression for passing a + * WC_HASH_TYPE_* value to wc_PRF_TLS: WC_HASH_TYPE_SHA256 aliases + * sha512_mac, so the PRF returned HASH_TYPE_E on SHA-512-less builds and + * the wrong digest otherwise. */ +#if !defined(WOLFSSL_HAVE_PRF) || defined(NO_HMAC) || defined(NO_SHA256) + return TEST_SKIPPED; +#else + static const uint8_t secret[] = "tls12 prf secret material"; + static const uint8_t label[] = "test label"; + static const uint8_t seed[] = "prf test seed bytes"; + uint8_t ref[40]; + uint8_t out[40]; + psa_key_derivation_operation_t op; + psa_status_t st; + int ret; + + ret = wc_PRF_TLS(ref, (word32)sizeof(ref), + secret, (word32)(sizeof(secret) - 1u), + label, (word32)(sizeof(label) - 1u), + seed, (word32)(sizeof(seed) - 1u), + 1, sha256_mac, NULL, INVALID_DEVID); + if (ret != 0) { + printf("FAIL: wc_PRF_TLS(sha256_mac) reference (%d)\n", ret); + return TEST_FAIL; + } + + memset(&op, 0, sizeof(op)); + st = psa_key_derivation_setup(&op, PSA_ALG_TLS12_PRF(PSA_ALG_SHA_256)); + if (check_status(st, "setup(TLS12_PRF)") != TEST_OK) + return TEST_FAIL; + st = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_SECRET, + secret, sizeof(secret) - 1u); + if (check_status(st, "input secret(TLS12_PRF)") != TEST_OK) { + psa_key_derivation_abort(&op); + return TEST_FAIL; + } + st = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_LABEL, + label, sizeof(label) - 1u); + if (check_status(st, "input label(TLS12_PRF)") != TEST_OK) { + psa_key_derivation_abort(&op); + return TEST_FAIL; + } + st = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_SEED, + seed, sizeof(seed) - 1u); + if (check_status(st, "input seed(TLS12_PRF)") != TEST_OK) { + psa_key_derivation_abort(&op); + return TEST_FAIL; + } + st = psa_key_derivation_output_bytes(&op, out, sizeof(out)); + if (check_status(st, "output(TLS12_PRF)") != TEST_OK) { + psa_key_derivation_abort(&op); + return TEST_FAIL; + } + (void)psa_key_derivation_abort(&op); + + if (check_buf_eq("TLS12_PRF matches wc_PRF_TLS(sha256_mac)", + out, ref, sizeof(out)) != TEST_OK) + return TEST_FAIL; + + return TEST_OK; +#endif +} + int main(int argc, char** argv) { psa_status_t st; @@ -9303,6 +9369,11 @@ int main(int argc, char** argv) return TEST_FAIL; } } + if (only == NULL || strcmp(only, "tls12_prf") == 0) { + if (run_named_test("tls12_prf", test_tls12_prf) == TEST_FAIL) { + return TEST_FAIL; + } + } printf("PSA API test: OK (passed=%d skipped=%d)\n", tests_passed, tests_skipped);