mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50:34 +03:00
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:
committed by
Ashish Sharma
parent
1e6621d285
commit
7684c3f86e
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user