Merge pull request #8041 from mpg/tfm-p256m
Test TF-M config with p256-m driver
diff --git a/3rdparty/p256-m/p256-m/p256-m.c b/3rdparty/p256-m/p256-m/p256-m.c
index 693cc6d..050ffa5 100644
--- a/3rdparty/p256-m/p256-m/p256-m.c
+++ b/3rdparty/p256-m/p256-m/p256-m.c
@@ -1466,4 +1466,49 @@
return P256_INVALID_SIGNATURE;
}
+/**********************************************************************
+ *
+ * Key management utilities
+ *
+ **********************************************************************/
+
+int p256_validate_pubkey(const uint8_t pub[64])
+{
+ uint32_t x[8], y[8];
+ int ret = point_from_bytes(x, y, pub);
+
+ return ret == 0 ? P256_SUCCESS : P256_INVALID_PUBKEY;
+}
+
+int p256_validate_privkey(const uint8_t priv[32])
+{
+ uint32_t s[8];
+ int ret = scalar_from_bytes(s, priv);
+ zeroize(s, sizeof(s));
+
+ return ret == 0 ? P256_SUCCESS : P256_INVALID_PRIVKEY;
+}
+
+int p256_public_from_private(uint8_t pub[64], const uint8_t priv[32])
+{
+ int ret;
+ uint32_t s[8];
+
+ ret = scalar_from_bytes(s, priv);
+ if (ret != 0)
+ return P256_INVALID_PRIVKEY;
+
+ /* compute and ouput the associated public key */
+ uint32_t x[8], y[8];
+ scalar_mult(x, y, p256_gx, p256_gy, s);
+
+ /* the associated public key is not a secret, the scalar was */
+ CT_UNPOISON(x, 32);
+ CT_UNPOISON(y, 32);
+ zeroize(s, sizeof(s));
+
+ point_to_bytes(pub, x, y);
+ return P256_SUCCESS;
+}
+
#endif
diff --git a/3rdparty/p256-m/p256-m/p256-m.h b/3rdparty/p256-m/p256-m/p256-m.h
index 398c846..28d319f 100644
--- a/3rdparty/p256-m/p256-m/p256-m.h
+++ b/3rdparty/p256-m/p256-m/p256-m.h
@@ -89,6 +89,45 @@
int p256_ecdsa_verify(const uint8_t sig[64], const uint8_t pub[64],
const uint8_t *hash, size_t hlen);
+/*
+ * Public key validation
+ *
+ * Note: you never need to call this function, as all other functions always
+ * validate their input; however it's availabe if you want to validate the key
+ * without performing an operation.
+ *
+ * [in] pub: the public key, as two big-endian integers
+ *
+ * return: P256_SUCCESS if the key is valid
+ * P256_INVALID_PUBKEY if pub is invalid
+ */
+int p256_validate_pubkey(const uint8_t pub[64]);
+
+/*
+ * Private key validation
+ *
+ * Note: you never need to call this function, as all other functions always
+ * validate their input; however it's availabe if you want to validate the key
+ * without performing an operation.
+ *
+ * [in] priv: the private key, as a big-endian integer
+ *
+ * return: P256_SUCCESS if the key is valid
+ * P256_INVALID_PRIVKEY if priv is invalid
+ */
+int p256_validate_privkey(const uint8_t priv[32]);
+
+/*
+ * Compute public key from private key
+ *
+ * [out] pub: the associated public key, as two big-endian integers
+ * [in] priv: the private key, as a big-endian integer
+ *
+ * return: P256_SUCCESS on success
+ * P256_INVALID_PRIVKEY if priv is invalid
+ */
+int p256_public_from_private(uint8_t pub[64], const uint8_t priv[32]);
+
#ifdef __cplusplus
}
#endif
diff --git a/3rdparty/p256-m/p256-m_driver_entrypoints.c b/3rdparty/p256-m/p256-m_driver_entrypoints.c
index 8828909..b2236e4 100644
--- a/3rdparty/p256-m/p256-m_driver_entrypoints.c
+++ b/3rdparty/p256-m/p256-m_driver_entrypoints.c
@@ -24,6 +24,7 @@
#include "psa/crypto.h"
#include "psa_crypto_driver_wrappers.h"
#include <stddef.h>
+#include <string.h>
#if defined(MBEDTLS_P256M_EXAMPLE_DRIVER_ENABLED)
@@ -37,10 +38,20 @@
* total of 65 bytes.
*
* p256-m's internal format for private keys matches PSA. Its format for public
- * keys is only 64 bytes; the same as PSA but without the leading byte (0x04).
+ * keys is only 64 bytes: the same as PSA but without the leading byte (0x04).
* Hence, when passing public keys from PSA to p256-m, the leading byte is
* removed.
+ *
+ * Shared secret and signature have the same format between PSA and p256-m.
*/
+#define PSA_PUBKEY_SIZE 65
+#define PSA_PUBKEY_HEADER_BYTE 0x04
+#define P256_PUBKEY_SIZE 64
+#define PRIVKEY_SIZE 32
+#define SHARED_SECRET_SIZE 32
+#define SIGNATURE_SIZE 64
+
+#define CURVE_BITS 256
/* Convert between p256-m and PSA error codes */
static psa_status_t p256_to_psa_error(int ret)
@@ -59,6 +70,83 @@
}
}
+psa_status_t p256_transparent_import_key(const psa_key_attributes_t *attributes,
+ const uint8_t *data,
+ size_t data_length,
+ uint8_t *key_buffer,
+ size_t key_buffer_size,
+ size_t *key_buffer_length,
+ size_t *bits)
+{
+ /* Check the key size */
+ if (*bits != 0 && *bits != CURVE_BITS) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ /* Validate the key (and its type and size) */
+ psa_key_type_t type = psa_get_key_type(attributes);
+ if (type == PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)) {
+ if (data_length != PSA_PUBKEY_SIZE) {
+ return *bits == 0 ? PSA_ERROR_NOT_SUPPORTED : PSA_ERROR_INVALID_ARGUMENT;
+ }
+ /* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */
+ if (p256_validate_pubkey(data + 1) != P256_SUCCESS) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ } else if (type == PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)) {
+ if (data_length != PRIVKEY_SIZE) {
+ return *bits == 0 ? PSA_ERROR_NOT_SUPPORTED : PSA_ERROR_INVALID_ARGUMENT;
+ }
+ if (p256_validate_privkey(data) != P256_SUCCESS) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ } else {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+ *bits = CURVE_BITS;
+
+ /* We only support the export format for input, so just copy. */
+ if (key_buffer_size < data_length) {
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+ memcpy(key_buffer, data, data_length);
+ *key_buffer_length = data_length;
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t p256_transparent_export_public_key(const psa_key_attributes_t *attributes,
+ const uint8_t *key_buffer,
+ size_t key_buffer_size,
+ uint8_t *data,
+ size_t data_size,
+ size_t *data_length)
+{
+ /* Is this the right curve? */
+ size_t bits = psa_get_key_bits(attributes);
+ psa_key_type_t type = psa_get_key_type(attributes);
+ if (bits != CURVE_BITS || type != PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ /* Validate sizes, as p256-m expects fixed-size buffers */
+ if (key_buffer_size != PRIVKEY_SIZE) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ if (data_size < PSA_PUBKEY_SIZE) {
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+
+ /* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */
+ data[0] = PSA_PUBKEY_HEADER_BYTE;
+ int ret = p256_public_from_private(data + 1, key_buffer);
+ if (ret == P256_SUCCESS) {
+ *data_length = PSA_PUBKEY_SIZE;
+ }
+
+ return p256_to_psa_error(ret);
+}
+
psa_status_t p256_transparent_generate_key(
const psa_key_attributes_t *attributes,
uint8_t *key_buffer,
@@ -69,13 +157,9 @@
* of driver entry-points. (void) used to avoid compiler warning. */
(void) attributes;
- psa_status_t status = PSA_ERROR_NOT_SUPPORTED;
-
- /*
- * p256-m generates a 32 byte private key, and expects to write to a buffer
- * that is of that size. */
- if (key_buffer_size != 32) {
- return status;
+ /* Validate sizes, as p256-m expects fixed-size buffers */
+ if (key_buffer_size != PRIVKEY_SIZE) {
+ return PSA_ERROR_BUFFER_TOO_SMALL;
}
/*
@@ -83,15 +167,14 @@
* keys. Allocate a buffer to which the public key will be written. The
* private key will be written to key_buffer, which is passed to this
* function as an argument. */
- uint8_t public_key_buffer[64];
+ uint8_t public_key_buffer[P256_PUBKEY_SIZE];
- status = p256_to_psa_error(
- p256_gen_keypair(key_buffer, public_key_buffer));
- if (status == PSA_SUCCESS) {
- *key_buffer_length = 32;
+ int ret = p256_gen_keypair(key_buffer, public_key_buffer);
+ if (ret == P256_SUCCESS) {
+ *key_buffer_length = PRIVKEY_SIZE;
}
- return status;
+ return p256_to_psa_error(ret);
}
psa_status_t p256_transparent_key_agreement(
@@ -111,25 +194,22 @@
(void) attributes;
(void) alg;
- /*
- * Check that private key = 32 bytes, peer public key = 65 bytes,
- * and that the shared secret buffer is big enough. */
- psa_status_t status = PSA_ERROR_NOT_SUPPORTED;
- if (key_buffer_size != 32 || shared_secret_size < 32 ||
- peer_key_length != 65) {
- return status;
+ /* Validate sizes, as p256-m expects fixed-size buffers */
+ if (key_buffer_size != PRIVKEY_SIZE || peer_key_length != PSA_PUBKEY_SIZE) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ if (shared_secret_size < SHARED_SECRET_SIZE) {
+ return PSA_ERROR_BUFFER_TOO_SMALL;
}
- /* We add 1 to peer_key pointer to omit the leading byte of the public key
- * representation (0x04). See information about PSA key formats at the top
- * of the file. */
- status = p256_to_psa_error(
- p256_ecdh_shared_secret(shared_secret, key_buffer, peer_key+1));
- if (status == PSA_SUCCESS) {
- *shared_secret_length = 32;
+ /* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */
+ const uint8_t *peer_key_p256m = peer_key + 1;
+ int ret = p256_ecdh_shared_secret(shared_secret, key_buffer, peer_key_p256m);
+ if (ret == P256_SUCCESS) {
+ *shared_secret_length = SHARED_SECRET_SIZE;
}
- return status;
+ return p256_to_psa_error(ret);
}
psa_status_t p256_transparent_sign_hash(
@@ -149,21 +229,23 @@
(void) attributes;
(void) alg;
- psa_status_t status = PSA_ERROR_NOT_SUPPORTED;
- if (key_buffer_size != 32 || signature_size != 64) {
- return status;
+ /* Validate sizes, as p256-m expects fixed-size buffers */
+ if (key_buffer_size != PRIVKEY_SIZE) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ if (signature_size < SIGNATURE_SIZE) {
+ return PSA_ERROR_BUFFER_TOO_SMALL;
}
- status = p256_to_psa_error(
- p256_ecdsa_sign(signature, key_buffer, hash, hash_length));
- if (status == PSA_SUCCESS) {
- *signature_length = 64;
+ int ret = p256_ecdsa_sign(signature, key_buffer, hash, hash_length);
+ if (ret == P256_SUCCESS) {
+ *signature_length = SIGNATURE_SIZE;
}
- return status;
+ return p256_to_psa_error(ret);
}
-/* This function expects the key buffer to contain a 65 byte public key,
+/* This function expects the key buffer to contain a PSA public key,
* as exported by psa_export_public_key() */
static psa_status_t p256_verify_hash_with_public_key(
const uint8_t *key_buffer,
@@ -173,19 +255,19 @@
const uint8_t *signature,
size_t signature_length)
{
- psa_status_t status = PSA_ERROR_NOT_SUPPORTED;
- if (key_buffer_size != 65 || signature_length != 64 || *key_buffer != 0x04) {
- return status;
+ /* Validate sizes, as p256-m expects fixed-size buffers */
+ if (key_buffer_size != PSA_PUBKEY_SIZE || *key_buffer != PSA_PUBKEY_HEADER_BYTE) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ if (signature_length != SIGNATURE_SIZE) {
+ return PSA_ERROR_INVALID_SIGNATURE;
}
- /* We add 1 to public_key_buffer pointer to omit the leading byte of the
- * public key representation (0x04). See information about PSA key formats
- * at the top of the file. */
- const uint8_t *public_key_buffer = key_buffer + 1;
- status = p256_to_psa_error(
- p256_ecdsa_verify(signature, public_key_buffer, hash, hash_length));
+ /* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */
+ const uint8_t *public_key_p256m = key_buffer + 1;
+ int ret = p256_ecdsa_verify(signature, public_key_p256m, hash, hash_length);
- return status;
+ return p256_to_psa_error(ret);
}
psa_status_t p256_transparent_verify_hash(
@@ -203,10 +285,10 @@
(void) alg;
psa_status_t status;
- uint8_t public_key_buffer[65];
- size_t public_key_buffer_size = 65;
+ uint8_t public_key_buffer[PSA_PUBKEY_SIZE];
+ size_t public_key_buffer_size = PSA_PUBKEY_SIZE;
- size_t public_key_length = 65;
+ size_t public_key_length = PSA_PUBKEY_SIZE;
/* As p256-m doesn't require dynamic allocation, we want to avoid it in
* the entrypoint functions as well. psa_driver_wrapper_export_public_key()
* requires size_t*, so we use a pointer to a stack variable. */
diff --git a/3rdparty/p256-m/p256-m_driver_entrypoints.h b/3rdparty/p256-m/p256-m_driver_entrypoints.h
index 9522ced..a509ba9 100644
--- a/3rdparty/p256-m/p256-m_driver_entrypoints.h
+++ b/3rdparty/p256-m/p256-m_driver_entrypoints.h
@@ -29,6 +29,66 @@
#include "psa/crypto_types.h"
+/** Import SECP256R1 key.
+ *
+ * \param[in] attributes The attributes of the key to use for the
+ * operation.
+ * \param[in] data The raw key material. For private keys
+ * this must be a big-endian integer of 32
+ * bytes; for public key this must be an
+ * uncompressed ECPoint (65 bytes).
+ * \param[in] data_length The size of the raw key material.
+ * \param[out] key_buffer The buffer to contain the key data in
+ * output format upon successful return.
+ * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes.
+ * \param[out] key_buffer_length The length of the data written in \p
+ * key_buffer in bytes.
+ * \param[out] bits The bitsize of the key.
+ *
+ * \retval #PSA_SUCCESS
+ * Success. Keypair generated and stored in buffer.
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ * The input is not supported by this driver (not SECP256R1).
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ * The input is invalid.
+ * \retval #PSA_ERROR_BUFFER_TOO_SMALL
+ * \p key_buffer_size is too small.
+ */
+psa_status_t p256_transparent_import_key(const psa_key_attributes_t *attributes,
+ const uint8_t *data,
+ size_t data_length,
+ uint8_t *key_buffer,
+ size_t key_buffer_size,
+ size_t *key_buffer_length,
+ size_t *bits);
+
+/** Export SECP256R1 public key, from the private key.
+ *
+ * \param[in] attributes The attributes of the key to use for the
+ * operation.
+ * \param[in] key_buffer The private key in the export format.
+ * \param[in] key_buffer_size The size of the private key in bytes.
+ * \param[out] data The buffer to contain the public key in
+ * the export format upon successful return.
+ * \param[in] data_size The size of the \p data buffer in bytes.
+ * \param[out] data_length The length written to \p data in bytes.
+ *
+ * \retval #PSA_SUCCESS
+ * Success. Keypair generated and stored in buffer.
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ * The input is not supported by this driver (not SECP256R1).
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ * The input is invalid.
+ * \retval #PSA_ERROR_BUFFER_TOO_SMALL
+ * \p key_buffer_size is too small.
+ */
+psa_status_t p256_transparent_export_public_key(const psa_key_attributes_t *attributes,
+ const uint8_t *key_buffer,
+ size_t key_buffer_size,
+ uint8_t *data,
+ size_t data_size,
+ size_t *data_length);
+
/** Generate SECP256R1 ECC Key Pair.
* Interface function which calls the p256-m key generation function and
* places it in the key buffer provided by the caller (Mbed TLS) in the
@@ -44,9 +104,10 @@
*
* \retval #PSA_SUCCESS
* Success. Keypair generated and stored in buffer.
- * \retval #PSA_ERROR_NOT_SUPPORTED
- * \retval #PSA_ERROR_GENERIC_ERROR
- * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
+ * \retval #PSA_ERROR_BUFFER_TOO_SMALL
+ * \p key_buffer_size is too small.
+ * \retval #PSA_ERROR_GENERIC_ERROR
+ * The internal RNG failed.
*/
psa_status_t p256_transparent_generate_key(
const psa_key_attributes_t *attributes,
@@ -72,9 +133,12 @@
* bytes.
* \param[out] shared_secret_length On success, the number of bytes that
* make up the returned shared secret.
- * \retval #PSA_SUCCESS
- * Success. Shared secret successfully calculated.
- * \retval #PSA_ERROR_NOT_SUPPORTED
+ * \retval #PSA_SUCCESS
+ * Success. Shared secret successfully calculated.
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ * The input is invalid.
+ * \retval #PSA_ERROR_BUFFER_TOO_SMALL
+ * \p shared_secret_size is too small.
*/
psa_status_t p256_transparent_key_agreement(
const psa_key_attributes_t *attributes,
@@ -103,10 +167,14 @@
* \param[out] signature_length On success, the number of bytes
* that make up the returned signature value.
*
- * \retval #PSA_SUCCESS
+ * \retval #PSA_SUCCESS
* Success. Hash was signed successfully.
- * respectively of the key.
- * \retval #PSA_ERROR_NOT_SUPPORTED
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ * The input is invalid.
+ * \retval #PSA_ERROR_BUFFER_TOO_SMALL
+ * \p signature_size is too small.
+ * \retval #PSA_ERROR_GENERIC_ERROR
+ * The internal RNG failed.
*/
psa_status_t p256_transparent_sign_hash(
const psa_key_attributes_t *attributes,
@@ -142,12 +210,13 @@
* \param[in] signature Buffer containing the signature to verify.
* \param[in] signature_length Size of the \p signature buffer in bytes.
*
- * \retval #PSA_SUCCESS
- * The signature is valid.
- * \retval #PSA_ERROR_INVALID_SIGNATURE
- * The calculation was performed successfully, but the passed
- * signature is not a valid signature.
- * \retval #PSA_ERROR_NOT_SUPPORTED
+ * \retval #PSA_SUCCESS
+ * The signature is valid.
+ * \retval #PSA_ERROR_INVALID_SIGNATURE
+ * The calculation was performed successfully, but the passed
+ * signature is not a valid signature.
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ * The input is invalid.
*/
psa_status_t p256_transparent_verify_hash(
const psa_key_attributes_t *attributes,
diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h
index 41e980d..aea602b 100644
--- a/include/mbedtls/pk.h
+++ b/include/mbedtls/pk.h
@@ -173,11 +173,11 @@
/* Internal helper to define which fields in the pk_context structure below
* should be used for EC keys: legacy ecp_keypair or the raw (PSA friendly)
- * format. It should be noticed that this only affects how data is stored, not
+ * format. It should be noted that this only affects how data is stored, not
* which functions are used for various operations. The overall picture looks
* like this:
- * - if USE_PSA is not defined and ECP_C is then use ecp_keypair data structure
- * and legacy functions
+ * - if USE_PSA is not defined and ECP_C is defined then use ecp_keypair data
+ * structure and legacy functions
* - if USE_PSA is defined and
* - if ECP_C then use ecp_keypair structure, convert data to a PSA friendly
* format and use PSA functions
@@ -185,13 +185,13 @@
*
* The main reason for the "intermediate" (USE_PSA + ECP_C) above is that as long
* as ECP_C is defined mbedtls_pk_ec() gives the user a read/write access to the
- * ecp_keypair structure inside the pk_context so he/she can modify it using
+ * ecp_keypair structure inside the pk_context so they can modify it using
* ECP functions which are not under PK module's control.
*/
#if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) && \
!defined(MBEDTLS_ECP_C)
#define MBEDTLS_PK_USE_PSA_EC_DATA
-#endif /* MBEDTLS_USE_PSA_CRYPTO && !MBEDTLS_ECP_C */
+#endif
/* Helper symbol to state that the PK module has support for EC keys. This
* can either be provided through the legacy ECP solution or through the
@@ -200,28 +200,6 @@
#define MBEDTLS_PK_HAVE_ECC_KEYS
#endif /* MBEDTLS_PK_USE_PSA_EC_DATA || MBEDTLS_ECP_C */
-/* Internal helper to define which fields in the pk_context structure below
- * should be used for EC keys: legacy ecp_keypair or the raw (PSA friendly)
- * format. It should be noted that this only affect how data is stored, not
- * which functions are used for various operations. The overall picture looks
- * like this:
- * - if USE_PSA is not defined and ECP_C is then use ecp_keypair data structure
- * and legacy functions
- * - if USE_PSA is defined and
- * - if ECP_C then use ecp_keypair structure, convert data to a PSA friendly
- * format and use PSA functions
- * - if !ECP_C then use new raw data and PSA functions directly.
- *
- * The main reason for the "intermediate" (USE_PSA + ECP_C) above is that as long
- * as ECP_C is defined mbedtls_pk_ec() gives the user read/write access to the
- * ecp_keypair structure inside the pk_context so they can modify it using
- * ECP functions which are not under the PK module's control.
- */
-#if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) && \
- !defined(MBEDTLS_ECP_C)
-#define MBEDTLS_PK_USE_PSA_EC_DATA
-#endif /* MBEDTLS_USE_PSA_CRYPTO && !MBEDTLS_ECP_C */
-
/**
* \brief Types for interfacing with the debug module
*/
diff --git a/scripts/data_files/driver_jsons/driverlist.json b/scripts/data_files/driver_jsons/driverlist.json
index 50ad816..42c186a 100644
--- a/scripts/data_files/driver_jsons/driverlist.json
+++ b/scripts/data_files/driver_jsons/driverlist.json
@@ -1 +1 @@
-["mbedtls_test_opaque_driver.json","mbedtls_test_transparent_driver.json"]
+["mbedtls_test_opaque_driver.json","mbedtls_test_transparent_driver.json","p256_transparent_driver.json"]
diff --git a/scripts/data_files/driver_jsons/p256_transparent_driver.json b/scripts/data_files/driver_jsons/p256_transparent_driver.json
new file mode 100644
index 0000000..97c11f9
--- /dev/null
+++ b/scripts/data_files/driver_jsons/p256_transparent_driver.json
@@ -0,0 +1,20 @@
+{
+ "prefix": "p256",
+ "type": "transparent",
+ "mbedtls/h_condition": "defined(MBEDTLS_P256M_EXAMPLE_DRIVER_ENABLED)",
+ "headers": ["../3rdparty/p256-m/p256-m_driver_entrypoints.h"],
+ "capabilities": [
+ {
+ "mbedtls/c_condition": "defined(MBEDTLS_P256M_EXAMPLE_DRIVER_ENABLED)",
+ "_comment_entry_points": "This is not the complete list of entry points supported by this driver, only those that are currently supported in JSON. See docs/psa-driver-example-and-guide.md",
+ "entry_points": ["import_key", "export_public_key"],
+ "algorithms": ["PSA_ALG_ECDH", "PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)"],
+ "key_types": [
+ "PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)",
+ "PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)"
+ ],
+ "key_sizes": [256],
+ "fallback": false
+ }
+ ]
+}
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index b044135..4541b57 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -2884,6 +2884,105 @@
common_test_psa_crypto_config_reference_ecc_ffdh_no_bignum "ECC_DH"
}
+# Helper for setting common configurations between:
+# - component_test_tfm_config_p256m_driver_accel_ec()
+# - component_test_tfm_config()
+common_tfm_config () {
+ # Enable TF-M config
+ cp configs/tfm_mbedcrypto_config_profile_medium.h "$CONFIG_H"
+ cp configs/crypto_config_profile_medium.h "$CRYPTO_CONFIG_H"
+
+ # Adjust for the fact that we're building outside the TF-M environment.
+ #
+ # TF-M has separation, our build doesn't
+ scripts/config.py unset MBEDTLS_PSA_CRYPTO_SPM
+ scripts/config.py unset MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+ # TF-M provdes its own (dummy) implemenation, from their tree
+ scripts/config.py unset MBEDTLS_AES_DECRYPT_ALT
+ scripts/config.py unset MBEDTLS_AES_SETKEY_DEC_ALT
+ # We have an OS that provides entropy, use it
+ scripts/config.py unset MBEDTLS_NO_PLATFORM_ENTROPY
+
+ # Other config adjustments to make the tests pass.
+ # Those should probably be adopted upstream.
+ #
+ # - USE_PSA_CRYPTO for PK_HAVE_ECC_KEYS
+ echo "#define MBEDTLS_USE_PSA_CRYPTO" >> "$CONFIG_H"
+ # pkparse.c and pkwrite.c fail to link without this
+ echo "#define MBEDTLS_OID_C" >> "$CONFIG_H"
+ # - ASN1_[PARSE/WRITE]_C found by check_config.h for pkparse/pkwrite
+ echo "#define MBEDTLS_ASN1_PARSE_C" >> "$CONFIG_H"
+ echo "#define MBEDTLS_ASN1_WRITE_C" >> "$CONFIG_H"
+ # - MD_C for HKDF_C
+ echo "#define MBEDTLS_MD_C" >> "$CONFIG_H"
+
+ # Config adjustments for better test coverage in our environment.
+ # These are not needed just to build and pass tests.
+ #
+ # Enable filesystem I/O for the benefit of PK parse/write tests.
+ echo "#define MBEDTLS_FS_IO" >> "$CONFIG_H"
+ # Disable this for maximal ASan efficiency
+ scripts/config.py unset MBEDTLS_MEMORY_BUFFER_ALLOC_C
+
+ # Config adjustments for features that are not supported
+ # when using only drivers / by p256-m
+ #
+ # Disable all the features that auto-enable ECP_LIGHT (see build_info.h)
+ scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE
+ # Disable deterministic ECDSA as p256-m only does randomized
+ scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_ALG_DETERMINISTIC_ECDSA
+
+}
+
+# Keep this in sync with component_test_tfm_config() as they are both meant
+# to be used in analyze_outcomes.py for driver's coverage analysis.
+component_test_tfm_config_p256m_driver_accel_ec () {
+ msg "build: TF-M config + p256m driver + accel ECDH(E)/ECDSA"
+
+ common_tfm_config
+
+ # Set the list of accelerated components in order to remove them from
+ # builtin support.
+ loc_accel_list="ALG_ECDSA \
+ ALG_ECDH \
+ KEY_TYPE_ECC_KEY_PAIR_BASIC \
+ KEY_TYPE_ECC_KEY_PAIR_IMPORT \
+ KEY_TYPE_ECC_KEY_PAIR_EXPORT \
+ KEY_TYPE_ECC_KEY_PAIR_GENERATE \
+ KEY_TYPE_ECC_PUBLIC_KEY"
+ loc_accel_flags="$( echo "$loc_accel_list" | sed 's/[^ ]* */-DMBEDTLS_PSA_ACCEL_&/g' )"
+
+ # Build crypto library specifying we want to use P256M code for EC operations
+ make CFLAGS="$ASAN_CFLAGS $loc_accel_flags -DMBEDTLS_P256M_EXAMPLE_DRIVER_ENABLED" LDFLAGS="$ASAN_CFLAGS"
+
+ # Make sure any built-in EC alg was not re-enabled by accident (additive config)
+ not grep mbedtls_ecdsa_ library/ecdsa.o
+ not grep mbedtls_ecdh_ library/ecdh.o
+ not grep mbedtls_ecjpake_ library/ecjpake.o
+ # Also ensure that ECP, RSA, DHM or BIGNUM modules were not re-enabled
+ not grep mbedtls_ecp_ library/ecp.o
+ not grep mbedtls_rsa_ library/rsa.o
+ not grep mbedtls_dhm_ library/dhm.o
+ not grep mbedtls_mpi_ library/bignum.o
+
+ # Run the tests
+ msg "test: TF-M config + p256m driver + accel ECDH(E)/ECDSA"
+ make test
+}
+
+# Keep this in sync with component_test_tfm_config_p256m_driver_accel_ec() as
+# they are both meant to be used in analyze_outcomes.py for driver's coverage
+# analysis.
+component_test_tfm_config() {
+ common_tfm_config
+
+ msg "build: TF-M config"
+ make tests
+
+ msg "test: TF-M config"
+ make test
+}
+
# Helper function used in:
# - component_test_psa_crypto_config_accel_all_curves_except_p192
# - component_test_psa_crypto_config_accel_all_curves_except_x25519
diff --git a/tests/scripts/analyze_outcomes.py b/tests/scripts/analyze_outcomes.py
index 7b0ab3d..119dbb5 100755
--- a/tests/scripts/analyze_outcomes.py
+++ b/tests/scripts/analyze_outcomes.py
@@ -521,6 +521,102 @@
'ignored_tests': {}
}
},
+ 'analyze_driver_vs_reference_tfm_config': {
+ 'test_function': do_analyze_driver_vs_reference,
+ 'args': {
+ 'component_ref': 'test_tfm_config',
+ 'component_driver': 'test_tfm_config_p256m_driver_accel_ec',
+ 'ignored_suites': [
+ # Ignore test suites for the modules that are disabled in the
+ # accelerated test case.
+ 'ecp',
+ 'ecdsa',
+ 'ecdh',
+ 'ecjpake',
+ 'bignum_core',
+ 'bignum_random',
+ 'bignum_mod',
+ 'bignum_mod_raw',
+ 'bignum.generated',
+ 'bignum.misc',
+ ],
+ 'ignored_tests': {
+ # Ignore all tests that require DERIVE support which is disabled
+ # in the driver version
+ 'test_suite_psa_crypto': [
+ 'PSA key agreement setup: ECDH + HKDF-SHA-256: good',
+ ('PSA key agreement setup: ECDH + HKDF-SHA-256: good, key algorithm broader '
+ 'than required'),
+ 'PSA key agreement setup: ECDH + HKDF-SHA-256: public key not on curve',
+ 'PSA key agreement setup: KDF instead of a key agreement algorithm',
+ 'PSA key agreement setup: bad key agreement algorithm',
+ 'PSA key agreement: ECDH SECP256R1 (RFC 5903) + HKDF-SHA-256: capacity=8160',
+ 'PSA key agreement: ECDH SECP256R1 (RFC 5903) + HKDF-SHA-256: read 0+32',
+ 'PSA key agreement: ECDH SECP256R1 (RFC 5903) + HKDF-SHA-256: read 1+31',
+ 'PSA key agreement: ECDH SECP256R1 (RFC 5903) + HKDF-SHA-256: read 31+1',
+ 'PSA key agreement: ECDH SECP256R1 (RFC 5903) + HKDF-SHA-256: read 32+0',
+ 'PSA key agreement: ECDH SECP256R1 (RFC 5903) + HKDF-SHA-256: read 32+32',
+ 'PSA key agreement: ECDH SECP256R1 (RFC 5903) + HKDF-SHA-256: read 64+0',
+ 'PSA key derivation: ECDH on P256 with HKDF-SHA256, info first',
+ 'PSA key derivation: ECDH on P256 with HKDF-SHA256, key output',
+ 'PSA key derivation: ECDH on P256 with HKDF-SHA256, missing info',
+ 'PSA key derivation: ECDH on P256 with HKDF-SHA256, omitted salt',
+ 'PSA key derivation: ECDH on P256 with HKDF-SHA256, raw output',
+ 'PSA key derivation: ECDH on P256 with HKDF-SHA256, salt after secret',
+ 'PSA key derivation: ECDH with TLS 1.2 PRF SHA-256, good case',
+ 'PSA key derivation: ECDH with TLS 1.2 PRF SHA-256, missing label',
+ 'PSA key derivation: ECDH with TLS 1.2 PRF SHA-256, missing label and secret',
+ 'PSA key derivation: ECDH with TLS 1.2 PRF SHA-256, no inputs',
+ 'PSA key derivation: HKDF-SHA-256 -> ECC secp256r1',
+ 'PSA key derivation: HKDF-SHA-256 -> ECC secp256r1 (1 redraw)',
+ 'PSA key derivation: HKDF-SHA-256 -> ECC secp256r1, exercise ECDSA',
+ 'PSA key derivation: TLS 1.2 Mix-PSK-to-MS, SHA-256, 0+48, ka',
+ 'PSA key derivation: TLS 1.2 Mix-PSK-to-MS, SHA-256, 24+24, ka',
+ 'PSA key derivation: TLS 1.2 Mix-PSK-to-MS, SHA-256, 48+0, ka',
+ 'PSA key derivation: TLS 1.2 Mix-PSK-to-MS, bad state #1, ka',
+ 'PSA key derivation: TLS 1.2 Mix-PSK-to-MS, bad state #3, ka',
+ 'PSA key derivation: TLS 1.2 Mix-PSK-to-MS, bad state #4, ka',
+ 'PSA key derivation: bits=7 invalid for ECC BRAINPOOL_P_R1 (ECC enabled)',
+ 'PSA key derivation: bits=7 invalid for ECC MONTGOMERY (ECC enabled)',
+ 'PSA key derivation: bits=7 invalid for ECC SECP_K1 (ECC enabled)',
+ 'PSA key derivation: bits=7 invalid for ECC SECP_R1 (ECC enabled)',
+ 'PSA key derivation: bits=7 invalid for ECC SECP_R2 (ECC enabled)',
+ 'PSA key derivation: bits=7 invalid for ECC SECT_K1 (ECC enabled)',
+ 'PSA key derivation: bits=7 invalid for ECC SECT_R1 (ECC enabled)',
+ 'PSA key derivation: bits=7 invalid for ECC SECT_R2 (ECC enabled)',
+ 'PSA raw key agreement: ECDH SECP256R1 (RFC 5903)',
+ ],
+ 'test_suite_random': [
+ 'PSA classic wrapper: ECDSA signature (SECP256R1)',
+ ],
+ 'test_suite_psa_crypto_pake': [
+ 'PSA PAKE: ecjpake size macros',
+ ],
+ 'test_suite_asn1parse': [
+ # This test depends on BIGNUM_C
+ 'INTEGER too large for mpi',
+ ],
+ 'test_suite_asn1write': [
+ # Following tests depends on BIGNUM_C
+ 'ASN.1 Write mpi 0 (1 limb)',
+ 'ASN.1 Write mpi 0 (null)',
+ 'ASN.1 Write mpi 0x100',
+ 'ASN.1 Write mpi 0x7f',
+ 'ASN.1 Write mpi 0x7f with leading 0 limb',
+ 'ASN.1 Write mpi 0x80',
+ 'ASN.1 Write mpi 0x80 with leading 0 limb',
+ 'ASN.1 Write mpi 0xff',
+ 'ASN.1 Write mpi 1',
+ 'ASN.1 Write mpi, 127*8 bits',
+ 'ASN.1 Write mpi, 127*8+1 bits',
+ 'ASN.1 Write mpi, 127*8-1 bits',
+ 'ASN.1 Write mpi, 255*8 bits',
+ 'ASN.1 Write mpi, 255*8-1 bits',
+ 'ASN.1 Write mpi, 256*8-1 bits',
+ ],
+ }
+ }
+ }
}
def main():
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index 88bdd6c..c5eeb49 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -1366,7 +1366,21 @@
psa_set_key_bits(&attributes, attr_bits);
status = psa_import_key(&attributes, data->x, data->len, &key);
- TEST_EQUAL(status, expected_status);
+ /* When expecting INVALID_ARGUMENT, also accept NOT_SUPPORTED.
+ *
+ * This can happen with a type supported only by a driver:
+ * - the driver sees the invalid data (for example wrong size) and thinks
+ * "well perhaps this is a key size I don't support" so it returns
+ * NOT_SUPPORTED which is correct at this point;
+ * - we fallback to built-ins, which don't support this type, so return
+ * NOT_SUPPORTED which again is correct at this point.
+ */
+ if (expected_status == PSA_ERROR_INVALID_ARGUMENT &&
+ status == PSA_ERROR_NOT_SUPPORTED) {
+ ; // OK
+ } else {
+ TEST_EQUAL(status, expected_status);
+ }
if (status != PSA_SUCCESS) {
goto exit;
}