Botan 3.6.0
Crypto and TLS for C&
Botan::TPM2::Context Class Referencefinal

#include <tpm2_context.h>

Inheritance diagram for Botan::TPM2::Context:

Public Member Functions

 Context (const Context &)=delete
 
 Context (Context &&ctx) noexcept=default
 
ESYS_CONTEXT * esys_context () noexcept
 
void evict (std::unique_ptr< TPM2::PrivateKey > key, const SessionBundle &sessions)
 Evicts a persistent key from the TPM. The key cannot be used after.
 
std::optional< TPM2_HANDLEfind_free_persistent_handle () const
 
std::string manufacturer () const
 
size_t max_random_bytes_per_request () const
 
 operator ESYS_CONTEXT * () noexcept
 
Contextoperator= (const Context &)=delete
 
Contextoperator= (Context &&ctx) noexcept=default
 
TPM2_HANDLE persist (TPM2::PrivateKey &key, const SessionBundle &sessions, std::span< const uint8_t > auth_value={}, std::optional< TPM2_HANDLE > persistent_handle=std::nullopt)
 Makes key persistent at location persistent_handle or any free.
 
std::vector< TPM2_HANDLEpersistent_handles () const
 
std::unique_ptr< TPM2::PrivateKeystorage_root_key (std::span< const uint8_t > auth_value, const SessionBundle &sessions)
 
bool supports_algorithm (std::string_view algo_name) const
 
std::vector< ESYS_TRtransient_handles () const
 
void use_botan_crypto_backend (const std::shared_ptr< Botan::RandomNumberGenerator > &rng)
 
bool uses_botan_crypto_backend () const noexcept
 
std::string vendor () const
 
 ~Context ()
 

Static Public Member Functions

static std::shared_ptr< Contextcreate (const std::string &tcti_nameconf)
 
static std::shared_ptr< Contextcreate (std::optional< std::string > tcti={}, std::optional< std::string > conf={})
 
static bool supports_botan_crypto_backend () noexcept
 

Detailed Description

Central class for interacting with a TPM2. Additional to managing the connection to the TPM, this provides authorative information about the TPM's capabilities. Also, it allows to persist and evict keys generated by the TPM.

Definition at line 39 of file tpm2_context.h.

Constructor & Destructor Documentation

◆ Context() [1/2]

Botan::TPM2::Context::Context ( const Context & )
delete

Referenced by create(), and create().

◆ Context() [2/2]

Botan::TPM2::Context::Context ( Context && ctx)
defaultnoexcept

◆ ~Context()

Botan::TPM2::Context::~Context ( )

Definition at line 399 of file tpm2_context.cpp.

399 {
400 if(m_impl) {
401 Esys_Finalize(&m_impl->m_ctx);
402 Tss2_TctiLdr_Finalize(&m_impl->m_tcti_ctx);
403 }
404}

Member Function Documentation

◆ create() [1/2]

std::shared_ptr< Context > Botan::TPM2::Context::create ( const std::string & tcti_nameconf)
static
Parameters
tcti_nameconfthis is passed to Tss2_TctiLdr_Initialize verbatim

Definition at line 53 of file tpm2_context.cpp.

53 {
54 // We cannot std::make_shared as the constructor is private
55 return std::shared_ptr<Context>(new Context(tcti_nameconf.c_str()));
56}
Context(const Context &)=delete

References Context().

Referenced by botan_tpm2_ctx_init(), and botan_tpm2_ctx_init_ex().

◆ create() [2/2]

std::shared_ptr< Context > Botan::TPM2::Context::create ( std::optional< std::string > tcti = {},
std::optional< std::string > conf = {} )
static
Parameters
tctiif set this is passed to Tss2_TctiLdr_Initialize_Ex verbatim otherwise a nullptr is passed.
confif set this is passed to Tss2_TctiLdr_Initialize_Ex verbatim otherwise a nullptr is passed.

Definition at line 58 of file tpm2_context.cpp.

