xref: /aosp_15_r20/external/mbedtls/docs/architecture/psa-thread-safety.md (revision 62c56f9862f102b96d72393aff6076c951fb8148)
1*62c56f98SSadaf EbrahimiThread safety of the PSA subsystem
2*62c56f98SSadaf Ebrahimi==================================
3*62c56f98SSadaf Ebrahimi
4*62c56f98SSadaf Ebrahimi## Requirements
5*62c56f98SSadaf Ebrahimi
6*62c56f98SSadaf Ebrahimi### Backward compatibility requirement
7*62c56f98SSadaf Ebrahimi
8*62c56f98SSadaf EbrahimiCode that is currently working must keep working. There can be an exception for code that uses features that are advertised as experimental; for example, it would be annoying but ok to add extra requirements for drivers.
9*62c56f98SSadaf Ebrahimi
10*62c56f98SSadaf Ebrahimi(In this section, “currently” means Mbed TLS releases without proper concurrency management: 3.0.0, 3.1.0, and any other subsequent 3.x version.)
11*62c56f98SSadaf Ebrahimi
12*62c56f98SSadaf EbrahimiIn particular, if you either protect all PSA calls with a mutex, or only ever call PSA functions from a single thread, your application currently works and must keep working. If your application currently builds and works with `MBEDTLS_PSA_CRYPTO_C` and `MBEDTLS_THREADING_C` enabled, it must keep building and working.
13*62c56f98SSadaf Ebrahimi
14*62c56f98SSadaf EbrahimiAs a consequence, we must not add a new platform requirement beyond mutexes for the base case. It would be ok to add new platform requirements if they're only needed for PSA drivers, or if they're only performance improvements.
15*62c56f98SSadaf Ebrahimi
16*62c56f98SSadaf EbrahimiTempting platform requirements that we cannot add to the default `MBEDTLS_THREADING_C` include:
17*62c56f98SSadaf Ebrahimi
18*62c56f98SSadaf Ebrahimi* Releasing a mutex from a different thread than the one that acquired it. This isn't even guaranteed to work with pthreads.
19*62c56f98SSadaf Ebrahimi* New primitives such as semaphores or condition variables.
20*62c56f98SSadaf Ebrahimi
21*62c56f98SSadaf Ebrahimi### Correctness out of the box
22*62c56f98SSadaf Ebrahimi
23*62c56f98SSadaf EbrahimiIf you build with `MBEDTLS_PSA_CRYPTO_C` and `MBEDTLS_THREADING_C`, the code must be functionally correct: no race conditions, deadlocks or livelocks.
24*62c56f98SSadaf Ebrahimi
25*62c56f98SSadaf EbrahimiThe [PSA Crypto API specification](https://armmbed.github.io/mbed-crypto/html/overview/conventions.html#concurrent-calls) defines minimum expectations for concurrent calls. They must work as if they had been executed one at a time, except that the following cases have undefined behavior:
26*62c56f98SSadaf Ebrahimi
27*62c56f98SSadaf Ebrahimi* Destroying a key while it's in use.
28*62c56f98SSadaf Ebrahimi* Concurrent calls using the same operation object. (An operation object may not be used by more than one thread at a time. But it can move from one thread to another between calls.)
29*62c56f98SSadaf Ebrahimi* Overlap of an output buffer with an input or output of a concurrent call.
30*62c56f98SSadaf Ebrahimi* Modification of an input buffer during a call.
31*62c56f98SSadaf Ebrahimi
32*62c56f98SSadaf EbrahimiNote that while the specification does not define the behavior in such cases, Mbed TLS can be used as a crypto service. It's acceptable if an application can mess itself up, but it is not acceptable if an application can mess up the crypto service. As a consequence, destroying a key while it's in use may violate the security property that all key material is erased as soon as `psa_destroy_key` returns, but it may not cause data corruption or read-after-free inside the key store.
33*62c56f98SSadaf Ebrahimi
34*62c56f98SSadaf Ebrahimi### No spinning
35*62c56f98SSadaf Ebrahimi
36*62c56f98SSadaf EbrahimiThe code must not spin on a potentially non-blocking task. For example, this is proscribed:
37*62c56f98SSadaf Ebrahimi```
38*62c56f98SSadaf Ebrahimilock(m);
39*62c56f98SSadaf Ebrahimiwhile (!its_my_turn) {
40*62c56f98SSadaf Ebrahimi    unlock(m);
41*62c56f98SSadaf Ebrahimi    lock(m);
42*62c56f98SSadaf Ebrahimi}
43*62c56f98SSadaf Ebrahimi```
44*62c56f98SSadaf Ebrahimi
45*62c56f98SSadaf EbrahimiRationale: this can cause battery drain, and can even be a livelock (spinning forever), e.g. if the thread that might unblock this one has a lower priority.
46*62c56f98SSadaf Ebrahimi
47*62c56f98SSadaf Ebrahimi### Driver requirements
48*62c56f98SSadaf Ebrahimi
49*62c56f98SSadaf EbrahimiAt the time of writing, the driver interface specification does not consider multithreaded environments.
50*62c56f98SSadaf Ebrahimi
51*62c56f98SSadaf EbrahimiWe need to define clear policies so that driver implementers know what to expect. Here are two possible policies at two ends of the spectrum; what is desirable is probably somewhere in between.
52*62c56f98SSadaf Ebrahimi
53*62c56f98SSadaf Ebrahimi* Driver entry points may be called concurrently from multiple threads, even if they're using the same key, and even including destroying a key while an operation is in progress on it.
54*62c56f98SSadaf Ebrahimi* At most one driver entry point is active at any given time.
55*62c56f98SSadaf Ebrahimi
56*62c56f98SSadaf EbrahimiA more reasonable policy could be:
57*62c56f98SSadaf Ebrahimi
58*62c56f98SSadaf Ebrahimi* By default, each driver only has at most one entry point active at any given time. In other words, each driver has its own exclusive lock.
59*62c56f98SSadaf Ebrahimi* Drivers have an optional `"thread_safe"` boolean property. If true, it allows concurrent calls to this driver.
60*62c56f98SSadaf Ebrahimi* Even with a thread-safe driver, the core never starts the destruction of a key while there are operations in progress on it, and never performs concurrent calls on the same multipart operation.
61*62c56f98SSadaf Ebrahimi
62*62c56f98SSadaf Ebrahimi### Long-term performance requirements
63*62c56f98SSadaf Ebrahimi
64*62c56f98SSadaf EbrahimiIn the short term, correctness is the important thing. We can start with a global lock.
65*62c56f98SSadaf Ebrahimi
66*62c56f98SSadaf EbrahimiIn the medium to long term, performing a slow or blocking operation (for example, a driver call, or an RSA decryption) should not block other threads, even if they're calling the same driver or using the same key object.
67*62c56f98SSadaf Ebrahimi
68*62c56f98SSadaf EbrahimiWe may want to go directly to a more sophisticated approach because when a system works with a global lock, it's typically hard to get rid of it to get more fine-grained concurrency.
69*62c56f98SSadaf Ebrahimi
70*62c56f98SSadaf Ebrahimi### Key destruction long-term requirements
71*62c56f98SSadaf Ebrahimi
72*62c56f98SSadaf EbrahimiAs noted above in [“Correctness out of the box”](#correctness-out-of-the-box), when a key is destroyed, it's ok if `psa_destroy_key` allows copies of the key to live until ongoing operations using the key return. In the long term, it would be good to guarantee that `psa_destroy_key` wipes all copies of the key material.
73*62c56f98SSadaf Ebrahimi
74*62c56f98SSadaf Ebrahimi#### Summary of guarantees when `psa_destroy_key` returns
75*62c56f98SSadaf Ebrahimi
76*62c56f98SSadaf Ebrahimi* The key identifier doesn't exist. Rationale: this is a functional requirement for persistent keys: the caller can immediately create a new key with the same identifier.
77*62c56f98SSadaf Ebrahimi* The resources from the key have been freed. Rationale: in a low-resource condition, this may be necessary for the caller to re-create a similar key, which should be possible.
78*62c56f98SSadaf Ebrahimi* The call must not block indefinitely, and in particular cannot wait for an event that is triggered by application code such as calling an abort function. Rationale: this may not strictly be a functional requirement, but it is an expectation `psa_destroy_key` does not block forever due to another thread, which could potentially be another process on a multi-process system.
79*62c56f98SSadaf Ebrahimi* In the long term, no copy of the key material exists. Rationale: this is a security requirement. We do not have this requirement yet, but we need to document this as a security weakness, and we would like to become compliant.
80*62c56f98SSadaf Ebrahimi
81*62c56f98SSadaf Ebrahimi## Resources to protect
82*62c56f98SSadaf Ebrahimi
83*62c56f98SSadaf EbrahimiAnalysis of the behavior of the PSA key store as of Mbed TLS 9202ba37b19d3ea25c8451fd8597fce69eaa6867.
84*62c56f98SSadaf Ebrahimi
85*62c56f98SSadaf Ebrahimi### Global variables
86*62c56f98SSadaf Ebrahimi
87*62c56f98SSadaf Ebrahimi* `psa_crypto_slot_management::global_data.key_slots[i]`: see [“Key slots”](#key-slots).
88*62c56f98SSadaf Ebrahimi
89*62c56f98SSadaf Ebrahimi* `psa_crypto_slot_management::global_data.key_slots_initialized`:
90*62c56f98SSadaf Ebrahimi    * `psa_initialize_key_slots`: modification.
91*62c56f98SSadaf Ebrahimi    * `psa_wipe_all_key_slots`: modification.
92*62c56f98SSadaf Ebrahimi    * `psa_get_empty_key_slot`: read.
93*62c56f98SSadaf Ebrahimi    * `psa_get_and_lock_key_slot`: read.
94*62c56f98SSadaf Ebrahimi
95*62c56f98SSadaf Ebrahimi* `psa_crypto::global_data.rng`: depends on the RNG implementation. See [“Random generator”](#random-generator).
96*62c56f98SSadaf Ebrahimi    * `psa_generate_random`: query.
97*62c56f98SSadaf Ebrahimi    * `mbedtls_psa_crypto_configure_entropy_sources` (only if `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is enabled): setup. Only called from `psa_crypto_init` via `mbedtls_psa_random_init`, or from test code.
98*62c56f98SSadaf Ebrahimi    * `mbedtls_psa_crypto_free`: deinit.
99*62c56f98SSadaf Ebrahimi    * `psa_crypto_init`: seed (via `mbedtls_psa_random_seed`); setup via `mbedtls_psa_crypto_configure_entropy_sources.
100*62c56f98SSadaf Ebrahimi
101*62c56f98SSadaf Ebrahimi* `psa_crypto::global_data.{initialized,rng_state}`: these are bit-fields and cannot be modified independently so they must be protected by the same mutex. The following functions access these fields:
102*62c56f98SSadaf Ebrahimi    * `mbedtls_psa_crypto_configure_entropy_sources` [`rng_state`] (only if `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is enabled): read. Only called from `psa_crypto_init` via `mbedtls_psa_random_init`, or from test code.
103*62c56f98SSadaf Ebrahimi    * `mbedtls_psa_crypto_free`: modification.
104*62c56f98SSadaf Ebrahimi    * `psa_crypto_init`: modification.
105*62c56f98SSadaf Ebrahimi    * Many functions via `GUARD_MODULE_INITIALIZED`: read.
106*62c56f98SSadaf Ebrahimi
107*62c56f98SSadaf Ebrahimi### Key slots
108*62c56f98SSadaf Ebrahimi
109*62c56f98SSadaf Ebrahimi#### Key slot array traversal
110*62c56f98SSadaf Ebrahimi
111*62c56f98SSadaf Ebrahimi“Occupied key slot” is determined by `psa_is_key_slot_occupied` based on `slot->attr.type`.
112*62c56f98SSadaf Ebrahimi
113*62c56f98SSadaf EbrahimiThe following functions traverse the key slot array:
114*62c56f98SSadaf Ebrahimi
115*62c56f98SSadaf Ebrahimi* `psa_get_and_lock_key_slot_in_memory`: reads `slot->attr.id`.
116*62c56f98SSadaf Ebrahimi* `psa_get_and_lock_key_slot_in_memory`: calls `psa_lock_key_slot` on one occupied slot.
117*62c56f98SSadaf Ebrahimi* `psa_get_empty_key_slot`: calls `psa_is_key_slot_occupied`.
118*62c56f98SSadaf Ebrahimi* `psa_get_empty_key_slot`: calls `psa_wipe_key_slot` and more modifications on one occupied slot with no active user.
119*62c56f98SSadaf Ebrahimi* `psa_get_empty_key_slot`: calls `psa_lock_key_slot` and more modification on one unoccupied slot.
120*62c56f98SSadaf Ebrahimi* `psa_wipe_all_key_slots`: writes to all slots.
121*62c56f98SSadaf Ebrahimi* `mbedtls_psa_get_stats`: reads from all slots.
122*62c56f98SSadaf Ebrahimi
123*62c56f98SSadaf Ebrahimi#### Key slot state
124*62c56f98SSadaf Ebrahimi
125*62c56f98SSadaf EbrahimiThe following functions modify a slot's usage state:
126*62c56f98SSadaf Ebrahimi
127*62c56f98SSadaf Ebrahimi* `psa_lock_key_slot`: writes to `slot->lock_count`.
128*62c56f98SSadaf Ebrahimi* `psa_unlock_key_slot`: writes to `slot->lock_count`.
129*62c56f98SSadaf Ebrahimi* `psa_wipe_key_slot`: writes to `slot->lock_count`.
130*62c56f98SSadaf Ebrahimi* `psa_destroy_key`: reads `slot->lock_count`, calls `psa_lock_key_slot`.
131*62c56f98SSadaf Ebrahimi* `psa_wipe_all_key_slots`: writes to all slots.
132*62c56f98SSadaf Ebrahimi* `psa_get_empty_key_slot`: writes to `slot->lock_count` and calls `psa_wipe_key_slot` and `psa_lock_key_slot` on one occupied slot with no active user; calls `psa_lock_key_slot` on one unoccupied slot.
133*62c56f98SSadaf Ebrahimi* `psa_close_key`: reads `slot->lock_count`; calls `psa_get_and_lock_key_slot_in_memory`, `psa_wipe_key_slot` and `psa_unlock_key_slot`.
134*62c56f98SSadaf Ebrahimi* `psa_purge_key`: reads `slot->lock_count`; calls `psa_get_and_lock_key_slot_in_memory`, `psa_wipe_key_slot` and `psa_unlock_key_slot`.
135*62c56f98SSadaf Ebrahimi
136*62c56f98SSadaf Ebrahimi**slot->attr access:**
137*62c56f98SSadaf Ebrahimi`psa_crypto_core.h`:
138*62c56f98SSadaf Ebrahimi* `psa_key_slot_set_flags` - writes to attr.flags
139*62c56f98SSadaf Ebrahimi* `psa_key_slot_set_bits_in_flags` - writes to attr.flags
140*62c56f98SSadaf Ebrahimi* `psa_key_slot_clear_bits` - writes to attr.flags
141*62c56f98SSadaf Ebrahimi* `psa_is_key_slot_occupied` - reads attr.type (but see “[Determining whether a key slot is occupied](#determining-whether-a-key-slot-is-occupied)”)
142*62c56f98SSadaf Ebrahimi* `psa_key_slot_get_flags` - reads attr.flags
143*62c56f98SSadaf Ebrahimi
144*62c56f98SSadaf Ebrahimi`psa_crypto_slot_management.c`:
145*62c56f98SSadaf Ebrahimi* `psa_get_and_lock_key_slot_in_memory` - reads attr.id
146*62c56f98SSadaf Ebrahimi* `psa_get_empty_key_slot` - reads attr.lifetime
147*62c56f98SSadaf Ebrahimi* `psa_load_persistent_key_into_slot` - passes attr pointer to psa_load_persistent_key
148*62c56f98SSadaf Ebrahimi* `psa_load_persistent_key` - reads attr.id and passes pointer to psa_parse_key_data_from_storage
149*62c56f98SSadaf Ebrahimi* `psa_parse_key_data_from_storage` - writes to many attributes
150*62c56f98SSadaf Ebrahimi* `psa_get_and_lock_key_slot` - writes to attr.id, attr.lifetime, and attr.policy.usage
151*62c56f98SSadaf Ebrahimi* `psa_purge_key` - reads attr.lifetime, calls psa_wipe_key_slot
152*62c56f98SSadaf Ebrahimi* `mbedtls_psa_get_stats` - reads attr.lifetime, attr.id
153*62c56f98SSadaf Ebrahimi
154*62c56f98SSadaf Ebrahimi`psa_crypto.c`:
155*62c56f98SSadaf Ebrahimi* `psa_get_and_lock_key_slot_with_policy` - reads attr.type, attr.policy.
156*62c56f98SSadaf Ebrahimi* `psa_get_and_lock_transparent_key_slot_with_policy` - reads attr.lifetime
157*62c56f98SSadaf Ebrahimi* `psa_destroy_key` - reads attr.lifetime, attr.id
158*62c56f98SSadaf Ebrahimi* `psa_get_key_attributes` - copies all publicly available attributes of a key
159*62c56f98SSadaf Ebrahimi* `psa_export_key` - copies attributes
160*62c56f98SSadaf Ebrahimi* `psa_export_public_key` - reads attr.type, copies attributes
161*62c56f98SSadaf Ebrahimi* `psa_start_key_creation` - writes to the whole attr structure
162*62c56f98SSadaf Ebrahimi* `psa_validate_optional_attributes` - reads attr.type, attr.bits
163*62c56f98SSadaf Ebrahimi* `psa_import_key` - reads attr.bits
164*62c56f98SSadaf Ebrahimi* `psa_copy_key` - reads attr.bits, attr.type, attr.lifetime, attr.policy
165*62c56f98SSadaf Ebrahimi* `psa_mac_setup` - copies whole attr structure
166*62c56f98SSadaf Ebrahimi* `psa_mac_compute_internal` - copies whole attr structure
167*62c56f98SSadaf Ebrahimi* `psa_verify_internal` - copies whole attr structure
168*62c56f98SSadaf Ebrahimi* `psa_sign_internal` - copies whole attr structure, reads attr.type
169*62c56f98SSadaf Ebrahimi* `psa_assymmetric_encrypt` - reads attr.type
170*62c56f98SSadaf Ebrahimi* `psa_assymetric_decrypt` - reads attr.type
171*62c56f98SSadaf Ebrahimi* `psa_cipher_setup` - copies whole attr structure, reads attr.type
172*62c56f98SSadaf Ebrahimi* `psa_cipher_encrypt` - copies whole attr structure, reads attr.type
173*62c56f98SSadaf Ebrahimi* `psa_cipher_decrypt` - copies whole attr structure, reads attr.type
174*62c56f98SSadaf Ebrahimi* `psa_aead_encrypt` - copies whole attr structure
175*62c56f98SSadaf Ebrahimi* `psa_aead_decrypt` - copies whole attr structure
176*62c56f98SSadaf Ebrahimi* `psa_aead_setup` - copies whole attr structure
177*62c56f98SSadaf Ebrahimi* `psa_generate_derived_key_internal` - reads attr.type, writes to and reads from attr.bits, copies whole attr structure
178*62c56f98SSadaf Ebrahimi* `psa_key_derivation_input_key` - reads attr.type
179*62c56f98SSadaf Ebrahimi* `psa_key_agreement_raw_internal` - reads attr.type and attr.bits
180*62c56f98SSadaf Ebrahimi
181*62c56f98SSadaf Ebrahimi#### Determining whether a key slot is occupied
182*62c56f98SSadaf Ebrahimi
183*62c56f98SSadaf Ebrahimi`psa_is_key_slot_occupied` currently uses the `attr.type` field to determine whether a key slot is occupied. This works because we maintain the invariant that an occupied slot contains key material. With concurrency, it is desirable to allow a key slot to be reserved, but not yet contain key material or even metadata. When creating a key, determining the key type can be costly, for example when loading a persistent key from storage or (not yet implemented) when importing or unwrapping a key using an interface that determines the key type from the data that it parses. So we should not need to hold the global key store lock while the key type is undetermined.
184*62c56f98SSadaf Ebrahimi
185*62c56f98SSadaf EbrahimiInstead, `psa_is_key_slot_occupied` should use the key identifier to decide whether a slot is occupied. The key identifier is always readily available: when allocating a slot for a persistent key, it's an input of the function that allocates the key slot; when allocating a slot for a volatile key, the identifier is calculated from the choice of slot.
186*62c56f98SSadaf Ebrahimi
187*62c56f98SSadaf Ebrahimi#### Key slot content
188*62c56f98SSadaf Ebrahimi
189*62c56f98SSadaf EbrahimiOther than what is used to determine the [“key slot state”](#key-slot-state), the contents of a key slot are only accessed as follows:
190*62c56f98SSadaf Ebrahimi
191*62c56f98SSadaf Ebrahimi* Modification during key creation (between `psa_start_key_creation` and `psa_finish_key_creation` or `psa_fail_key_creation`).
192*62c56f98SSadaf Ebrahimi* Destruction in `psa_wipe_key_slot`.
193*62c56f98SSadaf Ebrahimi* Read in many functions, between calls to `psa_lock_key_slot` and `psa_unlock_key_slot`.
194*62c56f98SSadaf Ebrahimi
195*62c56f98SSadaf Ebrahimi**slot->key access:**
196*62c56f98SSadaf Ebrahimi* `psa_allocate_buffer_to_slot` - allocates key.data, sets key.bytes;
197*62c56f98SSadaf Ebrahimi* `psa_copy_key_material_into_slot` - writes to key.data
198*62c56f98SSadaf Ebrahimi* `psa_remove_key_data_from_memory` - writes and reads to/from key data
199*62c56f98SSadaf Ebrahimi* `psa_get_key_attributes` - reads from key data
200*62c56f98SSadaf Ebrahimi* `psa_export_key` - passes key data to psa_driver_wrapper_export_key
201*62c56f98SSadaf Ebrahimi* `psa_export_public_key` - passes key data to psa_driver_wrapper_export_public_key
202*62c56f98SSadaf Ebrahimi* `psa_finish_key_creation` - passes key data to psa_save_persistent_key
203*62c56f98SSadaf Ebrahimi* `psa_validate_optional_attributes` - passes key data and bytes to mbedtls_psa_rsa_load_representation
204*62c56f98SSadaf Ebrahimi* `psa_import_key` - passes key data to psa_driver_wrapper_import_key
205*62c56f98SSadaf Ebrahimi* `psa_copy_key` - passes key data to psa_driver_wrapper_copy_key, psa_copy_key_material_into_slot
206*62c56f98SSadaf Ebrahimi* `psa_mac_setup` - passes key data to psa_driver_wrapper_mac_sign_setup, psa_driver_wrapper_mac_verify_setup
207*62c56f98SSadaf Ebrahimi* `psa_mac_compute_internal` - passes key data to psa_driver_wrapper_mac_compute
208*62c56f98SSadaf Ebrahimi* `psa_sign_internal` - passes key data to psa_driver_wrapper_sign_message, psa_driver_wrapper_sign_hash
209*62c56f98SSadaf Ebrahimi* `psa_verify_internal` - passes key data to psa_driver_wrapper_verify_message, psa_driver_wrapper_verify_hash
210*62c56f98SSadaf Ebrahimi* `psa_asymmetric_encrypt` - passes key data to mbedtls_psa_rsa_load_representation
211*62c56f98SSadaf Ebrahimi* `psa_asymmetric_decrypt` - passes key data to mbedtls_psa_rsa_load_representation
212*62c56f98SSadaf Ebrahimi* `psa_cipher_setup ` - passes key data to psa_driver_wrapper_cipher_encrypt_setup and psa_driver_wrapper_cipher_decrypt_setup
213*62c56f98SSadaf Ebrahimi* `psa_cipher_encrypt` - passes key data to psa_driver_wrapper_cipher_encrypt
214*62c56f98SSadaf Ebrahimi* `psa_cipher_decrypt` - passes key data to psa_driver_wrapper_cipher_decrypt
215*62c56f98SSadaf Ebrahimi* `psa_aead_encrypt` - passes key data to psa_driver_wrapper_aead_encrypt
216*62c56f98SSadaf Ebrahimi* `psa_aead_decrypt` - passes key data to psa_driver_wrapper_aead_decrypt
217*62c56f98SSadaf Ebrahimi* `psa_aead_setup` - passes key data to psa_driver_wrapper_aead_encrypt_setup and psa_driver_wrapper_aead_decrypt_setup
218*62c56f98SSadaf Ebrahimi* `psa_generate_derived_key_internal` - passes key data to psa_driver_wrapper_import_key
219*62c56f98SSadaf Ebrahimi* `psa_key_derivation_input_key` - passes key data to psa_key_derivation_input_internal
220*62c56f98SSadaf Ebrahimi* `psa_key_agreement_raw_internal` - passes key data to mbedtls_psa_ecp_load_representation
221*62c56f98SSadaf Ebrahimi* `psa_generate_key` - passes key data to psa_driver_wrapper_generate_key
222*62c56f98SSadaf Ebrahimi
223*62c56f98SSadaf Ebrahimi### Random generator
224*62c56f98SSadaf Ebrahimi
225*62c56f98SSadaf EbrahimiThe PSA RNG can be accessed both from various PSA functions, and from application code via `mbedtls_psa_get_random`.
226*62c56f98SSadaf Ebrahimi
227*62c56f98SSadaf EbrahimiWith the built-in RNG implementations using `mbedtls_ctr_drbg_context` or `mbedtls_hmac_drbg_context`, querying the RNG with `mbedtls_xxx_drbg_random()` is thread-safe (protected by a mutex inside the RNG implementation), but other operations (init, free, seed) are not.
228*62c56f98SSadaf Ebrahimi
229*62c56f98SSadaf EbrahimiWhen `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is enabled, thread safety depends on the implementation.
230*62c56f98SSadaf Ebrahimi
231*62c56f98SSadaf Ebrahimi### Driver resources
232*62c56f98SSadaf Ebrahimi
233*62c56f98SSadaf EbrahimiDepends on the driver. The PSA driver interface specification does not discuss whether drivers must support concurrent calls.
234*62c56f98SSadaf Ebrahimi
235*62c56f98SSadaf Ebrahimi## Simple global lock strategy
236*62c56f98SSadaf Ebrahimi
237*62c56f98SSadaf EbrahimiHave a single mutex protecting all accesses to the key store and other global variables. In practice, this means every PSA API function needs to take the lock on entry and release on exit, except for:
238*62c56f98SSadaf Ebrahimi
239*62c56f98SSadaf Ebrahimi* Hash function.
240*62c56f98SSadaf Ebrahimi* Accessors for key attributes and other local structures.
241*62c56f98SSadaf Ebrahimi
242*62c56f98SSadaf EbrahimiNote that operation functions do need to take the lock, since they need to prevent the destruction of the key.
243*62c56f98SSadaf Ebrahimi
244*62c56f98SSadaf EbrahimiNote that this does not protect access to the RNG via `mbedtls_psa_get_random`, which is guaranteed to be thread-safe when `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is disabled.
245*62c56f98SSadaf Ebrahimi
246*62c56f98SSadaf EbrahimiThis approach is conceptually simple, but requires extra instrumentation to every function and has bad performance in a multithreaded environment since a slow operation in one thread blocks unrelated operations on other threads.
247*62c56f98SSadaf Ebrahimi
248*62c56f98SSadaf Ebrahimi## Global lock excluding slot content
249*62c56f98SSadaf Ebrahimi
250*62c56f98SSadaf EbrahimiHave a single mutex protecting all accesses to the key store and other global variables, except that it's ok to access the content of a key slot without taking the lock if one of the following conditions holds:
251*62c56f98SSadaf Ebrahimi
252*62c56f98SSadaf Ebrahimi* The key slot is in a state that guarantees that the thread has exclusive access.
253*62c56f98SSadaf Ebrahimi* The key slot is in a state that guarantees that no other thread can modify the slot content, and the accessing thread is only reading the slot.
254*62c56f98SSadaf Ebrahimi
255*62c56f98SSadaf EbrahimiNote that a thread must hold the global mutex when it reads or changes a slot's state.
256*62c56f98SSadaf Ebrahimi
257*62c56f98SSadaf Ebrahimi### Slot states
258*62c56f98SSadaf Ebrahimi
259*62c56f98SSadaf EbrahimiFor concurrency purposes, a slot can be in one of three states:
260*62c56f98SSadaf Ebrahimi
261*62c56f98SSadaf Ebrahimi* UNUSED: no thread is currently accessing the slot. It may be occupied by a volatile key or a cached key.
262*62c56f98SSadaf Ebrahimi* WRITING: a thread has exclusive access to the slot. This can only happen in specific circumstances as detailed below.
263*62c56f98SSadaf Ebrahimi* READING: any thread may read from the slot.
264*62c56f98SSadaf Ebrahimi
265*62c56f98SSadaf EbrahimiA high-level view of state transitions:
266*62c56f98SSadaf Ebrahimi
267*62c56f98SSadaf Ebrahimi* `psa_get_empty_key_slot`: UNUSED → WRITING.
268*62c56f98SSadaf Ebrahimi* `psa_get_and_lock_key_slot_in_memory`: UNUSED or READING → READING. This function only accepts slots in the UNUSED or READING state. A slot with the correct id but in the WRITING state is considered free.
269*62c56f98SSadaf Ebrahimi* `psa_unlock_key_slot`: READING → UNUSED or READING.
270*62c56f98SSadaf Ebrahimi* `psa_finish_key_creation`: WRITING → READING.
271*62c56f98SSadaf Ebrahimi* `psa_fail_key_creation`: WRITING → UNUSED.
272*62c56f98SSadaf Ebrahimi* `psa_wipe_key_slot`: any → UNUSED. If the slot is READING or WRITING on entry, this function must wait until the writer or all readers have finished. (By the way, the WRITING state is possible if `mbedtls_psa_crypto_free` is called while a key creation is in progress.) See [“Destruction of a key in use”](#destruction of a key in use).
273*62c56f98SSadaf Ebrahimi
274*62c56f98SSadaf EbrahimiThe current `state->lock_count` corresponds to the difference between UNUSED and READING: a slot is in use iff its lock count is nonzero, so `lock_count == 0` corresponds to UNUSED and `lock_count != 0` corresponds to READING.
275*62c56f98SSadaf Ebrahimi
276*62c56f98SSadaf EbrahimiThere is currently no indication of when a slot is in the WRITING state. This only happens between a call to `psa_start_key_creation` and a call to one of `psa_finish_key_creation` or `psa_fail_key_creation`. This new state can be conveyed by a new boolean flag, or by setting `lock_count` to `~0`.
277*62c56f98SSadaf Ebrahimi
278*62c56f98SSadaf Ebrahimi### Destruction of a key in use
279*62c56f98SSadaf Ebrahimi
280*62c56f98SSadaf EbrahimiProblem: a key slot is destroyed (by `psa_wipe_key_slot`) while it's in use (READING or WRITING).
281*62c56f98SSadaf Ebrahimi
282*62c56f98SSadaf EbrahimiTODO: how do we ensure that? This needs something more sophisticated than mutexes (concurrency number >2)! Even a per-slot mutex isn't enough (we'd need a reader-writer lock).
283*62c56f98SSadaf Ebrahimi
284*62c56f98SSadaf EbrahimiSolution: after some team discussion, we've decided to rely on a new threading abstraction which mimics C11 (i.e. `mbedtls_fff` where `fff` is the C11 function name, having the same parameters and return type, with default implementations for C11, pthreads and Windows). We'll likely use condition variables in addition to mutexes.
285