Crypto: Rework the psa_sign_verify_hash_test()
Add the option to run both P-256 and P-384 tests. Also add
a test which exercise directly only the verification part
Signed-off-by: Antonio de Angelis <antonio.deangelis@arm.com>
Change-Id: I2ebb75e0adb40e49d575b0b11bf7eb7da9d9861c
diff --git a/tests_reg/test/secure_fw/suites/crypto/crypto_tests_common.c b/tests_reg/test/secure_fw/suites/crypto/crypto_tests_common.c
index 8b66d7a..a7f31ac 100644
--- a/tests_reg/test/secure_fw/suites/crypto/crypto_tests_common.c
+++ b/tests_reg/test/secure_fw/suites/crypto/crypto_tests_common.c
@@ -1,12 +1,14 @@
/*
- * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2025, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
-#include <string.h>
+#include <assert.h>
#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
#include "crypto_tests_common.h"
void psa_key_interface_test(const psa_key_type_t key_type,
@@ -3144,7 +3146,64 @@
return;
}
-void psa_sign_verify_hash_test(psa_algorithm_t alg,
+/* Structure containing the ECDSA key pairs used by the psa_sign_verify_hash_test() in particular */
+static const struct {
+ const char *priv;
+ const char *pub;
+ size_t priv_sz;
+} ecdsa_keys[2] = {
+ {
+ .priv_sz = 32,
+ .priv = "ed8faa23e28b1f51634f8ec9dc24920f3da17b476838e30d104a6da72d48a418",
+ .pub = "0441c6fcc5a4bb7045a7b25e50b32ed02a8da88e1b34c27157385c45abf2517b175ac505a99e4b7dddd7bfbb4551927d33338b1b705afd2bf27aa4bd3750ed349f"
+ },
+ {
+ .priv_sz = 48,
+ .priv = "ced92158aa56db2bc265e12530e80cefe1bebb1d3647d678600c149af60eab5e8c43a40f60c71044300f6da5d6cb39e7",
+ .pub = "048c98e1238fd6cec70df45cad0e6e3c3653da25202cbeed63d972a5030bef5bbf091e28fae781c1d73271d87bf7520c5f891dc89a016cefb7818d3662ea421bc402c55dcc7b5a8dff3020f2d554b5bf70e11baa975a7d66c4c4f1c0ef58604e8d"
+ }
+};
+
+/* Helper function to convert from string representation to binary */
+static uint8_t char_to_uint8_t(char c)
+{
+ if (c >= '0' && c <= '9') {
+ return c - '0';
+ } else if (c >= 'a' && c <= 'f') {
+ return c - 'a' + 10;
+ } else if (c >= 'A' && c <= 'F') {
+ return c - 'A' + 10;
+ } else {
+ assert(0);
+ }
+}
+
+static void StringToBuffer(const char *str, size_t len, uint8_t *buf) {
+ for (int i = 0; i < len; i++) {
+ buf[i] = char_to_uint8_t(*str) * 16 + char_to_uint8_t(*(str + 1));
+ str += 2;
+ }
+}
+
+/* Helper function to convert from binary to string representation */
+static char uint8_to_char(uint8_t u)
+{
+ assert( u < (1UL << 4));
+ const uint8_t arr[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+ return arr[u];
+}
+
+static void BufferToString(const uint8_t *buf, size_t len, char *str) {
+ for (int i = 0; i < len; i++) {
+ *str = uint8_to_char((buf[i] >> 4) & 0xf);
+ *(str + 1) = uint8_to_char(buf[i] & 0xf);
+ str += 2;
+ }
+ str[0] = '\0';
+}
+
+void psa_sign_verify_hash_test(psa_algorithm_t alg, uint8_t curve_selector,
struct test_result_t *ret)
{
psa_status_t status = PSA_SUCCESS;
@@ -3153,24 +3212,35 @@
psa_key_attributes_t input_key_attr = PSA_KEY_ATTRIBUTES_INIT;
const uint8_t message[] =
"This is the message that I would like to sign";
- uint8_t signature[SIGNATURE_BUFFER_SIZE] = {0};
+
+ if (curve_selector > 1) {
+ TEST_FAIL("curve_selector must be either 0 or 1");
+ return;
+ }
+
+ const size_t ecdsa_private_key_sz = ecdsa_keys[curve_selector].priv_sz;
+ uint8_t signature[PSA_ECDSA_SIGNATURE_SIZE(PSA_BYTES_TO_BITS(ecdsa_private_key_sz))];
+ char tmp_str[sizeof(signature) * 2 + 1]; /* enough to hold the hash string as well */
size_t signature_length = 0;
/* The expected format of the public key is uncompressed, i.e. 0x04 X Y */
uint8_t ecdsa_pub_key[
- PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_BYTES_TO_BITS(sizeof(ecdsa_private_key)))] = {0};
+ PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_BYTES_TO_BITS(ecdsa_private_key_sz))];
size_t pub_key_length = 0;
- uint32_t comp_result = 0;
- uint8_t hash[32] = {0}; /* Support only SHA-256 based signatures in the tests for simplicity */
+ const psa_algorithm_t hash_alg = PSA_ALG_GET_HASH(alg);
+ uint8_t hash[PSA_HASH_LENGTH(hash_alg)];
size_t hash_length = 0;
- uint8_t *p_key = (uint8_t *) ecdsa_public_key;
- size_t public_key_size;
+ uint8_t scratch_buffer[48 * 2 + 1]; /* Up to the P-384 pub key in uncompressed format */
- /* Get the BIT STRING for the public key */
- get_public_key_from_rfc5280_encoding(&p_key, &public_key_size);
+ /* Clear a few arrays on the stack */
+ memset(signature, 0, sizeof(signature));
+ memset(ecdsa_pub_key, 0, sizeof(ecdsa_pub_key));
/* Initialize to the passing value */
ret->val = TEST_PASSED;
+ /* Convert from string to binary */
+ StringToBuffer(ecdsa_keys[curve_selector].priv, ecdsa_keys[curve_selector].priv_sz, scratch_buffer);
+
/* Set attributes and import key */
psa_set_key_usage_flags(&input_key_attr,
PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_EXPORT);
@@ -3178,8 +3248,8 @@
key_type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1);
psa_set_key_type(&input_key_attr, key_type);
- status = psa_import_key(&input_key_attr, ecdsa_private_key,
- sizeof(ecdsa_private_key), &key_id_local);
+ status = psa_import_key(&input_key_attr, (const uint8_t *)scratch_buffer,
+ ecdsa_private_key_sz, &key_id_local);
if (status != PSA_SUCCESS) {
TEST_FAIL("Error importing the private key");
return;
@@ -3193,20 +3263,13 @@
}
if (pub_key_length !=
- PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_BYTES_TO_BITS(sizeof(ecdsa_private_key)))) {
+ PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_BYTES_TO_BITS(ecdsa_private_key_sz))) {
TEST_FAIL("Unexpected length for the public key!");
goto destroy_key;
}
- /* Check that exported key matches the reference key */
- comp_result = memcmp(ecdsa_pub_key, p_key, pub_key_length);
- if (comp_result != 0) {
- TEST_FAIL("Exported ECDSA public key does not match the reference!");
- goto destroy_key;
- }
-
/* Compute the hash */
- status = psa_hash_compute(PSA_ALG_GET_HASH(alg), message, sizeof(message), hash, sizeof(hash), &hash_length);
+ status = psa_hash_compute(hash_alg, message, sizeof(message), hash, sizeof(hash), &hash_length);
if (status != PSA_SUCCESS) {
TEST_FAIL("Failure hashing the message before signing the hash!");
goto destroy_key;
@@ -3217,6 +3280,9 @@
goto destroy_key;
}
+ BufferToString(hash, hash_length, tmp_str);
+ TEST_LOG("hash: %s\r\n", tmp_str);
+
status = psa_sign_hash(key_id_local, alg, hash, hash_length, signature, sizeof(signature), &signature_length);
if (status != PSA_SUCCESS) {
TEST_FAIL("Hash signing failed!");
@@ -3224,12 +3290,14 @@
}
if (signature_length != PSA_ECDSA_SIGNATURE_SIZE(
- PSA_BYTES_TO_BITS(
- sizeof(ecdsa_private_key)))) {
+ PSA_BYTES_TO_BITS(ecdsa_private_key_sz))) {
TEST_FAIL("Unexpected signature length");
goto destroy_key;
}
+ BufferToString(signature, signature_length, tmp_str);
+ TEST_LOG("signature: %s\r\n", tmp_str);
+
/* It is not possible to compare the signature against a reference because it might be non-deterministic */
status = psa_verify_hash(key_id_local, alg, hash, hash_length, signature, signature_length);
@@ -3251,8 +3319,11 @@
key_type = PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1);
psa_set_key_type(&input_key_attr, key_type);
- status = psa_import_key(&input_key_attr, p_key,
- public_key_size, &key_id_local);
+ /* Convert from string to binary */
+ StringToBuffer(ecdsa_keys[curve_selector].pub, ecdsa_keys[curve_selector].priv_sz * 2 + 1, scratch_buffer);
+
+ status = psa_import_key(&input_key_attr, (const uint8_t *)scratch_buffer,
+ pub_key_length, &key_id_local);
if (status != PSA_SUCCESS) {
TEST_FAIL("Error importing the public key");
return;
@@ -3268,6 +3339,71 @@
return;
}
+static const struct {
+ size_t sig_size;
+ const char *sig;
+ const char *pub;
+ const char *hash;
+} verify_hash_sig[1] = {
+ {
+ .sig_size = 96,
+ .sig = "849dd4d96d35f0145ba5a1f1e1d541e900382318f36f440a858a9be6ef1b0c399602585b1e84f30315db7bd612a5c1465dd51096f2d57f98ef64354429d42acf89a01993857f35a5dc12d9cfcf6d450fe424c32a0ab9df52ef63ed196592dd44",
+ .pub = "0444bcc8d8379964db002b1747cf6b898798d11de52071856a0232970a45eb4a28de84a3ba5180fa2b00507bc343f34ada6f9f6e3042c0194ca3838eb200ab04656f47f7fc10e25ef8e20eb20dd398a037bd7dc7b6afe4a65a30b3d32a7f52cf41",
+ .hash = "7cae4a9ffe65301045ab4a8c8ba8652c23340f7d033dae0ddf3ba54d6d3bdc95546921c81a0d5e1a2fce79600f0c09e5",
+ }
+};
+
+void psa_verify_hash_test(psa_algorithm_t alg, uint8_t curve_selector,
+ struct test_result_t *ret)
+{
+ psa_status_t status = PSA_SUCCESS;
+ psa_key_id_t key_id_local = PSA_KEY_ID_NULL;
+ psa_key_type_t key_type;
+ psa_key_attributes_t input_key_attr = PSA_KEY_ATTRIBUTES_INIT;
+
+ /* Initialize to the passing value */
+ ret->val = TEST_PASSED;
+
+ (void)curve_selector; /* This needs to change in case verify_hash_sig is extended */
+
+ /* Set attributes and import key */
+ psa_set_key_usage_flags(&input_key_attr, PSA_KEY_USAGE_VERIFY_HASH);
+ psa_set_key_algorithm(&input_key_attr, alg);
+ key_type = PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1);
+ psa_set_key_type(&input_key_attr, key_type);
+
+ uint8_t scratch_buffer1[97 * 2 + 1];
+ uint8_t scratch_buffer2[48 * 2 + 1];
+
+ const size_t pub_key_length = verify_hash_sig[0].sig_size + 1;
+ const size_t signature_length = verify_hash_sig[0].sig_size;
+ const size_t hash_length = verify_hash_sig[0].sig_size / 2;
+
+ TEST_LOG("hash: %s\r\n", verify_hash_sig[0].hash);
+ TEST_LOG("signature: %s\r\n", verify_hash_sig[0].sig);
+ TEST_LOG("0x04 x y: %s\r\n", verify_hash_sig[0].pub);
+
+ /* Convert from string to binary */
+ StringToBuffer(verify_hash_sig[0].pub, pub_key_length, scratch_buffer1);
+
+ status = psa_import_key(&input_key_attr, (const uint8_t *)scratch_buffer1,
+ pub_key_length, &key_id_local);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Error importing the private key");
+ return;
+ }
+
+ StringToBuffer(verify_hash_sig[0].sig, signature_length, scratch_buffer1);
+ StringToBuffer(verify_hash_sig[0].hash, hash_length, scratch_buffer2);
+
+ status = psa_verify_hash(key_id_local, alg, scratch_buffer2, hash_length, scratch_buffer1, signature_length);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Signature verification for the provided hash failed!");
+ }
+
+ psa_destroy_key(key_id_local);
+}
+
#if defined(TFM_CRYPTO_TEST_ALG_RSASSA_PSS_VERIFICATION)
/* DER encoding of the implementation defined in RFC 3279
*
diff --git a/tests_reg/test/secure_fw/suites/crypto/crypto_tests_common.h b/tests_reg/test/secure_fw/suites/crypto/crypto_tests_common.h
index c9f7a25..214cb09 100644
--- a/tests_reg/test/secure_fw/suites/crypto/crypto_tests_common.h
+++ b/tests_reg/test/secure_fw/suites/crypto/crypto_tests_common.h
@@ -285,12 +285,23 @@
/**
* \brief Hash sign/verify test
*
- * \param[in] alg Signing algorithm
- * \param[out] ret Test result
+ * \param[in] alg Signing algorithm
+ * \param[in] curve_selector 0 for P-256, 1 for P-384
+ * \param[out] ret Test result
*/
-void psa_sign_verify_hash_test(psa_algorithm_t alg,
+void psa_sign_verify_hash_test(psa_algorithm_t alg, uint8_t curve_selector,
struct test_result_t *ret);
+/**
+ * @brief Hash verify test
+ *
+ * @param[in] alg Signing algorithm
+ * @param[in] curve_selector Unused at the moment
+ * @param[out] ret Test result
+ */
+void psa_verify_hash_test(psa_algorithm_t alg, uint8_t curve_selector,
+ struct test_result_t *ret);
+
#ifdef TFM_CRYPTO_TEST_CHACHA20
/**
* \brief Verification of Chacha20 using RFC7539 test vectors
diff --git a/tests_reg/test/secure_fw/suites/crypto/non_secure/crypto_ns_interface_testsuite.c b/tests_reg/test/secure_fw/suites/crypto/non_secure/crypto_ns_interface_testsuite.c
index 3d63631..220e081 100644
--- a/tests_reg/test/secure_fw/suites/crypto/non_secure/crypto_ns_interface_testsuite.c
+++ b/tests_reg/test/secure_fw/suites/crypto/non_secure/crypto_ns_interface_testsuite.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2025, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -90,6 +90,7 @@
#endif /* TFM_CRYPTO_TEST_ALG_DETERMINISTIC_ECDSA */
#if TFM_CRYPTO_TEST_ALG_ECDSA
static void tfm_crypto_test_1053(struct test_result_t *ret);
+static void tfm_crypto_test_1056(struct test_result_t *ret);
#endif /* TFM_CRYPTO_TEST_ALG_ECDSA */
#endif /* CRYPTO_ASYM_SIGN_MODULE_ENABLED */
#ifdef TFM_CRYPTO_TEST_ALG_CBC
@@ -232,6 +233,8 @@
#if TFM_CRYPTO_TEST_ALG_ECDSA
{&tfm_crypto_test_1053, "TFM_NS_CRYPTO_TEST_1053",
"Non Secure Sign and verify hash interface (ECDSA-SECP256R1-SHA256)"},
+ {&tfm_crypto_test_1056, "TFM_NS_CRYPTO_TEST_1056",
+ "Non Secure Sign and verify hash interface (ECDSA-SECP384R1-SHA384)"},
#endif /* TFM_CRYPTO_TEST_ALG_ECDSA */
#endif /* CRYPTO_ASYM_SIGN_MODULE_ENABLED */
#ifdef TFM_CRYPTO_TEST_ALG_CBC
@@ -522,7 +525,19 @@
#if TFM_CRYPTO_TEST_ALG_ECDSA
static void tfm_crypto_test_1053(struct test_result_t *ret)
{
- psa_sign_verify_hash_test(PSA_ALG_ECDSA(PSA_ALG_SHA_256), ret);
+ psa_sign_verify_hash_test(PSA_ALG_ECDSA(PSA_ALG_SHA_256), 0, ret);
+}
+
+static void tfm_crypto_test_1056(struct test_result_t *ret)
+{
+#if defined(PSA_WANT_ECC_SECP_R1_384)
+ psa_sign_verify_hash_test(PSA_ALG_ECDSA(PSA_ALG_SHA_384), 1, ret);
+
+ psa_verify_hash_test(PSA_ALG_ECDSA(PSA_ALG_SHA_384), 1 /* Unused */, ret);
+#else
+ TEST_LOG("P384 is unsupported in the crypto config. Skipping...");
+ ret->val = 0;
+#endif
}
#endif /* TFM_CRYPTO_TEST_ALG_ECDSA */
#endif /* CRYPTO_ASYM_SIGN_MODULE_ENABLED */
diff --git a/tests_reg/test/secure_fw/suites/crypto/secure/crypto_sec_interface_testsuite.c b/tests_reg/test/secure_fw/suites/crypto/secure/crypto_sec_interface_testsuite.c
index b7c42c7..64881cb 100644
--- a/tests_reg/test/secure_fw/suites/crypto/secure/crypto_sec_interface_testsuite.c
+++ b/tests_reg/test/secure_fw/suites/crypto/secure/crypto_sec_interface_testsuite.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2025, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -92,6 +92,7 @@
#endif /* TFM_CRYPTO_TEST_ALG_DETERMINISTIC_ECDSA */
#if TFM_CRYPTO_TEST_ALG_ECDSA
static void tfm_crypto_test_1054(struct test_result_t *ret);
+static void tfm_crypto_test_1056(struct test_result_t *ret);
#endif /* TFM_CRYPTO_TEST_ALG_ECDSA */
#endif /* CRYPTO_ASYM_ENCRYPT_MODULE_ENABLED */
#ifdef TFM_CRYPTO_TEST_ALG_CBC
@@ -233,6 +234,8 @@
#if TFM_CRYPTO_TEST_ALG_ECDSA
{&tfm_crypto_test_1054, "TFM_S_CRYPTO_TEST_1054",
"Secure sign and verify hash interface (ECDSA-SECP256R1-SHA256)"},
+ {&tfm_crypto_test_1056, "TFM_S_CRYPTO_TEST_1056",
+ "Secure Sign and verify hash interface (ECDSA-SECP384R1-SHA384)"},
#endif /* TFM_CRYPTO_TEST_ALG_ECDSA */
#endif /* CRYPTO_ASYM_SIGN_MODULE_ENABLED */
#ifdef TFM_CRYPTO_TEST_ALG_CBC
@@ -559,7 +562,19 @@
#if TFM_CRYPTO_TEST_ALG_ECDSA
static void tfm_crypto_test_1054(struct test_result_t *ret)
{
- psa_sign_verify_hash_test(PSA_ALG_ECDSA(PSA_ALG_SHA_256), ret);
+ psa_sign_verify_hash_test(PSA_ALG_ECDSA(PSA_ALG_SHA_256), 0, ret);
+}
+
+static void tfm_crypto_test_1056(struct test_result_t *ret)
+{
+#if defined(PSA_WANT_ECC_SECP_R1_384)
+ psa_sign_verify_hash_test(PSA_ALG_ECDSA(PSA_ALG_SHA_384), 1, ret);
+
+ psa_verify_hash_test(PSA_ALG_ECDSA(PSA_ALG_SHA_384), 1 /* Unused */, ret);
+#else
+ TEST_LOG("P384 is unsupported in the crypto config. Skipping...");
+ ret->val = 0;
+#endif
}
#endif /* TFM_CRYPTO_TEST_ALG_ECDSA */
#endif /* CRYPTO_ASYM_SIGN_MODULE_ENABLED */