58 {
59 const auto tcti_ptr = tcti.has_value() ? tcti->c_str() : nullptr;
60 const auto conf_ptr = conf.has_value() ? conf->c_str() : nullptr;
61
62 // We cannot std::make_shared as the constructor is private
63 return std::shared_ptr<Context>(new Context(tcti_ptr, conf_ptr));
64}

References Context().

◆ esys_context()

ESYS_CONTEXT * Botan::TPM2::Context::esys_context ( )
noexcept
Returns
an ESYS_CONTEXT* for use in other TPM2 functions.

Definition at line 106 of file tpm2_context.cpp.

106 {
107 return m_impl->m_ctx;
108}

◆ evict()

void Botan::TPM2::Context::evict ( std::unique_ptr< TPM2::PrivateKey > key,
const SessionBundle & sessions )

Evicts a persistent key from the TPM. The key cannot be used after.

Definition at line 373 of file tpm2_context.cpp.

373 {
375
376 auto& handles = key->handles();
377 BOTAN_ARG_CHECK(handles.has_persistent_handle(), "Key does not have a persistent handle assigned");
378
379 // 1. Evict the key from the TPM's NV storage
380 // This will free the persistent handle, but the transient handle will
381 // still be valid.
382 ESYS_TR no_new_handle = ESYS_TR_NONE;
383 check_rc("Esys_EvictControl",
384 Esys_EvictControl(m_impl->m_ctx,
385 ESYS_TR_RH_OWNER /*TODO: hierarchy*/,
386 handles.transient_handle(),
387 sessions[0],
388 sessions[1],
389 sessions[2],
390 0,
391 &no_new_handle));
392 BOTAN_ASSERT(no_new_handle == ESYS_TR_NONE, "When deleting a key, no new handle is returned");
393
394 // 2. The persistent key was deleted and the transient key was flushed by
395 // Esys_EvictControl().
396 handles._disengage();
397}
#define BOTAN_ASSERT_NONNULL(ptr)
Definition assert.h:86
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:50
constexpr void check_rc(std::string_view location, TSS2_RC rc)
Definition tpm2_util.h:54
uint32_t ESYS_TR
Forward declaration of TSS2 type for convenience.

References BOTAN_ARG_CHECK, BOTAN_ASSERT, BOTAN_ASSERT_NONNULL, and Botan::TPM2::check_rc().

◆ find_free_persistent_handle()

std::optional< TPM2_HANDLE > Botan::TPM2::Context::find_free_persistent_handle ( ) const
Returns
a persistent handle that is currently not in use or std::nullopt if no such handle is available

Definition at line 288 of file tpm2_context.cpp.

288 {
289 const auto occupied_handles = persistent_handles();
290
291 // This is modeled after the implementation in tpm2-tools, which also takes
292 // "platform persistent" handles into account. We don't do that here, but
293 // we might need to in the future.
294 //
295 // See: https://github.com/tpm2-software/tpm2-tools/blob/bd832d3f79/lib/tpm2_capability.c#L143-L196
296
297 // all persistent handles are occupied
298 if(occupied_handles.size() >= TPM2_MAX_CAP_HANDLES) {
299 return std::nullopt;
300 }
301
302 // find the lowest handle that is not occupied
303 for(TPM2_HANDLE i = TPM2_PERSISTENT_FIRST; i < TPM2_PERSISTENT_LAST; ++i) {
304 if(!value_exists(occupied_handles, i)) {
305 return i;
306 }
307 }
308
310}
#define BOTAN_ASSERT_UNREACHABLE()
Definition assert.h:137
std::vector< TPM2_HANDLE > persistent_handles() const
bool value_exists(const std::vector< T > &vec, const OT &val)
Definition stl_util.h:60
uint32_t TPM2_HANDLE
Forward declaration of TSS2 type for convenience.

References BOTAN_ASSERT_UNREACHABLE, persistent_handles(), and Botan::value_exists().

Referenced by persist().

