10#include <botan/der_enc.h>
11#include <botan/hash.h>
12#include <botan/mem_ops.h>
13#include <botan/pk_ops.h>
15#include <botan/internal/fmt.h>
16#include <botan/internal/hash_id.h>
17#include <botan/internal/workfactor.h>
20#include <trousers/trousers.h>
21#include <tss/platform.h>
30void tss_error(TSS_RESULT res,
const char* expr,
const char* file,
int line) {
31 std::string err =
fmt(
"TPM error {} in layer {} executing {} at {}:{}",
32 Trspi_Error_String(res),
33 Trspi_Error_Layer(res),
41TSS_FLAG bit_flag(
size_t bits) {
45 return TSS_KEY_SIZE_1024;
47 return TSS_KEY_SIZE_2048;
51 return TSS_KEY_SIZE_4096;
53 return TSS_KEY_SIZE_8192;
55 return TSS_KEY_SIZE_16384;
62uint32_t to_uint32(T v) {
63 BOTAN_ARG_CHECK(v > std::numeric_limits<uint32_t>::max(),
"Value too large for 32bit unsigned integer");
64 return static_cast<uint32_t
>(v);
67#define TSPI_CHECK_SUCCESS(expr) \
69 TSS_RESULT res = expr; \
70 if(res != TSS_SUCCESS) \
71 tss_error(res, #expr, __FILE__, __LINE__); \
74std::vector<uint8_t> get_obj_attr(TSS_HCONTEXT ctx, TSS_HOBJECT obj, TSS_FLAG flag, TSS_FLAG sub_flag) {
79 std::vector<uint8_t> r(data, data + data_len);
86void set_policy_secret(TSS_HPOLICY policy,
const char* secret) {
88 BYTE* as_b =
const_cast<BYTE*
>(
reinterpret_cast<const BYTE*
>(secret));
89 TSPI_CHECK_SUCCESS(::Tspi_Policy_SetSecret(policy, TSS_SECRET_MODE_PLAIN, to_uint32(std::strlen(secret)), as_b));
91 static const uint8_t nullpass[20] = {0};
94 ::Tspi_Policy_SetSecret(policy, TSS_SECRET_MODE_SHA1,
sizeof(nullpass),
const_cast<BYTE*
>(nullpass)));
98TSS_UUID to_tss_uuid(
const UUID& uuid) {
99 static_assert(
sizeof(TSS_UUID) == 16,
"Expected size of packed UUID");
106UUID from_tss_uuid(
const TSS_UUID& tss_uuid) {
107 static_assert(
sizeof(TSS_UUID) == 16,
"Expected size of packed UUID");
109 std::vector<uint8_t> mem(16);
111 UUID uuid(std::move(mem));
116 if(flag == TSS_PS_TYPE_USER)
118 else if(flag == TSS_PS_TYPE_SYSTEM)
121 throw TPM_Error(
"Invalid storage flag " + std::to_string(flag));
126 return "tpmkey:uuid=" + uuid.to_string() +
";storage=" + storage_str;
129std::string format_url(
const TSS_UUID& tss_uuid, TSS_FLAG store_type) {
130 UUID uuid = from_tss_uuid(tss_uuid);
132 return format_url(from_tss_uuid(tss_uuid), storage_type_from_tss_flag(store_type));
143 const TSS_UUID SRK_UUID = TSS_UUID_SRK;
145 TSPI_CHECK_SUCCESS(::Tspi_Context_LoadKeyByUUID(m_ctx, TSS_PS_TYPE_SYSTEM, SRK_UUID, &m_srk));
148 set_policy_secret(m_srk_policy, srk_password);
170 copy_mem(out,
reinterpret_cast<const uint8_t*
>(mem), out_len);
175 TSPI_CHECK_SUCCESS(::Tspi_TPM_StirRandom(m_tpm, to_uint32(in_len),
const_cast<BYTE*
>(in)));
182 TSS_FLAG key_flags = bit_flag(bits) | TSS_KEY_VOLATILE | TSS_KEY_TYPE_SIGNING;
185 TSPI_CHECK_SUCCESS(::Tspi_Context_CreateObject(m_ctx.handle(), TSS_OBJECT_TYPE_RSAKEY, key_flags, &key));
188 ::Tspi_SetAttribUint32(key, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_SIGSCHEME, TSS_SS_RSASSAPKCS1V15_DER));
191 TSPI_CHECK_SUCCESS(::Tspi_Context_CreateObject(m_ctx.handle(), TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &policy));
192 set_policy_secret(policy, key_password);
201 m_ctx(
ctx), m_uuid(uuid_str), m_storage(storage_type) {
202 const TSS_FLAG key_ps_type = (m_storage ==
TPM_Storage_Type::User) ? TSS_PS_TYPE_USER : TSS_PS_TYPE_SYSTEM;
204 TSPI_CHECK_SUCCESS(::Tspi_Context_LoadKeyByUUID(m_ctx.handle(), key_ps_type, to_tss_uuid(m_uuid), &m_key));
209 m_ctx.handle(), m_ctx.srk(), to_uint32(blob.size()),
const_cast<uint8_t*
>(blob.data()), &m_key));
215 if(!m_uuid.is_valid()) {
218 m_storage = storage_type;
220 const TSS_UUID key_uuid = to_tss_uuid(m_uuid);
221 const TSS_FLAG key_ps_type = (storage_type ==
TPM_Storage_Type::User) ? TSS_PS_TYPE_USER : TSS_PS_TYPE_SYSTEM;
223 const TSS_UUID srk_uuid = TSS_UUID_SRK;
226 ::Tspi_Context_RegisterKey(m_ctx.handle(), m_key, key_ps_type, key_uuid, TSS_PS_TYPE_SYSTEM, srk_uuid));
231 if(storage_type != m_storage) {
232 throw TPM_Error(
"TPM key " + m_uuid.to_string() +
" already registered with different storage type");
235 return format_url(m_uuid, m_storage);
239 TSS_KM_KEYINFO2* key_info;
240 UINT32 key_info_size;
244 ::Tspi_Context_GetRegisteredKeysByUUID2(
ctx.handle(), TSS_PS_TYPE_SYSTEM,
nullptr, &key_info_size, &key_info));
246 std::vector<std::string> r(key_info_size);
248 for(
size_t i = 0; i != key_info_size; ++i) {
249 r[i] = format_url(key_info[i].keyUUID, key_info[i].persistentStorageType);
261 get_obj_attr(m_ctx.handle(), m_key, TSS_TSPATTRIB_RSAKEY_INFO, TSS_TSPATTRIB_KEYINFO_RSA_MODULUS));
270 get_obj_attr(m_ctx.handle(), m_key, TSS_TSPATTRIB_RSAKEY_INFO, TSS_TSPATTRIB_KEYINFO_RSA_EXPONENT));
289 std::vector<uint8_t> bits;
295 throw TPM_Error(
"Raw public key export not supported for RSA TPM keys");
299 throw TPM_Error(
"Private key export not supported for TPM keys");
303 return get_obj_attr(m_ctx.handle(), m_key, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_BLOB);
307 return std::make_unique<RSA_PublicKey>(
get_n(),
get_e());
318 TPM_Signing_Operation(
const TPM_PrivateKey& key, std::string_view hash_name) :
321 std::string hash_function()
const override {
return m_hash->name(); }
323 size_t signature_length()
const override {
return m_key.get_n().bytes(); }
325 void update(std::span<const uint8_t> msg)
override { m_hash->update(msg); }
327 AlgorithmIdentifier algorithm_identifier()
const override {
328 const std::string full_name =
"RSA/EMSA3(" + m_hash->name() +
")";
333 std::vector<uint8_t> sign(RandomNumberGenerator&)
override {
343 std::vector<uint8_t> id_and_msg;
344 id_and_msg.reserve(m_hash_id.size() + msg_hash.size());
345 id_and_msg.insert(id_and_msg.end(), m_hash_id.begin(), m_hash_id.end());
346 id_and_msg.insert(id_and_msg.end(), msg_hash.begin(), msg_hash.end());
348 TSS_HCONTEXT ctx = m_key.ctx().handle();
350 TSPI_CHECK_SUCCESS(::Tspi_Context_CreateObject(ctx, TSS_OBJECT_TYPE_HASH, TSS_HASH_OTHER, &tpm_hash));
351 TSPI_CHECK_SUCCESS(::Tspi_Hash_SetHashValue(tpm_hash, to_uint32(id_and_msg.size()), id_and_msg.data()));
353 BYTE* sig_bytes =
nullptr;
356 std::vector<uint8_t> sig(sig_bytes, sig_bytes + sig_len);
368 const TPM_PrivateKey m_key;
369 std::unique_ptr<HashFunction> m_hash;
370 std::vector<uint8_t> m_hash_id;
376 std::string_view params,
377 std::string_view )
const {
378 return std::make_unique<TPM_Signing_Operation>(*
this, params);
#define BOTAN_ARG_CHECK(expr, msg)
virtual OID object_identifier() const
static BigInt from_bytes(std::span< const uint8_t > bytes)
DER_Encoder & start_sequence()
DER_Encoder & encode(bool b)
static OID from_string(std::string_view str)
TPM_Context(pin_cb cb, const char *srk_password)
void gen_random(uint8_t out[], size_t out_len)
uint32_t current_counter()
std::function< std::string(std::string)> pin_cb
void stir_random(const uint8_t in[], size_t in_len)
std::vector< uint8_t > export_blob() const
std::vector< uint8_t > raw_public_key_bits() const override
std::string register_key(TPM_Storage_Type storage_type)
TPM_PrivateKey(TPM_Context &ctx, size_t bits, const char *key_password)
secure_vector< uint8_t > private_key_bits() const override
static std::vector< std::string > registered_keys(TPM_Context &ctx)
bool check_key(RandomNumberGenerator &rng, bool) const override
TPM_Context & ctx() const
std::unique_ptr< PK_Ops::Signature > create_signature_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
size_t key_length() const override
std::vector< uint8_t > public_key_bits() const override
size_t estimated_strength() const override
std::unique_ptr< Public_Key > public_key() const override
AlgorithmIdentifier algorithm_identifier() const override
constexpr void copy_mem(T *out, const T *in, size_t n)
std::string fmt(std::string_view format, const T &... args)
std::vector< uint8_t > pkcs_hash_id(std::string_view name)
std::vector< T, secure_allocator< T > > secure_vector
size_t if_work_factor(size_t bits)
constexpr void typecast_copy(ToR &&out, const FromR &in)
#define TSPI_CHECK_SUCCESS(expr)