diff --git a/src/lib/prov/tpm2/tpm2_rsa/tpm2_rsa.cpp b/src/lib/prov/tpm2/tpm2_rsa/tpm2_rsa.cpp index c70ed988c5..701554ee32 100644 --- a/src/lib/prov/tpm2/tpm2_rsa/tpm2_rsa.cpp +++ b/src/lib/prov/tpm2/tpm2_rsa/tpm2_rsa.cpp @@ -340,13 +340,25 @@ class RSA_Decryption_Operation final : public PK_Ops::Decryption { &label, out_ptr(plaintext))); - valid_mask = CT::Mask::is_equal(rc, TPM2_RC_SUCCESS).value(); - if(rc == TPM2_RC_SUCCESS) { - BOTAN_ASSERT_NONNULL(plaintext); - return copy_into>(*plaintext); - } else { - return {}; - } + const auto success = CT::Mask::is_equal(rc, TPM2_RC_SUCCESS).as_choice(); + valid_mask = CT::Mask::from_choice(success).value(); + + // A "typical" payload size for RSA encryption, assuming that we usually + // encrypt some symmetric key of a hybrid encryption scheme. + constexpr size_t default_plaintext_length = 32; + + // When Esys_RSA_Decrypt fails to decrypt the ciphertext (e.g. because + // of a PKCS#1.5 padding failure), the `plaintext` pointer will be nullptr. + // This behaviour in itself is likely exposing a timing side channel already. + // Nevertheless, we do our best to mitigate any oracles by always copying a + // dummy plaintext value in this case. + auto dummy_plaintext = init_with_size(default_plaintext_length); + auto* out = &dummy_plaintext; + auto* maybe_plaintext = plaintext.get(); + CT::conditional_swap_ptr(success.as_bool(), out, maybe_plaintext); + + BOTAN_ASSERT_NONNULL(out); + return copy_into>(*out); } size_t plaintext_length(size_t /* ciphertext_length */) const override { diff --git a/src/lib/prov/tpm2/tpm2_util.h b/src/lib/prov/tpm2/tpm2_util.h index 47f2c7a2f5..dd6b0895e6 100644 --- a/src/lib/prov/tpm2/tpm2_util.h +++ b/src/lib/prov/tpm2/tpm2_util.h @@ -137,14 +137,22 @@ constexpr OutT copy_into(const tpm2_buffer auto& data) { return result; } -/// Create an empty TPM2 buffer of the given type. +/// Create a TPM2 buffer of a given type and @p length. template -constexpr T init_empty() { +constexpr T init_with_size(size_t length) { T result; - result.size = 0; + BOTAN_ASSERT_NOMSG(length <= sizeof(result.buffer)); + result.size = length; + clear_bytes(result.buffer, length); return result; } +/// Create an empty TPM2 buffer of the given type. +template +constexpr T init_empty() { + return init_with_size(0); +} + struct esys_liberator { void operator()(void* handle) { Esys_Free(handle); } };