◆ manufacturer()

std::string Botan::TPM2::Context::manufacturer ( ) const
Returns
the Manufacturer of the TPM2

Definition at line 207 of file tpm2_context.cpp.

207 {
208 std::array<uint8_t, 4 + 1 /* ensure zero termination */> manufacturer_data{};
209 store_be(std::span{manufacturer_data}.first<4>(), get_tpm_property(m_impl->m_ctx, TPM2_PT_MANUFACTURER));
210 return std::string(cast_uint8_ptr_to_char(manufacturer_data.data()));
211}
const char * cast_uint8_ptr_to_char(const uint8_t *b)
Definition mem_ops.h:277
constexpr auto store_be(ParamTs &&... params)
Definition loadstor.h:773

References Botan::cast_uint8_ptr_to_char(), and Botan::store_be().

◆ max_random_bytes_per_request()

size_t Botan::TPM2::Context::max_random_bytes_per_request ( ) const
Returns
the maximum number of random bytes to be requested at once

Definition at line 275 of file tpm2_context.cpp.

275 {
276 return get_tpm_property(m_impl->m_ctx, TPM2_PT_MAX_DIGEST);
277}

◆ operator ESYS_CONTEXT *()

Botan::TPM2::Context::operator ESYS_CONTEXT * ( )
inlinenoexcept

Definition at line 91 of file tpm2_context.h.

91{ return esys_context(); }
ESYS_CONTEXT * esys_context() noexcept

◆ operator=() [1/2]

Context & Botan::TPM2::Context::operator= ( const Context & )
delete

◆ operator=() [2/2]

Context & Botan::TPM2::Context::operator= ( Context && ctx)
defaultnoexcept

◆ persist()

TPM2_HANDLE Botan::TPM2::Context::persist ( TPM2::PrivateKey & key,
const SessionBundle & sessions,
std::span< const uint8_t > auth_value = {},
std::optional< TPM2_HANDLE > persistent_handle = std::nullopt )

Makes key persistent at location persistent_handle or any free.

Definition at line 317 of file tpm2_context.cpp.

320 {
321 auto& handles = key.handles();
322
323 BOTAN_ARG_CHECK(!persistent_handle || !value_exists(persistent_handles(), persistent_handle.value()),
324 "Persistent handle already in use");
325 BOTAN_ARG_CHECK(!handles.has_persistent_handle(), "Key already has a persistent handle assigned");
326
327 // 1. Decide on the location to persist the key to.
328 // This uses either the handle provided by the caller or a free handle.
329 const TPMI_DH_PERSISTENT new_persistent_handle = [&] {
330 if(persistent_handle.has_value()) {
331 return persistent_handle.value();
332 } else {
333 const auto free_persistent_handle = find_free_persistent_handle();
334 BOTAN_STATE_CHECK(free_persistent_handle.has_value());
335 return free_persistent_handle.value();
336 }
337 }();
338
339 // 2. Persist the transient key in the TPM's NV storage
340 // This will flush the transient key handle and replace it with a new
341 // transient handle that references the persisted key.
342 check_rc("Esys_EvictControl",
343 Esys_EvictControl(m_impl->m_ctx,
344 ESYS_TR_RH_OWNER /*TODO: hierarchy*/,
345 handles.transient_handle(),
346 sessions[0],
347 sessions[1],
348 sessions[2],
349 new_persistent_handle,
350 out_transient_handle(handles)));
351 BOTAN_ASSERT_NOMSG(handles.has_transient_handle());
352
353 // 3. Reset the auth value of the key object
354 // This is necessary to ensure that the key object remains usable after
355 // the transient handle was recreated inside Esys_EvictControl().
356 if(!auth_value.empty()) {
357 const auto user_auth = copy_into<TPM2B_AUTH>(auth_value);
358 check_rc("Esys_TR_SetAuth", Esys_TR_SetAuth(m_impl->m_ctx, handles.transient_handle(), &user_auth));
359 }
360
361 // 4. Update the key object with the new persistent handle
362 // This double-checks that the key was persisted at the correct location,
363 // but also brings the key object into a consistent state.
364 check_rc("Esys_TR_GetTpmHandle",
365 Esys_TR_GetTpmHandle(m_impl->m_ctx, handles.transient_handle(), out_persistent_handle(handles)));
366
367 BOTAN_ASSERT_NOMSG(handles.has_persistent_handle());
368 BOTAN_ASSERT_EQUAL(new_persistent_handle, handles.persistent_handle(), "key was persisted at the correct location");
369
370 return new_persistent_handle;
371}
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:41
#define BOTAN_ASSERT_EQUAL(expr1, expr2, assertion_made)
Definition assert.h:68
std::optional< TPM2_HANDLE > find_free_persistent_handle() const
constexpr auto out_persistent_handle(Object &object)
Definition tpm2_util.h:215
constexpr auto out_transient_handle(Object &object)
Definition tpm2_util.h:209
constexpr void copy_into(T &dest, std::span< const uint8_t > data)
Definition tpm2_util.h:117

