psa_cipher_decrypt: treat status and output length as sensitive
In `psa_cipher_decrypt()` and in the corresponding function in our built-in
implementation `mbedtls_psa_cipher_decrypt()`, treat `status` and
`*output_length` as sensitive variables whose value must not leak through a
timing side channel. This is important when doing decryption with unpadding,
where leaking the validity or amount of padding can enable a padding oracle
attack.
With this change, `psa_cipher_decrypt()` should be constant-time if the
underlying legacy function (including the cipher implementation) is.
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 51ec72f..5f2cad4 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -4857,13 +4857,17 @@
exit:
unlock_status = psa_unregister_read_under_mutex(slot);
- if (status == PSA_SUCCESS) {
+ if (unlock_status != PSA_SUCCESS) {
status = unlock_status;
}
- if (status != PSA_SUCCESS) {
- *output_length = 0;
- }
+ /* Set *output_length to 0 if status != PSA_SUCCESS, without
+ * leaking the value of status through a timing side channel
+ * (status == PSA_ERROR_INVALID_PADDING is sensitive when doing
+ * unpadded decryption, due to the risk of padding oracle attack). */
+ mbedtls_ct_condition_t success =
+ mbedtls_ct_bool_not(mbedtls_ct_bool(status));
+ *output_length = mbedtls_ct_size_if_else_0(success, *output_length);
LOCAL_INPUT_FREE(input_external, input);
LOCAL_OUTPUT_FREE(output_external, output);