Botan 3.6.0
Crypto and TLS for C&
tpm2_algo_mappings.h
Go to the documentation of this file.
1/*
2* TPM 2 algorithm mappings
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#ifndef BOTAN_TPM2_ALGORITHM_MAPPINGS_H_
10#define BOTAN_TPM2_ALGORITHM_MAPPINGS_H_
11
12#include <botan/asn1_obj.h>
13#include <botan/exceptn.h>
14
15#include <botan/internal/fmt.h>
16#include <botan/internal/scan_name.h>
17
18#include <optional>
19#include <string>
20#include <string_view>
21
22#include <tss2/tss2_tpm2_types.h>
23
24namespace Botan::TPM2 {
25
26[[nodiscard]] inline std::optional<TPM2_ALG_ID> asymmetric_algorithm_botan_to_tss2(
27 std::string_view algo_name) noexcept {
28 if(algo_name == "RSA") {
29 return TPM2_ALG_RSA;
30 } else if(algo_name == "ECC") {
31 return TPM2_ALG_ECC;
32 } else if(algo_name == "ECDSA") {
33 return TPM2_ALG_ECDSA;
34 } else if(algo_name == "ECDH") {
35 return TPM2_ALG_ECDH;
36 } else if(algo_name == "ECDAA") {
37 return TPM2_ALG_ECDAA;
38 } else {
39 return std::nullopt;
40 }
41}
42
43/**
44 * @returns a TPMI_ALG_HASH value if the @p hash_name is known,
45 * otherwise std::nullopt
46 */
47[[nodiscard]] inline std::optional<TPMI_ALG_HASH> hash_algo_botan_to_tss2(std::string_view hash_name) noexcept {
48 if(hash_name == "SHA-1") {
49 return TPM2_ALG_SHA1;
50 } else if(hash_name == "SHA-256") {
51 return TPM2_ALG_SHA256;
52 } else if(hash_name == "SHA-384") {
53 return TPM2_ALG_SHA384;
54 } else if(hash_name == "SHA-512") {
55 return TPM2_ALG_SHA512;
56 } else if(hash_name == "SHA-3(256)") {
57 return TPM2_ALG_SHA3_256;
58 } else if(hash_name == "SHA-3(384)") {
59 return TPM2_ALG_SHA3_384;
60 } else if(hash_name == "SHA-3(512)") {
61 return TPM2_ALG_SHA3_512;
62 } else if(hash_name == "SM3") {
63 return TPM2_ALG_SM3_256;
64 } else {
65 return std::nullopt;
66 }
67}
68
69/**
70 * @returns a TPMI_ALG_HASH value if the @p hash_name is known,
71 * otherwise throws Lookup_Error
72 */
73[[nodiscard]] inline TPMI_ALG_HASH get_tpm2_hash_type(std::string_view hash_name) {
74 if(auto hash_id = hash_algo_botan_to_tss2(hash_name)) {
75 return hash_id.value();
76 }
77
78 throw Lookup_Error("TPM 2.0 Hash", hash_name);
79}
80
81/**
82 * @returns a Botan hash name string if the @p hash_id value is known,
83 * otherwise std::nullopt
84 */
85[[nodiscard]] inline std::optional<std::string> hash_algo_tss2_to_botan(TPMI_ALG_HASH hash_id) noexcept {
86 switch(hash_id) {
87 case TPM2_ALG_SHA1:
88 return "SHA-1";
89 case TPM2_ALG_SHA256:
90 return "SHA-256";
91 case TPM2_ALG_SHA384:
92 return "SHA-384";
93 case TPM2_ALG_SHA512:
94 return "SHA-512";
95 case TPM2_ALG_SHA3_256:
96 return "SHA-3(256)";
97 case TPM2_ALG_SHA3_384:
98 return "SHA-3(384)";
99 case TPM2_ALG_SHA3_512:
100 return "SHA-3(512)";
101 case TPM2_ALG_SM3_256:
102 return "SM3";
103 default: // TPMI_ALG_HASH is not an enum
104 return std::nullopt;
105 }
106}
107
108/**
109 * @returns a Botan hash name string if the @p hash_id value is known,
110 * otherwise throws Invalid_State
111 */
112[[nodiscard]] inline std::string get_botan_hash_name(TPM2_ALG_ID hash_id) {
113 if(auto hash_name = hash_algo_tss2_to_botan(hash_id)) {
114 return hash_name.value();
115 }
116
117 throw Invalid_State("TPM 2.0 hash object with unexpected hash type");
118}
119
120[[nodiscard]] inline std::optional<std::string> block_cipher_tss2_to_botan(TPMI_ALG_SYM cipher_id,
121 TPM2_KEY_BITS key_bits) noexcept {
122 switch(cipher_id) {
123 case TPM2_ALG_AES:
124 if(key_bits == 128) {
125 return "AES-128";
126 } else if(key_bits == 192) {
127 return "AES-192";
128 } else if(key_bits == 256) {
129 return "AES-256";
130 }
131 break;
132
133 case TPM2_ALG_SM4:
134 if(key_bits == 128) {
135 return "SM4";
136 }
137 break;
138
139 case TPM2_ALG_CAMELLIA:
140 if(key_bits == 128) {
141 return "Camellia-128";
142 } else if(key_bits == 192) {
143 return "Camellia-192";
144 } else if(key_bits == 256) {
145 return "Camellia-256";
146 }
147 break;
148
149 case TPM2_ALG_TDES:
150 return "3DES";
151
152 default:
153 break;
154 }
155
156 return std::nullopt;
157}
158
159[[nodiscard]] inline std::optional<std::pair<TPMI_ALG_SYM, TPM2_KEY_BITS>> block_cipher_botan_to_tss2(
160 std::string_view cipher_name) noexcept {
161 if(cipher_name == "AES-128") {
162 return std::pair{TPM2_ALG_AES, 128};
163 } else if(cipher_name == "AES-192") {
164 return std::pair{TPM2_ALG_AES, 192};
165 } else if(cipher_name == "AES-256") {
166 return std::pair{TPM2_ALG_AES, 256};
167 } else if(cipher_name == "SM4") {
168 return std::pair{TPM2_ALG_SM4, 128};
169 } else if(cipher_name == "Camellia-128") {
170 return std::pair{TPM2_ALG_CAMELLIA, 128};
171 } else if(cipher_name == "Camellia-192") {
172 return std::pair{TPM2_ALG_CAMELLIA, 192};
173 } else if(cipher_name == "Camellia-256") {
174 return std::pair{TPM2_ALG_CAMELLIA, 256};
175 } else if(cipher_name == "3DES") {
176 return std::pair{TPM2_ALG_TDES, 168};
177 } else {
178 return {};
179 }
180}
181
182[[nodiscard]] inline std::optional<std::string> cipher_mode_tss2_to_botan(TPMI_ALG_SYM_MODE mode_id) {
183 switch(mode_id) {
184 case TPM2_ALG_CFB:
185 return "CFB";
186 case TPM2_ALG_CBC:
187 return "CBC";
188 case TPM2_ALG_ECB:
189 return "ECB";
190 case TPM2_ALG_OFB:
191 return "OFB";
192 case TPM2_ALG_CTR:
193 return "CTR";
194 default: // TPMI_ALG_SYM_MODE is not an enum
195 return std::nullopt;
196 }
197}
198
199[[nodiscard]] inline std::optional<std::string> curve_id_tss2_to_botan(TPMI_ECC_CURVE mode_id) {
200 // Currently, tpm2-tss does not include support for Brainpool curves or 25519/448.
201 // Once the corresponding PR (https://github.com/tpm2-software/tpm2-tss/pull/2897) is merged and released,
202 // this function should be updated.
203 switch(mode_id) {
204 case TPM2_ECC_NIST_P192:
205 return "secp192r1";
206 case TPM2_ECC_NIST_P224:
207 return "secp224r1";
208 case TPM2_ECC_NIST_P256:
209 return "secp256r1";
210 case TPM2_ECC_NIST_P384:
211 return "secp384r1";
212 case TPM2_ECC_NIST_P521:
213 return "secp521r1";
214 case TPM2_ECC_SM2_P256:
215 return "sm2p256v1";
216 default:
217 return std::nullopt;
218 }
219}
220
221[[nodiscard]] inline std::optional<size_t> curve_id_order_byte_size(TPMI_ECC_CURVE curve_id) {
222 switch(curve_id) {
223 case TPM2_ECC_NIST_P192:
224 return 24;
225 case TPM2_ECC_NIST_P224:
226 return 28;
227 case TPM2_ECC_NIST_P256:
228 return 32;
229 case TPM2_ECC_NIST_P384:
230 return 48;
231 case TPM2_ECC_NIST_P521:
232 return 66; // Rounded up to the next full byte
233 case TPM2_ECC_SM2_P256:
234 return 32;
235 default:
236 return std::nullopt;
237 }
238}
239
240[[nodiscard]] inline std::optional<TPM2_ECC_CURVE> get_tpm2_curve_id(const OID& curve_oid) {
241 // Currently, tpm2-tss does not include support for Brainpool curves or 25519/448.
242 // Once the corresponding PR (https://github.com/tpm2-software/tpm2-tss/pull/2897) is merged and released,
243 // this function should be updated.
244 const std::string curve_name = curve_oid.to_formatted_string();
245 if(curve_name == "secp192r1") {
246 return TPM2_ECC_NIST_P192;
247 } else if(curve_name == "secp224r1") {
248 return TPM2_ECC_NIST_P224;
249 } else if(curve_name == "secp256r1") {
250 return TPM2_ECC_NIST_P256;
251 } else if(curve_name == "secp384r1") {
252 return TPM2_ECC_NIST_P384;
253 } else if(curve_name == "secp521r1") {
254 return TPM2_ECC_NIST_P521;
255 } else if(curve_name == "sm2p256v1") {
256 return TPM2_ECC_SM2_P256;
257 } else {
258 return std::nullopt;
259 }
260}
261
262[[nodiscard]] inline std::optional<TPMI_ALG_SYM_MODE> cipher_mode_botan_to_tss2(std::string_view mode_name) noexcept {
263 if(mode_name == "CFB") {
264 return TPM2_ALG_CFB;
265 } else if(mode_name == "CBC") {
266 return TPM2_ALG_CBC;
267 } else if(mode_name == "ECB") {
268 return TPM2_ALG_ECB;
269 } else if(mode_name == "OFB") {
270 return TPM2_ALG_OFB;
271 } else if(mode_name == "CTR" || mode_name == "CTR-BE") {
272 return TPM2_ALG_CTR;
273 } else {
274 return std::nullopt;
275 }
276}
277
278/**
279 * @returns a Botan cipher mode name string if the @p cipher_id, @p key_bits and
280 * @p mode_name are known, otherwise std::nullopt
281 */
282[[nodiscard]] inline std::optional<std::string> cipher_tss2_to_botan(TPMT_SYM_DEF cipher_def) noexcept {
283 const auto cipher_name = block_cipher_tss2_to_botan(cipher_def.algorithm, cipher_def.keyBits.sym);
284 if(!cipher_name) {
285 return std::nullopt;
286 }
287
288 const auto mode_name = cipher_mode_tss2_to_botan(cipher_def.mode.sym);
289 if(!mode_name) {
290 return std::nullopt;
291 }
292
293 return Botan::fmt("{}({})", mode_name.value(), cipher_name.value());
294}
295
296[[nodiscard]] inline std::optional<TPMT_SYM_DEF> cipher_botan_to_tss2(std::string_view algo_name) {
297 SCAN_Name spec(algo_name);
298 if(spec.arg_count() == 0) {
299 return std::nullopt;
300 }
301
302 const auto cipher = block_cipher_botan_to_tss2(spec.arg(0));
303 const auto mode = cipher_mode_botan_to_tss2(spec.algo_name());
304
305 if(!cipher || !mode) {
306 return std::nullopt;
307 }
308
309 return TPMT_SYM_DEF{
310 .algorithm = cipher->first,
311 .keyBits = {.sym = cipher->second},
312 .mode = {.sym = mode.value()},
313 };
314}
315
316[[nodiscard]] inline TPMT_SYM_DEF get_tpm2_sym_cipher_spec(std::string_view algo_name) {
317 if(auto cipher = cipher_botan_to_tss2(algo_name)) {
318 return cipher.value();
319 }
320
321 throw Lookup_Error("TPM 2.0 Symmetric Cipher Spec", algo_name);
322}
323
324[[nodiscard]] inline std::optional<TPMI_ALG_SIG_SCHEME> rsa_signature_padding_botan_to_tss2(
325 std::string_view padding_name) noexcept {
326 if(padding_name == "EMSA_PKCS1" || padding_name == "PKCS1v15" || padding_name == "EMSA-PKCS1-v1_5" ||
327 padding_name == "EMSA3") {
328 return TPM2_ALG_RSASSA;
329 } else if(padding_name == "PSS" || padding_name == "PSSR" || padding_name == "EMSA-PSS" ||
330 padding_name == "PSS-MGF1" || padding_name == "EMSA4") {
331 return TPM2_ALG_RSAPSS;
332 } else {
333 return std::nullopt;
334 }
335}
336
337[[nodiscard]] inline std::optional<TPMT_SIG_SCHEME> rsa_signature_scheme_botan_to_tss2(std::string_view name) {
338 const SCAN_Name req(name);
339 if(req.arg_count() == 0) {
340 return std::nullopt;
341 }
342
343 const auto scheme = rsa_signature_padding_botan_to_tss2(req.algo_name());
344 const auto hash = hash_algo_botan_to_tss2(req.arg(0));
345 if(!scheme || !hash) {
346 return std::nullopt;
347 }
348
349 if(scheme.value() == TPM2_ALG_RSAPSS && req.arg_count() != 1) {
350 // RSA signing using PSS with MGF1
351 return std::nullopt;
352 }
353
354 return TPMT_SIG_SCHEME{
355 .scheme = scheme.value(),
356 .details = {.any = {.hashAlg = hash.value()}},
357 };
358}
359
360[[nodiscard]] inline std::optional<TPMI_ALG_ASYM_SCHEME> rsa_encryption_padding_botan_to_tss2(
361 std::string_view name) noexcept {
362 if(name == "OAEP" || name == "EME-OAEP" || name == "EME1") {
363 return TPM2_ALG_OAEP;
364 } else if(name == "PKCS1v15" || name == "EME-PKCS1-v1_5") {
365 return TPM2_ALG_RSAES;
366 } else if(name == "Raw") {
367 return TPM2_ALG_NULL;
368 } else {
369 return std::nullopt;
370 }
371}
372
373[[nodiscard]] inline std::optional<TPMT_RSA_DECRYPT> rsa_encryption_scheme_botan_to_tss2(std::string_view padding) {
374 const SCAN_Name req(padding);
375 const auto scheme = rsa_encryption_padding_botan_to_tss2(req.algo_name());
376 if(!scheme) {
377 return std::nullopt;
378 }
379
380 if(scheme.value() == TPM2_ALG_OAEP) {
381 if(req.arg_count() < 1) {
382 return std::nullopt;
383 }
384
385 const auto hash = hash_algo_botan_to_tss2(req.arg(0));
386 if(!hash) {
387 return std::nullopt;
388 }
389
390 return TPMT_RSA_DECRYPT{
391 .scheme = scheme.value(),
392 .details = {.oaep = {.hashAlg = hash.value()}},
393 };
394 } else if(scheme.value() == TPM2_ALG_RSAES) {
395 return TPMT_RSA_DECRYPT{
396 .scheme = scheme.value(),
397 .details = {.rsaes = {}},
398 };
399 } else {
400 return std::nullopt;
401 }
402}
403
404} // namespace Botan::TPM2
405
406#endif
std::string to_formatted_string() const
Definition asn1_oid.cpp:139
std::string arg(size_t i) const
size_t arg_count() const
Definition scan_name.h:49
const std::string & algo_name() const
Definition scan_name.h:44
std::string name
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< std::string > cipher_mode_tss2_to_botan(TPMI_ALG_SYM_MODE mode_id)
std::optional< size_t > curve_id_order_byte_size(TPMI_ECC_CURVE curve_id)
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< std::string > block_cipher_tss2_to_botan(TPMI_ALG_SYM cipher_id, TPM2_KEY_BITS key_bits) noexcept
std::optional< std::string > curve_id_tss2_to_botan(TPMI_ECC_CURVE mode_id)
std::optional< TPMI_ALG_HASH > hash_algo_botan_to_tss2(std::string_view hash_name) noexcept
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)
std::optional< TPM2_ALG_ID > asymmetric_algorithm_botan_to_tss2(std::string_view algo_name) noexcept
TPMT_SYM_DEF get_tpm2_sym_cipher_spec(std::string_view algo_name)
std::optional< std::string > hash_algo_tss2_to_botan(TPMI_ALG_HASH hash_id) noexcept
std::optional< TPMI_ALG_SYM_MODE > cipher_mode_botan_to_tss2(std::string_view mode_name) noexcept
std::optional< std::string > cipher_tss2_to_botan(TPMT_SYM_DEF cipher_def) noexcept
std::string get_botan_hash_name(TPM2_ALG_ID hash_id)
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53