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