Unit tests for mbedtls_psa_ecp_generate_key()
Run the function on a few different curves with shorter, just-right and
larger buffer sizes. Perform some basic sanity checks on the output (which
is random).
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
diff --git a/tests/scripts/analyze_outcomes.py b/tests/scripts/analyze_outcomes.py
index f19d4b6..f6f7d87 100755
--- a/tests/scripts/analyze_outcomes.py
+++ b/tests/scripts/analyze_outcomes.py
@@ -409,6 +409,8 @@
IGNORED_SUITES = [
# Modules replaced by drivers
'ecdsa', 'ecdh', 'ecjpake',
+ # Unit tests for the built-in implementation
+ 'psa_crypto_ecp',
]
IGNORED_TESTS = {
'test_suite_config': [
@@ -449,6 +451,8 @@
IGNORED_SUITES = [
# Modules replaced by drivers
'ecp', 'ecdsa', 'ecdh', 'ecjpake',
+ # Unit tests for the built-in implementation
+ 'psa_crypto_ecp',
]
IGNORED_TESTS = {
'test_suite_config': [
@@ -489,6 +493,8 @@
'ecp', 'ecdsa', 'ecdh', 'ecjpake',
'bignum_core', 'bignum_random', 'bignum_mod', 'bignum_mod_raw',
'bignum.generated', 'bignum.misc',
+ # Unit tests for the built-in implementation
+ 'psa_crypto_ecp',
]
IGNORED_TESTS = {
'test_suite_config': [
@@ -534,6 +540,8 @@
'ecp', 'ecdsa', 'ecdh', 'ecjpake', 'dhm',
'bignum_core', 'bignum_random', 'bignum_mod', 'bignum_mod_raw',
'bignum.generated', 'bignum.misc',
+ # Unit tests for the built-in implementation
+ 'psa_crypto_ecp',
]
IGNORED_TESTS = {
'ssl-opt': [
@@ -604,6 +612,8 @@
'ecp', 'ecdsa', 'ecdh', 'ecjpake',
'bignum_core', 'bignum_random', 'bignum_mod', 'bignum_mod_raw',
'bignum.generated', 'bignum.misc',
+ # Unit tests for the built-in implementation
+ 'psa_crypto_ecp',
]
IGNORED_TESTS = {
'test_suite_config': [
diff --git a/tests/suites/test_suite_psa_crypto_ecp.data b/tests/suites/test_suite_psa_crypto_ecp.data
new file mode 100644
index 0000000..ffb7a7b
--- /dev/null
+++ b/tests/suites/test_suite_psa_crypto_ecp.data
@@ -0,0 +1,82 @@
+ECC generate: unknown family (0)
+generate_key:0:256:64:PSA_ERROR_NOT_SUPPORTED
+
+ECC generate: unknown family (0xff)
+generate_key:0xff:256:64:PSA_ERROR_NOT_SUPPORTED
+
+ECC generate: SECP_R1 bad bit-size (0)
+generate_key:PSA_ECC_FAMILY_SECP_R1:0:64:PSA_ERROR_NOT_SUPPORTED
+
+ECC generate: SECP_R1 bad bit-size (512)
+generate_key:PSA_ECC_FAMILY_SECP_R1:512:64:PSA_ERROR_NOT_SUPPORTED
+
+ECC generate: SECP_R1 bad bit-size (528)
+generate_key:PSA_ECC_FAMILY_SECP_R1:528:64:PSA_ERROR_NOT_SUPPORTED
+
+ECC generate: SECP_R1 256-bit not supported
+depends_on:!MBEDTLS_PSA_BUILTIN_ECC_SECP_R1_256
+generate_key:PSA_ECC_FAMILY_SECP_R1:256:32:PSA_ERROR_NOT_SUPPORTED
+
+ECC generate: SECP_R1 384-bit not supported
+depends_on:!MBEDTLS_PSA_BUILTIN_ECC_SECP_R1_384
+generate_key:PSA_ECC_FAMILY_SECP_R1:384:48:PSA_ERROR_NOT_SUPPORTED
+
+ECC generate: SECP_R1 521-bit not supported
+depends_on:!MBEDTLS_PSA_BUILTIN_ECC_SECP_R1_521
+generate_key:PSA_ECC_FAMILY_SECP_R1:521:66:PSA_ERROR_NOT_SUPPORTED
+
+ECC generate: SECP_K1 256-bit not supported
+depends_on:!MBEDTLS_PSA_BUILTIN_ECC_SECP_K1_256
+generate_key:PSA_ECC_FAMILY_SECP_K1:256:32:PSA_ERROR_NOT_SUPPORTED
+
+ECC generate: Curve25519 not supported
+depends_on:!MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_255
+generate_key:PSA_ECC_FAMILY_MONTGOMERY:255:32:PSA_ERROR_NOT_SUPPORTED
+
+ECC generate: Curve448 not supported
+depends_on:!MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_448
+generate_key:PSA_ECC_FAMILY_MONTGOMERY:448:56:PSA_ERROR_NOT_SUPPORTED
+
+ECC generate: SECP_R1 256-bit, size=31, too small
+depends_on:MBEDTLS_PSA_BUILTIN_ECC_SECP_R1_256
+generate_key:PSA_ECC_FAMILY_SECP_R1:256:31:PSA_ERROR_BUFFER_TOO_SMALL
+
+ECC generate: SECP_R1 256-bit, size=32, ok
+depends_on:MBEDTLS_PSA_BUILTIN_ECC_SECP_R1_256
+generate_key:PSA_ECC_FAMILY_SECP_R1:256:32:PSA_SUCCESS
+
+ECC generate: SECP_R1 256-bit, size=33, ok
+depends_on:MBEDTLS_PSA_BUILTIN_ECC_SECP_R1_256
+generate_key:PSA_ECC_FAMILY_SECP_R1:256:33:PSA_SUCCESS
+
+ECC generate: SECP_R1 521-bit, size=65, too small
+depends_on:MBEDTLS_PSA_BUILTIN_ECC_SECP_R1_521
+generate_key:PSA_ECC_FAMILY_SECP_R1:521:65:PSA_ERROR_BUFFER_TOO_SMALL
+
+ECC generate: SECP_R1 521-bit, size=66, ok
+depends_on:MBEDTLS_PSA_BUILTIN_ECC_SECP_R1_521
+generate_key:PSA_ECC_FAMILY_SECP_R1:521:66:PSA_SUCCESS
+
+ECC generate: Curve25519, size=31, too small
+depends_on:MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_255
+generate_key:PSA_ECC_FAMILY_MONTGOMERY:255:31:PSA_ERROR_BUFFER_TOO_SMALL
+
+ECC generate: Curve25519, size=32, ok
+depends_on:MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_255
+generate_key:PSA_ECC_FAMILY_MONTGOMERY:255:32:PSA_SUCCESS
+
+ECC generate: Curve25519, size=33, ok
+depends_on:MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_255
+generate_key:PSA_ECC_FAMILY_MONTGOMERY:255:33:PSA_SUCCESS
+
+ECC generate: Curve448, size=55, too small
+depends_on:MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_448
+generate_key:PSA_ECC_FAMILY_MONTGOMERY:448:55:PSA_ERROR_BUFFER_TOO_SMALL
+
+ECC generate: Curve448, size=56, ok
+depends_on:MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_448
+generate_key:PSA_ECC_FAMILY_MONTGOMERY:448:56:PSA_SUCCESS
+
+ECC generate: Curve448, size=57, ok
+depends_on:MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_448
+generate_key:PSA_ECC_FAMILY_MONTGOMERY:448:57:PSA_SUCCESS
diff --git a/tests/suites/test_suite_psa_crypto_ecp.function b/tests/suites/test_suite_psa_crypto_ecp.function
new file mode 100644
index 0000000..e577e75
--- /dev/null
+++ b/tests/suites/test_suite_psa_crypto_ecp.function
@@ -0,0 +1,108 @@
+/* BEGIN_HEADER */
+/* Unit tests for internal functions for built-in ECC mechanisms. */
+#include <psa/crypto.h>
+
+#include "psa_crypto_ecp.h"
+
+#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE)
+/*
+ * Check if a buffer is all-0 bytes:
+ * return 1 if it is,
+ * 0 if it isn't.
+ *
+ * TODO: we use this in multiple test suites. Move it to tests/src.
+ */
+static int buffer_is_all_zero(const uint8_t *buf, size_t size)
+{
+ for (size_t i = 0; i < size; i++) {
+ if (buf[i] != 0) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Do some sanity checks on an ECC private key. This is not intended to be
+ * a full validity check, just to catch some potential mistakes. */
+static int check_ecc_private_key(psa_ecc_family_t family, size_t bits,
+ const uint8_t *key, size_t key_length)
+{
+ int ok = 0;
+
+ /* Check the expected length (same calculation for all curves). */
+ TEST_EQUAL(PSA_BITS_TO_BYTES(bits), key_length);
+
+ /* All-bits zero is invalid and means no key material was copied to the
+ * output buffer, or a grave RNG pluming failure. */
+ TEST_ASSERT(!buffer_is_all_zero(key, key_length));
+
+ /* Check the top byte of the value for non-byte-aligned curve sizes.
+ * This is a partial endianness check. */
+ if (bits % 8 != 0) {
+ /* All supported non-byte-aligned curve sizes are for Weierstrass
+ * curves with a big-endian representation. */
+ uint8_t top_byte = key[0];
+ uint8_t mask = 0xff << (bits & 8);
+ TEST_EQUAL(top_byte & mask, 0);
+ }
+
+ /* Check masked bits on Curve25519 and Curve448. */
+#if defined(MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_255)
+ if (family == PSA_ECC_FAMILY_MONTGOMERY && bits == 255) {
+ TEST_EQUAL(key[0] & 0xf8, key[0]);
+ TEST_EQUAL(key[31] & 0xc0, 0x40);
+ }
+#endif /* MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_255 */
+#if defined(MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_448)
+ if (family == PSA_ECC_FAMILY_MONTGOMERY && bits == 448) {
+ TEST_EQUAL(key[0] & 0xfc, key[0]);
+ TEST_EQUAL(key[55] & 0x80, 0x80);
+ }
+#endif /* MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_448 */
+ (void) family; // unused in Weierstrass-only builds
+
+ ok = 1;
+exit:
+ return ok;
+}
+#endif
+
+/* END_HEADER */
+
+/* BEGIN_DEPENDENCIES
+ * depends_on:MBEDTLS_PSA_CRYPTO_C:MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY
+ * END_DEPENDENCIES
+ */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE */
+void generate_key(int family_arg, int bits_arg,
+ int output_size_arg,
+ psa_status_t expected_status)
+{
+ psa_ecc_family_t family = family_arg;
+ size_t bits = bits_arg;
+ size_t output_size = output_size_arg;
+
+ uint8_t *output = NULL;
+ size_t output_length = SIZE_MAX;
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(family));
+ psa_set_key_bits(&attributes, bits);
+ PSA_INIT();
+ TEST_CALLOC(output, output_size);
+
+ TEST_EQUAL(mbedtls_psa_ecp_generate_key(&attributes,
+ output, output_size,
+ &output_length),
+ expected_status);
+ if (expected_status == PSA_SUCCESS) {
+ TEST_LE_U(output_length, output_size);
+ TEST_ASSERT(check_ecc_private_key(family, bits,
+ output, output_length));
+ }
+
+exit:
+ PSA_DONE();
+ mbedtls_free(output);
+}
+/* END_CASE */