From 7ec993d804be1be2287b7e6314151d5b99424f51 Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Wed, 23 Aug 2023 16:00:14 +0100 Subject: [PATCH 1/6] Refine thread safety requirements Split and refine short term requirements for key deletion. Signed-off-by: Janos Follath --- docs/architecture/psa-thread-safety.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/docs/architecture/psa-thread-safety.md b/docs/architecture/psa-thread-safety.md index b0ca8088f7..cd1ba61f7a 100644 --- a/docs/architecture/psa-thread-safety.md +++ b/docs/architecture/psa-thread-safety.md @@ -67,16 +67,28 @@ In the medium to long term, performing a slow or blocking operation (for example We 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. -### Key destruction long-term requirements - -As 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. +### Key destruction short-term requirements #### Summary of guarantees when `psa_destroy_key` returns * 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. * 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. * 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. -* 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. + +As noted above in [“Correctness out of the box”](#correctness-out-of-the-box), destroying a key while it's in use is undefined behavior. The only guarantee in this case is that it won't cause data corruption or read-after-free inside the key store. In particular, any or all the listed guarantees may be violated when `psa_destroy_key` is called on a key that is in use. + +### Key destruction long-term requirements + +The [PSA Crypto API specification](https://armmbed.github.io/mbed-crypto/html/api/keys/management.html#key-destruction) mandates that implementations make a best effort to ensure that that the key material cannot be recovered. In the long term, it would be good to guarantee that `psa_destroy_key` wipes all copies of the key material. + +#### Summary of guarantees when `psa_destroy_key` returns + +* 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. +* 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. +* 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. +* 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. + +As opposed to the short term requirements, the above guarantees hold even if `psa_destroy_key` is called on a key that is in use. ## Resources to protect From 0385c2815ca55ce0a1bbb18e43bc22b13f7839e6 Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Wed, 30 Aug 2023 16:41:06 +0100 Subject: [PATCH 2/6] Tighten thread safety requirements We shouldn't violate the requirement that the key identifier can be reused. In practice, a key manager may destroy a key that's in use by another process, and the privileged world containing the key manager and the crypto service should not be perturbed by an unprivileged process. With respect to blocking, again, a key manager should not be blocked indefinitely by an unprivileged application. These are desirable properties even in the short term. Signed-off-by: Janos Follath --- docs/architecture/psa-thread-safety.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/architecture/psa-thread-safety.md b/docs/architecture/psa-thread-safety.md index cd1ba61f7a..fd948ac45a 100644 --- a/docs/architecture/psa-thread-safety.md +++ b/docs/architecture/psa-thread-safety.md @@ -71,11 +71,11 @@ We may want to go directly to a more sophisticated approach because when a syste #### Summary of guarantees when `psa_destroy_key` returns -* 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. -* 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. -* 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. +1. 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. +2. 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. +3. 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. -As noted above in [“Correctness out of the box”](#correctness-out-of-the-box), destroying a key while it's in use is undefined behavior. The only guarantee in this case is that it won't cause data corruption or read-after-free inside the key store. In particular, any or all the listed guarantees may be violated when `psa_destroy_key` is called on a key that is in use. +When `psa_destroy_key` is called on a key that is in use, guarantee 2. might be violated. (This is consistent with the requirement [“Correctness out of the box”](#correctness-out-of-the-box), as destroying a key while it's in use is undefined behavior.) ### Key destruction long-term requirements @@ -88,7 +88,7 @@ The [PSA Crypto API specification](https://armmbed.github.io/mbed-crypto/html/ap * 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. * 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. -As opposed to the short term requirements, the above guarantees hold even if `psa_destroy_key` is called on a key that is in use. +As opposed to the short term requirements, all the above guarantees hold even if `psa_destroy_key` is called on a key that is in use. ## Resources to protect From 15d9ec29be7f3bfa1dbd6d595f83b3ca7eb2df0f Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Thu, 31 Aug 2023 08:22:21 +0100 Subject: [PATCH 3/6] Improve thread safety presentation - Use unique section titles so that there are unique anchors - Make list style consistent between similar sections Signed-off-by: Janos Follath --- docs/architecture/psa-thread-safety.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/architecture/psa-thread-safety.md b/docs/architecture/psa-thread-safety.md index fd948ac45a..b4c51be958 100644 --- a/docs/architecture/psa-thread-safety.md +++ b/docs/architecture/psa-thread-safety.md @@ -69,7 +69,9 @@ We may want to go directly to a more sophisticated approach because when a syste ### Key destruction short-term requirements -#### Summary of guarantees when `psa_destroy_key` returns +#### Summary of guarantees in the short term + +When `psa_destroy_key` returns: 1. 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. 2. 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. @@ -81,12 +83,14 @@ When `psa_destroy_key` is called on a key that is in use, guarantee 2. might be The [PSA Crypto API specification](https://armmbed.github.io/mbed-crypto/html/api/keys/management.html#key-destruction) mandates that implementations make a best effort to ensure that that the key material cannot be recovered. In the long term, it would be good to guarantee that `psa_destroy_key` wipes all copies of the key material. -#### Summary of guarantees when `psa_destroy_key` returns +#### Summary of guarantees in the long term -* 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. -* 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. -* 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. -* 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. +When `psa_destroy_key` returns: + +1. 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. +2. 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. +3. 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. +4. 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. As opposed to the short term requirements, all the above guarantees hold even if `psa_destroy_key` is called on a key that is in use. From 35633dd977ede890715ca27f0f8af213aa901bd9 Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Thu, 31 Aug 2023 08:31:19 +0100 Subject: [PATCH 4/6] Add threading non-requirement State explicitly the non-requirement that it's ok for psa_destroy_key to block waiting for a driver. Signed-off-by: Janos Follath --- docs/architecture/psa-thread-safety.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/architecture/psa-thread-safety.md b/docs/architecture/psa-thread-safety.md index b4c51be958..1c80e3d340 100644 --- a/docs/architecture/psa-thread-safety.md +++ b/docs/architecture/psa-thread-safety.md @@ -75,7 +75,7 @@ When `psa_destroy_key` returns: 1. 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. 2. 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. -3. 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. +3. 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. (This doesn't mean that the call can't block at all. It is acceptable for example to block waiting for another thread to complete an API call that it had already started, but it is unacceptable to wait for another thread to make an API call.) When `psa_destroy_key` is called on a key that is in use, guarantee 2. might be violated. (This is consistent with the requirement [“Correctness out of the box”](#correctness-out-of-the-box), as destroying a key while it's in use is undefined behavior.) @@ -89,7 +89,7 @@ When `psa_destroy_key` returns: 1. 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. 2. 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. -3. 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. +3. 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. (This doesn't mean that the call can't block at all. It is acceptable for example to block waiting for another thread to complete an API call that it had already started, but it is unacceptable to wait for another thread to make an API call.) 4. 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. As opposed to the short term requirements, all the above guarantees hold even if `psa_destroy_key` is called on a key that is in use. From b6954730f077cebafd687636a8430e1c54132a81 Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Thu, 31 Aug 2023 13:54:21 +0100 Subject: [PATCH 5/6] Fix typo Co-authored-by: Ronald Cron Signed-off-by: Janos Follath --- docs/architecture/psa-thread-safety.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/psa-thread-safety.md b/docs/architecture/psa-thread-safety.md index 1c80e3d340..fb2b96303a 100644 --- a/docs/architecture/psa-thread-safety.md +++ b/docs/architecture/psa-thread-safety.md @@ -81,7 +81,7 @@ When `psa_destroy_key` is called on a key that is in use, guarantee 2. might be ### Key destruction long-term requirements -The [PSA Crypto API specification](https://armmbed.github.io/mbed-crypto/html/api/keys/management.html#key-destruction) mandates that implementations make a best effort to ensure that that the key material cannot be recovered. In the long term, it would be good to guarantee that `psa_destroy_key` wipes all copies of the key material. +The [PSA Crypto API specification](https://armmbed.github.io/mbed-crypto/html/api/keys/management.html#key-destruction) mandates that implementations make a best effort to ensure that the key material cannot be recovered. In the long term, it would be good to guarantee that `psa_destroy_key` wipes all copies of the key material. #### Summary of guarantees in the long term From b4527fbd821bf7c0aedfbd77a2819979ca1aba82 Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Thu, 31 Aug 2023 14:01:24 +0100 Subject: [PATCH 6/6] Add clarifications to the threading requirements Signed-off-by: Janos Follath --- docs/architecture/psa-thread-safety.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/architecture/psa-thread-safety.md b/docs/architecture/psa-thread-safety.md index fb2b96303a..06bdcc056d 100644 --- a/docs/architecture/psa-thread-safety.md +++ b/docs/architecture/psa-thread-safety.md @@ -75,7 +75,7 @@ When `psa_destroy_key` returns: 1. 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. 2. 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. -3. 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. (This doesn't mean that the call can't block at all. It is acceptable for example to block waiting for another thread to complete an API call that it had already started, but it is unacceptable to wait for another thread to make an API call.) +3. 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. In particular, it is only acceptable for `psa_destroy_key` to block, when waiting for another thread to complete a PSA Cryptography API call that it had already started. When `psa_destroy_key` is called on a key that is in use, guarantee 2. might be violated. (This is consistent with the requirement [“Correctness out of the box”](#correctness-out-of-the-box), as destroying a key while it's in use is undefined behavior.) @@ -89,8 +89,8 @@ When `psa_destroy_key` returns: 1. 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. 2. 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. -3. 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. (This doesn't mean that the call can't block at all. It is acceptable for example to block waiting for another thread to complete an API call that it had already started, but it is unacceptable to wait for another thread to make an API call.) -4. 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. +3. 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. In particular, it is only acceptable for `psa_destroy_key` to block, when waiting for another thread to complete a PSA Cryptography API call that it had already started. +4. 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 satisfy this security requirement in the future. As opposed to the short term requirements, all the above guarantees hold even if `psa_destroy_key` is called on a key that is in use.