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