References BOTAN_ARG_CHECK, BOTAN_ASSERT_EQUAL, BOTAN_ASSERT_NOMSG, BOTAN_STATE_CHECK, Botan::TPM2::check_rc(), Botan::TPM2::copy_into(), find_free_persistent_handle(), Botan::TPM2::PrivateKey::handles(), Botan::TPM2::out_persistent_handle(), Botan::TPM2::out_transient_handle(), persistent_handles(), and Botan::value_exists().

◆ persistent_handles()

std::vector< TPM2_HANDLE > Botan::TPM2::Context::persistent_handles ( ) const

Definition at line 312 of file tpm2_context.cpp.

312 {
313 return get_tpm_property_list<TPM2_CAP_HANDLES, TPM2_HANDLE>(
314 m_impl->m_ctx, TPM2_PERSISTENT_FIRST, TPM2_MAX_CAP_HANDLES);
315}

Referenced by find_free_persistent_handle(), and persist().

◆ storage_root_key()

std::unique_ptr< TPM2::PrivateKey > Botan::TPM2::Context::storage_root_key ( std::span< const uint8_t > auth_value,
const SessionBundle & sessions )

Definition at line 279 of file tpm2_context.cpp.

280 {
281 return TPM2::PrivateKey::load_persistent(shared_from_this(), storage_root_key_handle, auth_value, sessions);
282}
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)
Definition tpm2_key.cpp:180

References Botan::TPM2::PrivateKey::load_persistent().

◆ supports_algorithm()

bool Botan::TPM2::Context::supports_algorithm ( std::string_view algo_name) const

The algo_name can be any of the string algorithm specifiers used elsewhere. For example, "RSA", "AES-128", "SHA-1", "CTR(3DES)", etc.

Returns
true if the specified algorithm is supported by the TPM

Definition at line 213 of file tpm2_context.cpp.

