From 9f06681cb4d44ea31d9200909dd075f80729d91f Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Thu, 7 Dec 2023 11:02:48 +0000 Subject: [PATCH 01/12] Update psa-thread-safety.md Signed-off-by: Ryan Everett --- docs/architecture/psa-thread-safety.md | 34 ++++++++++++-------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/docs/architecture/psa-thread-safety.md b/docs/architecture/psa-thread-safety.md index 0d03e324d..79881a624 100644 --- a/docs/architecture/psa-thread-safety.md +++ b/docs/architecture/psa-thread-safety.md @@ -281,28 +281,24 @@ Note that a thread must hold the global mutex when it reads or changes a slot's #### Slot states -For concurrency purposes, a slot can be in one of three states: +For concurrency purposes, a slot can be in one of four states: -* UNUSED: no thread is currently accessing the slot. It may be occupied by a volatile key or a cached key. -* WRITING: a thread has exclusive access to the slot. This can only happen in specific circumstances as detailed below. -* READING: any thread may read from the slot. +* EMPTY: no thread is currently accessing the slot, and no information is stored in the slot. +* FILLING: one thread is currently loading or creating material to fill the slot, this thread is responsible for the next state transition. +* FULL: the slot contains a key, and any thread is able to use the key after registering as a reader. +* PENDING_DELETION: the key within the slot has been destroyed or marked for destruction, but at least one thread is still registered as a reader. No thread can register to read this slot. The slot must not be wiped until the last reader de-registers, wiping the slot by calling `psa_wipe_key_slot`. -A high-level view of state transitions: +To change `slot` to state `new_state`, a function must call `psa_slot_state_transition(slot, new_state)`. -* `psa_get_empty_key_slot`: UNUSED → WRITING. -* `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. -* `psa_unlock_key_slot`: READING → UNUSED or READING. -* `psa_finish_key_creation`: WRITING → READING. -* `psa_fail_key_creation`: WRITING → UNUSED. -* `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). +A counter field within each slot keeps track of how many readers have registered. Library functions must call `psa_register_read` before reading the key data witin a slot, and `psa_unregister_read` after they have finished operating. -The 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. +Library functions which operate on a slot will return `PSA_ERROR_BAD_STATE` if the slot is in an inappropriate state for the function at the linearization point. -There 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`. +A state transition diagram can be found in docs/architecture/psa-thread-safety/key-slot-state-transitions.jpg. In this diagram, an arrow between two states `q1` and `q2` with label `f` indicates that if the state of a slot is `q1` immediately before `f`'s linearization point, it may be `q2` immediately after `f`'s linearization point. This means that the linearization point of a state changing call to a function must be a call to `psa_slot_state_transition`. #### Destruction of a key in use -Problem: In [Key destruction long-term requirements](#key-destruction-long-term-requirements) we require that the key slot is destroyed (by `psa_wipe_key_slot`) even while it's in use (READING or WRITING). +Problem: In [Key destruction long-term requirements](#key-destruction-long-term-requirements) we require that the key slot is destroyed (by `psa_wipe_key_slot`) even while it's in use (FILLING or with at least one reader). 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). @@ -310,11 +306,11 @@ Solution: after some team discussion, we've decided to rely on a new threading a ##### Mutex only -When calling `psa_wipe_key_slot` it is the callers responsibility to set the slot state to WRITING first. For most functions this is a clean UNUSED -> WRITING transition: psa_get_empty_key_slot, psa_get_and_lock_key_slot, psa_close_key, psa_purge_key. +When calling `psa_wipe_key_slot` it is the callers responsibility to set the slot state to PENDING_DELETION first. For most functions this is a clean {FULL, !has_readers} -> PENDING_DELETION transition: psa_get_empty_key_slot, psa_get_and_lock_key_slot, psa_close_key, psa_purge_key. `psa_wipe_all_key_slots` is only called from `mbedtls_psa_crypto_free`, here we will need to return an error as we won't be able to free the key store if a key is in use without compromising the state of the secure side. This is acceptable as an untrusted application cannot call `mbedtls_psa_crypto_free` in a crypto service. In a service integration, `mbedtls_psa_crypto_free` on the client cuts the communication with the crypto service. Also, this is the current behaviour. -`psa_destroy_key` marks the slot as deleted, deletes persistent keys and opaque keys and returns. This only works if drivers are protected by a mutex (and the persistent storage as well if needed). When the last reading operation finishes, it wipes the key slot. This will free the key ID, but the slot might be still in use. In case of volatile keys freeing up the ID while the slot is still in use does not provide any benefit and we don't need to do it. +`psa_destroy_key` marks the slot as deleted, deletes persistent keys and opaque keys and returns. This only works if drivers are protected by a mutex (and the persistent storage as well if needed).`psa_destroy_key` transfers to PENDING_DELETION as an intermediate state, then, when the last reading operation finishes, it wipes the key slot. This will free the key ID, but the slot might be still in use. In case of volatile keys freeing up the ID while the slot is still in use does not provide any benefit and we don't need to do it. These are serious limitations, but this can be implemented with mutexes only and arguably satisfies the [Key destruction short-term requirements](#key-destruction-short-term-requirements). @@ -329,9 +325,9 @@ We can't reuse the `lock_count` field to mark key slots deleted, as we still nee #### Condition variables -Clean UNUSED -> WRITING transition works as before. +Clean UNUSED -> PENDING_DELETION transition works as before. -`psa_wipe_all_key_slots` and `psa_destroy_key` mark the slot as deleted and go to sleep until the slot state becomes UNUSED. When waking up, they wipe the slot, and return. +`psa_wipe_all_key_slots` and `psa_destroy_key` mark the slot as deleted and go to sleep until the slot has no registered readers. When waking up, they wipe the slot, and return. If the slot is already marked as deleted the threads calling `psa_wipe_all_key_slots` and `psa_destroy_key` go to sleep until the deletion completes. To satisfy [Key destruction long-term requirements](#key-destruction-long-term-requirements) none of the threads may return from the call until the slot is deleted completely. This can be achieved by signalling them when the slot has already been wiped and ready for use, that is not marked for deletion anymore. To handle spurious wake-ups, these threads need to be able to tell whether the slot was already deleted. This is not trivial, because by the time the thread wakes up, theoretically the slot might be in any state. It might have been reused and maybe even marked for deletion again. @@ -354,7 +350,7 @@ Alternatively, protecting operation contexts can be left as the responsibility o #### Drivers -Each driver that hasn’t got the "thread_safe” property set has a dedicated mutex. +Each driver that hasn’t got the "thread_safe” property set has a dedicated mutex. Implementing "thread_safe” drivers depends on the condition variable protection in the key store, as we must guarantee that the core never starts the destruction of a key while there are operations in progress on it. From 1e9733c6a8d2505218801dd415065fdf34a8aa7c Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Thu, 7 Dec 2023 11:03:14 +0000 Subject: [PATCH 02/12] Add graph Signed-off-by: Ryan Everett --- .../key-slot-state-transitions.drawio | 183 ++++++++++++++++++ .../key-slot-state-transitions.jpg | Bin 0 -> 46583 bytes 2 files changed, 183 insertions(+) create mode 100644 docs/architecture/psa-thread-safety/key-slot-state-transitions.drawio create mode 100644 docs/architecture/psa-thread-safety/key-slot-state-transitions.jpg diff --git a/docs/architecture/psa-thread-safety/key-slot-state-transitions.drawio b/docs/architecture/psa-thread-safety/key-slot-state-transitions.drawio new file mode 100644 index 000000000..5da2a7fcc --- /dev/null +++ b/docs/architecture/psa-thread-safety/key-slot-state-transitions.drawio @@ -0,0 +1,183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/architecture/psa-thread-safety/key-slot-state-transitions.jpg b/docs/architecture/psa-thread-safety/key-slot-state-transitions.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ebfadcb4963d39f59cc3f21d30a21a62ce1676c0 GIT binary patch literal 46583 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 literal 0 HcmV?d00001 From 204c8524422e3a2c9010b01f9427d3b8d1daf35d Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Thu, 7 Dec 2023 11:03:43 +0000 Subject: [PATCH 03/12] Move psa-thread-safety.md Signed-off-by: Ryan Everett --- docs/architecture/{ => psa-thread-safety}/psa-thread-safety.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/architecture/{ => psa-thread-safety}/psa-thread-safety.md (100%) diff --git a/docs/architecture/psa-thread-safety.md b/docs/architecture/psa-thread-safety/psa-thread-safety.md similarity index 100% rename from docs/architecture/psa-thread-safety.md rename to docs/architecture/psa-thread-safety/psa-thread-safety.md From 177a45f556f9a44f35c37a34926eefd45260def8 Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Thu, 7 Dec 2023 11:24:30 +0000 Subject: [PATCH 04/12] Small clarifications in documentation Signed-off-by: Ryan Everett --- docs/architecture/psa-thread-safety/psa-thread-safety.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/architecture/psa-thread-safety/psa-thread-safety.md b/docs/architecture/psa-thread-safety/psa-thread-safety.md index 79881a624..97273f387 100644 --- a/docs/architecture/psa-thread-safety/psa-thread-safety.md +++ b/docs/architecture/psa-thread-safety/psa-thread-safety.md @@ -294,7 +294,7 @@ A counter field within each slot keeps track of how many readers have registered Library functions which operate on a slot will return `PSA_ERROR_BAD_STATE` if the slot is in an inappropriate state for the function at the linearization point. -A state transition diagram can be found in docs/architecture/psa-thread-safety/key-slot-state-transitions.jpg. In this diagram, an arrow between two states `q1` and `q2` with label `f` indicates that if the state of a slot is `q1` immediately before `f`'s linearization point, it may be `q2` immediately after `f`'s linearization point. This means that the linearization point of a state changing call to a function must be a call to `psa_slot_state_transition`. +A state transition diagram can be found in docs/architecture/psa-thread-safety/key-slot-state-transitions.jpg. In this diagram, an arrow between two states `q1` and `q2` with label `f` indicates that if the state of a slot is `q1` immediately before `f`'s linearization point, it may be `q2` immediately after `f`'s linearization point. The linearization point of a state changing call to a function must be a call to `psa_slot_state_transition`. #### Destruction of a key in use @@ -310,7 +310,7 @@ When calling `psa_wipe_key_slot` it is the callers responsibility to set the slo `psa_wipe_all_key_slots` is only called from `mbedtls_psa_crypto_free`, here we will need to return an error as we won't be able to free the key store if a key is in use without compromising the state of the secure side. This is acceptable as an untrusted application cannot call `mbedtls_psa_crypto_free` in a crypto service. In a service integration, `mbedtls_psa_crypto_free` on the client cuts the communication with the crypto service. Also, this is the current behaviour. -`psa_destroy_key` marks the slot as deleted, deletes persistent keys and opaque keys and returns. This only works if drivers are protected by a mutex (and the persistent storage as well if needed).`psa_destroy_key` transfers to PENDING_DELETION as an intermediate state, then, when the last reading operation finishes, it wipes the key slot. This will free the key ID, but the slot might be still in use. In case of volatile keys freeing up the ID while the slot is still in use does not provide any benefit and we don't need to do it. +`psa_destroy_key` registers as a reader, marks the slot as deleted, deletes persistent keys and opaque keys and unregisters before returning. This will free the key ID, but the slot might be still in use. This only works if drivers are protected by a mutex (and the persistent storage as well if needed). `psa_destroy_key` transfers to PENDING_DELETION as an intermediate state. The last reading operation will wipe the key slot upon unregistering. In case of volatile keys freeing up the ID while the slot is still in use does not provide any benefit and we don't need to do it. These are serious limitations, but this can be implemented with mutexes only and arguably satisfies the [Key destruction short-term requirements](#key-destruction-short-term-requirements). From b461b8731c5549c5fb5e20f4c7f80ab8e40973bd Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Thu, 14 Dec 2023 14:40:36 +0000 Subject: [PATCH 05/12] Change how the state transition diagram is stored Store the source of the diagram as a url instead of an xml file. Signed-off-by: Ryan Everett --- .../key-slot-state-transitions.drawio | 183 ------------------ .../psa-thread-safety/psa-thread-safety.md | 6 + 2 files changed, 6 insertions(+), 183 deletions(-) delete mode 100644 docs/architecture/psa-thread-safety/key-slot-state-transitions.drawio diff --git a/docs/architecture/psa-thread-safety/key-slot-state-transitions.drawio b/docs/architecture/psa-thread-safety/key-slot-state-transitions.drawio deleted file mode 100644 index 5da2a7fcc..000000000 --- a/docs/architecture/psa-thread-safety/key-slot-state-transitions.drawio +++ /dev/null @@ -1,183 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/architecture/psa-thread-safety/psa-thread-safety.md b/docs/architecture/psa-thread-safety/psa-thread-safety.md index 97273f387..d8256b5c5 100644 --- a/docs/architecture/psa-thread-safety/psa-thread-safety.md +++ b/docs/architecture/psa-thread-safety/psa-thread-safety.md @@ -296,6 +296,12 @@ Library functions which operate on a slot will return `PSA_ERROR_BAD_STATE` if t A state transition diagram can be found in docs/architecture/psa-thread-safety/key-slot-state-transitions.jpg. In this diagram, an arrow between two states `q1` and `q2` with label `f` indicates that if the state of a slot is `q1` immediately before `f`'s linearization point, it may be `q2` immediately after `f`'s linearization point. The linearization point of a state changing call to a function must be a call to `psa_slot_state_transition`. +#### Generating the state transition diagram from source + +To generate the state transition diagram in https://app.diagrams.net/, open the following url: + +https://viewer.diagrams.net/?tags=%7B%7D&highlight=FFFFFF&edit=_blank&layers=1&nav=1&title=key-slot-state-transitions#R5Vxbd5s4EP4t%2B%2BDH5iAJcXms4ySbrdtNT7qX9MWHgGyrxcABHNv59SsM2EhgDBhs3PVL0CANoBl9fDMaMkC3i%2FWDb3jzz65F7AGUrPUAjQYQAqBh9ieSbGKJIqFYMPOplXTaC57pO0mEUiJdUosEXMfQde2QerzQdB2HmCEnM3zfXfHdpq7NX9UzZiQneDYNOy%2F9h1rhPJZqUN3Lfyd0Nk%2BvDBQ9PrMw0s7JkwRzw3JXGRG6G6Bb33XD%2BGixviV2NHnpvMTj7g%2Bc3d2YT5ywyoDv4H08%2Ffvxj9VX3XGGw5cf3o9PHxJjvBn2MnngAVRspm9o0Td2OIsO7%2F8aj1Mx0585U9B5bgQTnxgW8YP07Ksv9he1bOcn3KSTzm6c2Zc1hqs5DcmzZ5jRmRVzsegK4cJmLcAOjcCLjT6la2LtVGUnJZmnN%2BKHZJ0RJZP0QNwFCf0N65KclbXEYDuPTdqrjP0T0Txj%2BlRmJB4322neG4UdJHapYSMACowkzphjfYy8nbVM2wgCavIT5btLx4pmaCSxFpscf%2FNvcmrbeMk2Rutsv9Emba1puBvEjl8y8v2QqJGOOGiNwF36Jjnul6Hhz0hY0k%2BO%2BxGLW8V522Zshwtsl8p8YhshfePXfpFBkys8uZQ92UHXwYrgE%2FFzJ6Oya1VUpOo3euancWplJKiNpymnduttu0k4wQFhzgGXjk9mNAiJv13seX9kBhkbr%2BxlwK9Xm86cyEeZQxCfCaJlSRnafkxOLKhlRTqGPgnou%2FG61Re5khc93PZx8XCAR4XOVb56RADYvTOSq3CwXAQM0g2UVJ2zxAd4mt%2BkaoAwxJ1OA9KNLasA%2Ft3np28v14nevQNvvXXwTmBYysAwKIXhHdxLWbiXjsB9c%2FCGFcEb9Au8ec%2FJgWxl7D7yDugYrFO6mXE4LzAmU4Pak59kMzEZXofUdfoM2ema6SNkJ5ohp1Qc3x1%2B51%2FF94%2Fj8eOXh17DMFIuDMNyldderTjnt18u0Lm4kXAVIz3dfRlt3b2inUZ347tvj39%2BuU4b9Y7PqF3RmepRZbPotTmdSdNOx%2BgM7BWdgRJ7%2BWkyVAGLJmWs8G9BLCs3KsAq1FTMGkhQX5XrAEUgTfJ5yY5WyHXYFSdk4YWbLeEJbDfsMdlJF1Qfuc5OjXwuegOKXtTt48sNbhIwxaMuGjL1K98VYYwkpRijMDjg0QBEWawUZJAmqc1QRpYElGG%2BjgSX7DoFVow0U%2BrQYH41cVW6uE7Gmg%2FM7rKu8mCDWvEpRSvUegboKaKfgi3Npf%2B2RZaYbZwv51492dMcg6rm3FGvMEhWMecwitowb4MVQZHIoQ9ADPMBY5PplizPwzes82imSlL5fUGhPzjSX9bK9LOD%2BI6bLp7RUDYBfTA9%2B50sH%2Bkz%2Fvi0rha6CVsGFQO4lNEZjjWxXfNnhtTV0GDabkCiobVGeUtm8uyo%2BtFjf9A%2FtVEb6A%2BQxntZO1k1nr5CfC7sR0X74K3QzixwVwxrMzyz2zy9XBHw%2B5WnhyrkvATjhoAPDuVWzsQpUVGsUwhDFglC392cDl%2FNoPKKQW%2B3sFsIr2VN4eObdGGc6NA7ZN5wINg96smXYLzH4Kw%2BcB4EwJ4AFiN8mVwb0gBnbaSCorO12ausZtJ9CtDrXKQjZouQVn7P4l2iI8wWl%2BrvhtnmCyaup%2FZFbo3ysXgfC47bEvh1kVosNGT7OxeXxrfWCB7sFV4iIeDFTSsxkCrkDStG9G153HXtTpQumlZiRl3YhGqLPqV5zS5ThoWzc5barsqbFTwMdbhZUTVRiHsNKwpoCitChZfSXTluMSMprvDigsTeAkprpV0RoECekbQVj%2FH7Gl2UdhXb9Ux1%2FsehoQkMNYcTXBFO%2BhXVwQNp%2BdpwAgWWonRXMFrsdrDA7XKJoVzQUyOhtKIeyWXtryOpVL5Q26jZ2H0h1y6IAXQhEMuT3pwlz55TOohNfcESIXHSeA8TbbNAGpahrMs6RBoS9XL1GrAS0NRNA7GnyV4F6PxNqBK6UaG0%2B6HyJwJ6qTIA6ijDze%2Bso%2BxSPoToZXqpfK3%2Fz9JLT3S5Hk%2FhRNNmX9%2B%2B338yHccr%2FLCqHfLGFaE1%2BkizM%2BpWtTS2X2VrSKgnw2JeqDLc4iOZqvaoW6HPVWJuEQOzXcOaeMQPIlxxwi0ZY%2Ffk1q%2Bj2Gp6XVI7pM4JakoLOq6DGpaiQAuIiGVQGIie6Pxnq6mAl6wJqu9Cv9g3mFVT%2F1WL%2Bfa74OmW%2Brk2T%2Fnkbu4Lg8pFxIKiqtUee0WnLBnW3P%2Bnj7j7%2Fv%2BloLv%2FAA%3D%3D + #### Destruction of a key in use Problem: In [Key destruction long-term requirements](#key-destruction-long-term-requirements) we require that the key slot is destroyed (by `psa_wipe_key_slot`) even while it's in use (FILLING or with at least one reader). From 3eb4274a57cbfc514e9dcb36bf92fc231dcf9e1e Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Thu, 14 Dec 2023 14:47:03 +0000 Subject: [PATCH 06/12] Fix transitions in diagram Move the finish_key_creation transition Neaten the diagram Add transitions for the key loading functions in psa_get_and_lock_key_slot Add psa_wipe_key_slot transition Change file to be a png Signed-off-by: Ryan Everett --- .../key-slot-state-transitions.jpg | Bin 46583 -> 0 bytes .../key-slot-state-transitions.png | Bin 0 -> 70492 bytes .../psa-thread-safety/psa-thread-safety.md | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 docs/architecture/psa-thread-safety/key-slot-state-transitions.jpg create mode 100644 docs/architecture/psa-thread-safety/key-slot-state-transitions.png diff --git a/docs/architecture/psa-thread-safety/key-slot-state-transitions.jpg b/docs/architecture/psa-thread-safety/key-slot-state-transitions.jpg deleted file mode 100644 index ebfadcb4963d39f59cc3f21d30a21a62ce1676c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46583 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 diff --git a/docs/architecture/psa-thread-safety/key-slot-state-transitions.png b/docs/architecture/psa-thread-safety/key-slot-state-transitions.png new file mode 100644 index 0000000000000000000000000000000000000000..34cc79b3596d12a8e4e98ffbbb5620d0c7c8221c GIT binary patch literal 70492 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 Date: Thu, 14 Dec 2023 14:48:43 +0000 Subject: [PATCH 07/12] Add some clarifications in thread_safety.md Make it clearer how it is possible to reason here using linearization Signed-off-by: Ryan Everett --- docs/architecture/psa-thread-safety/psa-thread-safety.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/architecture/psa-thread-safety/psa-thread-safety.md b/docs/architecture/psa-thread-safety/psa-thread-safety.md index 8e9f59e30..f7452a5e1 100644 --- a/docs/architecture/psa-thread-safety/psa-thread-safety.md +++ b/docs/architecture/psa-thread-safety/psa-thread-safety.md @@ -292,9 +292,11 @@ To change `slot` to state `new_state`, a function must call `psa_slot_state_tran A counter field within each slot keeps track of how many readers have registered. Library functions must call `psa_register_read` before reading the key data witin a slot, and `psa_unregister_read` after they have finished operating. +Any call to `psa_slot_state_transition`, `psa_register_read` or `psa_unregister_read` must be performed by a function which holds the global mutex. + Library functions which operate on a slot will return `PSA_ERROR_BAD_STATE` if the slot is in an inappropriate state for the function at the linearization point. -A state transition diagram can be found in docs/architecture/psa-thread-safety/key-slot-state-transitions.jpg. In this diagram, an arrow between two states `q1` and `q2` with label `f` indicates that if the state of a slot is `q1` immediately before `f`'s linearization point, it may be `q2` immediately after `f`'s linearization point. The linearization point of a state changing call to a function must be a call to `psa_slot_state_transition`. +A state transition diagram can be found in docs/architecture/psa-thread-safety/key-slot-state-transitions.png. In this diagram, an arrow between two states `q1` and `q2` with label `f` indicates that if the state of a slot is `q1` immediately before `f`'s linearization point, it may be `q2` immediately after `f`'s linearization point. The linearization point of a state changing call to a function must be a call to `psa_slot_state_transition`. (A function which: locks the global mutex, performs some operation, calls `psa_slot_state_transition` and then unlocks the global mutex, cleans up and returns can satisfy this requirement). #### Generating the state transition diagram from source @@ -316,7 +318,7 @@ When calling `psa_wipe_key_slot` it is the callers responsibility to set the slo `psa_wipe_all_key_slots` is only called from `mbedtls_psa_crypto_free`, here we will need to return an error as we won't be able to free the key store if a key is in use without compromising the state of the secure side. This is acceptable as an untrusted application cannot call `mbedtls_psa_crypto_free` in a crypto service. In a service integration, `mbedtls_psa_crypto_free` on the client cuts the communication with the crypto service. Also, this is the current behaviour. -`psa_destroy_key` registers as a reader, marks the slot as deleted, deletes persistent keys and opaque keys and unregisters before returning. This will free the key ID, but the slot might be still in use. This only works if drivers are protected by a mutex (and the persistent storage as well if needed). `psa_destroy_key` transfers to PENDING_DELETION as an intermediate state. The last reading operation will wipe the key slot upon unregistering. In case of volatile keys freeing up the ID while the slot is still in use does not provide any benefit and we don't need to do it. +`psa_destroy_key` registers as a reader, marks the slot as deleted, deletes persistent keys and opaque keys and unregisters before returning. This will free the key ID, but the slot might be still in use. This only works if drivers are protected by a mutex (and the persistent storage as well if needed). `psa_destroy_key` transfers to PENDING_DELETION as an intermediate state. The last reading operation will wipe the key slot upon unregistering. In case of volatile keys freeing up the ID while the slot is still in use does not provide any benefit and we don't need to do it. These are serious limitations, but this can be implemented with mutexes only and arguably satisfies the [Key destruction short-term requirements](#key-destruction-short-term-requirements). From 6ecb9ce5fc7d77b6d54881ab4d78231fb4784f98 Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Thu, 14 Dec 2023 14:54:24 +0000 Subject: [PATCH 08/12] Link directly to the state transition diagram Signed-off-by: Ryan Everett --- docs/architecture/psa-thread-safety/psa-thread-safety.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/architecture/psa-thread-safety/psa-thread-safety.md b/docs/architecture/psa-thread-safety/psa-thread-safety.md index f7452a5e1..4b122c838 100644 --- a/docs/architecture/psa-thread-safety/psa-thread-safety.md +++ b/docs/architecture/psa-thread-safety/psa-thread-safety.md @@ -296,7 +296,9 @@ Any call to `psa_slot_state_transition`, `psa_register_read` or `psa_unregister_ Library functions which operate on a slot will return `PSA_ERROR_BAD_STATE` if the slot is in an inappropriate state for the function at the linearization point. -A state transition diagram can be found in docs/architecture/psa-thread-safety/key-slot-state-transitions.png. In this diagram, an arrow between two states `q1` and `q2` with label `f` indicates that if the state of a slot is `q1` immediately before `f`'s linearization point, it may be `q2` immediately after `f`'s linearization point. The linearization point of a state changing call to a function must be a call to `psa_slot_state_transition`. (A function which: locks the global mutex, performs some operation, calls `psa_slot_state_transition` and then unlocks the global mutex, cleans up and returns can satisfy this requirement). +![](key-slot-state-transitions.png) + +In the state transition diagram above, an arrow between two states `q1` and `q2` with label `f` indicates that if the state of a slot is `q1` immediately before `f`'s linearization point, it may be `q2` immediately after `f`'s linearization point. The linearization point of a state changing call to a function must be a call to `psa_slot_state_transition`. (A function which: locks the global mutex, performs some operation, calls `psa_slot_state_transition` and then unlocks the global mutex, cleans up and returns can satisfy this requirement). #### Generating the state transition diagram from source From c1c6e0d906664103438fe96e7fc09c4f7a5e6d70 Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Fri, 15 Dec 2023 12:26:38 +0000 Subject: [PATCH 09/12] Justify linearization points Signed-off-by: Ryan Everett --- .../psa-thread-safety/psa-thread-safety.md | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/docs/architecture/psa-thread-safety/psa-thread-safety.md b/docs/architecture/psa-thread-safety/psa-thread-safety.md index 4b122c838..70b1341c2 100644 --- a/docs/architecture/psa-thread-safety/psa-thread-safety.md +++ b/docs/architecture/psa-thread-safety/psa-thread-safety.md @@ -283,8 +283,8 @@ Note that a thread must hold the global mutex when it reads or changes a slot's For concurrency purposes, a slot can be in one of four states: -* EMPTY: no thread is currently accessing the slot, and no information is stored in the slot. -* FILLING: one thread is currently loading or creating material to fill the slot, this thread is responsible for the next state transition. +* EMPTY: no thread is currently accessing the slot, and no information is stored in the slot. Any thread is able to change the slot's state to FILLING and begin loading data. +* FILLING: one thread is currently loading or creating material to fill the slot, this thread is responsible for the next state transition. Other threads cannot read the contents of a slot which is in FILLING. * FULL: the slot contains a key, and any thread is able to use the key after registering as a reader. * PENDING_DELETION: the key within the slot has been destroyed or marked for destruction, but at least one thread is still registered as a reader. No thread can register to read this slot. The slot must not be wiped until the last reader de-registers, wiping the slot by calling `psa_wipe_key_slot`. @@ -292,15 +292,32 @@ To change `slot` to state `new_state`, a function must call `psa_slot_state_tran A counter field within each slot keeps track of how many readers have registered. Library functions must call `psa_register_read` before reading the key data witin a slot, and `psa_unregister_read` after they have finished operating. -Any call to `psa_slot_state_transition`, `psa_register_read` or `psa_unregister_read` must be performed by a function which holds the global mutex. +Any call to `psa_slot_state_transition`, `psa_register_read` or `psa_unregister_read` must be performed by a thread which holds the global mutex. + +##### Linearizability of the system + +To satisfy the requirements in [Correctness out of the box](#correctness-out-of-the-box), we require our functions to be "linearizable" (under certain constraints). This means that any (constraint satisfying) set of concurrent calls are performed as if they were executed in some sequential order. + +The standard way of reasoning that this is the case is to identify a "linearization point" for each call, this is a single execution step where the function takes effect (this is usually a step in which the effects of the call become visible to other threads). If every call has a linearization point, the set of calls is equivalent to sequentially performing the calls in order of when their linearization point occured. + +We only access and modify a slot's state and reader count while we hold the global lock. This ensures the memory in which these fields are stored is correctly synchronized. It also ensures that the key data within the slot is synchronised where needed (the writer unlocks the mutex after filling the data, and any reader must lock the mutex before reading the data). + +To help justify that our system is linearizable, here is a list of key slot state changing functions and their linearization points (for the sake of brevity not all failure cases are covered, but those cases are not complex): +* `psa_wipe_key_slot, psa_register_read, psa_unregister_read, psa_slot_state_transition,` - These functions are all always performed under the global mutex, so they have no effects visible to other threads (this implies that they are linearizable). +* `psa_get_empty_key_slot, psa_get_and_lock_key_slot_in_memory, psa_load_X_key_into_slot, psa_fail_key_creation` - These functions hold the mutex for all non-setup/finalizing code, their linearization points are the release of the mutex. +* `psa_get_and_lock_key_slot` - If the key is already in a slot, the linearization point is the linearization point of the call to `psa_get_and_lock_key_slot_in_memory`. If the key is not in a slot and is loaded into one, the linearization point is the linearization point of the call to `psa_load_X_key_into_slot`. +* `psa_finish_key_creation` - On a successful load, we lock the mutex and set the state of the slot to FULL, the linearization point is then the following unlock. On an unsuccessful load, the linearization point is when we return - no action we have performed has been made visible to another thread as the slot is still in a FILLING state. +* `psa_destroy_key, psa_close_key, psa_purge_key` - As per the requirements, we need only argue for the case where the key is not in use here. The linearization point is the unlock after wiping the data and setting the slot state to EMPTY. Library functions which operate on a slot will return `PSA_ERROR_BAD_STATE` if the slot is in an inappropriate state for the function at the linearization point. +##### Key slot state transition diagram + ![](key-slot-state-transitions.png) -In the state transition diagram above, an arrow between two states `q1` and `q2` with label `f` indicates that if the state of a slot is `q1` immediately before `f`'s linearization point, it may be `q2` immediately after `f`'s linearization point. The linearization point of a state changing call to a function must be a call to `psa_slot_state_transition`. (A function which: locks the global mutex, performs some operation, calls `psa_slot_state_transition` and then unlocks the global mutex, cleans up and returns can satisfy this requirement). +In the state transition diagram above, an arrow between two states `q1` and `q2` with label `f` indicates that if the state of a slot is `q1` immediately before `f`'s linearization point, it may be `q2` immediately after `f`'s linearization point. -#### Generating the state transition diagram from source +##### Generating the key slot state transition diagram from source To generate the state transition diagram in https://app.diagrams.net/, open the following url: From abd8977cc15a460213afc72a02aeca778c3f2bfd Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Fri, 15 Dec 2023 12:28:38 +0000 Subject: [PATCH 10/12] Make check_files ignore png files in docs Signed-off-by: Ryan Everett --- tests/scripts/check_files.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/scripts/check_files.py b/tests/scripts/check_files.py index a2a9dfa8d..a93b8256f 100755 --- a/tests/scripts/check_files.py +++ b/tests/scripts/check_files.py @@ -105,6 +105,7 @@ class FileIssueTracker: BINARY_FILE_PATH_RE_LIST = [ r'docs/.*\.pdf\Z', + r'docs/.*\.png\Z', r'programs/fuzz/corpuses/[^.]+\Z', r'tests/data_files/[^.]+\Z', r'tests/data_files/.*\.(crt|csr|db|der|key|pubkey)\Z', From f5e135670b5e86e38e20b62beac9942cb982ac58 Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Wed, 20 Dec 2023 15:24:47 +0000 Subject: [PATCH 11/12] Clarify key generation and memory-management correctness Signed-off-by: Ryan Everett --- .../psa-thread-safety/psa-thread-safety.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/architecture/psa-thread-safety/psa-thread-safety.md b/docs/architecture/psa-thread-safety/psa-thread-safety.md index 70b1341c2..075c8c4e3 100644 --- a/docs/architecture/psa-thread-safety/psa-thread-safety.md +++ b/docs/architecture/psa-thread-safety/psa-thread-safety.md @@ -29,7 +29,7 @@ Tempting platform requirements that we cannot add to the default `MBEDTLS_THREAD If you build with `MBEDTLS_PSA_CRYPTO_C` and `MBEDTLS_THREADING_C`, the code must be functionally correct: no race conditions, deadlocks or livelocks. -The [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: +The [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 (excluding resource-management errors), except that the following cases have undefined behavior: * Destroying a key while it's in use. * 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.) @@ -290,7 +290,7 @@ For concurrency purposes, a slot can be in one of four states: To change `slot` to state `new_state`, a function must call `psa_slot_state_transition(slot, new_state)`. -A counter field within each slot keeps track of how many readers have registered. Library functions must call `psa_register_read` before reading the key data witin a slot, and `psa_unregister_read` after they have finished operating. +A counter field within each slot keeps track of how many readers have registered. Library functions must call `psa_register_read` before reading the key data within a slot, and `psa_unregister_read` after they have finished operating. Any call to `psa_slot_state_transition`, `psa_register_read` or `psa_unregister_read` must be performed by a thread which holds the global mutex. @@ -298,7 +298,9 @@ Any call to `psa_slot_state_transition`, `psa_register_read` or `psa_unregister_ To satisfy the requirements in [Correctness out of the box](#correctness-out-of-the-box), we require our functions to be "linearizable" (under certain constraints). This means that any (constraint satisfying) set of concurrent calls are performed as if they were executed in some sequential order. -The standard way of reasoning that this is the case is to identify a "linearization point" for each call, this is a single execution step where the function takes effect (this is usually a step in which the effects of the call become visible to other threads). If every call has a linearization point, the set of calls is equivalent to sequentially performing the calls in order of when their linearization point occured. +The standard way of reasoning that this is the case is to identify a "linearization point" for each call, this is a single execution step where the function takes effect (this is usually a step in which the effects of the call become visible to other threads). If every call has a linearization point, the set of calls is equivalent to sequentially performing the calls in order of when their linearization point occurred. + +We only require linearizability to hold in the case where a resource-management error is not returned. In a set of concurrent calls, it is permitted for a call c to fail with a PSA_ERROR_INSUFFICIENT_MEMORY return code even if there does not exist a sequential ordering of the calls in which c returns this error. We only access and modify a slot's state and reader count while we hold the global lock. This ensures the memory in which these fields are stored is correctly synchronized. It also ensures that the key data within the slot is synchronised where needed (the writer unlocks the mutex after filling the data, and any reader must lock the mutex before reading the data). @@ -306,8 +308,11 @@ To help justify that our system is linearizable, here is a list of key slot stat * `psa_wipe_key_slot, psa_register_read, psa_unregister_read, psa_slot_state_transition,` - These functions are all always performed under the global mutex, so they have no effects visible to other threads (this implies that they are linearizable). * `psa_get_empty_key_slot, psa_get_and_lock_key_slot_in_memory, psa_load_X_key_into_slot, psa_fail_key_creation` - These functions hold the mutex for all non-setup/finalizing code, their linearization points are the release of the mutex. * `psa_get_and_lock_key_slot` - If the key is already in a slot, the linearization point is the linearization point of the call to `psa_get_and_lock_key_slot_in_memory`. If the key is not in a slot and is loaded into one, the linearization point is the linearization point of the call to `psa_load_X_key_into_slot`. +* `psa_start_key_creation` - From the perspective of other threads, the only effect of a successful call to this function is that the amount of usable resources decreases (a key slot which was usable is now unusable). Since we do not consider resource management as linearizable behaviour, when arguing for linearizability of the system we consider this function to have no visible effect to other threads. * `psa_finish_key_creation` - On a successful load, we lock the mutex and set the state of the slot to FULL, the linearization point is then the following unlock. On an unsuccessful load, the linearization point is when we return - no action we have performed has been made visible to another thread as the slot is still in a FILLING state. * `psa_destroy_key, psa_close_key, psa_purge_key` - As per the requirements, we need only argue for the case where the key is not in use here. The linearization point is the unlock after wiping the data and setting the slot state to EMPTY. +* `psa_import_key, psa_copy_key, psa_generate_key, mbedtls_psa_register_se_key` - These functions call both `psa_start_key_creation` and `psa_finish_key_creation`, the linearization point of a successful call is the linearization point of the call to `psa_finish_key_creation`. The linearization point of an unsuccessful call is the linearization point of the call to `psa_fail_key_creation`. +* `psa_key_derivation_output_key` - Same as above. If the operation object is in use by multiple threads, the behaviour need not be linearizable. Library functions which operate on a slot will return `PSA_ERROR_BAD_STATE` if the slot is in an inappropriate state for the function at the linearization point. From 3dd6cde0d819a9eb45f3be694fbf72e70d54cceb Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Wed, 20 Dec 2023 16:45:31 +0000 Subject: [PATCH 12/12] Mention functional correctness explicitly Signed-off-by: Ryan Everett --- docs/architecture/psa-thread-safety/psa-thread-safety.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/psa-thread-safety/psa-thread-safety.md b/docs/architecture/psa-thread-safety/psa-thread-safety.md index 075c8c4e3..dc5d7e189 100644 --- a/docs/architecture/psa-thread-safety/psa-thread-safety.md +++ b/docs/architecture/psa-thread-safety/psa-thread-safety.md @@ -300,7 +300,7 @@ To satisfy the requirements in [Correctness out of the box](#correctness-out-of- The standard way of reasoning that this is the case is to identify a "linearization point" for each call, this is a single execution step where the function takes effect (this is usually a step in which the effects of the call become visible to other threads). If every call has a linearization point, the set of calls is equivalent to sequentially performing the calls in order of when their linearization point occurred. -We only require linearizability to hold in the case where a resource-management error is not returned. In a set of concurrent calls, it is permitted for a call c to fail with a PSA_ERROR_INSUFFICIENT_MEMORY return code even if there does not exist a sequential ordering of the calls in which c returns this error. +We only require linearizability to hold in the case where a resource-management error is not returned. In a set of concurrent calls, it is permitted for a call c to fail with a PSA_ERROR_INSUFFICIENT_MEMORY return code even if there does not exist a sequential ordering of the calls in which c returns this error. Even if such an error occurs, all calls are still required to be functionally correct. We only access and modify a slot's state and reader count while we hold the global lock. This ensures the memory in which these fields are stored is correctly synchronized. It also ensures that the key data within the slot is synchronised where needed (the writer unlocks the mutex after filling the data, and any reader must lock the mutex before reading the data).