Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance Side Channel resistance of TPM2 RSA Decryption Wrapper #4429

Merged
merged 1 commit into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions src/lib/prov/tpm2/tpm2_rsa/tpm2_rsa.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,13 +340,25 @@ class RSA_Decryption_Operation final : public PK_Ops::Decryption {
&label,
out_ptr(plaintext)));

valid_mask = CT::Mask<uint8_t>::is_equal(rc, TPM2_RC_SUCCESS).value();
if(rc == TPM2_RC_SUCCESS) {
BOTAN_ASSERT_NONNULL(plaintext);
return copy_into<secure_vector<uint8_t>>(*plaintext);
} else {
return {};
}
const auto success = CT::Mask<decltype(rc)>::is_equal(rc, TPM2_RC_SUCCESS).as_choice();
valid_mask = CT::Mask<uint8_t>::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<TPM2B_PUBLIC_KEY_RSA>(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<secure_vector<uint8_t>>(*out);
}

size_t plaintext_length(size_t /* ciphertext_length */) const override {
Expand Down
14 changes: 11 additions & 3 deletions src/lib/prov/tpm2/tpm2_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <tpm2_buffer T>
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 <tpm2_buffer T>
constexpr T init_empty() {
return init_with_size<T>(0);
}

struct esys_liberator {
void operator()(void* handle) { Esys_Free(handle); }
};
Expand Down
Loading