213 {
214 // Go through all the string mappings we have available and check if we
215 // can find the algorithm name in any of them. If we do, we can check if
216 // the TPM supports the required algorithms.
217 const auto required_alg_ids = [&]() -> std::vector<TPM2_ALG_ID> {
218 std::vector<TPM2_ALG_ID> result;
219 if(auto algo_id = asymmetric_algorithm_botan_to_tss2(algo_name)) {
220 result.push_back(algo_id.value());
221 }
222
223 if(auto hash_id = hash_algo_botan_to_tss2(algo_name)) {
224 result.push_back(hash_id.value());
225 }
226
227 if(auto block_id = block_cipher_botan_to_tss2(algo_name)) {
228 result.push_back(block_id->first);
229 }
230
231 if(auto cipher_mode_id = cipher_mode_botan_to_tss2(algo_name)) {
232 result.push_back(cipher_mode_id.value());
233 }
234
235 if(auto cipher_spec = cipher_botan_to_tss2(algo_name)) {
236 result.push_back(cipher_spec->algorithm);
237 result.push_back(cipher_spec->mode.sym);
238 }
239
240 if(auto sig_padding = rsa_signature_padding_botan_to_tss2(algo_name)) {
241 result.push_back(sig_padding.value());
242 }
243
244 if(auto sig = rsa_signature_scheme_botan_to_tss2(algo_name)) {
245 result.push_back(sig->scheme);
246 result.push_back(sig->details.any.hashAlg);
247 }
248
249 if(auto enc_scheme = rsa_encryption_scheme_botan_to_tss2(algo_name)) {
250 result.push_back(enc_scheme->scheme);
251 if(enc_scheme->scheme == TPM2_ALG_OAEP) {
252 result.push_back(enc_scheme->details.oaep.hashAlg);
253 }
254 }
255
256 if(auto enc_id = rsa_encryption_padding_botan_to_tss2(algo_name)) {
257 result.push_back(enc_id.value());
258 }
259
260 return result;
261 }();
262
263 if(required_alg_ids.empty()) {
264 // The algorithm name is not known to us, so we cannot check for support.
265 return false;
266 }
267
268 const auto algo_caps =
269 get_tpm_property_list<TPM2_CAP_ALGS, TPM2_ALG_ID>(m_impl->m_ctx, TPM2_ALG_FIRST, TPM2_MAX_CAP_ALGS);
270
271 return std::all_of(
272 required_alg_ids.begin(), required_alg_ids.end(), [&](TPM2_ALG_ID id) { return value_exists(algo_caps, id); });
273}
std::optional< TPMT_SIG_SCHEME > rsa_signature_scheme_botan_to_tss2(std::string_view name)
std::optional< TPMI_ALG_SIG_SCHEME > rsa_signature_padding_botan_to_tss2(std::string_view padding_name) noexcept
std::optional< TPMI_ALG_ASYM_SCHEME > rsa_encryption_padding_botan_to_tss2(std::string_view name) noexcept
std::optional< std::pair< TPMI_ALG_SYM, TPM2_KEY_BITS > > block_cipher_botan_to_tss2(std::string_view cipher_name) noexcept
std::optional< TPMT_SYM_DEF > cipher_botan_to_tss2(std::string_view algo_name)
std::optional< TPMT_RSA_DECRYPT > rsa_encryption_scheme_botan_to_tss2(std::string_view padding)
std::optional< TPMI_ALG_HASH > hash_algo_botan_to_tss2(std::string_view hash_name) noexcept
std::optional< TPM2_ALG_ID > asymmetric_algorithm_botan_to_tss2(std::string_view algo_name) noexcept
std::optional< TPMI_ALG_SYM_MODE > cipher_mode_botan_to_tss2(std::string_view mode_name) noexcept

References Botan::TPM2::asymmetric_algorithm_botan_to_tss2(), Botan::TPM2::block_cipher_botan_to_tss2(), Botan::TPM2::cipher_botan_to_tss2(), Botan::TPM2::cipher_mode_botan_to_tss2(), Botan::TPM2::hash_algo_botan_to_tss2(), Botan::TPM2::rsa_encryption_padding_botan_to_tss2(), Botan::TPM2::rsa_encryption_scheme_botan_to_tss2(), Botan::TPM2::rsa_signature_padding_botan_to_tss2(), and Botan::TPM2::rsa_signature_scheme_botan_to_tss2().

◆ supports_botan_crypto_backend()

bool Botan::TPM2::Context::supports_botan_crypto_backend ( )
staticnoexcept

Checks if the TSS2 supports registering Botan's crypto backend at runtime. Older versions of the TSS2 do not support this feature ( 4.0.0), also Botan may be compiled without support for TSS' crypto backend.

Returns
true if the TSS2 supports Botan's crypto backend

Definition at line 45 of file tpm2_context.cpp.

