9#include <botan/internal/tpm2_crypto_backend.h>
11#include <botan/cipher_mode.h>
12#include <botan/hash.h>
14#include <botan/mem_ops.h>
15#include <botan/pubkey.h>
16#include <botan/tpm2_context.h>
17#include <botan/tpm2_key.h>
19#if defined(BOTAN_HAS_RSA)
20 #include <botan/rsa.h>
23#if defined(BOTAN_HAS_ECDH)
24 #include <botan/ecdh.h>
27#include <botan/internal/eme.h>
28#include <botan/internal/fmt.h>
29#include <botan/internal/tpm2_algo_mappings.h>
30#include <botan/internal/tpm2_util.h>
32#if defined(BOTAN_HAS_EME_OAEP)
33 #include <botan/internal/oaep.h>
36#include <tss2/tss2_esys.h>
37#include <tss2/tss2_mu.h>
41#if defined(BOTAN_TSS2_SUPPORTS_CRYPTO_CALLBACKS)
47 std::variant<std::unique_ptr<Botan::HashFunction>, std::unique_ptr<Botan::MessageAuthenticationCode>>;
57typedef struct ESYS_CRYPTO_CONTEXT_BLOB {
67 requires std::constructible_from<DigestObject, std::unique_ptr<T>>
68[[nodiscard]] std::optional<std::reference_wrapper<T>> get(DigestCallbackState* blob)
noexcept {
73 if(!std::holds_alternative<std::unique_ptr<T>>(blob->ctx)) {
77 return {std::ref(*std::get<std::unique_ptr<T>>(blob->ctx))};
81 requires std::constructible_from<DigestObject, std::unique_ptr<T>>
82[[nodiscard]] std::optional<std::reference_wrapper<T>> get(DigestCallbackState** blob)
noexcept {
91[[nodiscard]] std::optional<std::reference_wrapper<Botan::TPM2::CryptoCallbackState>> get(
void* userdata)
noexcept {
109template <std::invocable<> F>
110 requires std::same_as<std::invoke_result_t<F>,
TSS2_RC>
111[[nodiscard]]
TSS2_RC thunk(F f)
noexcept {
115 return TSS2_ESYS_RC_BAD_VALUE;
117 return TSS2_ESYS_RC_BAD_SEQUENCE;
119 return TSS2_ESYS_RC_NOT_IMPLEMENTED;
121 return TSS2_ESYS_RC_MALFORMED_RESPONSE;
123 return TSS2_ESYS_RC_GENERAL_FAILURE;
125 return TSS2_ESYS_RC_GENERAL_FAILURE;
135 TPM2_ALG_ID tpm_sym_alg,
136 TPMI_AES_KEY_BITS key_bits,
137 TPM2_ALG_ID tpm_mode,
140 const uint8_t* iv)
noexcept {
144 : TSS2_ESYS_RC_NO_DECRYPT_PARAM;
148 if(!buffer && buffer_size != 0) {
149 return TSS2_ESYS_RC_BAD_VALUE;
153 .algorithm = tpm_sym_alg,
154 .keyBits = {.sym = key_bits},
155 .mode = {.sym = tpm_mode},
158 return TSS2_ESYS_RC_NOT_SUPPORTED;
163 return TSS2_ESYS_RC_NOT_IMPLEMENTED;
168 if(cipher->authenticated()) {
169 return TSS2_ESYS_RC_INSUFFICIENT_BUFFER;
173 const size_t keylength =
static_cast<size_t>(key_bits) / 8;
174 if(!cipher->valid_keylength(keylength)) {
175 return TSS2_ESYS_RC_BAD_VALUE;
178 const auto s_data = std::span{buffer, buffer_size};
179 const auto s_key = std::span{key, keylength};
180 const auto s_iv = [&]() -> std::span<const uint8_t> {
182 return {iv, cipher->default_nonce_length()};
188 cipher->set_key(s_key);
190 cipher->process(s_data);
191 return TSS2_RC_SUCCESS;
206TSS2_RC hash_start(ESYS_CRYPTO_CONTEXT_BLOB** context, TPM2_ALG_ID hash_alg,
void* userdata) {
210 return TSS2_ESYS_RC_BAD_REFERENCE;
215 return TSS2_ESYS_RC_NOT_SUPPORTED;
220 return TSS2_ESYS_RC_NOT_IMPLEMENTED;
224 *context =
new DigestCallbackState{std::move(hash)};
225 return TSS2_RC_SUCCESS;
240TSS2_RC hash_update(ESYS_CRYPTO_CONTEXT_BLOB* context,
const uint8_t* buffer,
size_t size,
void* userdata) {
243 const auto hash = get<Botan::HashFunction>(context);
245 return TSS2_ESYS_RC_BAD_REFERENCE;
249 if(!buffer && size != 0) {
250 return TSS2_ESYS_RC_BAD_VALUE;
253 hash->get().update(std::span{buffer, size});
254 return TSS2_RC_SUCCESS;
269TSS2_RC hash_finish(ESYS_CRYPTO_CONTEXT_BLOB** context, uint8_t* buffer,
size_t* size,
void* userdata) {
271 if(size !=
nullptr) {
276 auto hash = get<Botan::HashFunction>(context);
277 if(!hash || !buffer) {
278 return TSS2_ESYS_RC_BAD_REFERENCE;
281 const auto digest_size = hash->get().output_length();
282 hash->get().final(std::span{buffer, digest_size});
283 if(size !=
nullptr) {
289 return TSS2_RC_SUCCESS;
299void hash_abort(ESYS_CRYPTO_CONTEXT_BLOB** context,
void* userdata) {
320 ESYS_CRYPTO_CONTEXT_BLOB** context, TPM2_ALG_ID hash_alg,
const uint8_t* key,
size_t size,
void* userdata) {
323 if(!context || !key) {
324 return TSS2_ESYS_RC_BAD_REFERENCE;
329 return TSS2_ESYS_RC_NOT_SUPPORTED;
334 return TSS2_ESYS_RC_NOT_IMPLEMENTED;
337 hmac->set_key(std::span{key, size});
340 *context =
new DigestCallbackState{std::move(hmac)};
341 return TSS2_RC_SUCCESS;
356TSS2_RC hmac_update(ESYS_CRYPTO_CONTEXT_BLOB* context,
const uint8_t* buffer,
size_t size,
void* userdata) {
359 auto hmac = get<Botan::MessageAuthenticationCode>(context);
361 return TSS2_ESYS_RC_BAD_REFERENCE;
365 if(!buffer && size != 0) {
366 return TSS2_ESYS_RC_BAD_VALUE;
369 hmac->get().update(std::span{buffer, size});
370 return TSS2_RC_SUCCESS;
385TSS2_RC hmac_finish(ESYS_CRYPTO_CONTEXT_BLOB** context, uint8_t* buffer,
size_t* size,
void* userdata) {
387 if(size !=
nullptr) {
392 auto hmac = get<Botan::MessageAuthenticationCode>(context);
393 if(!hmac || !buffer) {
394 return TSS2_ESYS_RC_BAD_REFERENCE;
397 const auto digest_size = hmac->get().output_length();
398 hmac->get().final(std::span{buffer, digest_size});
399 if(size !=
nullptr) {
405 return TSS2_RC_SUCCESS;
415void hmac_abort(ESYS_CRYPTO_CONTEXT_BLOB** context,
void* userdata) {
433TSS2_RC get_random2b(TPM2B_NONCE* nonce,
size_t num_bytes,
void* userdata) {
435 auto ccs = get(userdata);
436 if(!ccs || !ccs->get().rng || !nonce) {
437 return TSS2_ESYS_RC_BAD_REFERENCE;
441 return TSS2_RC_SUCCESS;
460TSS2_RC rsa_pk_encrypt(TPM2B_PUBLIC* pub_tpm_key,
468 if(out_size !=
nullptr) {
479 #if defined(BOTAN_HAS_RSA)
480 auto create_eme = [&](
481 const TPMT_RSA_SCHEME& scheme,
482 [[maybe_unused]] TPM2_ALG_ID name_algo,
483 [[maybe_unused]] TPMU_ASYM_SCHEME scheme_detail) -> std::optional<std::unique_ptr<Botan::EME>> {
487 auto create_oaep = [&]() -> std::optional<std::unique_ptr<Botan::EME>> {
488 #if defined(BOTAN_HAS_EME_OAEP)
493 (scheme_detail.oaep.hashAlg == TPM2_ALG_NULL || scheme_detail.oaep.hashAlg == TPM2_ALG_ERROR)
494 ? pub_tpm_key->publicArea.nameAlg
495 : scheme_detail.oaep.hashAlg);
501 if(!label_hash || !mgf1_hash) {
507 if(!H_label || !H_mgf1) {
514 std::string_view label_with_zero_terminator{label, std::strlen(label) + 1};
515 return std::make_unique<Botan::OAEP>(std::move(H_label), std::move(H_mgf1), label_with_zero_terminator);
523 switch(scheme.scheme) {
525 return create_oaep();
541 auto ccs = get(userdata);
542 if(!ccs || !pub_tpm_key || !in_buffer || !out_buffer || !ccs->get().rng) {
543 return TSS2_ESYS_RC_BAD_REFERENCE;
550 const auto maybe_eme = create_eme(pub_tpm_key->publicArea.parameters.rsaDetail.scheme,
551 pub_tpm_key->publicArea.nameAlg,
552 pub_tpm_key->publicArea.parameters.rsaDetail.scheme.details);
553 if(!maybe_eme.has_value()) {
554 return TSS2_ESYS_RC_NOT_SUPPORTED;
557 const auto& eme = maybe_eme.value();
559 return TSS2_ESYS_RC_NOT_IMPLEMENTED;
573 const auto pubkey = Botan::TPM2::rsa_pubkey_from_tss2_public(pub_tpm_key);
574 const auto keybits = pubkey.key_length();
575 const auto output_size = keybits / 8;
576 if(eme->maximum_input_size(keybits) < in_size) {
577 return TSS2_ESYS_RC_BAD_VALUE;
580 if(output_size > max_out_size) {
581 return TSS2_ESYS_RC_INSUFFICIENT_BUFFER;
584 const auto max_raw_bits = keybits - 1;
585 const auto max_raw_bytes = (max_raw_bits + 7) / 8;
586 const auto padded_bytes = eme->pad({out_buffer, max_raw_bytes}, {in_buffer, in_size}, max_raw_bits, rng);
591 const auto encrypted = encryptor.encrypt({out_buffer, padded_bytes}, rng);
597 if(out_size !=
nullptr) {
598 *out_size = encrypted.size();
601 return TSS2_RC_SUCCESS;
604 BOTAN_UNUSED(pub_tpm_key, in_size, in_buffer, max_out_size, out_buffer, label, userdata);
605 return TSS2_ESYS_RC_NOT_IMPLEMENTED;
626TSS2_RC get_ecdh_point(TPM2B_PUBLIC* key,
628 TPM2B_ECC_PARAMETER* Z,
633 if(out_size !=
nullptr) {
637 #if defined(BOTAN_HAS_ECDH)
639 auto ccs = get(userdata);
640 if(!ccs || !key || !Z || !Q || !out_buffer | !ccs->get().rng) {
641 return TSS2_ESYS_RC_BAD_REFERENCE;
647 const auto [tpm_ec_group, tpm_ec_point] = Botan::TPM2::ecc_pubkey_from_tss2_public(key);
650 const auto curve_order_byte_size = tpm_sw_pubkey.domain().get_p_bytes();
663 const auto shared_secret = ecdh.derive_key(0 , tpm_sw_pubkey.public_value()).bits_of();
668 Tss2_MU_TPMS_ECC_POINT_Marshal(Q, out_buffer, max_out_size, out_size));
670 return TSS2_RC_SUCCESS;
673 BOTAN_UNUSED(key, max_out_size, Z, Q, out_buffer, userdata);
674 return TSS2_ESYS_RC_NOT_IMPLEMENTED;
693TSS2_RC aes_encrypt(uint8_t* key,
694 TPM2_ALG_ID tpm_sym_alg,
695 TPMI_AES_KEY_BITS key_bits,
696 TPM2_ALG_ID tpm_mode,
702 if(tpm_sym_alg != TPM2_ALG_AES) {
703 return TSS2_ESYS_RC_BAD_VALUE;
724TSS2_RC aes_decrypt(uint8_t* key,
725 TPM2_ALG_ID tpm_sym_alg,
726 TPMI_AES_KEY_BITS key_bits,
727 TPM2_ALG_ID tpm_mode,
733 if(tpm_sym_alg != TPM2_ALG_AES) {
734 return TSS2_ESYS_RC_BAD_VALUE;
740 #if defined(BOTAN_TSS2_SUPPORTS_SM4_IN_CRYPTO_CALLBACKS)
757TSS2_RC sm4_encrypt(uint8_t* key,
758 TPM2_ALG_ID tpm_sym_alg,
759 TPMI_SM4_KEY_BITS key_bits,
760 TPM2_ALG_ID tpm_mode,
766 if(tpm_sym_alg != TPM2_ALG_SM4) {
767 return TSS2_ESYS_RC_BAD_VALUE;
788TSS2_RC sm4_decrypt(uint8_t* key,
789 TPM2_ALG_ID tpm_sym_alg,
790 TPMI_SM4_KEY_BITS key_bits,
791 TPM2_ALG_ID tpm_mode,
797 if(tpm_sym_alg != TPM2_ALG_SM4) {
798 return TSS2_ESYS_RC_BAD_VALUE;
817 auto ccs = get(userdata);
819 return TSS2_ESYS_RC_BAD_REFERENCE;
821 if(!ccs->get().rng) {
822 return TSS2_ESYS_RC_BAD_SEQUENCE;
824 return TSS2_RC_SUCCESS;
868#if defined(BOTAN_TSS2_SUPPORTS_CRYPTO_CALLBACKS)
872 ESYS_CRYPTO_CALLBACKS callbacks{
873 .rsa_pk_encrypt = &rsa_pk_encrypt,
874 .hash_start = &hash_start,
875 .hash_update = &hash_update,
876 .hash_finish = &hash_finish,
877 .hash_abort = &hash_abort,
878 .hmac_start = &hmac_start,
879 .hmac_update = &hmac_update,
880 .hmac_finish = &hmac_finish,
881 .hmac_abort = &hmac_abort,
882 .get_random2b = &get_random2b,
883 .get_ecdh_point = &get_ecdh_point,
884 .aes_encrypt = &aes_encrypt,
885 .aes_decrypt = &aes_decrypt,
887 .userdata = &ctx->crypto_callback_state(),
888#if defined(BOTAN_TSS2_SUPPORTS_SM4_IN_CRYPTO_CALLBACKS)
889 .sm4_encrypt = &sm4_encrypt,
890 .sm4_decrypt = &sm4_decrypt,
895 check_rc(
"Esys_SetCryptoCallbacks", Esys_SetCryptoCallbacks(*ctx, &callbacks));
899 "This build of botan was compiled with a TSS2 version lower than 4.0.0, "
900 "which does not support custom runtime crypto backends");
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_DEBUG_ASSERT(expr)
#define BOTAN_ASSERT_NONNULL(ptr)
void serialize_to(std::span< uint8_t > out) const
static std::unique_ptr< Cipher_Mode > create(std::string_view algo, Cipher_Dir direction, std::string_view provider="")
BigInt get_affine_x() const
BigInt get_affine_y() const
static std::unique_ptr< EME > create(std::string_view algo_spec)
static std::unique_ptr< HashFunction > create(std::string_view algo_spec, std::string_view provider="")
static std::unique_ptr< MessageAuthenticationCode > create(std::string_view algo_spec, std::string_view provider="")
void enable_crypto_callbacks(const std::shared_ptr< Context > &ctx)
constexpr void check_rc(std::string_view location, TSS2_RC rc)
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.
std::optional< std::string > hash_algo_tss2_to_botan(TPMI_ALG_HASH hash_id) noexcept
std::optional< std::string > cipher_tss2_to_botan(TPMT_SYM_DEF cipher_def) noexcept
std::string fmt(std::string_view format, const T &... args)
constexpr void copy_mem(T *out, const T *in, size_t n)
uint32_t TSS2_RC
Forward declaration of TSS2 type for convenience.