9#include <botan/tpm2_key.h> 
   11#if defined(BOTAN_HAS_TPM2_RSA_ADAPTER) 
   12   #include <botan/tpm2_rsa.h> 
   14#if defined(BOTAN_HAS_TPM2_ECC_ADAPTER) 
   15   #include <botan/tpm2_ecc.h> 
   18#include <botan/internal/fmt.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_util.h> 
   24#include <tss2/tss2_esys.h> 
   25#include <tss2/tss2_mu.h> 
   29#if defined(BOTAN_HAS_RSA) 
   30Botan::RSA_PublicKey rsa_pubkey_from_tss2_public(
const TPM2B_PUBLIC* public_area) {
 
   33   return std::apply([](
const BigInt& n, 
const BigInt& e) { 
return Botan::RSA_PublicKey(n, e); },
 
   34                     rsa_pubkey_components_from_tss2_public(public_area));
 
   38#if defined(BOTAN_HAS_ECC_GROUP) 
   39std::pair<EC_Group, EC_AffinePoint> ecc_pubkey_from_tss2_public(
const TPM2B_PUBLIC* public_blob) {
 
   41   BOTAN_ARG_CHECK(public_blob->publicArea.type == TPM2_ALG_ECC, 
"Public blob is not an ECC key");
 
   43   const auto curve_id = public_blob->publicArea.parameters.eccDetail.curveID;
 
   46      throw Invalid_Argument(
Botan::fmt(
"Unsupported ECC curve: {}", curve_id));
 
   53                                            concat(std::vector<uint8_t>({0x04}),
 
   54                                                   as_span(public_blob->publicArea.unique.ecc.x),
 
   55                                                   as_span(public_blob->publicArea.unique.ecc.y)));
 
   57      throw Invalid_Argument(
"Invalid ECC Point");
 
   59   return {std::move(curve), std::move(point.value())};
 
   65Object load_persistent_object(
const std::shared_ptr<Context>& ctx,
 
   67                              std::span<const uint8_t> auth_value,
 
   70      TPM2_PERSISTENT_FIRST <= persistent_object_handle && persistent_object_handle <= TPM2_PERSISTENT_LAST,
 
   71      "persistent_object_handle out of range");
 
   73   const bool is_persistent = 
value_exists(ctx->persistent_handles(), persistent_object_handle);
 
   79            Esys_TR_FromTPMPublic(
 
   80               *ctx, persistent_object_handle, sessions[0], sessions[1], sessions[2], 
out_transient_handle(
object)));
 
   82   if(!auth_value.empty()) {
 
   84      check_rc(
"Esys_TR_SetAuth", Esys_TR_SetAuth(*ctx, 
object.transient_handle(), &user_auth));
 
   90   const auto key_type = 
object._public_info(sessions).pub->publicArea.type;
 
   92                   "persistent object is neither RSA nor ECC public key");
 
   97std::vector<uint8_t> marshal_public_blob(
const TPM2B_PUBLIC* public_data) {
 
   98   size_t bytes_required = 0;
 
   99   std::vector<uint8_t> marshalled_blob(
sizeof(TPM2B_PUBLIC));
 
  100   check_rc(
"Tss2_MU_TPM2B_PUBLIC_Marshal",
 
  101            Tss2_MU_TPM2B_PUBLIC_Marshal(public_data, marshalled_blob.data(), marshalled_blob.size(), &bytes_required));
 
  102   marshalled_blob.resize(bytes_required);
 
  103   marshalled_blob.shrink_to_fit();
 
  104   return marshalled_blob;
 
  107TPM2B_PUBLIC unmarshal_public_blob(std::span<const uint8_t> marshalled_blob) {
 
  108   TPM2B_PUBLIC public_data{};
 
  110   check_rc(
"Tss2_MU_TPM2B_PUBLIC_Unmarshal",
 
  111            Tss2_MU_TPM2B_PUBLIC_Unmarshal(marshalled_blob.data(), marshalled_blob.size(), &offset, &public_data));
 
  116TPM2B_TEMPLATE marshal_template(
const TPMT_PUBLIC& key_template) {
 
  117   TPM2B_TEMPLATE result = {};
 
  119   check_rc(
"Tss2_MU_TPMT_PUBLIC_Marshal",
 
  120            Tss2_MU_TPMT_PUBLIC_Marshal(&key_template, result.buffer, 
sizeof(TPMT_PUBLIC), &offset));
 
  122   result.size = 
static_cast<uint16_t
>(offset);
 
  135                                                     std::span<const uint8_t> public_blob,
 
  137   const auto public_data = unmarshal_public_blob(public_blob);
 
  143            Esys_LoadExternal(*ctx,
 
 
  155   return marshal_public_blob(m_handle._public_info(m_sessions).pub.get());
 
 
  159   [[maybe_unused]] 
const auto* pubinfo = 
handles._public_info(
sessions).pub.get();
 
  160#if defined(BOTAN_HAS_TPM2_RSA_ADAPTER) 
  161   if(pubinfo->publicArea.type == TPM2_ALG_RSA) {
 
  165#if defined(BOTAN_HAS_TPM2_ECC_ADAPTER) 
  166   if(pubinfo->publicArea.type == TPM2_ALG_ECC) {
 
  172                                    handles.has_persistent_handle() ? 
"persistent" : 
"transient"));
 
 
  179                                                        std::span<const uint8_t> auth_value,
 
  181   return create(load_persistent_object(ctx, persistent_object_handle, auth_value, 
sessions),
 
 
  188                                                       std::span<const uint8_t> auth_value,
 
  190                                                       std::span<const uint8_t> public_blob,
 
  191                                                       std::span<const uint8_t> private_blob,
 
  196   const auto public_data = unmarshal_public_blob(public_blob);
 
  209   if(!auth_value.empty()) {
 
  214   return create(std::move(handle), 
sessions, 
nullptr , private_blob);
 
 
  220                                                                       const TPMT_PUBLIC& key_template,
 
  221                                                                       const TPM2B_SENSITIVE_CREATE& sensitive_data) {
 
  226   switch(key_template.type) {
 
  228#if not defined(BOTAN_HAS_TPM2_RSA_ADAPTER) 
  229         throw Not_Implemented(
"TPM2-based RSA keys are not supported in this build");
 
  233#if not defined(BOTAN_HAS_TPM2_ECC_ADAPTER) 
  234         throw Not_Implemented(
"TPM2-based ECC keys are not supported in this build");
 
  243   const auto marshalled_template = marshal_template(key_template);
 
  257            Esys_CreateLoaded(*ctx,
 
  263                              &marshalled_template,
 
 
  281   return marshal_public_blob(m_handle._public_info(m_sessions).pub.get());
 
 
  288   const auto attrs = m_handle.attributes(m_sessions);
 
  289   return attrs.decrypt && attrs.restricted && !attrs.sign_encrypt;
 
 
  294                                               [[maybe_unused]] 
const TPM2B_PUBLIC* public_info,
 
  295                                               [[maybe_unused]] std::span<const uint8_t> private_blob) {
 
  296   if(public_info == 
nullptr) {
 
  300#if defined(BOTAN_HAS_TPM2_RSA_ADAPTER) 
  301   if(public_info->publicArea.type == TPM2_ALG_RSA) {
 
  302      return std::unique_ptr<RSA_PrivateKey>(
 
  307#if defined(BOTAN_HAS_TPM2_ECC_ADAPTER) 
  308   if(public_info->publicArea.type == TPM2_ALG_ECC) {
 
  314                                    handles.has_persistent_handle() ? 
"persistent" : 
"transient"));
 
 
#define BOTAN_ASSERT_NOMSG(expr)
 
#define BOTAN_STATE_CHECK(expr)
 
#define BOTAN_ASSERT_NONNULL(ptr)
 
#define BOTAN_ARG_CHECK(expr, msg)
 
static std::optional< EC_AffinePoint > deserialize(const EC_Group &group, std::span< const uint8_t > bytes)
 
static EC_Group from_name(std::string_view name)
 
bool has_transient_handle() const
 
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)
 
std::vector< uint8_t > raw_public_key_bits() const override
 
static std::unique_ptr< PrivateKey > create(Object handles, const SessionBundle &sessions, const TPM2B_PUBLIC *public_info, std::span< const uint8_t > private_blob)
 
static std::unique_ptr< PrivateKey > load_persistent(const std::shared_ptr< Context > &ctx, TPM2_HANDLE persistent_object_handle, std::span< const uint8_t > auth_value, const SessionBundle &sessions)
 
static std::unique_ptr< PrivateKey > load_transient(const std::shared_ptr< Context > &ctx, std::span< const uint8_t > auth_value, const TPM2::PrivateKey &parent, std::span< const uint8_t > public_blob, std::span< const uint8_t > private_blob, const SessionBundle &sessions)
 
const SessionBundle & sessions() const
 
secure_vector< uint8_t > raw_private_key_bits() const override
 
static std::unique_ptr< PublicKey > create(Object handles, const SessionBundle &sessions)
 
std::vector< uint8_t > raw_public_key_bits() const override
 
static std::unique_ptr< PublicKey > load_persistent(const std::shared_ptr< Context > &ctx, TPM2_HANDLE persistent_object_handle, const SessionBundle &sessions={})
 
const Object & handles() const
 
const SessionBundle & sessions() const
 
static std::unique_ptr< PublicKey > load_transient(const std::shared_ptr< Context > &ctx, std::span< const uint8_t > public_blob, const SessionBundle &sessions)
 
constexpr void check_rc(std::string_view location, TSS2_RC rc)
 
constexpr auto out_persistent_handle(Object &object)
 
std::unique_ptr< T, esys_liberator > unique_esys_ptr
A unique pointer type for ESYS handles that automatically frees the handle.
 
std::optional< std::string > curve_id_tss2_to_botan(TPMI_ECC_CURVE mode_id)
 
constexpr auto out_transient_handle(Object &object)
 
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 auto out_ptr(T &outptr) noexcept
 
std::string fmt(std::string_view format, const T &... args)
 
secure_vector< T > lock(const std::vector< T > &in)
 
constexpr auto concat(Rs &&... ranges)
 
bool value_exists(const std::vector< T > &vec, const OT &val)
 
std::vector< T, secure_allocator< T > > secure_vector
 
uint32_t ESYS_TR
Forward declaration of TSS2 type for convenience.
 
uint32_t TPM2_HANDLE
Forward declaration of TSS2 type for convenience.