Botan 3.6.0
Crypto and TLS for C&
tpm2_pkops.cpp
Go to the documentation of this file.
1/*
2* TPM 2.0 Public Key Operations
3* (C) 2024 Jack Lloyd
4* (C) 2024 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity GmbH, financed by LANCOM Systems GmbH
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/internal/tpm2_pkops.h>
10
11#include <botan/internal/stl_util.h>
12#include <botan/internal/tpm2_algo_mappings.h>
13#include <botan/internal/tpm2_hash.h>
14
15namespace Botan::TPM2 {
16
17namespace {
18
19/**
20* Signing with a restricted key requires a validation ticket that is provided
21* when hashing the data to sign on the TPM. Otherwise, it is fine to hash the
22* data in software.
23*
24* @param key_handle the key to create the signature with
25* @param sessions the sessions to use for the TPM operations
26* @param hash_name the name of the hash function to use
27*
28* @return a HashFunction that hashes in hardware if the key is restricted
29*/
30std::unique_ptr<Botan::HashFunction> create_hash_function(const Object& key_handle,
31 const SessionBundle& sessions,
32 std::string_view hash_name) {
33 if(key_handle.attributes(sessions).restricted) {
34 // TODO: this could also be ENDORSEMENT or PLATFORM, and we're not 100% sure
35 // that OWNER is always the right choice here.
36 const TPMI_RH_HIERARCHY hierarchy = ESYS_TR_RH_OWNER;
37 return std::make_unique<HashFunction>(key_handle.context(), hash_name, hierarchy, sessions);
38 } else {
40 }
41}
42
43} // namespace
44
46 const SessionBundle& sessions,
47 const SignatureAlgorithmSelection& algorithms) :
49 object, sessions, algorithms, create_hash_function(object, sessions, algorithms.hash_name)) {}
50
52 BOTAN_UNUSED(rng);
53
54 auto do_sign = [this](const TPM2B_DIGEST& digest, const TPMT_TK_HASHCHECK& validation) {
56 check_rc("Esys_Sign",
57 Esys_Sign(*key_handle().context(),
58 key_handle().transient_handle(),
59 sessions()[0],
60 sessions()[1],
61 sessions()[2],
62 &digest,
63 &scheme(),
64 &validation,
65 out_ptr(signature)));
66 BOTAN_ASSERT_NONNULL(signature);
67 BOTAN_ASSERT_NOMSG(signature->sigAlg == scheme().scheme);
68 BOTAN_ASSERT_NOMSG(signature->signature.any.hashAlg == scheme().details.any.hashAlg);
69 return signature;
70 };
71
72 auto signature = [&] {
73 if(auto h = dynamic_cast<HashFunction*>(hash())) {
74 // This is a TPM2-based hash object that calculated the digest on
75 // the TPM. We can use the validation ticket to create the signature.
76 auto [digest, validation] = h->final_with_ticket();
78 BOTAN_ASSERT_NONNULL(validation);
79 return do_sign(*digest, *validation);
80 } else {
81 // This is a software hash, so we have to stub the validation ticket
82 // and create the signature without it.
83 TPM2B_DIGEST digest;
84 hash()->final(as_span(digest, hash()->output_length()));
85 return do_sign(digest,
86 TPMT_TK_HASHCHECK{
87 .tag = TPM2_ST_HASHCHECK,
88 .hierarchy = TPM2_RH_NULL,
89 .digest = init_empty<TPM2B_DIGEST>(),
90 });
91 }
92 }();
93
94 return marshal_signature(*signature);
95}
96
98 const SessionBundle& sessions,
99 const SignatureAlgorithmSelection& algorithms) :
100 Signature_Operation_Base<PK_Ops::Verification>(
101 object, sessions, algorithms, Botan::HashFunction::create_or_throw(algorithms.hash_name)) {}
102
103bool Verification_Operation::is_valid_signature(std::span<const uint8_t> sig_data) {
104 TPM2B_DIGEST digest;
105 hash()->final(as_span(digest, hash()->output_length()));
106
107 const auto signature = unmarshal_signature(sig_data);
108
109 // If the signature is not valid, this returns TPM2_RC_SIGNATURE.
110 const auto rc = check_rc_expecting<TPM2_RC_SIGNATURE>("Esys_VerifySignature",
111 Esys_VerifySignature(*key_handle().context(),
112 key_handle().transient_handle(),
113 sessions()[0],
114 sessions()[1],
115 sessions()[2],
116 &digest,
117 &signature,
118 nullptr /* validation */));
119
120 return rc == TPM2_RC_SUCCESS;
121}
122
123} // namespace Botan::TPM2
#define BOTAN_UNUSED
Definition assert.h:118
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
#define BOTAN_ASSERT_NONNULL(ptr)
Definition assert.h:86
void final(uint8_t out[])
Definition buf_comp.h:70
static std::unique_ptr< HashFunction > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition hash.cpp:298
Signature_Operation(const Object &object, const SessionBundle &sessions, const SignatureAlgorithmSelection &algorithms)
virtual std::vector< uint8_t > marshal_signature(const TPMT_SIGNATURE &signature) const =0
std::vector< uint8_t > sign(Botan::RandomNumberGenerator &rng) override
virtual TPMT_SIGNATURE unmarshal_signature(std::span< const uint8_t > sig_data) const =0
Verification_Operation(const Object &object, const SessionBundle &sessions, const SignatureAlgorithmSelection &algorithms)
bool is_valid_signature(std::span< const uint8_t > sig_data) override
constexpr T init_empty()
Create an empty TPM2 buffer of the given type.
Definition tpm2_util.h:142
constexpr void check_rc(std::string_view location, TSS2_RC rc)
Definition tpm2_util.h:54
std::unique_ptr< T, esys_liberator > unique_esys_ptr
A unique pointer type for ESYS handles that automatically frees the handle.
Definition tpm2_util.h:154
constexpr auto as_span(tpm2_buffer auto &data)
Construct a std::span as a view into a TPM2 buffer.
Definition tpm2_util.h:102
constexpr TSS2_RC check_rc_expecting(std::string_view location, TSS2_RC rc)
Definition tpm2_util.h:72
constexpr auto out_ptr(T &outptr) noexcept
Definition stl_util.h:420