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