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/concat_util.h>
19#include <botan/internal/fmt.h>
20#include <botan/internal/stl_util.h>
21#include <botan/internal/tpm2_algo_mappings.h>
22#include <botan/internal/tpm2_hash.h>
23#include <botan/internal/tpm2_util.h>
25#include <tss2/tss2_esys.h>
26#include <tss2/tss2_mu.h>
30#if defined(BOTAN_HAS_RSA)
31Botan::RSA_PublicKey rsa_pubkey_from_tss2_public(
const TPM2B_PUBLIC* public_area) {
34 return std::apply([](
const BigInt& n,
const BigInt& e) {
return Botan::RSA_PublicKey(n, e); },
35 rsa_pubkey_components_from_tss2_public(public_area));
39#if defined(BOTAN_HAS_ECC_GROUP)
40std::pair<EC_Group, EC_AffinePoint> ecc_pubkey_from_tss2_public(
const TPM2B_PUBLIC* public_blob) {
42 BOTAN_ARG_CHECK(public_blob->publicArea.type == TPM2_ALG_ECC,
"Public blob is not an ECC key");
44 const auto curve_id = public_blob->publicArea.parameters.eccDetail.curveID;
47 throw Invalid_Argument(
Botan::fmt(
"Unsupported ECC curve: {}", curve_id));
54 concat(std::vector<uint8_t>({0x04}),
55 as_span(public_blob->publicArea.unique.ecc.x),
56 as_span(public_blob->publicArea.unique.ecc.y)));
58 throw Invalid_Argument(
"Invalid ECC Point");
60 return {std::move(curve), std::move(point.value())};
66Object load_persistent_object(
const std::shared_ptr<Context>& ctx,
68 std::span<const uint8_t> auth_value,
71 TPM2_PERSISTENT_FIRST <= persistent_object_handle && persistent_object_handle <= TPM2_PERSISTENT_LAST,
72 "persistent_object_handle out of range");
74 const bool is_persistent =
value_exists(ctx->persistent_handles(), persistent_object_handle);
80 Esys_TR_FromTPMPublic(ctx->esys_context(),
81 persistent_object_handle,
87 if(!auth_value.empty()) {
89 check_rc(
"Esys_TR_SetAuth", Esys_TR_SetAuth(ctx->esys_context(),
object.transient_handle(), &user_auth));
95 const auto key_type =
object._public_info(sessions).pub->publicArea.type;
97 "persistent object is neither RSA nor ECC public key");
102std::vector<uint8_t> marshal_public_blob(
const TPM2B_PUBLIC* public_data) {
103 size_t bytes_required = 0;
104 std::vector<uint8_t> marshalled_blob(
sizeof(TPM2B_PUBLIC));
105 check_rc(
"Tss2_MU_TPM2B_PUBLIC_Marshal",
106 Tss2_MU_TPM2B_PUBLIC_Marshal(public_data, marshalled_blob.data(), marshalled_blob.size(), &bytes_required));
107 marshalled_blob.resize(bytes_required);
108 marshalled_blob.shrink_to_fit();
109 return marshalled_blob;
112TPM2B_PUBLIC unmarshal_public_blob(std::span<const uint8_t> marshalled_blob) {
113 TPM2B_PUBLIC public_data{};
115 check_rc(
"Tss2_MU_TPM2B_PUBLIC_Unmarshal",
116 Tss2_MU_TPM2B_PUBLIC_Unmarshal(marshalled_blob.data(), marshalled_blob.size(), &offset, &public_data));
121TPM2B_TEMPLATE marshal_template(
const TPMT_PUBLIC& key_template) {
122 TPM2B_TEMPLATE result = {};
124 check_rc(
"Tss2_MU_TPMT_PUBLIC_Marshal",
125 Tss2_MU_TPMT_PUBLIC_Marshal(&key_template, result.buffer,
sizeof(TPMT_PUBLIC), &offset));
127 result.size =
static_cast<uint16_t
>(offset);
140 std::span<const uint8_t> public_blob,
142 const auto public_data = unmarshal_public_blob(public_blob);
148 Esys_LoadExternal(ctx->esys_context(),
160 return marshal_public_blob(m_handle._public_info(m_sessions).pub.get());
164 [[maybe_unused]]
const auto* pubinfo =
handles._public_info(
sessions).pub.get();
165#if defined(BOTAN_HAS_TPM2_RSA_ADAPTER)
166 if(pubinfo->publicArea.type == TPM2_ALG_RSA) {
170#if defined(BOTAN_HAS_TPM2_ECC_ADAPTER)
171 if(pubinfo->publicArea.type == TPM2_ALG_ECC) {
177 handles.has_persistent_handle() ?
"persistent" :
"transient"));
184 std::span<const uint8_t> auth_value,
186 return create(load_persistent_object(ctx, persistent_object_handle, auth_value,
sessions),
193 std::span<const uint8_t> auth_value,
195 std::span<const uint8_t> public_blob,
196 std::span<const uint8_t> private_blob,
201 const auto public_data = unmarshal_public_blob(public_blob);
205 Esys_Load(ctx->esys_context(),
214 if(!auth_value.empty()) {
219 return create(std::move(handle),
sessions,
nullptr , private_blob);
225 const TPMT_PUBLIC& key_template,
226 const TPM2B_SENSITIVE_CREATE& sensitive_data) {
231 switch(key_template.type) {
233#if not defined(BOTAN_HAS_TPM2_RSA_ADAPTER)
234 throw Not_Implemented(
"TPM2-based RSA keys are not supported in this build");
238#if not defined(BOTAN_HAS_TPM2_ECC_ADAPTER)
239 throw Not_Implemented(
"TPM2-based ECC keys are not supported in this build");
248 const auto marshalled_template = marshal_template(key_template);
262 Esys_CreateLoaded(ctx->esys_context(),
268 &marshalled_template,
286 return marshal_public_blob(m_handle._public_info(m_sessions).pub.get());
293 const auto attrs = m_handle.attributes(m_sessions);
294 return attrs.decrypt && attrs.restricted && !attrs.sign_encrypt;
299 [[maybe_unused]]
const TPM2B_PUBLIC* public_info,
300 [[maybe_unused]] std::span<const uint8_t> private_blob) {
301 if(public_info ==
nullptr) {
305#if defined(BOTAN_HAS_TPM2_RSA_ADAPTER)
306 if(public_info->publicArea.type == TPM2_ALG_RSA) {
307 return std::unique_ptr<RSA_PrivateKey>(
312#if defined(BOTAN_HAS_TPM2_ECC_ADAPTER)
313 if(public_info->publicArea.type == TPM2_ALG_ECC) {
319 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 V &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.