Botan 2.13.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

pkcs8.cpp
Go to the documentation of this file.
1 /*
2 * PKCS #8
3 * (C) 1999-2010,2014,2018 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7
8 #include <botan/pkcs8.h>
9 #include <botan/rng.h>
10 #include <botan/der_enc.h>
11 #include <botan/ber_dec.h>
12 #include <botan/alg_id.h>
13 #include <botan/oids.h>
14 #include <botan/pem.h>
15 #include <botan/scan_name.h>
16 #include <botan/pk_algs.h>
17
18 #if defined(BOTAN_HAS_PKCS5_PBES2)
19 #include <botan/pbes2.h>
20 #endif
21
22 namespace Botan {
23
24 namespace PKCS8 {
25
26 namespace {
27
28 /*
29 * Get info from an EncryptedPrivateKeyInfo
30 */
31 secure_vector<uint8_t> PKCS8_extract(DataSource& source,
32 AlgorithmIdentifier& pbe_alg_id)
33 {
34 secure_vector<uint8_t> key_data;
35
36 BER_Decoder(source)
37 .start_cons(SEQUENCE)
38 .decode(pbe_alg_id)
39 .decode(key_data, OCTET_STRING)
40 .verify_end();
41
42 return key_data;
43 }
44
45 /*
46 * PEM decode and/or decrypt a private key
47 */
48 secure_vector<uint8_t> PKCS8_decode(
49 DataSource& source,
50 std::function<std::string ()> get_passphrase,
51 AlgorithmIdentifier& pk_alg_id,
52 bool is_encrypted)
53 {
54 AlgorithmIdentifier pbe_alg_id;
55 secure_vector<uint8_t> key_data, key;
56
57 try {
58 if(ASN1::maybe_BER(source) && !PEM_Code::matches(source))
59 {
60 if(is_encrypted)
61 {
62 key_data = PKCS8_extract(source, pbe_alg_id);
63 }
64 else
65 {
66 // todo read more efficiently
67 while(!source.end_of_data())
68 {
69 uint8_t b;
70 size_t read = source.read_byte(b);
71 if(read)
72 {
73 key_data.push_back(b);
74 }
75 }
76 }
77 }
78 else
79 {
80 std::string label;
81 key_data = PEM_Code::decode(source, label);
82
83 // todo remove autodetect for pem as well?
84 if(label == "PRIVATE KEY")
85 is_encrypted = false;
86 else if(label == "ENCRYPTED PRIVATE KEY")
87 {
88 DataSource_Memory key_source(key_data);
89 key_data = PKCS8_extract(key_source, pbe_alg_id);
90 }
91 else
92 throw PKCS8_Exception("Unknown PEM label " + label);
93 }
94
95 if(key_data.empty())
96 throw PKCS8_Exception("No key data found");
97 }
98 catch(Decoding_Error& e)
99 {
100 throw Decoding_Error("PKCS #8 private key decoding", e);
101 }
102
103 try
104 {
105 if(is_encrypted)
106 {
107 if(OIDS::oid2str_or_throw(pbe_alg_id.get_oid()) != "PBE-PKCS5v20")
108 throw PKCS8_Exception("Unknown PBE type " + pbe_alg_id.get_oid().to_string());
109 #if defined(BOTAN_HAS_PKCS5_PBES2)
110 key = pbes2_decrypt(key_data, get_passphrase(), pbe_alg_id.get_parameters());
111 #else
112 BOTAN_UNUSED(get_passphrase);
113 throw Decoding_Error("Private key is encrypted but PBES2 was disabled in build");
114 #endif
115 }
116 else
117 key = key_data;
118
119 BER_Decoder(key)
120 .start_cons(SEQUENCE)
121 .decode_and_check<size_t>(0, "Unknown PKCS #8 version number")
122 .decode(pk_alg_id)
123 .decode(key, OCTET_STRING)
124 .discard_remaining()
125 .end_cons();
126 }
127 catch(std::exception& e)
128 {
129 throw Decoding_Error("PKCS #8 private key decoding", e);
130 }
131 return key;
132 }
133
134 }
135
136 /*
137 * BER encode a PKCS #8 private key, unencrypted
138 */
139 secure_vector<uint8_t> BER_encode(const Private_Key& key)
140 {
141 // keeping around for compat
142 return key.private_key_info();
143 }
144
145 /*
146 * PEM encode a PKCS #8 private key, unencrypted
147 */
148 std::string PEM_encode(const Private_Key& key)
149 {
150 return PEM_Code::encode(PKCS8::BER_encode(key), "PRIVATE KEY");
151 }
152
153 #if defined(BOTAN_HAS_PKCS5_PBES2)
154
155 namespace {
156
157 std::pair<std::string, std::string>
158 choose_pbe_params(const std::string& pbe_algo, const std::string& key_algo)
159 {
160 if(pbe_algo.empty())
161 {
162 /*
163 * For algorithms where we are using a non-RFC format anyway, default to
164 * SIV or GCM. For others (RSA, ECDSA, ...) default to something widely
165 * compatible.
166 */
167 const bool nonstandard_pk = (key_algo == "McEliece" || key_algo == "XMSS");
168
169 if(nonstandard_pk)
170 {
171 #if defined(BOTAN_HAS_AEAD_SIV) && defined(BOTAN_HAS_SHA2_64)
172 return std::make_pair("AES-256/SIV", "SHA-512");
173 #elif defined(BOTAN_HAS_AEAD_GCM) && defined(BOTAN_HAS_SHA2_64)
174 return std::make_pair("AES-256/GCM", "SHA-512");
175 #endif
176 }
177
178 // Default is something compatible with everyone else
179 return std::make_pair("AES-256/CBC", "SHA-256");
180 }
181
182 SCAN_Name request(pbe_algo);
183
184 if(request.arg_count() != 2 ||
185 (request.algo_name() != "PBE-PKCS5v20" && request.algo_name() != "PBES2"))
186 {
187 throw Invalid_Argument("Unsupported PBE " + pbe_algo);
188 }
189
190 return std::make_pair(request.arg(0), request.arg(1));
191 }
192
193 }
194
195 #endif
196
197 /*
198 * BER encode a PKCS #8 private key, encrypted
199 */
200 std::vector<uint8_t> BER_encode(const Private_Key& key,
201 RandomNumberGenerator& rng,
202 const std::string& pass,
203 std::chrono::milliseconds msec,
204 const std::string& pbe_algo)
205 {
206 #if defined(BOTAN_HAS_PKCS5_PBES2)
207 const auto pbe_params = choose_pbe_params(pbe_algo, key.algo_name());
208
209 const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info =
210 pbes2_encrypt_msec(PKCS8::BER_encode(key), pass, msec, nullptr,
211 pbe_params.first, pbe_params.second, rng);
212
213 std::vector<uint8_t> output;
214 DER_Encoder der(output);
215 der.start_cons(SEQUENCE)
216 .encode(pbe_info.first)
217 .encode(pbe_info.second, OCTET_STRING)
218 .end_cons();
219
220 return output;
221 #else
222 BOTAN_UNUSED(key, rng, pass, msec, pbe_algo);
223 throw Encoding_Error("PKCS8::BER_encode cannot encrypt because PBES2 was disabled in build");
224 #endif
225 }
226
227 /*
228 * PEM encode a PKCS #8 private key, encrypted
229 */
230 std::string PEM_encode(const Private_Key& key,
231 RandomNumberGenerator& rng,
232 const std::string& pass,
233 std::chrono::milliseconds msec,
234 const std::string& pbe_algo)
235 {
236 if(pass.empty())
237 return PEM_encode(key);
238
239 return PEM_Code::encode(PKCS8::BER_encode(key, rng, pass, msec, pbe_algo),
240 "ENCRYPTED PRIVATE KEY");
241 }
242
243 /*
244 * BER encode a PKCS #8 private key, encrypted
245 */
246 std::vector<uint8_t> BER_encode_encrypted_pbkdf_iter(const Private_Key& key,
247 RandomNumberGenerator& rng,
248 const std::string& pass,
249 size_t pbkdf_iterations,
250 const std::string& cipher,
251 const std::string& pbkdf_hash)
252 {
253 #if defined(BOTAN_HAS_PKCS5_PBES2)
254 const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info =
255 pbes2_encrypt_iter(key.private_key_info(),
256 pass, pbkdf_iterations,
257 cipher.empty() ? "AES-256/CBC" : cipher,
258 pbkdf_hash.empty() ? "SHA-256" : pbkdf_hash,
259 rng);
260
261 std::vector<uint8_t> output;
262 DER_Encoder der(output);
263 der.start_cons(SEQUENCE)
264 .encode(pbe_info.first)
265 .encode(pbe_info.second, OCTET_STRING)
266 .end_cons();
267
268 return output;
269
270 #else
271 BOTAN_UNUSED(key, rng, pass, pbkdf_iterations, cipher, pbkdf_hash);
272 throw Encoding_Error("PKCS8::BER_encode_encrypted_pbkdf_iter cannot encrypt because PBES2 disabled in build");
273 #endif
274 }
275
276 /*
277 * PEM encode a PKCS #8 private key, encrypted
278 */
279 std::string PEM_encode_encrypted_pbkdf_iter(const Private_Key& key,
280 RandomNumberGenerator& rng,
281 const std::string& pass,
282 size_t pbkdf_iterations,
283 const std::string& cipher,
284 const std::string& pbkdf_hash)
285 {
286 return PEM_Code::encode(
287 PKCS8::BER_encode_encrypted_pbkdf_iter(key, rng, pass, pbkdf_iterations, cipher, pbkdf_hash),
288 "ENCRYPTED PRIVATE KEY");
289 }
290
291 /*
292 * BER encode a PKCS #8 private key, encrypted
293 */
294 std::vector<uint8_t> BER_encode_encrypted_pbkdf_msec(const Private_Key& key,
295 RandomNumberGenerator& rng,
296 const std::string& pass,
297 std::chrono::milliseconds pbkdf_msec,
298 size_t* pbkdf_iterations,
299 const std::string& cipher,
300 const std::string& pbkdf_hash)
301 {
302 #if defined(BOTAN_HAS_PKCS5_PBES2)
303 const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info =
304 pbes2_encrypt_msec(key.private_key_info(), pass,
305 pbkdf_msec, pbkdf_iterations,
306 cipher.empty() ? "AES-256/CBC" : cipher,
307 pbkdf_hash.empty() ? "SHA-256" : pbkdf_hash,
308 rng);
309
310 std::vector<uint8_t> output;
311 DER_Encoder(output)
312 .start_cons(SEQUENCE)
313 .encode(pbe_info.first)
314 .encode(pbe_info.second, OCTET_STRING)
315 .end_cons();
316
317 return output;
318 #else
319 BOTAN_UNUSED(key, rng, pass, pbkdf_msec, pbkdf_iterations, cipher, pbkdf_hash);
320 throw Encoding_Error("BER_encode_encrypted_pbkdf_msec cannot encrypt because PBES2 disabled in build");
321 #endif
322 }
323
324 /*
325 * PEM encode a PKCS #8 private key, encrypted
326 */
327 std::string PEM_encode_encrypted_pbkdf_msec(const Private_Key& key,
328 RandomNumberGenerator& rng,
329 const std::string& pass,
330 std::chrono::milliseconds pbkdf_msec,
331 size_t* pbkdf_iterations,
332 const std::string& cipher,
333 const std::string& pbkdf_hash)
334 {
335 return PEM_Code::encode(
336 PKCS8::BER_encode_encrypted_pbkdf_msec(key, rng, pass, pbkdf_msec, pbkdf_iterations, cipher, pbkdf_hash),
337 "ENCRYPTED PRIVATE KEY");
338 }
339
340 namespace {
341
342 /*
343 * Extract a private key (encrypted/unencrypted) and return it
344 */
345 std::unique_ptr<Private_Key>
346 load_key(DataSource& source,
347 std::function<std::string ()> get_pass,
348 bool is_encrypted)
349 {
350 AlgorithmIdentifier alg_id;
351 secure_vector<uint8_t> pkcs8_key = PKCS8_decode(source, get_pass, alg_id, is_encrypted);
352
353 const std::string alg_name = OIDS::oid2str_or_empty(alg_id.get_oid());
354 if(alg_name.empty())
355 throw PKCS8_Exception("Unknown algorithm OID: " +
356 alg_id.get_oid().to_string());
357
358 return load_private_key(alg_id, pkcs8_key);
359 }
360
361 }
362
363 /*
364 * Extract an encrypted private key and return it
365 */
366 std::unique_ptr<Private_Key> load_key(DataSource& source,
367 std::function<std::string ()> get_pass)
368 {
369 return load_key(source, get_pass, true);
370 }
371
372 /*
373 * Extract an encrypted private key and return it
374 */
375 std::unique_ptr<Private_Key> load_key(DataSource& source,
376 const std::string& pass)
377 {
378 return load_key(source, [pass]() { return pass; }, true);
379 }
380
381 /*
382 * Extract an unencrypted private key and return it
383 */
384 std::unique_ptr<Private_Key> load_key(DataSource& source)
385 {
386 auto fail_fn = []() -> std::string {
387 throw PKCS8_Exception("Internal error: Attempt to read password for unencrypted key");
388 };
389
390 return load_key(source, fail_fn, false);
391 }
392
393 /*
394 * Make a copy of this private key
395 */
396 std::unique_ptr<Private_Key> copy_key(const Private_Key& key)
397 {
398 DataSource_Memory source(PEM_encode(key));
399 return PKCS8::load_key(source);
400 }
401
402 /*
403 * Extract an encrypted private key and return it
404 */
405 Private_Key* load_key(DataSource& source,
406 RandomNumberGenerator& rng,
407 std::function<std::string ()> get_pass)
408 {
409 BOTAN_UNUSED(rng);
410 return PKCS8::load_key(source, get_pass).release();
411 }
412
413 /*
414 * Extract an encrypted private key and return it
415 */
416 Private_Key* load_key(DataSource& source,
417 RandomNumberGenerator& rng,
418 const std::string& pass)
419 {
420 BOTAN_UNUSED(rng);
421 return PKCS8::load_key(source, pass).release();
422 }
423
424 /*
425 * Extract an unencrypted private key and return it
426 */
427 Private_Key* load_key(DataSource& source,
428 RandomNumberGenerator& rng)
429 {
430 BOTAN_UNUSED(rng);
431 return PKCS8::load_key(source).release();
432 }
433
434 #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
435
436 /*
437 * Extract an encrypted private key and return it
438 */
439 Private_Key* load_key(const std::string& fsname,
440 RandomNumberGenerator& rng,
441 std::function<std::string ()> get_pass)
442 {
443 BOTAN_UNUSED(rng);
444 DataSource_Stream in(fsname);
445 return PKCS8::load_key(in, get_pass).release();
446 }
447
448 /*
449 * Extract an encrypted private key and return it
450 */
451 Private_Key* load_key(const std::string& fsname,
452 RandomNumberGenerator& rng,
453 const std::string& pass)
454 {
455 BOTAN_UNUSED(rng);
456 DataSource_Stream in(fsname);
457 return PKCS8::load_key(in, [pass]() { return pass; }).release();
458 }
459
460 /*
461 * Extract an unencrypted private key and return it
462 */
463 Private_Key* load_key(const std::string& fsname,
464 RandomNumberGenerator& rng)
465 {
466 BOTAN_UNUSED(rng);
467 DataSource_Stream in(fsname);
468 return PKCS8::load_key(in).release();
469 }
470 #endif
471
472 /*
473 * Make a copy of this private key
474 */
475 Private_Key* copy_key(const Private_Key& key,
476 RandomNumberGenerator& rng)
477 {
478 BOTAN_UNUSED(rng);
479 return PKCS8::copy_key(key).release();
480 }
481
482
483
484 }
485
486 }
Botan::OIDS::oid2str_or_throw
BOTAN_UNSTABLE_API std::string oid2str_or_throw(const OID &oid)
Definition: oids.cpp:121
Botan::DataSource_Stream
Definition: data_src.h:143
Botan::load_private_key
std::unique_ptr< Private_Key > load_private_key(const AlgorithmIdentifier &alg_id, const secure_vector< uint8_t > &key_bits)
Definition: pk_algs.cpp:163
Botan::PKCS8::copy_key
std::unique_ptr< Private_Key > copy_key(const Private_Key &key)
Definition: pkcs8.cpp:396
Botan::RandomNumberGenerator
Definition: rng.h:24
Botan::Private_Key
Definition: pk_keys.h:181
Botan::BER_Decoder::decode_and_check
BER_Decoder & decode_and_check(const T &expected, const std::string &error_msg)
Definition: ber_dec.h:277
Botan::OIDS::oid2str_or_empty
BOTAN_UNSTABLE_API std::string oid2str_or_empty(const OID &oid)
Definition: oids.cpp:111
Botan::pbes2_encrypt_msec
std::pair< AlgorithmIdentifier, std::vector< uint8_t > > pbes2_encrypt_msec(const secure_vector< uint8_t > &key_bits, const std::string &passphrase, std::chrono::milliseconds msec, size_t *out_iterations_if_nonnull, const std::string &cipher, const std::string &digest, RandomNumberGenerator &rng)
Definition: pbes2.cpp:273
Botan::Public_Key::algo_name
virtual std::string algo_name() const =0
Botan::PKCS8::BER_encode_encrypted_pbkdf_iter
std::vector< uint8_t > BER_encode_encrypted_pbkdf_iter(const Private_Key &key, RandomNumberGenerator &rng, const std::string &pass, size_t pbkdf_iterations, const std::string &cipher, const std::string &pbkdf_hash)
Definition: pkcs8.cpp:246
Botan::ASN1::maybe_BER
bool maybe_BER(DataSource &source)
Definition: asn1_obj.cpp:222
Botan::DER_Encoder::end_cons
DER_Encoder & end_cons()
Definition: der_enc.cpp:191
Botan::DataSource
Definition: data_src.h:21
Botan::PKCS8_Exception
Definition: pkcs8.h:26
Botan::PKCS8::BER_encode_encrypted_pbkdf_msec
std::vector< uint8_t > BER_encode_encrypted_pbkdf_msec(const Private_Key &key, RandomNumberGenerator &rng, const std::string &pass, std::chrono::milliseconds pbkdf_msec, size_t *pbkdf_iterations, const std::string &cipher, const std::string &pbkdf_hash)
Definition: pkcs8.cpp:294
Botan::BER_Decoder::decode
BER_Decoder & decode(bool &out)
Definition: ber_dec.h:170
Botan::Decoding_Error
Definition: exceptn.h:199
Botan::DER_Encoder::encode
DER_Encoder & encode(bool b)
Definition: der_enc.cpp:285
Botan::SEQUENCE
Definition: asn1_obj.h:40
Botan::DER_Encoder
Definition: der_enc.h:23
Botan::secure_vector
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:65
Botan::PEM_Code::encode
std::string encode(const uint8_t der[], size_t length, const std::string &label, size_t width)
Definition: pem.cpp:43
Botan::PEM_Code::matches
bool matches(DataSource &source, const std::string &extra, size_t search_range)
Definition: pem.cpp:142
Botan::DataSource::end_of_data
virtual bool end_of_data() const =0
Botan::pbes2_encrypt_iter
std::pair< AlgorithmIdentifier, std::vector< uint8_t > > pbes2_encrypt_iter(const secure_vector< uint8_t > &key_bits, const std::string &passphrase, size_t pbkdf_iter, const std::string &cipher, const std::string &digest, RandomNumberGenerator &rng)
Definition: pbes2.cpp:292
Botan::OID::to_string
std::string to_string() const
Definition: asn1_oid.cpp:98
Botan::PKCS8::PEM_encode
std::string PEM_encode(const Private_Key &key)
Definition: pkcs8.cpp:148
Botan::PEM_Code::decode
secure_vector< uint8_t > decode(DataSource &source, std::string &label)
Definition: pem.cpp:68
Botan::BER_Decoder::start_cons
BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: ber_dec.cpp:290
Botan
Definition: alg_id.cpp:13
Botan::DataSource::read_byte
size_t read_byte(uint8_t &out)
Definition: data_src.cpp:23
Botan::AlgorithmIdentifier::get_oid
const OID & get_oid() const
Definition: alg_id.h:37
Botan::PKCS8::BER_encode
secure_vector< uint8_t > BER_encode(const Private_Key &key)
Definition: pkcs8.cpp:139
Botan::pbes2_decrypt
secure_vector< uint8_t > pbes2_decrypt(const secure_vector< uint8_t > &key_bits, const std::string &passphrase, const std::vector< uint8_t > &params)
Definition: pbes2.cpp:303
BOTAN_UNUSED
#define BOTAN_UNUSED(...)
Definition: assert.h:142
Botan::OCTET_STRING
Definition: asn1_obj.h:36
Botan::PKCS8::PEM_encode_encrypted_pbkdf_iter
std::string PEM_encode_encrypted_pbkdf_iter(const Private_Key &key, RandomNumberGenerator &rng, const std::string &pass, size_t pbkdf_iterations, const std::string &cipher, const std::string &pbkdf_hash)
Definition: pkcs8.cpp:279
Botan::Private_Key::private_key_info
secure_vector< uint8_t > private_key_info() const
Definition: pk_keys.cpp:61
Botan::Encoding_Error
Definition: exceptn.h:184
Botan::BER_Decoder::verify_end
BER_Decoder & verify_end()
Definition: ber_dec.cpp:208
Botan::DataSource_Memory
Definition: data_src.h:98
Botan::AlgorithmIdentifier
Definition: alg_id.h:21
Botan::DER_Encoder::start_cons
DER_Encoder & start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: der_enc.cpp:181
Botan::PKCS8::load_key
std::unique_ptr< Private_Key > load_key(DataSource &source, std::function< std::string()> get_pass)
Definition: pkcs8.cpp:366
Botan::BER_Decoder
Definition: ber_dec.h:21
Botan::AlgorithmIdentifier::get_parameters
const std::vector< uint8_t > & get_parameters() const
Definition: alg_id.h:38
Botan::PKCS8::PEM_encode_encrypted_pbkdf_msec
std::string PEM_encode_encrypted_pbkdf_msec(const Private_Key &key, RandomNumberGenerator &rng, const std::string &pass, std::chrono::milliseconds pbkdf_msec, size_t *pbkdf_iterations, const std::string &cipher, const std::string &pbkdf_hash)
Definition: pkcs8.cpp:327