fix(wpa_supplicant): fix ECDSA signature verification for PSA compatibility

- Convert DER-encoded signatures to raw format (r||s) before PSA verification
  as psa_verify_hash() expects raw format, not DER
- Infer hash algorithm from data length (SHA1/SHA256/SHA384/SHA512) instead
  of hardcoding SHA256
- Enforce DER format validation per API specification
- Update test cases to use DER format as required by the API

This fixes signature verification failures that occurred when DER-encoded
signatures were passed directly to PSA, which expects raw format.
This commit is contained in:
Sarvesh Bodakhe
2025-12-19 07:29:08 +08:00
committed by Ashish Sharma
parent 1e6621d285
commit 7684c3f86e
2 changed files with 100 additions and 6 deletions
@@ -1905,8 +1905,65 @@ int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data,
if (!wrapper) {
return -1;
}
psa_status_t status = psa_verify_hash(wrapper->key_id, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), data, len, sig, sig_len);
/* Get key attributes to extract key_bits needed for DER-to-raw conversion */
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_status_t status = psa_get_key_attributes(wrapper->key_id, &key_attributes);
if (status != PSA_SUCCESS) {
wpa_printf(MSG_ERROR, "crypto_ec_key_verify_signature: psa_get_key_attributes failed: %d", status);
psa_reset_key_attributes(&key_attributes);
return -1;
}
size_t key_bits = psa_get_key_bits(&key_attributes);
psa_reset_key_attributes(&key_attributes);
/* Determine hash algorithm from data length */
psa_algorithm_t verify_alg;
if (len == 32) {
verify_alg = PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256);
} else if (len == 48) {
verify_alg = PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_384);
} else if (len == 64) {
verify_alg = PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_512);
} else if (len == 20) {
verify_alg = PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_1);
} else {
wpa_printf(MSG_ERROR, "crypto_ec_key_verify_signature: Unsupported hash length %d", (int)len);
return -1;
}
/* Convert DER-encoded signature to raw format (r||s) for PSA */
/* PSA verify_hash expects raw format, not DER format */
/* API specification requires DER format input */
/* Raw signature length = 2 * PSA_BITS_TO_BYTES(key_bits), max 132 bytes for P-521 */
unsigned char raw_sig[132];
size_t raw_sig_len = 0;
const u8 *sig_to_verify = sig;
size_t sig_len_to_verify = sig_len;
/* Check if signature is DER format (starts with 0x30) */
if (sig_len > 0 && sig[0] == 0x30) {
/* Convert DER to raw format */
int ret = mbedtls_ecdsa_der_to_raw(key_bits, sig, sig_len,
raw_sig, sizeof(raw_sig), &raw_sig_len);
if (ret != 0) {
wpa_printf(MSG_ERROR, "crypto_ec_key_verify_signature: Failed to convert DER to raw format: %d", ret);
return -1;
}
sig_to_verify = raw_sig;
sig_len_to_verify = raw_sig_len;
} else {
/* Signature must be in DER format as per API specification */
wpa_printf(MSG_ERROR, "crypto_ec_key_verify_signature: Invalid signature format (expected DER, got 0x%02x)", sig_len > 0 ? sig[0] : 0);
return -1;
}
/* Perform signature verification */
status = psa_verify_hash(wrapper->key_id, verify_alg,
data, len, sig_to_verify, sig_len_to_verify);
if (status != PSA_SUCCESS) {
wpa_printf(MSG_ERROR, "crypto_ec_key_verify_signature: psa_verify_hash failed: %d", status);
return -1;
}
@@ -27,6 +27,11 @@
typedef struct crypto_bignum crypto_bignum;
/* Minimal structure to access key_id from crypto_ec_key wrapper (for test purposes) */
typedef struct {
psa_key_id_t key_id;
} crypto_ec_key_wrapper_test_t;
TEST_CASE("Test crypto lib bignum apis", "[wpa_crypto]")
{
set_leak_threshold(300);
@@ -831,12 +836,28 @@ TEST_CASE("Test crypto lib ecdsa apis", "[wpa_crypto]")
ret = crypto_bignum_to_bin(s, s_buf, sizeof(s_buf), 32);
TEST_ASSERT(ret == 32);
/* Construct signature as r||s */
/* Construct signature as r||s (raw format) */
memcpy(signature, r_buf, 32);
memcpy(signature + 32, s_buf, 32);
/* Convert raw signature to DER format as required by crypto_ec_key_verify_signature API */
/* Get key bits from the key object */
crypto_ec_key_wrapper_test_t *key_wrapper = (crypto_ec_key_wrapper_test_t *)eckey;
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_status_t status = psa_get_key_attributes(key_wrapper->key_id, &key_attributes);
TEST_ASSERT(status == PSA_SUCCESS);
size_t key_bits = psa_get_key_bits(&key_attributes);
psa_reset_key_attributes(&key_attributes);
TEST_ASSERT(key_bits > 0);
uint8_t der_sig[MBEDTLS_ECDSA_DER_MAX_SIG_LEN(key_bits)];
size_t der_sig_len = 0;
ret = mbedtls_ecdsa_raw_to_der(key_bits, signature, 64, der_sig, sizeof(der_sig), &der_sig_len);
TEST_ASSERT(ret == 0);
TEST_ASSERT(der_sig_len > 0);
uint8_t expected_data[64] = {[0 ... 63] = 0xA5};
ret = crypto_ec_key_verify_signature(eckey, expected_data, 64, signature, 64);
ret = crypto_ec_key_verify_signature(eckey, expected_data, 64, der_sig, der_sig_len);
TEST_ASSERT(ret == 1); /* Returns 1 on success */
ret = crypto_ec_key_verify_signature_r_s(eckey, expected_data, 64, r_buf, 32, s_buf, 32);
@@ -844,7 +865,7 @@ TEST_CASE("Test crypto lib ecdsa apis", "[wpa_crypto]")
// Negative test case
expected_data[0] = 0x5A;
ret = crypto_ec_key_verify_signature(eckey, expected_data, 64, signature, 64);
ret = crypto_ec_key_verify_signature(eckey, expected_data, 64, der_sig, der_sig_len);
TEST_ASSERT(ret == -1);
crypto_bignum_deinit(r, 1);
@@ -1339,12 +1360,28 @@ TEST_CASE("Test crypto lib ecdh apis", "[wpa_crypto]")
ret = crypto_bignum_to_bin(s, s_buf, sizeof(s_buf), 32);
TEST_ASSERT(ret == 32);
/* Construct signature as r||s */
/* Construct signature as r||s (raw format) */
memcpy(signature, r_buf, 32);
memcpy(signature + 32, s_buf, 32);
/* Convert raw signature to DER format as required by crypto_ec_key_verify_signature API */
/* Get key bits from the key object */
crypto_ec_key_wrapper_test_t *key_wrapper = (crypto_ec_key_wrapper_test_t *)key;
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_status_t status = psa_get_key_attributes(key_wrapper->key_id, &key_attributes);
TEST_ASSERT(status == PSA_SUCCESS);
size_t key_bits = psa_get_key_bits(&key_attributes);
psa_reset_key_attributes(&key_attributes);
TEST_ASSERT(key_bits > 0);
uint8_t der_sig[MBEDTLS_ECDSA_DER_MAX_SIG_LEN(key_bits)];
size_t der_sig_len = 0;
ret = mbedtls_ecdsa_raw_to_der(key_bits, signature, 64, der_sig, sizeof(der_sig), &der_sig_len);
TEST_ASSERT(ret == 0);
TEST_ASSERT(der_sig_len > 0);
/* Verify the signature */
ret = crypto_ec_key_verify_signature(key, data, 64, signature, 64);
ret = crypto_ec_key_verify_signature(key, data, 64, der_sig, der_sig_len);
TEST_ASSERT(ret == 1); /* Returns 1 on success */
/* Now test ECDH with the same key */