Botan 3.11.0
Crypto and TLS for C&
tpm2_ecc.cpp
Go to the documentation of this file.
1/*
2* TPM 2.0 ECC Key Wrappres
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/tpm2_ecc.h>
10
11#include <botan/internal/concat_util.h>
12#include <botan/internal/tpm2_algo_mappings.h>
13#include <botan/internal/tpm2_hash.h>
14#include <botan/internal/tpm2_pkops.h>
15#include <botan/internal/tpm2_util.h>
16
17#include <tss2/tss2_esys.h>
18
19namespace Botan::TPM2 {
20
21EC_PublicKey::EC_PublicKey(Object handle, SessionBundle sessions, const TPM2B_PUBLIC* public_blob) :
22 EC_PublicKey(std::move(handle), std::move(sessions), ecc_pubkey_from_tss2_public(public_blob)) {}
23
26 const std::pair<EC_Group, EC_AffinePoint>& public_key) :
27 Botan::TPM2::PublicKey(std::move(handle), std::move(sessions)),
28 Botan::EC_PublicKey(public_key.first, public_key.second) {}
29
32 const TPM2B_PUBLIC* public_blob,
33 std::span<const uint8_t> private_blob) :
34 EC_PrivateKey(std::move(handle), std::move(sessions), ecc_pubkey_from_tss2_public(public_blob), private_blob) {}
35
38 const std::pair<EC_Group, EC_AffinePoint>& public_key,
39 std::span<const uint8_t> private_blob) :
40 Botan::TPM2::PrivateKey(std::move(handle), std::move(sessions), private_blob),
41 Botan::EC_PublicKey(public_key.first, public_key.second) {}
42
43std::unique_ptr<Public_Key> EC_PrivateKey::public_key() const {
44 return std::make_unique<Botan::ECDSA_PublicKey>(domain(), _public_ec_point());
45}
46
47std::vector<uint8_t> EC_PublicKey::public_key_bits() const {
49}
50
51std::vector<uint8_t> EC_PublicKey::raw_public_key_bits() const {
53}
54
55std::vector<uint8_t> EC_PrivateKey::public_key_bits() const {
57}
58
59std::vector<uint8_t> EC_PrivateKey::raw_public_key_bits() const {
61}
62
63std::unique_ptr<TPM2::PrivateKey> EC_PrivateKey::create_unrestricted_transient(const std::shared_ptr<Context>& ctx,
65 std::span<const uint8_t> auth_value,
66 const TPM2::PrivateKey& parent,
67 const EC_Group& group) {
68 // TODO: Code duplication from RSA_PrivateKey::create_unrestricted_transient
69 BOTAN_ARG_CHECK(parent.is_parent(), "The passed key cannot be used as a parent key");
70
71 const auto curve_id = get_tpm2_curve_id(group.get_curve_oid());
72 if(!curve_id) {
73 throw Invalid_Argument("Unsupported ECC curve");
74 }
75
76 const TPM2B_SENSITIVE_CREATE sensitive_data = {
77 .size = 0, // ignored
78 .sensitive =
79 {
80 .userAuth = copy_into<TPM2B_AUTH>(auth_value),
81
82 // Architecture Document, Section 25.2.3
83 // When an asymmetric key is created, the caller is not allowed to
84 // provide the sensitive data of the key.
86 },
87 };
88
89 const TPMT_PUBLIC key_template = {
90 .type = TPM2_ALG_ECC,
91
92 // This is the algorithm for fingerprinting the newly created public key.
93 // For best compatibility we always use SHA-256.
94 .nameAlg = TPM2_ALG_SHA256,
95
96 // This sets up the key to be both a decryption and a signing key, forbids
97 // its duplication (fixed_tpm, fixed_parent) and ensures that the key's
98 // private portion can be used only by a user with an HMAC or password
99 // session.
100 .objectAttributes = ObjectAttributes::render({
101 .fixed_tpm = true,
102 .fixed_parent = true,
103 .sensitive_data_origin = true,
104 .user_with_auth = true,
105 .decrypt = true, // TODO: Shall we set this?
106 .sign_encrypt = true,
107 }),
108
109 // We currently do not support policy-based authorization
110 .authPolicy = init_empty<TPM2B_DIGEST>(),
111 .parameters =
112 {
113 .eccDetail =
114 {
115 // Structures Document (Part 2), Section 12.2.3.5
116 // If the key is not a restricted decryption key, this field
117 // shall be set to TPM_ALG_NULL.
118 //
119 // TODO: Once we stop supporting TSS < 4.0, we could use
120 // `.keyBits = {.null = {}}, .mode = {.null = {}}`
121 // which better reflects our intention here.
122 .symmetric =
123 {
124 .algorithm = TPM2_ALG_NULL,
125 .keyBits = {.sym = 0},
126 .mode = {.sym = TPM2_ALG_NULL},
127 },
128
129 // Structures Document (Part 2), Section 12.2.3.6
130 // If the decrypt attribute of the key is SET, then this shall be a
131 // valid key exchange scheme or TPM_ALG_NULL
132 //
133 // TODO: Once we stop supporting TSS < 4.0, we could use
134 // `.details = {.null = {}}`
135 // which better reflects our intention here.
136 .scheme =
137 {
138 .scheme = TPM2_ALG_NULL,
139 .details = {.anySig = {.hashAlg = TPM2_ALG_NULL}},
140 },
141 .curveID = curve_id.value(),
142
143 // Structures Document (Part 2), Section 12.2.3.6
144 // If the kdf parameter associated with curveID is not
145 // TPM_ALG_NULL then this is required to be NULL.
146 // NOTE There are currently no commands where this parameter
147 // has effect and, in the reference code, this field needs to
148 // be set to TPM_ALG_NULL
149 // TODO: Easier initialization?
150 .kdf = {.scheme = TPM2_ALG_NULL, .details = {.kdf2 = {.hashAlg = TPM2_ALG_NULL}}},
151 },
152 },
153
154 // For creating an asymmetric key this value is not used.
155 .unique = {.ecc = {}},
156 };
157
159 ctx, sessions, parent.handles().transient_handle(), key_template, sensitive_data);
160}
161
162namespace {
163
164SignatureAlgorithmSelection make_signature_scheme(std::string_view hash_name) {
165 return {
166 .signature_scheme =
167 TPMT_SIG_SCHEME{
168 .scheme = TPM2_ALG_ECDSA, // Only support ECDSA
169 .details = {.any = {.hashAlg = get_tpm2_hash_type(hash_name)}},
170 },
171 .hash_name = std::string(hash_name),
172 .padding = std::nullopt,
173 };
174}
175
176size_t signature_length_for_ecdsa_key_handle(const SessionBundle& sessions, const Object& object) {
177 const auto curve_id = object._public_info(sessions, TPM2_ALG_ECDSA).pub->publicArea.parameters.eccDetail.curveID;
178
179 const auto order_bytes = curve_id_order_byte_size(curve_id);
180 if(!order_bytes) {
181 throw Invalid_Argument(Botan::fmt("Unsupported ECC curve: {}", curve_id));
182 };
183 return 2 * order_bytes.value();
184}
185
186class EC_Signature_Operation final : public Signature_Operation {
187 public:
188 EC_Signature_Operation(const Object& object, const SessionBundle& sessions, std::string_view hash) :
189 Signature_Operation(object, sessions, make_signature_scheme(hash)) {}
190
191 size_t signature_length() const override {
192 return signature_length_for_ecdsa_key_handle(sessions(), key_handle());
193 }
194
195 AlgorithmIdentifier algorithm_identifier() const override {
196 // Copied from ECDSA
197 const std::string full_name = "ECDSA/" + hash_function();
198 const OID oid = OID::from_string(full_name);
199 return AlgorithmIdentifier(oid, AlgorithmIdentifier::USE_EMPTY_PARAM);
200 }
201
202 private:
203 std::vector<uint8_t> marshal_signature(const TPMT_SIGNATURE& signature) const override {
204 BOTAN_STATE_CHECK(signature.sigAlg == TPM2_ALG_ECDSA);
205
206 const auto r = as_span(signature.signature.ecdsa.signatureR);
207 const auto s = as_span(signature.signature.ecdsa.signatureS);
208 const auto sig_len = signature_length_for_ecdsa_key_handle(sessions(), key_handle());
209 BOTAN_ASSERT_NOMSG(sig_len % 2 == 0);
210 BOTAN_ASSERT_NOMSG(r.size() == sig_len / 2 && s.size() == sig_len / 2);
211
212 return concat<std::vector<uint8_t>>(r, s);
213 }
214};
215
216class EC_Verification_Operation final : public Verification_Operation {
217 public:
218 EC_Verification_Operation(const Object& object, const SessionBundle& sessions, std::string_view hash) :
219 Verification_Operation(object, sessions, make_signature_scheme(hash)) {}
220
221 private:
222 TPMT_SIGNATURE unmarshal_signature(std::span<const uint8_t> sig_data) const override {
223 BOTAN_STATE_CHECK(scheme().scheme == TPM2_ALG_ECDSA);
224
225 const auto sig_len = signature_length_for_ecdsa_key_handle(sessions(), key_handle());
226 BOTAN_ARG_CHECK(sig_data.size() == sig_len, "Invalid signature length");
227 BOTAN_ASSERT_NOMSG(sig_len % 2 == 0);
228
229 return {
230 .sigAlg = TPM2_ALG_ECDSA,
231 .signature =
232 {
233 .ecdsa =
234 {
235 .hash = scheme().details.any.hashAlg,
236 .signatureR = copy_into<TPM2B_ECC_PARAMETER>(sig_data.first(sig_len / 2)),
237 .signatureS = copy_into<TPM2B_ECC_PARAMETER>(sig_data.last(sig_len / 2)),
238 },
239 },
240 };
241 }
242};
243
244} // namespace
245
246std::unique_ptr<PK_Ops::Verification> EC_PublicKey::create_verification_op(std::string_view params,
247 std::string_view provider) const {
248 BOTAN_UNUSED(provider);
249 return std::make_unique<EC_Verification_Operation>(handles(), sessions(), params);
250}
251
253 std::string_view params,
254 std::string_view provider) const {
255 BOTAN_UNUSED(rng, provider);
256 return std::make_unique<EC_Signature_Operation>(handles(), sessions(), params);
257}
258
259} // namespace Botan::TPM2
#define BOTAN_UNUSED
Definition assert.h:144
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:49
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
const OID & get_curve_oid() const
Definition ec_group.cpp:677
const EC_Group & domain() const
Definition ecc_key.cpp:64
EC_PublicKey(const EC_PublicKey &other)=default
std::vector< uint8_t > raw_public_key_bits() const override
Definition ecc_key.cpp:90
EC_PublicKey()=default
const EC_AffinePoint & _public_ec_point() const
Definition ecc_key.cpp:76
static OID from_string(std::string_view str)
Definition asn1_oid.cpp:86
std::vector< uint8_t > raw_public_key_bits() const override
Definition tpm2_ecc.cpp:59
static std::unique_ptr< TPM2::PrivateKey > create_unrestricted_transient(const std::shared_ptr< Context > &ctx, const SessionBundle &sessions, std::span< const uint8_t > auth_value, const TPM2::PrivateKey &parent, const EC_Group &group)
Definition tpm2_ecc.cpp:63
std::unique_ptr< Public_Key > public_key() const override
Definition tpm2_ecc.cpp:43
std::unique_ptr< PK_Ops::Signature > create_signature_op(Botan::RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
Definition tpm2_ecc.cpp:252
EC_PrivateKey(Object handle, SessionBundle sessions, const TPM2B_PUBLIC *public_blob, std::span< const uint8_t > private_blob={})
Definition tpm2_ecc.cpp:30
friend class TPM2::PrivateKey
Definition tpm2_ecc.h:104
std::vector< uint8_t > public_key_bits() const override
Definition tpm2_ecc.cpp:55
std::vector< uint8_t > public_key_bits() const override
Definition tpm2_ecc.cpp:47
EC_PublicKey(Object handle, SessionBundle sessions, const TPM2B_PUBLIC *public_blob)
Definition tpm2_ecc.cpp:21
std::vector< uint8_t > raw_public_key_bits() const override
Definition tpm2_ecc.cpp:51
std::unique_ptr< PK_Ops::Verification > create_verification_op(std::string_view params, std::string_view provider) const override
Definition tpm2_ecc.cpp:246
friend class TPM2::PublicKey
Definition tpm2_ecc.h:44
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)
Definition tpm2_key.cpp:222
std::vector< uint8_t > raw_public_key_bits() const override
Definition tpm2_key.cpp:285
const SessionBundle & sessions() const
Definition tpm2_key.h:224
std::vector< uint8_t > raw_public_key_bits() const override
Definition tpm2_key.cpp:159
const Object & handles() const
Definition tpm2_key.h:99
const SessionBundle & sessions() const
Definition tpm2_key.h:101
constexpr T init_empty()
Create an empty TPM2 buffer of the given type.
Definition tpm2_util.h:153
std::optional< size_t > curve_id_order_byte_size(TPMI_ECC_CURVE curve_id)
TPMI_ALG_HASH get_tpm2_hash_type(std::string_view hash_name)
std::optional< TPM2_ECC_CURVE > get_tpm2_curve_id(const OID &curve_oid)
constexpr void copy_into(T &dest, std::span< const uint8_t > data)
Definition tpm2_util.h:118
constexpr auto as_span(tpm2_buffer auto &data)
Construct a std::span as a view into a TPM2 buffer.
Definition tpm2_util.h:103
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
constexpr auto concat(Rs &&... ranges)
Definition concat_util.h:90
static TPMA_OBJECT render(ObjectAttributes attributes)