9#include <botan/tpm2_rsa.h>
11#include <botan/hash.h>
12#include <botan/pss_params.h>
15#include <botan/internal/ct_utils.h>
16#include <botan/internal/emsa.h>
17#include <botan/internal/fmt.h>
18#include <botan/internal/scan_name.h>
19#include <botan/internal/stl_util.h>
20#include <botan/internal/tpm2_algo_mappings.h>
21#include <botan/internal/tpm2_hash.h>
22#include <botan/internal/tpm2_pkops.h>
23#include <botan/internal/tpm2_util.h>
25#include <tss2/tss2_esys.h>
31 const auto& pub = public_area->publicArea;
32 BOTAN_ARG_CHECK(pub.type == TPM2_ALG_RSA,
"Public key is not an RSA key");
35 const auto exponent = (pub.parameters.rsaDetail.exponent == 0) ? 65537 : pub.parameters.rsaDetail.exponent;
45 Botan::TPM2::
PublicKey(std::move(handle), std::move(session_bundle)),
52 const TPM2B_PUBLIC* public_blob,
53 std::span<const uint8_t> private_blob) :
55 std::move(session_bundle),
61 const std::pair<BigInt, BigInt>& pubkey,
62 std::span<const uint8_t> private_blob) :
63 Botan::TPM2::
PrivateKey(std::move(handle), std::move(session_bundle), private_blob),
70 std::span<const uint8_t> auth_value,
73 std::optional<uint32_t> exponent) {
76 TPM2B_SENSITIVE_CREATE sensitive_data = {
89 TPMT_PUBLIC key_template = {
94 .nameAlg = TPM2_ALG_SHA256,
102 .fixed_parent =
true,
103 .sensitive_data_origin =
true,
104 .user_with_auth =
true,
106 .sign_encrypt =
true,
124 .algorithm = TPM2_ALG_NULL,
125 .keyBits = {.sym = 0},
126 .mode = {.sym = TPM2_ALG_NULL},
138 .scheme = TPM2_ALG_NULL,
139 .details = {.anySig = {.hashAlg = TPM2_ALG_NULL}},
141 .keyBits = keylength,
142 .exponent = exponent.value_or(0 ),
158 if(req.arg_count() == 0) {
159 throw Invalid_Argument(
"RSA signing padding scheme must at least specify a hash function");
168 .signature_scheme = sig_scheme.value(),
169 .hash_name = req.arg(0),
170 .padding = std::string(padding),
174size_t signature_length_for_key_handle(
const SessionBundle& sessions,
const Object& key_handle) {
175 return key_handle._public_info(sessions, TPM2_ALG_RSA).pub->publicArea.parameters.rsaDetail.keyBits / 8;
178class RSA_Signature_Operation
final :
public Signature_Operation {
180 RSA_Signature_Operation(
const Object&
object,
const SessionBundle& sessions, std::string_view padding) :
181 Signature_Operation(object, sessions, select_signature_algorithms(padding)) {}
183 size_t signature_length()
const override {
return signature_length_for_key_handle(sessions(), key_handle()); }
185 AlgorithmIdentifier algorithm_identifier()
const override {
196 const std::string emsa_name = emsa->name();
199 const std::string full_name =
"RSA/" + emsa_name;
202 }
catch(Lookup_Error&) {}
204 if(emsa_name.starts_with(
"PSS(")) {
206 return AlgorithmIdentifier(
"RSA/PSS", parameters);
209 throw Invalid_Argument(
fmt(
"Signatures using RSA/{} are not supported", emsa_name));
213 std::vector<uint8_t> marshal_signature(
const TPMT_SIGNATURE& signature)
const override {
214 const auto& sig = [&] {
215 if(signature.sigAlg == TPM2_ALG_RSASSA) {
216 return signature.signature.rsassa;
217 }
else if(signature.sigAlg == TPM2_ALG_RSAPSS) {
218 return signature.signature.rsapss;
220 throw Invalid_State(
fmt(
"TPM2 returned an unexpected signature scheme {}", signature.sigAlg));
228class RSA_Verification_Operation
final :
public Verification_Operation {
230 RSA_Verification_Operation(
const Object&
object,
const SessionBundle& sessions, std::string_view padding) :
231 Verification_Operation(object, sessions, select_signature_algorithms(padding)) {}
234 TPMT_SIGNATURE unmarshal_signature(std::span<const uint8_t> signature)
const override {
235 BOTAN_ARG_CHECK(signature.size() == signature_length_for_key_handle(sessions(), key_handle()),
236 "Unexpected signature byte length");
239 sig.sigAlg = scheme().scheme;
241 auto& sig_data = [&]() -> TPMS_SIGNATURE_RSA& {
242 if(sig.sigAlg == TPM2_ALG_RSASSA) {
243 return sig.signature.rsassa;
244 }
else if(sig.sigAlg == TPM2_ALG_RSAPSS) {
245 return sig.signature.rsapss;
247 throw Invalid_State(
fmt(
"Requested an unexpected signature scheme {}", sig.sigAlg));
250 sig_data.hash = scheme().details.any.hashAlg;
256TPMT_RSA_DECRYPT select_encryption_algorithms(std::string_view padding) {
259 throw Not_Implemented(
Botan::fmt(
"RSA encryption with padding scheme {}", padding));
261 return scheme.value();
264class RSA_Encryption_Operation
final :
public PK_Ops::Encryption {
266 RSA_Encryption_Operation(
const Object&
object,
const SessionBundle& sessions, std::string_view padding) :
267 m_key_handle(object), m_sessions(sessions), m_scheme(select_encryption_algorithms(padding)) {}
282 Esys_RSA_Encrypt(*m_key_handle.context(),
283 m_key_handle.transient_handle(),
300 size_t max_input_bits()
const override {
301 const auto max_ptext_bytes =
302 (m_key_handle._public_info(m_sessions, TPM2_ALG_RSA).pub->publicArea.parameters.rsaDetail.keyBits - 1) / 8;
303 auto hash_output_bytes = [](TPM2_ALG_ID hash) ->
size_t {
307 case TPM2_ALG_SHA256:
308 case TPM2_ALG_SHA3_256:
310 case TPM2_ALG_SHA384:
311 case TPM2_ALG_SHA3_384:
313 case TPM2_ALG_SHA512:
314 case TPM2_ALG_SHA3_512:
317 throw Invalid_State(
"Unexpected hash algorithm");
321 const auto max_input_bytes = [&]() ->
size_t {
322 switch(m_scheme.scheme) {
324 return max_ptext_bytes - 10;
326 return max_ptext_bytes - 2 * hash_output_bytes(m_scheme.details.oaep.hashAlg) - 1;
328 return max_ptext_bytes;
330 throw Invalid_State(
"Unexpected RSA encryption scheme");
334 return max_input_bytes * 8;
337 size_t ciphertext_length(
size_t )
const override {
338 return m_key_handle._public_info(m_sessions, TPM2_ALG_RSA).pub->publicArea.parameters.rsaDetail.keyBits - 1;
342 const Object& m_key_handle;
343 const SessionBundle& m_sessions;
344 TPMT_RSA_DECRYPT m_scheme;
347class RSA_Decryption_Operation
final :
public PK_Ops::Decryption {
349 RSA_Decryption_Operation(
const Object&
object,
const SessionBundle& sessions, std::string_view padding) :
350 m_key_handle(object), m_sessions(sessions), m_scheme(select_encryption_algorithms(padding)) {}
361 Esys_RSA_Decrypt(*m_key_handle.context(),
362 m_key_handle.transient_handle(),
371 const auto success = CT::Mask<
decltype(rc)>::is_equal(rc, TPM2_RC_SUCCESS).as_choice();
376 constexpr size_t default_plaintext_length = 32;
384 auto* out = &dummy_plaintext;
385 auto* maybe_plaintext = plaintext.get();
392 size_t plaintext_length(
size_t )
const override {
393 return m_key_handle._public_info(m_sessions, TPM2_ALG_RSA).pub->publicArea.parameters.rsaDetail.keyBits / 8;
397 const Object& m_key_handle;
398 const SessionBundle& m_sessions;
399 TPMT_RSA_DECRYPT m_scheme;
405 std::string_view provider)
const {
407 return std::make_unique<RSA_Verification_Operation>(
handles(),
sessions(), params);
411 std::string_view params,
412 std::string_view provider)
const {
414 return std::make_unique<RSA_Signature_Operation>(
handles(),
sessions(), params);
418 std::string_view params,
419 std::string_view provider)
const {
421 return std::make_unique<RSA_Encryption_Operation>(
handles(),
sessions(), params);
425 std::string_view params,
426 std::string_view provider)
const {
428 return std::make_unique<RSA_Decryption_Operation>(
handles(),
sessions(), params);
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_STATE_CHECK(expr)
#define BOTAN_ASSERT_NONNULL(ptr)
#define BOTAN_ARG_CHECK(expr, msg)
static constexpr Mask< T > from_choice(Choice c)
static std::unique_ptr< EMSA > create_or_throw(std::string_view algo_spec)
static OID from_string(std::string_view str)
std::vector< uint8_t > serialize() const
static PSS_Params from_emsa_name(std::string_view emsa_name)
ESYS_TR transient_handle() const noexcept
static std::unique_ptr< PrivateKey > create_transient_from_template(const std::shared_ptr< Context > &ctx, const SessionBundle &sessions, ESYS_TR parent, const TPMT_PUBLIC &key_template, const TPM2B_SENSITIVE_CREATE &sensitive_data)
const SessionBundle & sessions() const
const Object & handles() const
const SessionBundle & sessions() const
RSA_PrivateKey(Object handle, SessionBundle sessions, const TPM2B_PUBLIC *public_blob, std::span< const uint8_t > private_blob={})
static std::unique_ptr< TPM2::PrivateKey > create_unrestricted_transient(const std::shared_ptr< Context > &ctx, const SessionBundle &sessions, std::span< const uint8_t > auth_value, const TPM2::PrivateKey &parent, uint16_t keylength, std::optional< uint32_t > exponent={})
std::unique_ptr< PK_Ops::Decryption > create_decryption_op(Botan::RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
std::unique_ptr< PK_Ops::Signature > create_signature_op(Botan::RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
std::unique_ptr< PK_Ops::Encryption > create_encryption_op(Botan::RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
std::unique_ptr< PK_Ops::Verification > create_verification_op(std::string_view params, std::string_view provider) const override
int(* final)(unsigned char *, CTX *)
constexpr void conditional_swap_ptr(bool cnd, T &x, T &y)
std::string encrypt(const uint8_t input[], size_t input_len, std::string_view passphrase, RandomNumberGenerator &rng)
std::string decrypt(const uint8_t input[], size_t input_len, std::string_view passphrase)
std::optional< TPMT_SIG_SCHEME > rsa_signature_scheme_botan_to_tss2(std::string_view name)
constexpr T init_empty()
Create an empty TPM2 buffer of the given type.
constexpr void check_rc(std::string_view location, TSS2_RC rc)
std::optional< TPMT_RSA_DECRYPT > rsa_encryption_scheme_botan_to_tss2(std::string_view padding)
std::pair< BigInt, BigInt > rsa_pubkey_components_from_tss2_public(const TPM2B_PUBLIC *public_area)
std::unique_ptr< T, esys_liberator > unique_esys_ptr
A unique pointer type for ESYS handles that automatically frees the handle.
constexpr T init_with_size(size_t length)
Create a TPM2 buffer of a given type and length.
constexpr void copy_into(T &dest, std::span< const uint8_t > data)
constexpr auto as_span(tpm2_buffer auto &data)
Construct a std::span as a view into a TPM2 buffer.
constexpr TSS2_RC check_rc_expecting(std::string_view location, TSS2_RC rc)
constexpr auto out_ptr(T &outptr) noexcept
std::string fmt(std::string_view format, const T &... args)
std::vector< T, secure_allocator< T > > secure_vector
static TPMA_OBJECT render(ObjectAttributes attributes)