45 {
46#if defined(BOTAN_TSS2_SUPPORTS_CRYPTO_CALLBACKS) and defined(BOTAN_HAS_TPM2_CRYPTO_BACKEND)
47 return true;
48#else
49 return false;
50#endif
51}

Referenced by botan_tpm2_supports_crypto_backend().

◆ transient_handles()

std::vector< ESYS_TR > Botan::TPM2::Context::transient_handles ( ) const

Definition at line 284 of file tpm2_context.cpp.

284 {
285 return get_tpm_property_list<TPM2_CAP_HANDLES, ESYS_TR>(m_impl->m_ctx, TPM2_TRANSIENT_FIRST, TPM2_MAX_CAP_HANDLES);
286}

◆ use_botan_crypto_backend()

void Botan::TPM2::Context::use_botan_crypto_backend ( const std::shared_ptr< Botan::RandomNumberGenerator > & rng)

Overrides the TSS2's crypto callbacks with Botan's functionality.

This replaces all cryptographic functionality required for the communication with the TPM by botan's implementations. The TSS2 would otherwise use OpenSSL or mbedTLS.

Note that the provided rng should not be dependent on the TPM.

Parameters
rngthe RNG to use for the crypto operations
Exceptions
Not_Implementedif the TPM2-TSS does not support crypto callbacks
See also
supports_botan_crypto_backend()

Definition at line 80 of file tpm2_context.cpp.

80 {
81#if defined(BOTAN_HAS_TPM2_CRYPTO_BACKEND)
83 m_impl->m_crypto_callback_state = std::make_unique<CryptoCallbackState>(rng);
84 enable_crypto_callbacks(shared_from_this());
85#else
86 BOTAN_UNUSED(rng);
87 throw Not_Implemented("This build of botan does not provide the TPM2 crypto backend");
88#endif
89}
#define BOTAN_UNUSED
Definition assert.h:118
bool uses_botan_crypto_backend() const noexcept
void enable_crypto_callbacks(const std::shared_ptr< Context > &ctx)

References BOTAN_STATE_CHECK, BOTAN_UNUSED, Botan::TPM2::enable_crypto_callbacks(), and uses_botan_crypto_backend().

◆ uses_botan_crypto_backend()

bool Botan::TPM2::Context::uses_botan_crypto_backend ( ) const
noexcept
Returns
true if botan is used for the TSS' crypto functions

Definition at line 91 of file tpm2_context.cpp.

91 {
92#if defined(BOTAN_HAS_TPM2_CRYPTO_BACKEND)
93 return m_impl->m_crypto_callback_state != nullptr;
94#else
95 return false;
96#endif
97}

Referenced by use_botan_crypto_backend().

◆ vendor()

std::string Botan::TPM2::Context::vendor ( ) const
Returns
the Vendor of the TPM2

Definition at line 190 of file tpm2_context.cpp.

190 {
191 constexpr std::array properties = {
192 TPM2_PT_VENDOR_STRING_1, TPM2_PT_VENDOR_STRING_2, TPM2_PT_VENDOR_STRING_3, TPM2_PT_VENDOR_STRING_4};
193 std::array<uint8_t, properties.size() * 4 + 1 /* ensure zero-termination */> vendor_string{};
194
195 BufferStuffer bs(vendor_string);
196
197 // The vendor name is transported in several uint32_t fields that are
198 // loaded as big-endian bytes and concatenated to form the vendor string.
199 for(auto prop : properties) {
200 bs.append(store_be(get_tpm_property(m_impl->m_ctx, prop)));
201 }
202
203 BOTAN_ASSERT_NOMSG(bs.remaining_capacity() == 1); // the ensured zero-termination
204 return std::string(cast_uint8_ptr_to_char(vendor_string.data()));
205}

References Botan::BufferStuffer::append(), BOTAN_ASSERT_NOMSG, Botan::cast_uint8_ptr_to_char(), Botan::BufferStuffer::remaining_capacity(), and Botan::store_be().


The documentation for this class was generated from the following files: