mbedtls_pk_get_psa_attributes: ECC support
Add code and unit tests for MBEDTLS_PK_ECxxx in
mbedtls_pk_get_psa_attributes().
This commit only supports built-in ECC (MBEDTLS_ECP_C). A subsequent commit
will handle driver-only ECC.
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
diff --git a/library/pk.c b/library/pk.c
index 1485bd7..432fbcf 100644
--- a/library/pk.c
+++ b/library/pk.c
@@ -406,22 +406,28 @@
{
mbedtls_pk_type_t pk_type = mbedtls_pk_get_type(pk);
+ psa_key_usage_t more_usage = usage;
+ if (usage == PSA_KEY_USAGE_SIGN_MESSAGE) {
+ more_usage |= PSA_KEY_USAGE_VERIFY_MESSAGE;
+ } else if (usage == PSA_KEY_USAGE_SIGN_HASH) {
+ more_usage |= PSA_KEY_USAGE_VERIFY_HASH;
+ } else if (usage == PSA_KEY_USAGE_DECRYPT) {
+ more_usage |= PSA_KEY_USAGE_ENCRYPT;
+ }
+ more_usage |= PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_COPY;
+
switch (pk_type) {
#if defined(MBEDTLS_RSA_C)
case MBEDTLS_PK_RSA:
+ {
int want_crypt = 0;
int want_private = 0;
switch (usage) {
case PSA_KEY_USAGE_SIGN_MESSAGE:
- usage |= PSA_KEY_USAGE_VERIFY_MESSAGE;
- want_private = 1;
- break;
case PSA_KEY_USAGE_SIGN_HASH:
- usage |= PSA_KEY_USAGE_VERIFY_HASH;
want_private = 1;
break;
case PSA_KEY_USAGE_DECRYPT:
- usage |= PSA_KEY_USAGE_ENCRYPT;
want_private = 1;
want_crypt = 1;
break;
@@ -448,8 +454,61 @@
psa_set_key_algorithm(attributes,
psa_algorithm_for_rsa(rsa, want_crypt));
break;
+ }
#endif /* MBEDTLS_RSA_C */
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
+ case MBEDTLS_PK_ECKEY:
+ case MBEDTLS_PK_ECKEY_DH:
+ case MBEDTLS_PK_ECDSA:
+ {
+ int sign_ok = (pk_type != MBEDTLS_PK_ECKEY_DH);
+ int derive_ok = (pk_type != MBEDTLS_PK_ECDSA);
+ mbedtls_ecp_keypair *ec = mbedtls_pk_ec(*pk);
+ int has_private = (ec->d.n != 0);
+ size_t bits = 0;
+ psa_ecc_family_t family =
+ mbedtls_ecc_group_to_psa(ec->grp.id, &bits);
+ int want_private = 0;
+ psa_algorithm_t alg = 0;
+ switch (usage) {
+ case PSA_KEY_USAGE_SIGN_MESSAGE:
+ case PSA_KEY_USAGE_SIGN_HASH:
+ want_private = 1;
+ /* FALLTHROUGH */
+ case PSA_KEY_USAGE_VERIFY_MESSAGE:
+ case PSA_KEY_USAGE_VERIFY_HASH:
+ if (!sign_ok) {
+ return MBEDTLS_ERR_PK_TYPE_MISMATCH;
+ }
+#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
+ alg = PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_ANY_HASH);
+#else
+ alg = PSA_ALG_ECDSA(PSA_ALG_ANY_HASH);
+#endif
+ break;
+ case PSA_KEY_USAGE_DERIVE:
+ want_private = 1;
+ alg = PSA_ALG_ECDH;
+ if (!derive_ok) {
+ return MBEDTLS_ERR_PK_TYPE_MISMATCH;
+ }
+ break;
+ default:
+ return MBEDTLS_ERR_PK_TYPE_MISMATCH;
+ }
+ if (want_private && !has_private) {
+ return MBEDTLS_ERR_PK_TYPE_MISMATCH;
+ }
+ psa_set_key_type(attributes, (want_private ?
+ PSA_KEY_TYPE_ECC_KEY_PAIR(family) :
+ PSA_KEY_TYPE_ECC_PUBLIC_KEY(family)));
+ psa_set_key_bits(attributes, bits);
+ psa_set_key_algorithm(attributes, alg);
+ break;
+ }
+#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
+
#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT)
case MBEDTLS_PK_RSA_ALT:
return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
@@ -459,8 +518,7 @@
return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
}
- usage |= PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_COPY;
- psa_set_key_usage_flags(attributes, usage);
+ psa_set_key_usage_flags(attributes, more_usage);
#if defined(MBEDTLS_PSA_CRYPTO_C)
/* Assume that we have all Mbed TLS attributes. When
* MBEDTLS_PSA_CRYPTO_CLIENT is enabled but not MBEDTLS_PSA_CRYPTO_C,
diff --git a/tests/suites/test_suite_pk.data b/tests/suites/test_suite_pk.data
index bc0de71..f0903e3 100644
--- a/tests/suites/test_suite_pk.data
+++ b/tests/suites/test_suite_pk.data
@@ -789,3 +789,171 @@
PSA attributes for pk: RSA v15 public DERIVE (bad)
depends_on:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
pk_get_psa_attributes_fail:MBEDTLS_PK_RSA:0:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY pair DECRYPT (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:1:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY_DH pair DECRYPT (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:1:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECDSA pair DECRYPT (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:1:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY public DECRYPT (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:0:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY_DH public DECRYPT (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:0:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECDSA public DECRYPT (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:0:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY pair ENCRYPT (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:1:PSA_KEY_USAGE_ENCRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY_DH pair ENCRYPT (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:1:PSA_KEY_USAGE_ENCRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECDSA pair ENCRYPT (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:1:PSA_KEY_USAGE_ENCRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY public ENCRYPT (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:0:PSA_KEY_USAGE_ENCRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY_DH public ENCRYPT (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:0:PSA_KEY_USAGE_ENCRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECDSA public ENCRYPT (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:0:PSA_KEY_USAGE_ENCRYPT:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY pair DERIVE
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes:MBEDTLS_PK_ECKEY:1:PSA_KEY_USAGE_DERIVE:1:PSA_ALG_ECDH
+
+PSA attributes for pk: ECKEY_DH pair DERIVE
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes:MBEDTLS_PK_ECKEY_DH:1:PSA_KEY_USAGE_DERIVE:1:PSA_ALG_ECDH
+
+PSA attributes for pk: ECDSA pair DERIVE (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:1:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY public DERIVE (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:0:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY_DH public DERIVE (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:0:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECDSA public DERIVE (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:0:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY pair SIGN_MESSAGE
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes:MBEDTLS_PK_ECKEY:1:PSA_KEY_USAGE_SIGN_MESSAGE:1:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+
+PSA attributes for pk: ECDSA pair SIGN_MESSAGE
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes:MBEDTLS_PK_ECDSA:1:PSA_KEY_USAGE_SIGN_MESSAGE:1:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+
+PSA attributes for pk: ECKEY pair SIGN_HASH
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes:MBEDTLS_PK_ECKEY:1:PSA_KEY_USAGE_SIGN_HASH:1:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+
+PSA attributes for pk: ECDSA pair SIGN_HASH
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes:MBEDTLS_PK_ECDSA:1:PSA_KEY_USAGE_SIGN_HASH:1:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+
+PSA attributes for pk: ECKEY pair->public VERIFY_MESSAGE
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes:MBEDTLS_PK_ECKEY:1:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+
+PSA attributes for pk: ECDSA pair->public VERIFY_MESSAGE
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes:MBEDTLS_PK_ECDSA:1:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+
+PSA attributes for pk: ECKEY pair->public VERIFY_HASH
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes:MBEDTLS_PK_ECKEY:1:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+
+PSA attributes for pk: ECDSA pair->public VERIFY_HASH
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes:MBEDTLS_PK_ECDSA:1:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+
+PSA attributes for pk: ECKEY public VERIFY_MESSAGE
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes:MBEDTLS_PK_ECKEY:0:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+
+PSA attributes for pk: ECDSA public VERIFY_MESSAGE
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes:MBEDTLS_PK_ECDSA:0:PSA_KEY_USAGE_VERIFY_MESSAGE:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+
+PSA attributes for pk: ECKEY public VERIFY_HASH
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes:MBEDTLS_PK_ECKEY:0:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+
+PSA attributes for pk: ECDSA public VERIFY_HASH
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes:MBEDTLS_PK_ECDSA:0:PSA_KEY_USAGE_VERIFY_HASH:0:PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)
+
+PSA attributes for pk: ECKEY public SIGN_MESSAGE (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:0:PSA_KEY_USAGE_SIGN_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECDSA public SIGN_MESSAGE (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:0:PSA_KEY_USAGE_SIGN_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY public SIGN_HASH (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY:0:PSA_KEY_USAGE_SIGN_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECDSA public SIGN_HASH (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECDSA:0:PSA_KEY_USAGE_SIGN_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY_DH pair SIGN_MESSAGE (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:1:PSA_KEY_USAGE_SIGN_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY_DH pair SIGN_HASH (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:1:PSA_KEY_USAGE_SIGN_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY_DH pair VERIFY_MESSAGE (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:1:PSA_KEY_USAGE_VERIFY_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY_DH pair VERIFY_HASH (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:1:PSA_KEY_USAGE_VERIFY_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY_DH public SIGN_MESSAGE (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:0:PSA_KEY_USAGE_SIGN_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY_DH public SIGN_HASH (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:0:PSA_KEY_USAGE_SIGN_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY_DH public VERIFY_MESSAGE (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:0:PSA_KEY_USAGE_VERIFY_MESSAGE:MBEDTLS_ERR_PK_TYPE_MISMATCH
+
+PSA attributes for pk: ECKEY_DH public VERIFY_HASH (bad)
+depends_on:MBEDTLS_PK_HAVE_ECC_KEYS
+pk_get_psa_attributes_fail:MBEDTLS_PK_ECKEY_DH:0:PSA_KEY_USAGE_VERIFY_HASH:MBEDTLS_ERR_PK_TYPE_MISMATCH
diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function
index d6902b4..90c5044 100644
--- a/tests/suites/test_suite_pk.function
+++ b/tests/suites/test_suite_pk.function
@@ -187,7 +187,7 @@
} else {
unsigned char N[PSA_BITS_TO_BYTES(MBEDTLS_RSA_GEN_KEY_MIN_BITS)] = { 0xff };
N[sizeof(N) - 1] = 0x03;
- const unsigned char E[1] = {0x03};
+ const unsigned char E[1] = { 0x03 };
TEST_EQUAL(mbedtls_rsa_import_raw(rsa,
N, sizeof(N),
NULL, 0, NULL, 0, NULL, 0,
@@ -198,6 +198,23 @@
}
#endif /* MBEDTLS_RSA_C */
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
+ case MBEDTLS_PK_ECKEY:
+ case MBEDTLS_PK_ECKEY_DH:
+ case MBEDTLS_PK_ECDSA:
+ {
+ mbedtls_ecp_group_id grp_id = mbedtls_ecp_grp_id_list()[0];
+ size_t bits;
+ *psa_type = PSA_KEY_TYPE_ECC_KEY_PAIR(mbedtls_ecc_group_to_psa(grp_id, &bits));
+ TEST_EQUAL(pk_genkey(pk, grp_id), 0);
+ if (!want_pair) {
+ mbedtls_ecp_keypair *ec = mbedtls_pk_ec(*pk);
+ mbedtls_mpi_free(&ec->d);
+ }
+ break;
+ }
+#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
+
default:
TEST_FAIL("Unknown PK type in test data");
break;
@@ -1674,6 +1691,17 @@
}
expected_usage |= PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_COPY;
+#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
+ /* When the resulting algorithm is ECDSA, the compile-time configuration
+ * can cause it to be either deterministic or randomized ECDSA.
+ * Rather than have two near-identical sets of test data depending on
+ * the configuration, always use randomized in the test data and
+ * tweak the expected result here. */
+ if (expected_alg == PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)) {
+ expected_alg = PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_ANY_HASH);
+ }
+#endif
+
TEST_EQUAL(mbedtls_pk_get_psa_attributes(&pk, usage, &attributes), 0);
TEST_EQUAL(psa_get_key_lifetime(&attributes), lifetime);