diff --git a/pkg/micro-ecc/psa_uecc/p192.c b/pkg/micro-ecc/psa_uecc/p192.c index 751f71464708..be859f577f5e 100644 --- a/pkg/micro-ecc/psa_uecc/p192.c +++ b/pkg/micro-ecc/psa_uecc/p192.c @@ -32,7 +32,15 @@ psa_status_t psa_generate_ecc_p192r1_key_pair( const psa_key_attributes_t *attr const struct uECC_Curve_t *curve = uECC_secp192r1(); - ret = uECC_make_key(pub_key_buffer, priv_key_buffer, curve); + /** + * Add 0x04 prefix for SEC 1 encoded uncompressed elliptic curve points. + * Micro-ECC represents public keys in SEC 1 uncompressed format without the 0x04 prefix [1]. + * PSA Crypto uses a standard SEC 1 uncompressed representation [2]. + * [1] https://github.com/kmackay/micro-ecc/blob/master/README.md#point-representation + * [2] https://arm-software.github.io/psa-api/crypto/1.1/api/keys/management.html#key-formats + */ + pub_key_buffer[0] = 0x04; + ret = uECC_make_key(pub_key_buffer+1, priv_key_buffer, curve); if (!ret) { return PSA_ERROR_GENERIC_ERROR; } @@ -90,7 +98,8 @@ psa_status_t psa_ecc_p192r1_verify_hash(const psa_key_attributes_t *attributes, int ret = 0; const struct uECC_Curve_t *curve = uECC_secp192r1(); - ret = uECC_verify(key_buffer, hash, hash_length, signature, curve); + /* Micro-ECC expects uncompressed public key without 0x04 prefix */ + ret = uECC_verify(key_buffer+1, hash, hash_length, signature, curve); if (!ret) { return PSA_ERROR_GENERIC_ERROR; } diff --git a/pkg/micro-ecc/psa_uecc/p256.c b/pkg/micro-ecc/psa_uecc/p256.c index f07357aa2803..4f1118770b34 100644 --- a/pkg/micro-ecc/psa_uecc/p256.c +++ b/pkg/micro-ecc/psa_uecc/p256.c @@ -32,7 +32,15 @@ psa_status_t psa_generate_ecc_p256r1_key_pair( const psa_key_attributes_t *attr const struct uECC_Curve_t *curve = uECC_secp256r1(); - ret = uECC_make_key(pub_key_buffer, priv_key_buffer, curve); + /** + * Add 0x04 prefix for SEC 1 encoded uncompressed elliptic curve points. + * Micro-ECC represents public keys in SEC 1 uncompressed format without the 0x04 prefix [1]. + * PSA Crypto uses a standard SEC 1 uncompressed representation [2]. + * [1] https://github.com/kmackay/micro-ecc/blob/master/README.md#point-representation + * [2] https://arm-software.github.io/psa-api/crypto/1.1/api/keys/management.html#key-formats + */ + pub_key_buffer[0] = 0x04; + ret = uECC_make_key(pub_key_buffer+1, priv_key_buffer, curve); if (!ret) { return PSA_ERROR_GENERIC_ERROR; } @@ -90,7 +98,8 @@ psa_status_t psa_ecc_p256r1_verify_hash(const psa_key_attributes_t *attributes, int ret = 0; const struct uECC_Curve_t *curve = uECC_secp256r1(); - ret = uECC_verify(key_buffer, hash, hash_length, signature, curve); + /* Micro-ECC expects uncompressed public key without 0x04 prefix */ + ret = uECC_verify(key_buffer+1, hash, hash_length, signature, curve); if (!ret) { return PSA_ERROR_GENERIC_ERROR; } diff --git a/tests/sys/psa_crypto_ecdsa/main.c b/tests/sys/psa_crypto_ecdsa/main.c index 3d402a596a6e..dbb6115fee92 100644 --- a/tests/sys/psa_crypto_ecdsa/main.c +++ b/tests/sys/psa_crypto_ecdsa/main.c @@ -23,6 +23,7 @@ #include "ztimer.h" extern psa_status_t example_ecdsa_p256(void); +extern psa_status_t test_ecdsa_p256_vectors(void); int main(void) { @@ -31,6 +32,12 @@ int main(void) psa_crypto_init(); + status = test_ecdsa_p256_vectors(); + if (status != PSA_SUCCESS) { + failed = true; + printf("ECDSA test vectors failed: %s\n", psa_status_to_humanly_readable(status)); + } + ztimer_acquire(ZTIMER_USEC); ztimer_now_t start = ztimer_now(ZTIMER_USEC); diff --git a/tests/sys/psa_crypto_ecdsa/test_ecdsa_p256_vectors.c b/tests/sys/psa_crypto_ecdsa/test_ecdsa_p256_vectors.c new file mode 100644 index 000000000000..254add9410b8 --- /dev/null +++ b/tests/sys/psa_crypto_ecdsa/test_ecdsa_p256_vectors.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2024 Lars Pfau + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Tests PSA ECDSA with test vectors + * + * @author Lars Pfau + * + * @} + */ +#include +#include + +#include "psa/crypto.h" + +/* + * RFC6979 test vector for P-256, SHA256 [1]. + * + * [1] https://www.rfc-editor.org/rfc/rfc6979#appendix-A.2.5 + */ +static const psa_algorithm_t algo = PSA_ALG_ECDSA(PSA_ALG_SHA_256); +static const psa_key_type_t type = PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1); + +static const uint8_t private_key[] = {0xC9, 0xAF, 0xA9, 0xD8, 0x45, 0xBA, 0x75, 0x16, 0x6B, 0x5C, + 0x21, 0x57, 0x67, 0xB1, 0xD6, 0x93, 0x4E, 0x50, 0xC3, 0xDB, 0x36, 0xE8, 0x9B, 0x12, 0x7B, 0x8A, + 0x62, 0x2B, 0x12, 0x0F, 0x67, 0x21}; + +static const uint8_t public_key[] = {0x04, 0x60, 0xFE, 0xD4, 0xBA, 0x25, 0x5A, 0x9D, 0x31, 0xC9, + 0x61, 0xEB, 0x74, 0xC6, 0x35, 0x6D, 0x68, 0xC0, 0x49, 0xB8, 0x92, 0x3B, 0x61, 0xFA, 0x6C, 0xE6, + 0x69, 0x62, 0x2E, 0x60, 0xF2, 0x9F, 0xB6, 0x79, 0x03, 0xFE, 0x10, 0x08, 0xB8, 0xBC, 0x99, 0xA4, + 0x1A, 0xE9, 0xE9, 0x56, 0x28, 0xBC, 0x64, 0xF2, 0xF1, 0xB2, 0x0C, 0x2D, 0x7E, 0x9F, 0x51, 0x77, + 0xA3, 0xC2, 0x94, 0xD4, 0x46, 0x22, 0x99}; + +static const uint8_t message[6] = "sample"; + +static const uint8_t signature[] = {0xEF, 0xD4, 0x8B, 0x2A, 0xAC, 0xB6, 0xA8, 0xFD, 0x11, 0x40, + 0xDD, 0x9C, 0xD4, 0x5E, 0x81, 0xD6, 0x9D, 0x2C, 0x87, 0x7B, 0x56, 0xAA, 0xF9, 0x91, 0xC3, 0x4D, + 0x0E, 0xA8, 0x4E, 0xAF, 0x37, 0x16, 0xF7, 0xCB, 0x1C, 0x94, 0x2D, 0x65, 0x7C, 0x41, 0xD4, 0x36, + 0xC7, 0xA1, 0xB6, 0xE2, 0x9F, 0x65, 0xF3, 0xE9, 0x00, 0xDB, 0xB9, 0xAF, 0xF4, 0x06, 0x4D, 0xC4, + 0xAB, 0x2F, 0x84, 0x3A, 0xCD, 0xA8}; + +/** + * @brief Verify a sample NIST P-256 signature from a message using SHA256 + * + * @return psa_status_t + */ +psa_status_t test_ecdsa_p256_vectors(void) { + psa_key_attributes_t key_attr = psa_key_attributes_init(); + psa_key_id_t key_id; + + psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_VERIFY_MESSAGE); + psa_set_key_algorithm(&key_attr, algo); + psa_set_key_bits(&key_attr, PSA_BYTES_TO_BITS(sizeof(private_key))); + psa_set_key_type(&key_attr, type); + + psa_status_t status; + status = psa_import_key(&key_attr, public_key, sizeof(public_key), &key_id); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_verify_message(key_id, algo, message, sizeof(message), signature, sizeof(signature)); + + psa_destroy_key(key_id); + + return status; +}