Merge pull request #8934 from paul-elliott-arm/add_threading_changelog
Add changelog entry for threading MVP
diff --git a/ChangeLog.d/early-data.txt b/ChangeLog.d/early-data.txt
new file mode 100644
index 0000000..3c3826c
--- /dev/null
+++ b/ChangeLog.d/early-data.txt
@@ -0,0 +1,5 @@
+Features
+ * Mbed TLS now supports the writing and reading of TLS 1.3 early data (see
+ docs/tls13-early-data.md). The support enablement is controlled at build
+ time by the MBEDTLS_SSL_EARLY_DATA configuration option and at runtime by
+ the mbedtls_ssl_conf_early_data() API (by default disabled in both cases).
diff --git a/docs/architecture/tls13-support.md b/docs/architecture/tls13-support.md
index 6db0e54..d6fc19e 100644
--- a/docs/architecture/tls13-support.md
+++ b/docs/architecture/tls13-support.md
@@ -4,17 +4,8 @@
Overview
--------
-Mbed TLS provides a partial implementation of the TLS 1.3 protocol defined in
-the "Support description" section below. The TLS 1.3 support enablement
-is controlled by the MBEDTLS_SSL_PROTO_TLS1_3 configuration option.
-
-The development of the TLS 1.3 protocol is based on the TLS 1.3 prototype
-located at https://github.com/hannestschofenig/mbedtls. The prototype is
-itself based on a version of the development branch that we aim to keep as
-recent as possible (ideally the head) by merging regularly commits of the
-development branch into the prototype. The section "Prototype upstreaming
-status" below describes what remains to be upstreamed.
-
+Mbed TLS provides an implementation of the TLS 1.3 protocol. The TLS 1.3 support
+may be enabled using the MBEDTLS_SSL_PROTO_TLS1_3 configuration option.
Support description
-------------------
@@ -26,14 +17,14 @@
- Mbed TLS supports ECDHE key establishment.
- - Mbed TLS does not support DHE key establishment.
+ - Mbed TLS supports DHE key establishment.
- Mbed TLS supports pre-shared keys for key establishment, pre-shared keys
provisioned externally as well as provisioned via the ticket mechanism.
- Mbed TLS supports session resumption via the ticket mechanism.
- - Mbed TLS does not support sending or receiving early data (0-RTT data).
+ - Mbed TLS supports sending and receiving early data (0-RTT data).
- Supported cipher suites: depends on the library configuration. Potentially
all of them:
@@ -51,7 +42,7 @@
| signature_algorithms | YES |
| use_srtp | no |
| heartbeat | no |
- | apln | YES |
+ | alpn | YES |
| signed_certificate_timestamp | no |
| client_certificate_type | no |
| server_certificate_type | no |
@@ -59,7 +50,7 @@
| key_share | YES |
| pre_shared_key | YES |
| psk_key_exchange_modes | YES |
- | early_data | no |
+ | early_data | YES |
| cookie | no |
| supported_versions | YES |
| certificate_authorities | no |
@@ -71,7 +62,8 @@
Potentially all ECDHE groups:
secp256r1, x25519, secp384r1, x448 and secp521r1.
- Finite field groups (DHE) are not supported.
+ Potentially all DHE groups:
+ ffdhe2048, ffdhe3072, ffdhe4096, ffdhe6144 and ffdhe8192.
- Supported signature algorithms (both for certificates and CertificateVerify):
depends on the library configuration.
@@ -105,7 +97,7 @@
| Mbed TLS configuration option | Support |
| ---------------------------------------- | ------- |
- | MBEDTLS_SSL_ALL_ALERT_MESSAGES | no |
+ | MBEDTLS_SSL_ALL_ALERT_MESSAGES | yes |
| MBEDTLS_SSL_ASYNC_PRIVATE | no |
| MBEDTLS_SSL_CONTEXT_SERIALIZATION | no |
| MBEDTLS_SSL_DEBUG_ALL | no |
@@ -167,33 +159,6 @@
TLS 1.3 specification.
-Prototype upstreaming status
-----------------------------
-
-The following parts of the TLS 1.3 prototype remain to be upstreamed:
-
-- Sending (client) and receiving (server) early data (0-RTT data).
-
-- New TLS Message Processing Stack (MPS)
-
- The TLS 1.3 prototype is developed alongside a rewrite of the TLS messaging layer,
- encompassing low-level details such as record parsing, handshake reassembly, and
- DTLS retransmission state machine.
-
- MPS has the following components:
- - Layer 1 (Datagram handling)
- - Layer 2 (Record handling)
- - Layer 3 (Message handling)
- - Layer 4 (Retransmission State Machine)
- - Reader (Abstracted pointer arithmetic and reassembly logic for incoming data)
- - Writer (Abstracted pointer arithmetic and fragmentation logic for outgoing data)
-
- Of those components, the following have been upstreamed
- as part of `MBEDTLS_SSL_PROTO_TLS1_3`:
-
- - Reader ([`library/mps_reader.h`](../../library/mps_reader.h))
-
-
Coding rules checklist for TLS 1.3
----------------------------------
@@ -266,10 +231,6 @@
- the macro to check for data when reading from an input buffer
`MBEDTLS_SSL_CHK_BUF_READ_PTR`.
- These macros were introduced after the prototype was written thus are
- likely not to be used in prototype where we now would use them in
- development.
-
The three first types, MBEDTLS_BYTE_{0-8}, MBEDTLS_PUT_UINT{8|16|32|64}_BE
and MBEDTLS_GET_UINT{8|16|32|64}_BE improve the readability of the code and
reduce the risk of writing or reading bytes in the wrong order.
@@ -472,175 +433,3 @@
* state change: the state change is done in the main state handler to ease
the navigation of the state machine transitions.
-
-
-Writing and reading early or 0-RTT data
----------------------------------------
-
-An application function to write and send a buffer of data to a server through
-TLS may plausibly look like:
-
-```
-int write_data( mbedtls_ssl_context *ssl,
- const unsigned char *data_to_write,
- size_t data_to_write_len,
- size_t *data_written )
-{
- *data_written = 0;
-
- while( *data_written < data_to_write_len )
- {
- ret = mbedtls_ssl_write( ssl, data_to_write + *data_written,
- data_to_write_len - *data_written );
-
- if( ret < 0 &&
- ret != MBEDTLS_ERR_SSL_WANT_READ &&
- ret != MBEDTLS_ERR_SSL_WANT_WRITE )
- {
- return( ret );
- }
-
- *data_written += ret;
- }
-
- return( 0 );
-}
-```
-where ssl is the SSL context to use, data_to_write the address of the data
-buffer and data_to_write_len the number of data bytes. The handshake may
-not be completed, not even started for the SSL context ssl when the function is
-called and in that case the mbedtls_ssl_write() API takes care transparently of
-completing the handshake before to write and send data to the server. The
-mbedtls_ssl_write() may not been able to write and send all data in one go thus
-the need for a loop calling it as long as there are still data to write and
-send.
-
-An application function to write and send early data and only early data,
-data sent during the first flight of client messages while the handshake is in
-its initial phase, would look completely similar but the call to
-mbedtls_ssl_write_early_data() instead of mbedtls_ssl_write().
-```
-int write_early_data( mbedtls_ssl_context *ssl,
- const unsigned char *data_to_write,
- size_t data_to_write_len,
- size_t *data_written )
-{
- *data_written = 0;
-
- while( *data_written < data_to_write_len )
- {
- ret = mbedtls_ssl_write_early_data( ssl, data_to_write + *data_written,
- data_to_write_len - *data_written );
-
- if( ret < 0 &&
- ret != MBEDTLS_ERR_SSL_WANT_READ &&
- ret != MBEDTLS_ERR_SSL_WANT_WRITE )
- {
- return( ret );
- }
-
- *data_written += ret;
- }
-
- return( 0 );
-}
-```
-Note that compared to write_data(), write_early_data() can also return
-MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA and that should be handled
-specifically by the user of write_early_data(). A fresh SSL context (typically
-just after a call to mbedtls_ssl_setup() or mbedtls_ssl_session_reset()) would
-be expected when calling `write_early_data`.
-
-All together, code to write and send a buffer of data as long as possible as
-early data and then as standard post-handshake application data could
-plausibly look like:
-
-```
-ret = write_early_data( ssl, data_to_write, data_to_write_len,
- &early_data_written );
-if( ret < 0 &&
- ret != MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA )
-{
- goto error;
-}
-
-ret = write_data( ssl, data_to_write + early_data_written,
- data_to_write_len - early_data_written, &data_written );
-if( ret < 0 )
- goto error;
-
-data_written += early_data_written;
-```
-
-Finally, taking into account that the server may reject early data, application
-code to write and send a buffer of data could plausibly look like:
-```
-ret = write_early_data( ssl, data_to_write, data_to_write_len,
- &early_data_written );
-if( ret < 0 &&
- ret != MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA )
-{
- goto error;
-}
-
-/*
- * Make sure the handshake is completed as it is a requisite to
- * mbedtls_ssl_get_early_data_status().
- */
-while( !mbedtls_ssl_is_handshake_over( ssl ) )
-{
- ret = mbedtls_ssl_handshake( ssl );
- if( ret < 0 &&
- ret != MBEDTLS_ERR_SSL_WANT_READ &&
- ret != MBEDTLS_ERR_SSL_WANT_WRITE )
- {
- goto error;
- }
-}
-
-ret = mbedtls_ssl_get_early_data_status( ssl );
-if( ret < 0 )
- goto error;
-
-if( ret == MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED )
- early_data_written = 0;
-
-ret = write_data( ssl, data_to_write + early_data_written,
- data_to_write_len - early_data_written, &data_written );
-if( ret < 0 )
- goto error;
-
-data_written += early_data_written;
-```
-
-Basically, the same holds for reading early data on the server side without the
-complication of possible rejection. An application function to read early data
-into a given buffer could plausibly look like:
-```
-int read_early_data( mbedtls_ssl_context *ssl,
- unsigned char *buffer,
- size_t buffer_size,
- size_t *data_len )
-{
- *data_len = 0;
-
- while( *data_len < buffer_size )
- {
- ret = mbedtls_ssl_read_early_data( ssl, buffer + *data_len,
- buffer_size - *data_len );
-
- if( ret < 0 &&
- ret != MBEDTLS_ERR_SSL_WANT_READ &&
- ret != MBEDTLS_ERR_SSL_WANT_WRITE )
- {
- return( ret );
- }
-
- *data_len += ret;
- }
-
- return( 0 );
-}
-```
-with again calls to read_early_data() expected to be done with a fresh SSL
-context.
diff --git a/docs/tls13-early-data.md b/docs/tls13-early-data.md
new file mode 100644
index 0000000..4b6f5d3
--- /dev/null
+++ b/docs/tls13-early-data.md
@@ -0,0 +1,192 @@
+
+Writing early data
+------------------
+
+An application function to write and send a buffer of data to a server through
+TLS may plausibly look like:
+
+```
+int write_data(mbedtls_ssl_context *ssl,
+ const unsigned char *data_to_write,
+ size_t data_to_write_len,
+ size_t *data_written)
+{
+ int ret;
+ *data_written = 0;
+
+ while (*data_written < data_to_write_len) {
+ ret = mbedtls_ssl_write(ssl, data_to_write + *data_written,
+ data_to_write_len - *data_written);
+
+ if (ret < 0 &&
+ ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ return ret;
+ }
+
+ *data_written += ret;
+ }
+
+ return 0;
+}
+```
+where ssl is the SSL context to use, data_to_write the address of the data
+buffer and data_to_write_len the number of data bytes. The handshake may
+not be completed, not even started for the SSL context ssl when the function is
+called and in that case the mbedtls_ssl_write() API takes care transparently of
+completing the handshake before to write and send data to the server. The
+mbedtls_ssl_write() may not be able to write and send all data in one go thus
+the need for a loop calling it as long as there are still data to write and
+send.
+
+An application function to write and send early data and only early data,
+data sent during the first flight of client messages while the handshake is in
+its initial phase, would look completely similar but the call to
+mbedtls_ssl_write_early_data() instead of mbedtls_ssl_write().
+```
+int write_early_data(mbedtls_ssl_context *ssl,
+ const unsigned char *data_to_write,
+ size_t data_to_write_len,
+ size_t *data_written)
+{
+ int ret;
+ *data_written = 0;
+
+ while (*data_written < data_to_write_len) {
+ ret = mbedtls_ssl_write_early_data(ssl, data_to_write + *data_written,
+ data_to_write_len - *data_written);
+
+ if (ret < 0 &&
+ ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ return ret;
+ }
+
+ *data_written += ret;
+ }
+
+ return 0;
+}
+```
+Note that compared to write_data(), write_early_data() can also return
+MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA and that should be handled
+specifically by the user of write_early_data(). A fresh SSL context (typically
+just after a call to mbedtls_ssl_setup() or mbedtls_ssl_session_reset()) would
+be expected when calling `write_early_data`.
+
+All together, code to write and send a buffer of data as long as possible as
+early data and then as standard post-handshake application data could
+plausibly look like:
+
+```
+ret = write_early_data(ssl,
+ data_to_write,
+ data_to_write_len,
+ &early_data_written);
+if (ret < 0 &&
+ ret != MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA) {
+ goto error;
+}
+
+ret = write_data(ssl,
+ data_to_write + early_data_written,
+ data_to_write_len - early_data_written,
+ &data_written);
+if (ret < 0) {
+ goto error;
+}
+
+data_written += early_data_written;
+```
+
+Finally, taking into account that the server may reject early data, application
+code to write and send a buffer of data could plausibly look like:
+```
+ret = write_early_data(ssl,
+ data_to_write,
+ data_to_write_len,
+ &early_data_written);
+if (ret < 0 &&
+ ret != MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA) {
+ goto error;
+}
+
+/*
+ * Make sure the handshake is completed as it is a requisite of
+ * mbedtls_ssl_get_early_data_status().
+ */
+while (!mbedtls_ssl_is_handshake_over(ssl)) {
+ ret = mbedtls_ssl_handshake(ssl);
+ if (ret < 0 &&
+ ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ goto error;
+ }
+}
+
+ret = mbedtls_ssl_get_early_data_status(ssl);
+if (ret < 0) {
+ goto error;
+}
+
+if (ret == MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED) {
+ early_data_written = 0;
+}
+
+ret = write_data(ssl,
+ data_to_write + early_data_written,
+ data_to_write_len - early_data_written,
+ &data_written);
+if (ret < 0) {
+ goto error;
+}
+
+data_written += early_data_written;
+```
+
+Reading early data
+------------------
+Mbed TLS provides the mbedtls_ssl_read_early_data() API to read the early data
+that a TLS 1.3 server might receive during the TLS 1.3 handshake.
+
+While establishing a TLS 1.3 connection with a client using a combination
+of the mbedtls_ssl_handshake(), mbedtls_ssl_read() and mbedtls_ssl_write() APIs,
+the reception of early data is signaled by an API returning the
+MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA error code. Early data can then be read
+with the mbedtls_ssl_read_early_data() API.
+
+For example, a typical code to establish a TLS connection, where ssl is the SSL
+context to use:
+```
+while ((int ret = mbedtls_ssl_handshake(&ssl)) != 0) {
+
+ if (ret < 0 &&
+ ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ break;
+ }
+}
+```
+could be adapted to handle early data in the following way:
+```
+size_t data_read_len = 0;
+while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
+
+ if (ret == MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA) {
+ ret = mbedtls_ssl_read_early_data(&ssl,
+ buffer + data_read_len,
+ sizeof(buffer) - data_read_len);
+ if (ret < 0) {
+ break;
+ }
+ data_read_len += ret;
+ continue;
+ }
+
+ if (ret < 0 &&
+ ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ break;
+ }
+}
+```
diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h
index 5f550c8..cf6d406 100644
--- a/include/mbedtls/mbedtls_config.h
+++ b/include/mbedtls/mbedtls_config.h
@@ -1854,9 +1854,6 @@
* Comment this to disable support for early data. If MBEDTLS_SSL_PROTO_TLS1_3
* is not enabled, this option does not have any effect on the build.
*
- * This feature is experimental, not completed and thus not ready for
- * production.
- *
* \note The maximum amount of early data can be set with
* MBEDTLS_SSL_MAX_EARLY_DATA_SIZE.
*
@@ -4145,10 +4142,6 @@
*
* If MBEDTLS_SSL_EARLY_DATA is not defined, this default value does not
* have any impact on the build.
- *
- * This feature is experimental, not completed and thus not ready for
- * production.
- *
*/
//#define MBEDTLS_SSL_MAX_EARLY_DATA_SIZE 1024
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 57d7bc6..172d469 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -2102,9 +2102,6 @@
* MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA indicating that some early data have
* been received. To read the early data, call mbedtls_ssl_read_early_data()
* before calling the original function again.
- *
- * \warning This interface is experimental and may change without notice.
- *
*/
void mbedtls_ssl_conf_early_data(mbedtls_ssl_config *conf,
int early_data_enabled);
@@ -2130,12 +2127,9 @@
* \param[in] conf The SSL configuration to use.
* \param[in] max_early_data_size The maximum amount of 0-RTT data.
*
- * \warning This interface is experimental and may change without notice.
- *
* \warning This interface DOES NOT influence/limit the amount of early data
* that can be received through previously created and issued tickets,
* which clients may have stored.
- *
*/
void mbedtls_ssl_conf_max_early_data_size(
mbedtls_ssl_config *conf, uint32_t max_early_data_size);
@@ -5229,6 +5223,11 @@
* same warnings apply to any use of the
* early_exporter_master_secret.
*
+ * \warning Mbed TLS does not implement any of the anti-replay defenses
+ * defined in section 8 of the TLS 1.3 specification:
+ * single-use of tickets or ClientHello recording within a
+ * given time window.
+ *
* \note This function is used in conjunction with
* mbedtls_ssl_handshake(), mbedtls_ssl_handshake_step(),
* mbedtls_ssl_read() and mbedtls_ssl_write() to read early
diff --git a/include/mbedtls/threading.h b/include/mbedtls/threading.h
index b4e0502..d50d04e 100644
--- a/include/mbedtls/threading.h
+++ b/include/mbedtls/threading.h
@@ -112,6 +112,20 @@
* psa_key_slot_state_transition(), psa_register_read(), psa_unregister_read(),
* psa_key_slot_has_readers() and psa_wipe_key_slot(). */
extern mbedtls_threading_mutex_t mbedtls_threading_key_slot_mutex;
+
+/*
+ * A mutex used to make the non-rng PSA global_data struct members thread safe.
+ *
+ * This mutex must be held when reading or writing to any of the PSA global_data
+ * structure members, other than the rng_state or rng struct. */
+extern mbedtls_threading_mutex_t mbedtls_threading_psa_globaldata_mutex;
+
+/*
+ * A mutex used to make the PSA global_data rng data thread safe.
+ *
+ * This mutex must be held when reading or writing to the PSA
+ * global_data rng_state or rng struct members. */
+extern mbedtls_threading_mutex_t mbedtls_threading_psa_rngdata_mutex;
#endif
#endif /* MBEDTLS_THREADING_C */
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index ec9d115..a0a002a 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -71,6 +71,7 @@
#include "mbedtls/sha256.h"
#include "mbedtls/sha512.h"
#include "mbedtls/psa_util.h"
+#include "mbedtls/threading.h"
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT) || \
@@ -92,30 +93,93 @@
#define RNG_INITIALIZED 1
#define RNG_SEEDED 2
+/* IDs for PSA crypto subsystems. Starts at 1 to catch potential uninitialized
+ * variables as arguments. */
+typedef enum {
+ PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS = 1,
+ PSA_CRYPTO_SUBSYSTEM_KEY_SLOTS,
+ PSA_CRYPTO_SUBSYSTEM_RNG,
+ PSA_CRYPTO_SUBSYSTEM_TRANSACTION,
+} mbedtls_psa_crypto_subsystem;
+
+/* Initialization flags for global_data::initialized */
+#define PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS_INITIALIZED 0x01
+#define PSA_CRYPTO_SUBSYSTEM_KEY_SLOTS_INITIALIZED 0x02
+#define PSA_CRYPTO_SUBSYSTEM_TRANSACTION_INITIALIZED 0x04
+
+#define PSA_CRYPTO_SUBSYSTEM_ALL_INITIALISED ( \
+ PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS_INITIALIZED | \
+ PSA_CRYPTO_SUBSYSTEM_KEY_SLOTS_INITIALIZED | \
+ PSA_CRYPTO_SUBSYSTEM_TRANSACTION_INITIALIZED)
+
typedef struct {
uint8_t initialized;
uint8_t rng_state;
- uint8_t drivers_initialized;
mbedtls_psa_random_context_t rng;
} psa_global_data_t;
static psa_global_data_t global_data;
+static uint8_t psa_get_initialized(void)
+{
+ uint8_t initialized;
+
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_lock(&mbedtls_threading_psa_rngdata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ initialized = global_data.rng_state == RNG_SEEDED;
+
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_unlock(&mbedtls_threading_psa_rngdata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ initialized =
+ (initialized && (global_data.initialized == PSA_CRYPTO_SUBSYSTEM_ALL_INITIALISED));
+
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_unlock(&mbedtls_threading_psa_globaldata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ return initialized;
+}
+
+static uint8_t psa_get_drivers_initialized(void)
+{
+ uint8_t initialized;
+
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ initialized = (global_data.initialized & PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS_INITIALIZED) != 0;
+
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_unlock(&mbedtls_threading_psa_globaldata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ return initialized;
+}
+
#define GUARD_MODULE_INITIALIZED \
- if (global_data.initialized == 0) \
+ if (psa_get_initialized() == 0) \
return PSA_ERROR_BAD_STATE;
int psa_can_do_hash(psa_algorithm_t hash_alg)
{
(void) hash_alg;
- return global_data.drivers_initialized;
+ return psa_get_drivers_initialized();
}
int psa_can_do_cipher(psa_key_type_t key_type, psa_algorithm_t cipher_alg)
{
(void) key_type;
(void) cipher_alg;
- return global_data.drivers_initialized;
+ return psa_get_drivers_initialized();
}
@@ -7082,6 +7146,9 @@
#endif
/** Initialize the PSA random generator.
+ *
+ * Note: the mbedtls_threading_psa_rngdata_mutex should be held when calling
+ * this function if mutexes are enabled.
*/
static void mbedtls_psa_random_init(mbedtls_psa_random_context_t *rng)
{
@@ -7114,6 +7181,9 @@
}
/** Deinitialize the PSA random generator.
+ *
+ * Note: the mbedtls_threading_psa_rngdata_mutex should be held when calling
+ * this function if mutexes are enabled.
*/
static void mbedtls_psa_random_free(mbedtls_psa_random_context_t *rng)
{
@@ -7189,7 +7259,7 @@
psa_status_t mbedtls_psa_inject_entropy(const uint8_t *seed,
size_t seed_size)
{
- if (global_data.initialized) {
+ if (psa_get_initialized()) {
return PSA_ERROR_NOT_PERMITTED;
}
@@ -7431,28 +7501,77 @@
void (* entropy_init)(mbedtls_entropy_context *ctx),
void (* entropy_free)(mbedtls_entropy_context *ctx))
{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_lock(&mbedtls_threading_psa_rngdata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
+
if (global_data.rng_state != RNG_NOT_INITIALIZED) {
- return PSA_ERROR_BAD_STATE;
+ status = PSA_ERROR_BAD_STATE;
+ } else {
+ global_data.rng.entropy_init = entropy_init;
+ global_data.rng.entropy_free = entropy_free;
+ status = PSA_SUCCESS;
}
- global_data.rng.entropy_init = entropy_init;
- global_data.rng.entropy_free = entropy_free;
- return PSA_SUCCESS;
+
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_unlock(&mbedtls_threading_psa_rngdata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ return status;
}
#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */
void mbedtls_psa_crypto_free(void)
{
- psa_wipe_all_key_slots();
+
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ /* Nothing to do to free transaction. */
+ if (global_data.initialized & PSA_CRYPTO_SUBSYSTEM_TRANSACTION_INITIALIZED) {
+ global_data.initialized &= ~PSA_CRYPTO_SUBSYSTEM_TRANSACTION_INITIALIZED;
+ }
+
+ if (global_data.initialized & PSA_CRYPTO_SUBSYSTEM_KEY_SLOTS_INITIALIZED) {
+ psa_wipe_all_key_slots();
+ global_data.initialized &= ~PSA_CRYPTO_SUBSYSTEM_KEY_SLOTS_INITIALIZED;
+ }
+
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_unlock(&mbedtls_threading_psa_globaldata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_lock(&mbedtls_threading_psa_rngdata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
+
if (global_data.rng_state != RNG_NOT_INITIALIZED) {
mbedtls_psa_random_free(&global_data.rng);
}
- /* Wipe all remaining data, including configuration.
- * In particular, this sets all state indicator to the value
- * indicating "uninitialized". */
- mbedtls_platform_zeroize(&global_data, sizeof(global_data));
+ global_data.rng_state = RNG_NOT_INITIALIZED;
+ mbedtls_platform_zeroize(&global_data.rng, sizeof(global_data.rng));
+
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_unlock(&mbedtls_threading_psa_rngdata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
/* Terminate drivers */
- psa_driver_wrapper_free();
+ if (global_data.initialized & PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS_INITIALIZED) {
+ psa_driver_wrapper_free();
+ global_data.initialized &= ~PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS_INITIALIZED;
+ }
+
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_unlock(&mbedtls_threading_psa_globaldata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
+
}
#if defined(PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS)
@@ -7480,57 +7599,171 @@
}
#endif /* PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS */
+static psa_status_t mbedtls_psa_crypto_init_subsystem(mbedtls_psa_crypto_subsystem subsystem)
+{
+ psa_status_t status = PSA_SUCCESS;
+ uint8_t driver_wrappers_initialized = 0;
+
+ switch (subsystem) {
+ case PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS:
+
+#if defined(MBEDTLS_THREADING_C)
+ PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex));
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ if (!(global_data.initialized & PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS_INITIALIZED)) {
+ /* Init drivers */
+ status = psa_driver_wrapper_init();
+
+ /* Drivers need shutdown regardless of startup errors. */
+ global_data.initialized |= PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS_INITIALIZED;
+
+
+ }
+#if defined(MBEDTLS_THREADING_C)
+ PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_unlock(
+ &mbedtls_threading_psa_globaldata_mutex));
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ break;
+
+ case PSA_CRYPTO_SUBSYSTEM_KEY_SLOTS:
+
+#if defined(MBEDTLS_THREADING_C)
+ PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex));
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ if (!(global_data.initialized & PSA_CRYPTO_SUBSYSTEM_KEY_SLOTS_INITIALIZED)) {
+ status = psa_initialize_key_slots();
+
+ /* Need to wipe keys even if initialization fails. */
+ global_data.initialized |= PSA_CRYPTO_SUBSYSTEM_KEY_SLOTS_INITIALIZED;
+
+ }
+#if defined(MBEDTLS_THREADING_C)
+ PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_unlock(
+ &mbedtls_threading_psa_globaldata_mutex));
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ break;
+
+ case PSA_CRYPTO_SUBSYSTEM_RNG:
+
+#if defined(MBEDTLS_THREADING_C)
+ PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex));
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ driver_wrappers_initialized =
+ (global_data.initialized & PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS_INITIALIZED);
+
+#if defined(MBEDTLS_THREADING_C)
+ PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_unlock(
+ &mbedtls_threading_psa_globaldata_mutex));
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ /* Need to use separate mutex here, as initialisation can require
+ * testing of init flags, which requires locking the global data
+ * mutex. */
+#if defined(MBEDTLS_THREADING_C)
+ PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_lock(&mbedtls_threading_psa_rngdata_mutex));
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ /* Initialize and seed the random generator. */
+ if (global_data.rng_state == RNG_NOT_INITIALIZED && driver_wrappers_initialized) {
+ mbedtls_psa_random_init(&global_data.rng);
+ global_data.rng_state = RNG_INITIALIZED;
+
+ status = mbedtls_psa_random_seed(&global_data.rng);
+ if (status == PSA_SUCCESS) {
+ global_data.rng_state = RNG_SEEDED;
+ }
+ }
+
+#if defined(MBEDTLS_THREADING_C)
+ PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_unlock(
+ &mbedtls_threading_psa_rngdata_mutex));
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ break;
+
+ case PSA_CRYPTO_SUBSYSTEM_TRANSACTION:
+
+#if defined(MBEDTLS_THREADING_C)
+ PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex));
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ if (!(global_data.initialized & PSA_CRYPTO_SUBSYSTEM_TRANSACTION_INITIALIZED)) {
+#if defined(PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS)
+ status = psa_crypto_load_transaction();
+ if (status == PSA_SUCCESS) {
+ status = psa_crypto_recover_transaction(&psa_crypto_transaction);
+ if (status == PSA_SUCCESS) {
+ global_data.initialized |= PSA_CRYPTO_SUBSYSTEM_TRANSACTION_INITIALIZED;
+ }
+ status = psa_crypto_stop_transaction();
+ } else if (status == PSA_ERROR_DOES_NOT_EXIST) {
+ /* There's no transaction to complete. It's all good. */
+ global_data.initialized |= PSA_CRYPTO_SUBSYSTEM_TRANSACTION_INITIALIZED;
+ status = PSA_SUCCESS;
+ }
+#else /* defined(PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS) */
+ global_data.initialized |= PSA_CRYPTO_SUBSYSTEM_TRANSACTION_INITIALIZED;
+ status = PSA_SUCCESS;
+#endif /* defined(PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS) */
+ }
+
+#if defined(MBEDTLS_THREADING_C)
+ PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_unlock(
+ &mbedtls_threading_psa_globaldata_mutex));
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ break;
+
+ default:
+ status = PSA_ERROR_CORRUPTION_DETECTED;
+ }
+
+ /* Exit label only required when using threading macros. */
+#if defined(MBEDTLS_THREADING_C)
+exit:
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ return status;
+}
+
psa_status_t psa_crypto_init(void)
{
psa_status_t status;
- /* Double initialization is explicitly allowed. */
- if (global_data.initialized != 0) {
+ /* Double initialization is explicitly allowed. Early out if everything is
+ * done. */
+ if (psa_get_initialized()) {
return PSA_SUCCESS;
}
- /* Init drivers */
- status = psa_driver_wrapper_init();
- if (status != PSA_SUCCESS) {
- goto exit;
- }
- global_data.drivers_initialized = 1;
-
- status = psa_initialize_key_slots();
+ status = mbedtls_psa_crypto_init_subsystem(PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS);
if (status != PSA_SUCCESS) {
goto exit;
}
- /* Initialize and seed the random generator. */
- mbedtls_psa_random_init(&global_data.rng);
- global_data.rng_state = RNG_INITIALIZED;
- status = mbedtls_psa_random_seed(&global_data.rng);
+ status = mbedtls_psa_crypto_init_subsystem(PSA_CRYPTO_SUBSYSTEM_KEY_SLOTS);
if (status != PSA_SUCCESS) {
goto exit;
}
- global_data.rng_state = RNG_SEEDED;
-#if defined(PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS)
- status = psa_crypto_load_transaction();
- if (status == PSA_SUCCESS) {
- status = psa_crypto_recover_transaction(&psa_crypto_transaction);
- if (status != PSA_SUCCESS) {
- goto exit;
- }
- status = psa_crypto_stop_transaction();
- } else if (status == PSA_ERROR_DOES_NOT_EXIST) {
- /* There's no transaction to complete. It's all good. */
- status = PSA_SUCCESS;
+ status = mbedtls_psa_crypto_init_subsystem(PSA_CRYPTO_SUBSYSTEM_RNG);
+ if (status != PSA_SUCCESS) {
+ goto exit;
}
-#endif /* PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS */
- /* All done. */
- global_data.initialized = 1;
+ status = mbedtls_psa_crypto_init_subsystem(PSA_CRYPTO_SUBSYSTEM_TRANSACTION);
exit:
+
if (status != PSA_SUCCESS) {
mbedtls_psa_crypto_free();
}
+
return status;
}
diff --git a/library/psa_crypto_slot_management.c b/library/psa_crypto_slot_management.c
index 5dee32f..b184ed0 100644
--- a/library/psa_crypto_slot_management.c
+++ b/library/psa_crypto_slot_management.c
@@ -34,6 +34,23 @@
static psa_global_data_t global_data;
+static uint8_t psa_get_key_slots_initialized(void)
+{
+ uint8_t initialized;
+
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ initialized = global_data.key_slots_initialized;
+
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_unlock(&mbedtls_threading_psa_globaldata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
+
+ return initialized;
+}
+
int psa_is_valid_key_id(mbedtls_svc_key_id_t key, int vendor_ok)
{
psa_key_id_t key_id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(key);
@@ -136,7 +153,9 @@
{
/* Nothing to do: program startup and psa_wipe_all_key_slots() both
* guarantee that the key slots are initialized to all-zero, which
- * means that all the key slots are in a valid, empty state. */
+ * means that all the key slots are in a valid, empty state. The global
+ * data mutex is already held when calling this function, so no need to
+ * lock it here, to set the flag. */
global_data.key_slots_initialized = 1;
return PSA_SUCCESS;
}
@@ -151,6 +170,7 @@
slot->state = PSA_SLOT_PENDING_DELETION;
(void) psa_wipe_key_slot(slot);
}
+ /* The global data mutex is already held when calling this function. */
global_data.key_slots_initialized = 0;
}
@@ -161,7 +181,7 @@
size_t slot_idx;
psa_key_slot_t *selected_slot, *unused_persistent_key_slot;
- if (!global_data.key_slots_initialized) {
+ if (!psa_get_key_slots_initialized()) {
status = PSA_ERROR_BAD_STATE;
goto error;
}
@@ -344,7 +364,7 @@
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
*p_slot = NULL;
- if (!global_data.key_slots_initialized) {
+ if (!psa_get_key_slots_initialized()) {
return PSA_ERROR_BAD_STATE;
}
diff --git a/library/threading.c b/library/threading.c
index c28290f..85db243 100644
--- a/library/threading.c
+++ b/library/threading.c
@@ -150,6 +150,8 @@
#endif
#if defined(MBEDTLS_PSA_CRYPTO_C)
mbedtls_mutex_init(&mbedtls_threading_key_slot_mutex);
+ mbedtls_mutex_init(&mbedtls_threading_psa_globaldata_mutex);
+ mbedtls_mutex_init(&mbedtls_threading_psa_rngdata_mutex);
#endif
}
@@ -166,6 +168,8 @@
#endif
#if defined(MBEDTLS_PSA_CRYPTO_C)
mbedtls_mutex_free(&mbedtls_threading_key_slot_mutex);
+ mbedtls_mutex_free(&mbedtls_threading_psa_globaldata_mutex);
+ mbedtls_mutex_free(&mbedtls_threading_psa_rngdata_mutex);
#endif
}
#endif /* MBEDTLS_THREADING_ALT */
@@ -184,6 +188,8 @@
#endif
#if defined(MBEDTLS_PSA_CRYPTO_C)
mbedtls_threading_mutex_t mbedtls_threading_key_slot_mutex MUTEX_INIT;
+mbedtls_threading_mutex_t mbedtls_threading_psa_globaldata_mutex MUTEX_INIT;
+mbedtls_threading_mutex_t mbedtls_threading_psa_rngdata_mutex MUTEX_INIT;
#endif
#endif /* MBEDTLS_THREADING_C */
diff --git a/tests/suites/test_suite_pk.data b/tests/suites/test_suite_pk.data
index 561297c..a0dacf0 100644
--- a/tests/suites/test_suite_pk.data
+++ b/tests/suites/test_suite_pk.data
@@ -1310,6 +1310,82 @@
depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:MBEDTLS_PK_CAN_ECDSA_SOME
pk_import_into_psa_fail:MBEDTLS_PK_ECDSA:FROM_PUBLIC:PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY):0:MBEDTLS_ERR_PK_TYPE_MISMATCH
+PSA import into PSA: transparent -> volatile pair
+pk_import_into_psa_lifetime:0:0:1:0:0
+
+PSA import into PSA: transparent -> persistent pair
+pk_import_into_psa_lifetime:0:0:1:0:1
+
+PSA import into PSA: transparent -> volatile public
+pk_import_into_psa_lifetime:0:0:1:1:0
+
+PSA import into PSA: transparent -> persistent public
+pk_import_into_psa_lifetime:0:0:1:1:1
+
+PSA import into PSA: opaque volatile [export] -> volatile pair
+depends_on:MBEDTLS_USE_PSA_CRYPTO
+pk_import_into_psa_lifetime:1:0:1:0:0
+
+PSA import into PSA: opaque volatile [export] -> persistent pair
+depends_on:MBEDTLS_USE_PSA_CRYPTO
+pk_import_into_psa_lifetime:1:0:1:0:1
+
+PSA import into PSA: opaque volatile [export] -> volatile public
+depends_on:MBEDTLS_USE_PSA_CRYPTO
+pk_import_into_psa_lifetime:1:0:1:1:0
+
+PSA import into PSA: opaque volatile [export] -> persistent public
+depends_on:MBEDTLS_USE_PSA_CRYPTO
+pk_import_into_psa_lifetime:1:0:1:1:1
+
+PSA import into PSA: opaque volatile [copy] -> volatile pair
+depends_on:MBEDTLS_USE_PSA_CRYPTO
+pk_import_into_psa_lifetime:1:0:0:0:0
+
+PSA import into PSA: opaque volatile [copy] -> persistent pair
+depends_on:MBEDTLS_USE_PSA_CRYPTO
+pk_import_into_psa_lifetime:1:0:0:0:1
+
+PSA import into PSA: opaque volatile [copy] -> volatile public
+depends_on:MBEDTLS_USE_PSA_CRYPTO
+pk_import_into_psa_lifetime:1:0:0:1:0
+
+PSA import into PSA: opaque volatile [copy] -> persistent public
+depends_on:MBEDTLS_USE_PSA_CRYPTO
+pk_import_into_psa_lifetime:1:0:0:1:1
+
+PSA import into PSA: opaque persistent [export] -> volatile pair
+depends_on:MBEDTLS_USE_PSA_CRYPTO
+pk_import_into_psa_lifetime:1:1:1:0:0
+
+PSA import into PSA: opaque persistent [export] -> persistent pair
+depends_on:MBEDTLS_USE_PSA_CRYPTO
+pk_import_into_psa_lifetime:1:1:1:0:1
+
+PSA import into PSA: opaque persistent [export] -> volatile public
+depends_on:MBEDTLS_USE_PSA_CRYPTO
+pk_import_into_psa_lifetime:1:1:1:1:0
+
+PSA import into PSA: opaque persistent [export] -> persistent public
+depends_on:MBEDTLS_USE_PSA_CRYPTO
+pk_import_into_psa_lifetime:1:1:1:1:1
+
+PSA import into PSA: opaque persistent [copy] -> volatile pair
+depends_on:MBEDTLS_USE_PSA_CRYPTO
+pk_import_into_psa_lifetime:1:1:0:0:0
+
+PSA import into PSA: opaque persistent [copy] -> persistent pair
+depends_on:MBEDTLS_USE_PSA_CRYPTO
+pk_import_into_psa_lifetime:1:1:0:0:1
+
+PSA import into PSA: opaque persistent [copy] -> volatile public
+depends_on:MBEDTLS_USE_PSA_CRYPTO
+pk_import_into_psa_lifetime:1:1:0:1:0
+
+PSA import into PSA: opaque persistent [copy] -> persistent public
+depends_on:MBEDTLS_USE_PSA_CRYPTO
+pk_import_into_psa_lifetime:1:1:0:1:1
+
PSA import into PSA: opaque RSA, COPY (ok)
depends_on:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
pk_import_into_psa_opaque:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_RSA_GEN_KEY_MIN_BITS:PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:0
diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function
index 089202b..7df9aa9 100644
--- a/tests/suites/test_suite_pk.function
+++ b/tests/suites/test_suite_pk.function
@@ -2220,6 +2220,92 @@
}
/* END_CASE */
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:MBEDTLS_TEST_PSA_ECC_AT_LEAST_ONE_CURVE:MBEDTLS_PSA_CRYPTO_STORAGE_C */
+void pk_import_into_psa_lifetime(int from_opaque,
+ int from_persistent, /* when from opaque */
+ int from_exportable, /* when from opaque */
+ int to_public,
+ int to_persistent)
+{
+ mbedtls_pk_context pk;
+ mbedtls_pk_init(&pk);
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ mbedtls_svc_key_id_t old_key_id = MBEDTLS_SVC_KEY_ID_INIT;
+ mbedtls_svc_key_id_t new_key_id = MBEDTLS_SVC_KEY_ID_INIT;
+ mbedtls_svc_key_id_t expected_key_id = MBEDTLS_SVC_KEY_ID_INIT;
+ psa_key_lifetime_t expected_lifetime = PSA_KEY_LIFETIME_VOLATILE;
+
+ PSA_INIT();
+
+ if (from_opaque) {
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ psa_key_type_t from_psa_type =
+ PSA_KEY_TYPE_ECC_KEY_PAIR(MBEDTLS_TEST_PSA_ECC_ONE_FAMILY);
+ psa_set_key_type(&attributes, from_psa_type);
+ psa_set_key_bits(&attributes, MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS);
+ psa_set_key_usage_flags(
+ &attributes,
+ (from_exportable ? PSA_KEY_USAGE_EXPORT : PSA_KEY_USAGE_COPY) |
+ PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH);
+ psa_set_key_algorithm(&attributes, PSA_ALG_ECDH);
+ if (from_persistent) {
+ psa_set_key_id(&attributes, mbedtls_svc_key_id_make(0, 1));
+ }
+ PSA_ASSERT(psa_generate_key(&attributes, &old_key_id));
+ TEST_EQUAL(mbedtls_pk_setup_opaque(&pk, old_key_id), 0);
+ psa_reset_key_attributes(&attributes);
+#else
+ (void) from_persistent;
+ (void) from_exportable;
+ TEST_FAIL("Attempted to test opaque key without opaque key support");
+#endif
+ } else {
+ psa_key_type_t psa_type_according_to_setup;
+ TEST_EQUAL(pk_setup_for_type(MBEDTLS_PK_ECKEY, 1,
+ &pk, &psa_type_according_to_setup), 0);
+ }
+
+ if (to_persistent) {
+ expected_key_id = mbedtls_svc_key_id_make(42, 2);
+ psa_set_key_id(&attributes, expected_key_id);
+ /* psa_set_key_id() sets the lifetime to PERSISTENT */
+ expected_lifetime = PSA_KEY_LIFETIME_PERSISTENT;
+ }
+
+ psa_key_usage_t to_usage =
+ to_public ? PSA_KEY_USAGE_VERIFY_HASH : PSA_KEY_USAGE_SIGN_HASH;
+ TEST_EQUAL(mbedtls_pk_get_psa_attributes(&pk, to_usage,
+ &attributes), 0);
+ /* mbedtls_pk_get_psa_attributes() is specified to not modify
+ * the persistence attributes. */
+ TEST_EQUAL(psa_get_key_lifetime(&attributes), expected_lifetime);
+ TEST_EQUAL(MBEDTLS_SVC_KEY_ID_GET_KEY_ID(psa_get_key_id(&attributes)),
+ MBEDTLS_SVC_KEY_ID_GET_KEY_ID(expected_key_id));
+
+ TEST_EQUAL(mbedtls_pk_import_into_psa(&pk, &attributes, &new_key_id), 0);
+ if (!mbedtls_test_key_consistency_psa_pk(new_key_id, &pk)) {
+ goto exit;
+ }
+
+ PSA_ASSERT(psa_get_key_attributes(new_key_id, &attributes));
+ TEST_EQUAL(psa_get_key_lifetime(&attributes), expected_lifetime);
+ /* Here expected_key_id=0 for a volatile key, but we expect
+ * attributes to contain a dynamically assigned key id which we
+ * can't predict. */
+ if (to_persistent) {
+ TEST_ASSERT(mbedtls_svc_key_id_equal(psa_get_key_id(&attributes),
+ expected_key_id));
+ }
+
+exit:
+ mbedtls_pk_free(&pk);
+ psa_reset_key_attributes(&attributes);
+ psa_destroy_key(old_key_id);
+ psa_destroy_key(new_key_id);
+ PSA_DONE();
+}
+/* END_CASE */
+
/* BEGIN_CASE depends_on:MBEDTLS_USE_PSA_CRYPTO */
void pk_get_psa_attributes_opaque(int from_type_arg, int from_bits_arg,
int from_usage_arg, int from_alg_arg,
@@ -2246,7 +2332,6 @@
psa_set_key_usage_flags(&attributes, from_usage);
psa_set_key_algorithm(&attributes, alg);
psa_set_key_enrollment_algorithm(&attributes, 42);
- //TODO: test with persistent key
PSA_ASSERT(psa_generate_key(&attributes, &old_key_id));
TEST_EQUAL(mbedtls_pk_setup_opaque(&pk, old_key_id), 0);
diff --git a/tests/suites/test_suite_psa_crypto_init.data b/tests/suites/test_suite_psa_crypto_init.data
index 8c5b41d..147d03f 100644
--- a/tests/suites/test_suite_psa_crypto_init.data
+++ b/tests/suites/test_suite_psa_crypto_init.data
@@ -10,6 +10,9 @@
PSA deinit twice
deinit_without_init:1
+PSA threaded init checks
+psa_threaded_init:100
+
No random without init
validate_module_init_generate_random:0
diff --git a/tests/suites/test_suite_psa_crypto_init.function b/tests/suites/test_suite_psa_crypto_init.function
index 7a43432..9ff33a6 100644
--- a/tests/suites/test_suite_psa_crypto_init.function
+++ b/tests/suites/test_suite_psa_crypto_init.function
@@ -1,6 +1,7 @@
/* BEGIN_HEADER */
#include <stdint.h>
+#include "psa_crypto_core.h"
/* Some tests in this module configure entropy sources. */
#include "psa_crypto_invasive.h"
@@ -112,6 +113,59 @@
#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */
+#if defined MBEDTLS_THREADING_PTHREAD
+
+typedef struct {
+ int do_init;
+} thread_psa_init_ctx_t;
+
+static void *thread_psa_init_function(void *ctx)
+{
+ thread_psa_init_ctx_t *init_context = (thread_psa_init_ctx_t *) ctx;
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ uint8_t random[10] = { 0 };
+
+ if (init_context->do_init) {
+ PSA_ASSERT(psa_crypto_init());
+ }
+
+ /* If this is a test only thread, then we can assume PSA is being started
+ * up on another thread and thus we cannot know whether the following tests
+ * will be successful or not. These checks are still useful, however even
+ * without checking the return codes as they may show up race conditions on
+ * the flags they check under TSAN.*/
+
+ /* Test getting if drivers are initialised. */
+ int can_do = psa_can_do_hash(PSA_ALG_NONE);
+
+ if (init_context->do_init) {
+ TEST_ASSERT(can_do == 1);
+ }
+
+#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+
+ /* Test getting global_data.rng_state. */
+ status = mbedtls_psa_crypto_configure_entropy_sources(NULL, NULL);
+
+ if (init_context->do_init) {
+ /* Bad state due to entropy sources already being setup in
+ * psa_crypto_init() */
+ TEST_EQUAL(status, PSA_ERROR_BAD_STATE);
+ }
+#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */
+
+ /* Test using the PSA RNG ony if we know PSA is up and running. */
+ if (init_context->do_init) {
+ status = psa_generate_random(random, sizeof(random));
+
+ TEST_EQUAL(status, PSA_SUCCESS);
+ }
+
+exit:
+ return NULL;
+}
+#endif /* defined MBEDTLS_THREADING_PTHREAD */
+
/* END_HEADER */
/* BEGIN_DEPENDENCIES
@@ -154,6 +208,67 @@
}
/* END_CASE */
+/* BEGIN_CASE depends_on:MBEDTLS_THREADING_PTHREAD */
+void psa_threaded_init(int arg_thread_count)
+{
+ thread_psa_init_ctx_t init_context;
+ thread_psa_init_ctx_t init_context_2;
+
+ size_t thread_count = (size_t) arg_thread_count;
+ mbedtls_test_thread_t *threads = NULL;
+
+ TEST_CALLOC(threads, sizeof(mbedtls_test_thread_t) * thread_count);
+
+ init_context.do_init = 1;
+
+ /* Test initialising PSA and testing certain protected globals on multiple
+ * threads. */
+ for (size_t i = 0; i < thread_count; i++) {
+ TEST_EQUAL(
+ mbedtls_test_thread_create(&threads[i],
+ thread_psa_init_function,
+ (void *) &init_context),
+ 0);
+ }
+
+ for (size_t i = 0; i < thread_count; i++) {
+ TEST_EQUAL(mbedtls_test_thread_join(&threads[i]), 0);
+ }
+
+ PSA_DONE();
+
+ init_context_2.do_init = 0;
+
+ /* Test initialising PSA whilst also testing flags on other threads. */
+ for (size_t i = 0; i < thread_count; i++) {
+
+ if (i & 1) {
+
+ TEST_EQUAL(
+ mbedtls_test_thread_create(&threads[i],
+ thread_psa_init_function,
+ (void *) &init_context),
+ 0);
+ } else {
+ TEST_EQUAL(
+ mbedtls_test_thread_create(&threads[i],
+ thread_psa_init_function,
+ (void *) &init_context_2),
+ 0);
+ }
+ }
+
+ for (size_t i = 0; i < thread_count; i++) {
+ TEST_EQUAL(mbedtls_test_thread_join(&threads[i]), 0);
+ }
+exit:
+
+ PSA_DONE();
+
+ mbedtls_free(threads);
+}
+/* END_CASE */
+
/* BEGIN_CASE */
void validate_module_init_generate_random(int count)
{