Botan 3.0.0
Crypto and TLS for C&
p11_mechanism.cpp
Go to the documentation of this file.
1/*
2* PKCS#11 Mechanism
3* (C) 2016 Daniel Neus, Sirrix AG
4* (C) 2016 Philipp Weber, Sirrix AG
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/internal/p11_mechanism.h>
10#include <botan/internal/scan_name.h>
11#include <botan/internal/parsing.h>
12#include <botan/internal/fmt.h>
13#include <tuple>
14
15namespace Botan::PKCS11 {
16
17namespace {
18using PSS_Params = std::tuple<size_t, MechanismType, MGF>;
19
20// maps a PSS mechanism type to the number of bytes used for the salt, the mechanism type of the underlying hash algorithm and the MGF
21const std::map<MechanismType, PSS_Params> PssOptions =
22 {
29 };
30
31class MechanismData
32 {
33 public:
34 explicit MechanismData(MechanismType type) : m_type(type) {}
35
36 MechanismData(const MechanismData& other) = default;
37 MechanismData(MechanismData&& other) = default;
38
39 MechanismData& operator=(const MechanismData& other) = default;
40 MechanismData& operator=(MechanismData&& other) = default;
41
42 virtual ~MechanismData() = default;
43
44 MechanismType type() const { return m_type; }
45
46 private:
47 // the mechanism to perform
48 MechanismType m_type;
49 };
50
51class RSA_SignMechanism final : public MechanismData
52 {
53 public:
54 explicit RSA_SignMechanism(MechanismType typ) :
55 MechanismData(typ),
56 m_hash(static_cast<MechanismType>(0)),
57 m_mgf(static_cast<MGF>(0)),
58 m_salt_size(0)
59 {
60 auto pss_option = PssOptions.find(type());
61 if(pss_option != PssOptions.end())
62 {
63 m_hash = std::get<1>(pss_option->second);
64 m_mgf = std::get<2>(pss_option->second);
65 m_salt_size = std::get<0>(pss_option->second);
66 }
67 }
68
69 MechanismType hash() const { return m_hash; }
70 MGF mgf() const { return m_mgf; }
71 size_t salt_size() const { return m_salt_size; }
72
73 private:
74
75 /*
76 hash algorithm used in the PSS encoding; if the signature
77 mechanism does not include message hashing, then this value must
78 be the mechanism used by the application to generate the message
79 hash; if the signature mechanism includes hashing, then this
80 value must match the hash algorithm indicated by the signature mechanism
81 */
82 MechanismType m_hash;
83
84 // mask generation function to use on the encoded block
85 MGF m_mgf;
86
87 // length, in bytes, of the salt value used in the PSS encoding; typical values are the length of the message hash and zero
88 size_t m_salt_size;
89 };
90
91// note: when updating this map, update the documentation for `MechanismWrapper::create_rsa_sign_mechanism`
92const std::map<std::string, RSA_SignMechanism> SignMechanisms =
93 {
94 { "Raw", RSA_SignMechanism(MechanismType::RsaX509) },
95
96 { "EMSA2(Raw)", RSA_SignMechanism(MechanismType::RsaX931) },
97 { "EMSA2(SHA-1)", RSA_SignMechanism(MechanismType::Sha1RsaX931) },
98
99 // RSASSA PKCS#1 v1.5
100 { "EMSA3(Raw)", RSA_SignMechanism(MechanismType::RsaPkcs) },
101 { "EMSA3(SHA-1)", RSA_SignMechanism(MechanismType::Sha1RsaPkcs) },
102 { "EMSA3(SHA-224)", RSA_SignMechanism(MechanismType::Sha224RsaPkcs) },
103 { "EMSA3(SHA-256)", RSA_SignMechanism(MechanismType::Sha256RsaPkcs) },
104 { "EMSA3(SHA-384)", RSA_SignMechanism(MechanismType::Sha384RsaPkcs) },
105 { "EMSA3(SHA-512)", RSA_SignMechanism(MechanismType::Sha512RsaPkcs) },
106
107 { "EMSA_PKCS1(SHA-1)", RSA_SignMechanism(MechanismType::Sha1RsaPkcs) },
108 { "EMSA_PKCS1(SHA-224)", RSA_SignMechanism(MechanismType::Sha224RsaPkcs) },
109 { "EMSA_PKCS1(SHA-256)", RSA_SignMechanism(MechanismType::Sha256RsaPkcs) },
110 { "EMSA_PKCS1(SHA-384)", RSA_SignMechanism(MechanismType::Sha384RsaPkcs) },
111 { "EMSA_PKCS1(SHA-512)", RSA_SignMechanism(MechanismType::Sha512RsaPkcs) },
112
113 // RSASSA PKCS#1 PSS
114 { "EMSA4(Raw)", RSA_SignMechanism(MechanismType::RsaPkcsPss) },
115 { "EMSA4(SHA-1)", RSA_SignMechanism(MechanismType::Sha1RsaPkcsPss) },
116 { "EMSA4(SHA-224)", RSA_SignMechanism(MechanismType::Sha224RsaPkcsPss) },
117
118 { "EMSA4(SHA-256)", RSA_SignMechanism(MechanismType::Sha256RsaPkcsPss) },
119 { "EMSA4(SHA-256,MGF1,32)", RSA_SignMechanism(MechanismType::Sha256RsaPkcsPss) },
120 { "PSSR(SHA-256,MGF1,32)", RSA_SignMechanism(MechanismType::Sha256RsaPkcsPss) },
121
122 { "EMSA4(SHA-384)", RSA_SignMechanism(MechanismType::Sha384RsaPkcsPss) },
123 { "EMSA4(SHA-384,MGF1,48)", RSA_SignMechanism(MechanismType::Sha384RsaPkcsPss) },
124 { "PSSR(SHA-384,MGF1,48)", RSA_SignMechanism(MechanismType::Sha384RsaPkcsPss) },
125
126 { "EMSA4(SHA-512)", RSA_SignMechanism(MechanismType::Sha512RsaPkcsPss) },
127 { "EMSA4(SHA-512,MGF1,64)", RSA_SignMechanism(MechanismType::Sha512RsaPkcsPss) },
128 { "PSSR(SHA-512,MGF1,64)", RSA_SignMechanism(MechanismType::Sha512RsaPkcsPss) },
129
130 { "ISO9796", RSA_SignMechanism(MechanismType::Rsa9796) }
131 };
132
133struct RSA_CryptMechanism final : public MechanismData
134 {
135 public:
136 RSA_CryptMechanism(MechanismType typ,
137 size_t padding_size,
138 MechanismType hash,
139 MGF mgf) :
140 MechanismData(typ),
141 m_hash(hash),
142 m_mgf(mgf),
143 m_padding_size(padding_size)
144 {}
145
146 RSA_CryptMechanism(MechanismType typ, size_t padding_size) :
147 RSA_CryptMechanism(typ, padding_size, static_cast<MechanismType>(0), static_cast<MGF>(0))
148 {}
149
150 MechanismType hash() const { return m_hash; }
151 MGF mgf() const { return m_mgf; }
152 size_t padding_size() const { return m_padding_size; }
153
154 private:
155 // mechanism ID of the message digest algorithm used to calculate the digest of the encoding parameter
156 MechanismType m_hash;
157
158 // mask generation function to use on the encoded block
159 MGF m_mgf;
160
161 // number of bytes required for the padding
162 size_t m_padding_size;
163 };
164
165// note: when updating this map, update the documentation for `MechanismWrapper::create_rsa_crypt_mechanism`
166const std::map<std::string, RSA_CryptMechanism> CryptMechanisms =
167 {
168 { "Raw", RSA_CryptMechanism(MechanismType::RsaX509, 0) },
169 { "EME-PKCS1-v1_5", RSA_CryptMechanism(MechanismType::RsaPkcs, 11) },
170 { "OAEP(SHA-1)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 20, MechanismType::Sha1, MGF::Mgf1Sha1) },
171 { "OAEP(SHA-224)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 28, MechanismType::Sha224, MGF::Mgf1Sha224) },
172 { "OAEP(SHA-256)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 32, MechanismType::Sha256, MGF::Mgf1Sha256) },
173 { "OAEP(SHA-384)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 48, MechanismType::Sha384, MGF::Mgf1Sha384) },
174 { "OAEP(SHA-512)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 64, MechanismType::Sha512, MGF::Mgf1Sha512) }
175 };
176
177// note: when updating this map, update the documentation for `MechanismWrapper::create_ecdsa_mechanism`
178const std::map<std::string, MechanismType> EcdsaHash =
179 {
180 { "Raw", MechanismType::Ecdsa },
181 { "SHA-1", MechanismType::EcdsaSha1 },
182 { "SHA-224", MechanismType::EcdsaSha224 },
183 { "SHA-256", MechanismType::EcdsaSha256 },
184 { "SHA-384", MechanismType::EcdsaSha384 },
185 { "SHA-512", MechanismType::EcdsaSha512 }
186 };
187
188// note: when updating this map, update the documentation for `MechanismWrapper::create_ecdh_mechanism`
189const std::map<std::string, KeyDerivation> EcdhHash =
190 {
191 { "Raw", KeyDerivation::Null },
192 { "SHA-1", KeyDerivation::Sha1Kdf },
193 { "SHA-224", KeyDerivation::Sha224Kdf },
194 { "SHA-256", KeyDerivation::Sha256Kdf },
195 { "SHA-384", KeyDerivation::Sha384Kdf },
196 { "SHA-512", KeyDerivation::Sha512Kdf }
197 };
198}
199
201 : m_mechanism( { static_cast<CK_MECHANISM_TYPE>(mechanism_type), nullptr, 0 }), m_parameters(nullptr)
202 {}
203
205 {
206 const std::string padding(padding_view);
207 auto mechanism_info_it = CryptMechanisms.find(padding);
208 if(mechanism_info_it == CryptMechanisms.end())
209 {
210 // at this point it would be possible to support additional configurations that are not predefined above by parsing `padding`
211 throw Lookup_Error("PKCS#11 RSA encrypt/decrypt does not support EME " + padding);
212 }
213 RSA_CryptMechanism mechanism_info = mechanism_info_it->second;
214
215 MechanismWrapper mech(mechanism_info.type());
216 if(mechanism_info.type() == MechanismType::RsaPkcsOaep)
217 {
218 mech.m_parameters = std::make_shared<MechanismParameters>();
219 mech.m_parameters->oaep_params.hashAlg = static_cast<CK_MECHANISM_TYPE>(mechanism_info.hash());
220 mech.m_parameters->oaep_params.mgf = static_cast<CK_RSA_PKCS_MGF_TYPE>(mechanism_info.mgf());
221 mech.m_parameters->oaep_params.source = CKZ_DATA_SPECIFIED;
222 mech.m_parameters->oaep_params.pSourceData = nullptr;
223 mech.m_parameters->oaep_params.ulSourceDataLen = 0;
224 mech.m_mechanism.pParameter = mech.m_parameters.get();
225 mech.m_mechanism.ulParameterLen = sizeof(RsaPkcsOaepParams);
226 }
227 mech.m_padding_size = mechanism_info.padding_size();
228 return mech;
229 }
230
232 {
233 const std::string padding(padding_view);
234 auto mechanism_info_it = SignMechanisms.find(padding);
235 if(mechanism_info_it == SignMechanisms.end())
236 {
237 // at this point it would be possible to support additional configurations that are not predefined above by parsing `padding`
238 throw Lookup_Error("PKCS#11 RSA sign/verify does not support EMSA " + padding);
239 }
240 RSA_SignMechanism mechanism_info = mechanism_info_it->second;
241
242 MechanismWrapper mech(mechanism_info.type());
243 if(PssOptions.find(mechanism_info.type()) != PssOptions.end())
244 {
245 mech.m_parameters = std::make_shared<MechanismParameters>();
246 mech.m_parameters->pss_params.hashAlg = static_cast<CK_MECHANISM_TYPE>(mechanism_info.hash());
247 mech.m_parameters->pss_params.mgf = static_cast<CK_RSA_PKCS_MGF_TYPE>(mechanism_info.mgf());
248 mech.m_parameters->pss_params.sLen = static_cast<Ulong>(mechanism_info.salt_size());
249 mech.m_mechanism.pParameter = mech.m_parameters.get();
250 mech.m_mechanism.ulParameterLen = sizeof(RsaPkcsPssParams);
251 }
252 return mech;
253 }
254
256 {
257 const std::string hash_spec(hash_spec_view);
258 auto mechanism = EcdsaHash.find(hash_spec);
259 if(mechanism != EcdsaHash.end())
260 return MechanismWrapper(mechanism->second);
261
262 SCAN_Name req(hash_spec);
263
264 if(req.algo_name() == "EMSA1" && req.arg_count() == 1)
265 {
266 mechanism = EcdsaHash.find(req.arg(0));
267 if(mechanism != EcdsaHash.end())
268 return MechanismWrapper(mechanism->second);
269 }
270
271 throw Lookup_Error(fmt("PKCS #11 ECDSA sign/verify does not support {}", hash_spec));
272 }
273
275 {
276 std::vector<std::string> param_parts = split_on(params, ',');
277
278 if(param_parts.empty() || param_parts.size() > 2)
279 {
280 throw Invalid_Argument(fmt("PKCS #11 ECDH key derivation bad params {}", params));
281 }
282
283 const bool use_cofactor =
284 (param_parts[0] == "Cofactor") ||
285 (param_parts.size() == 2 && param_parts[1] == "Cofactor");
286
287 std::string kdf_name = (param_parts[0] == "Cofactor" ? param_parts[1] : param_parts[0]);
288 std::string hash = kdf_name;
289
290 if(kdf_name != "Raw")
291 {
292 SCAN_Name kdf_hash(kdf_name);
293
294 if(kdf_hash.arg_count() > 0)
295 {
296 hash = kdf_hash.arg(0);
297 }
298 }
299
300 auto kdf = EcdhHash.find(hash);
301 if(kdf == EcdhHash.end())
302 {
303 throw Lookup_Error("PKCS#11 ECDH key derivation does not support KDF " + kdf_name);
304 }
306 mech.m_parameters = std::make_shared<MechanismParameters>();
307 mech.m_parameters->ecdh_params.kdf = static_cast<CK_EC_KDF_TYPE>(kdf->second);
308 mech.m_mechanism.pParameter = mech.m_parameters.get();
309 mech.m_mechanism.ulParameterLen = sizeof(Ecdh1DeriveParams);
310 return mech;
311 }
312
313}
static MechanismWrapper create_rsa_sign_mechanism(std::string_view padding)
static MechanismWrapper create_ecdh_mechanism(std::string_view params)
MechanismType mechanism_type() const
Definition: p11_mechanism.h:89
static MechanismWrapper create_rsa_crypt_mechanism(std::string_view padding)
static MechanismWrapper create_ecdsa_mechanism(std::string_view hash)
MechanismWrapper(MechanismType mechanism_type)
std::string arg(size_t i) const
Definition: scan_name.cpp:129
size_t arg_count() const
Definition: scan_name.h:50
const std::string algo_name() const
Definition: scan_name.h:45
int(* final)(unsigned char *, CTX *)
CK_RSA_PKCS_OAEP_PARAMS RsaPkcsOaepParams
Definition: p11.h:850
CK_RSA_PKCS_PSS_PARAMS RsaPkcsPssParams
Definition: p11.h:851
MechanismType
Definition: p11.h:338
CK_ECDH1_DERIVE_PARAMS Ecdh1DeriveParams
Definition: p11.h:852
CK_ULONG Ulong
Definition: p11.h:838
std::string fmt(std::string_view format, const T &... args)
Definition: fmt.h:60
std::vector< std::string > split_on(std::string_view str, char delim)
Definition: parsing.cpp:117
CK_ULONG CK_EC_KDF_TYPE
Definition: pkcs11t.h:1287
#define CKZ_DATA_SPECIFIED
Definition: pkcs11t.h:1261
CK_ULONG CK_RSA_PKCS_MGF_TYPE
Definition: pkcs11t.h:1241
CK_ULONG CK_MECHANISM_TYPE
Definition: pkcs11t.h:583
CK_VOID_PTR pParameter
Definition: pkcs11t.h:985
CK_ULONG ulParameterLen
Definition: pkcs11t.h:986