Botan  2.1.0
Crypto and TLS for C++11
pkcs8.cpp
Go to the documentation of this file.
1 /*
2 * PKCS #8
3 * (C) 1999-2010,2014 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/der_enc.h>
10 #include <botan/ber_dec.h>
11 #include <botan/alg_id.h>
12 #include <botan/oids.h>
13 #include <botan/pem.h>
14 #include <botan/pbes2.h>
15 #include <botan/scan_name.h>
16 #include <botan/pk_algs.h>
17 
18 namespace Botan {
19 
20 namespace PKCS8 {
21 
22 namespace {
23 
24 /*
25 * Get info from an EncryptedPrivateKeyInfo
26 */
27 secure_vector<uint8_t> PKCS8_extract(DataSource& source,
28  AlgorithmIdentifier& pbe_alg_id)
29  {
30  secure_vector<uint8_t> key_data;
31 
32  BER_Decoder(source)
34  .decode(pbe_alg_id)
35  .decode(key_data, OCTET_STRING)
36  .verify_end();
37 
38  return key_data;
39  }
40 
41 /*
42 * PEM decode and/or decrypt a private key
43 */
44 secure_vector<uint8_t> PKCS8_decode(
45  DataSource& source,
46  std::function<std::string ()> get_passphrase,
47  AlgorithmIdentifier& pk_alg_id,
48  bool is_encrypted)
49  {
50  AlgorithmIdentifier pbe_alg_id;
51  secure_vector<uint8_t> key_data, key;
52 
53  try {
54  if(ASN1::maybe_BER(source) && !PEM_Code::matches(source))
55  {
56  if ( is_encrypted )
57  {
58  key_data = PKCS8_extract(source, pbe_alg_id);
59  }
60  else
61  {
62  // todo read more efficiently
63  while ( !source.end_of_data() )
64  {
65  uint8_t b;
66  size_t read = source.read_byte( b );
67  if ( read )
68  {
69  key_data.push_back( b );
70  }
71  }
72  }
73  }
74  else
75  {
76  std::string label;
77  key_data = PEM_Code::decode(source, label);
78 
79  // todo remove autodetect for pem as well?
80  if(label == "PRIVATE KEY")
81  is_encrypted = false;
82  else if(label == "ENCRYPTED PRIVATE KEY")
83  {
84  DataSource_Memory key_source(key_data);
85  key_data = PKCS8_extract(key_source, pbe_alg_id);
86  }
87  else
88  throw PKCS8_Exception("Unknown PEM label " + label);
89  }
90 
91  if(key_data.empty())
92  throw PKCS8_Exception("No key data found");
93  }
94  catch(Decoding_Error& e)
95  {
96  throw Decoding_Error("PKCS #8 private key decoding failed: " + std::string(e.what()));
97  }
98 
99  try
100  {
101  if(is_encrypted)
102  {
103  if(OIDS::lookup(pbe_alg_id.oid) != "PBE-PKCS5v20")
104  throw Exception("Unknown PBE type " + pbe_alg_id.oid.as_string());
105  key = pbes2_decrypt(key_data, get_passphrase(), pbe_alg_id.parameters);
106  }
107  else
108  key = key_data;
109 
110  BER_Decoder(key)
112  .decode_and_check<size_t>(0, "Unknown PKCS #8 version number")
113  .decode(pk_alg_id)
114  .decode(key, OCTET_STRING)
115  .discard_remaining()
116  .end_cons();
117  }
118  catch(std::exception& e)
119  {
120  throw Decoding_Error("PKCS #8 private key decoding failed: " + std::string(e.what()));
121  }
122  return key;
123  }
124 
125 }
126 
127 /*
128 * BER encode a PKCS #8 private key, unencrypted
129 */
131  {
132  // keeping around for compat
133  return key.private_key_info();
134  }
135 
136 /*
137 * PEM encode a PKCS #8 private key, unencrypted
138 */
139 std::string PEM_encode(const Private_Key& key)
140  {
141  return PEM_Code::encode(PKCS8::BER_encode(key), "PRIVATE KEY");
142  }
143 
144 namespace {
145 
146 std::pair<std::string, std::string>
147 choose_pbe_params(const std::string& pbe_algo, const std::string& key_algo)
148  {
149  if(pbe_algo.empty())
150  {
151  // Defaults:
152  if(key_algo == "Curve25519" || key_algo == "McEliece")
153  return std::make_pair("AES-256/GCM", "SHA-512");
154  else // for everything else (RSA, DSA, ECDSA, GOST, ...)
155  return std::make_pair("AES-256/CBC", "SHA-256");
156  }
157 
158  SCAN_Name request(pbe_algo);
159  if(request.algo_name() != "PBE-PKCS5v20" || request.arg_count() != 2)
160  throw Exception("Unsupported PBE " + pbe_algo);
161  return std::make_pair(request.arg(1), request.arg(0));
162  }
163 
164 }
165 
166 /*
167 * BER encode a PKCS #8 private key, encrypted
168 */
169 std::vector<uint8_t> BER_encode(const Private_Key& key,
171  const std::string& pass,
172  std::chrono::milliseconds msec,
173  const std::string& pbe_algo)
174  {
175  const auto pbe_params = choose_pbe_params(pbe_algo, key.algo_name());
176 
177  const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info =
178  pbes2_encrypt_msec(PKCS8::BER_encode(key), pass, msec, nullptr,
179  pbe_params.first, pbe_params.second, rng);
180 
181  return DER_Encoder()
183  .encode(pbe_info.first)
184  .encode(pbe_info.second, OCTET_STRING)
185  .end_cons()
187  }
188 
189 /*
190 * PEM encode a PKCS #8 private key, encrypted
191 */
192 std::string PEM_encode(const Private_Key& key,
194  const std::string& pass,
195  std::chrono::milliseconds msec,
196  const std::string& pbe_algo)
197  {
198  if(pass.empty())
199  return PEM_encode(key);
200 
201  return PEM_Code::encode(PKCS8::BER_encode(key, rng, pass, msec, pbe_algo),
202  "ENCRYPTED PRIVATE KEY");
203  }
204 
205 /*
206 * BER encode a PKCS #8 private key, encrypted
207 */
208 std::vector<uint8_t> BER_encode_encrypted_pbkdf_iter(const Private_Key& key,
210  const std::string& pass,
211  size_t pbkdf_iterations,
212  const std::string& cipher,
213  const std::string& pbkdf_hash)
214  {
215  const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info =
217  pass, pbkdf_iterations,
218  cipher.empty() ? "AES-256/CBC" : cipher,
219  pbkdf_hash.empty() ? "SHA-256" : pbkdf_hash,
220  rng);
221 
222  return DER_Encoder()
224  .encode(pbe_info.first)
225  .encode(pbe_info.second, OCTET_STRING)
226  .end_cons()
228  }
229 
230 /*
231 * PEM encode a PKCS #8 private key, encrypted
232 */
235  const std::string& pass,
236  size_t pbkdf_iterations,
237  const std::string& cipher,
238  const std::string& pbkdf_hash)
239  {
240  return PEM_Code::encode(
241  PKCS8::BER_encode_encrypted_pbkdf_iter(key, rng, pass, pbkdf_iterations, cipher, pbkdf_hash),
242  "ENCRYPTED PRIVATE KEY");
243  }
244 
245 /*
246 * BER encode a PKCS #8 private key, encrypted
247 */
248 std::vector<uint8_t> BER_encode_encrypted_pbkdf_msec(const Private_Key& key,
250  const std::string& pass,
251  std::chrono::milliseconds pbkdf_msec,
252  size_t* pbkdf_iterations,
253  const std::string& cipher,
254  const std::string& pbkdf_hash)
255  {
256  const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info =
258  pbkdf_msec, pbkdf_iterations,
259  cipher.empty() ? "AES-256/CBC" : cipher,
260  pbkdf_hash.empty() ? "SHA-256" : pbkdf_hash,
261  rng);
262 
263  return DER_Encoder()
265  .encode(pbe_info.first)
266  .encode(pbe_info.second, OCTET_STRING)
267  .end_cons()
269  }
270 
271 /*
272 * PEM encode a PKCS #8 private key, encrypted
273 */
276  const std::string& pass,
277  std::chrono::milliseconds pbkdf_msec,
278  size_t* pbkdf_iterations,
279  const std::string& cipher,
280  const std::string& pbkdf_hash)
281  {
282  return PEM_Code::encode(
283  PKCS8::BER_encode_encrypted_pbkdf_msec(key, rng, pass, pbkdf_msec, pbkdf_iterations, cipher, pbkdf_hash),
284  "ENCRYPTED PRIVATE KEY");
285  }
286 
287 namespace {
288 
289 /*
290 * Extract a private key (encrypted/unencrypted) and return it
291 */
293  RandomNumberGenerator& /*rng*/,
294  std::function<std::string ()> get_pass,
295  bool is_encrypted)
296  {
297  AlgorithmIdentifier alg_id;
298  secure_vector<uint8_t> pkcs8_key = PKCS8_decode(source, get_pass, alg_id, is_encrypted);
299 
300  const std::string alg_name = OIDS::lookup(alg_id.oid);
301  if(alg_name.empty() || alg_name == alg_id.oid.as_string())
302  throw PKCS8_Exception("Unknown algorithm OID: " +
303  alg_id.oid.as_string());
304 
305  return load_private_key(alg_id, pkcs8_key).release();
306  }
307 
308 }
309 
310 /*
311 * Extract an encrypted private key and return it
312 */
315  std::function<std::string ()> get_pass)
316  {
317  return load_key(source, rng, get_pass, true);
318  }
319 
320 /*
321 * Extract an encrypted private key and return it
322 */
325  const std::string& pass)
326  {
327  return load_key(source, rng, [pass]() { return pass; }, true);
328  }
329 
330 /*
331 * Extract an unencrypted private key and return it
332 */
335  {
336  return load_key(source, rng, []() -> std::string {
337  throw PKCS8_Exception( "Internal error: Attempt to read password for unencrypted key" );}, false);
338  }
339 
340 #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
341 
342 /*
343 * Extract an encrypted private key and return it
344 */
345 Private_Key* load_key(const std::string& fsname,
347  std::function<std::string ()> get_pass)
348  {
349  DataSource_Stream source(fsname, true);
350  return load_key(source, rng, get_pass, true);
351  }
352 
353 /*
354 * Extract an encrypted private key and return it
355 */
356 Private_Key* load_key(const std::string& fsname,
357  RandomNumberGenerator& rng,
358  const std::string& pass)
359  {
360  return PKCS8::load_key(fsname, rng, [pass]() { return pass; });
361  }
362 
363 /*
364 * Extract an unencrypted private key and return it
365 */
366 Private_Key* load_key(const std::string& fsname,
367  RandomNumberGenerator& rng)
368  {
369  DataSource_Stream source(fsname, true);
370  return load_key(source, rng, []() -> std::string {
371  throw PKCS8_Exception( "Internal error: Attempt to read password for unencrypted key" );}, false);
372  }
373 #endif
374 
375 /*
376 * Make a copy of this private key
377 */
380  {
381  DataSource_Memory source(PEM_encode(key));
382  return PKCS8::load_key(source, rng);
383  }
384 
385 }
386 
387 }
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:208
secure_vector< uint8_t > decode(DataSource &source, std::string &label)
Definition: pem.cpp:68
std::vector< uint8_t > get_contents_unlocked()
Definition: der_enc.h:27
std::vector< uint8_t > parameters
Definition: alg_id.h:39
std::string encode(const uint8_t der[], size_t length, const std::string &label, size_t width)
Definition: pem.cpp:43
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:153
BER_Decoder & decode_and_check(const T &expected, const std::string &error_msg)
Definition: ber_dec.h:146
secure_vector< uint8_t > BER_encode(const Private_Key &key)
Definition: pkcs8.cpp:130
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:233
virtual std::string algo_name() const =0
BER_Decoder & decode(bool &v)
Definition: ber_dec.cpp:376
bool maybe_BER(DataSource &source)
Definition: asn1_obj.cpp:55
std::string PEM_encode(const Private_Key &key)
Definition: pkcs8.cpp:139
DER_Encoder & end_cons()
Definition: der_enc.cpp:147
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:134
Private_Key * load_key(DataSource &source, RandomNumberGenerator &rng, std::function< std::string()> get_pass)
Definition: pkcs8.cpp:313
DER_Encoder & encode(bool b)
Definition: der_enc.cpp:216
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:121
std::string lookup(const OID &oid)
Definition: oids.cpp:18
virtual bool end_of_data() const =0
const char * what() const BOTAN_NOEXCEPT override
Definition: exceptn.h:26
BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: ber_dec.cpp:258
Private_Key * copy_key(const Private_Key &key, RandomNumberGenerator &rng)
Definition: pkcs8.cpp:378
Definition: alg_id.cpp:13
size_t read_byte(uint8_t &out)
Definition: data_src.cpp:22
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:164
bool matches(DataSource &source, const std::string &extra, size_t search_range)
Definition: pem.cpp:140
secure_vector< uint8_t > private_key_info() const
Definition: pk_keys.cpp:41
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:248
BER_Decoder & verify_end()
Definition: ber_dec.cpp:168
std::string as_string() const
Definition: asn1_oid.cpp:50
DER_Encoder & start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: der_enc.cpp:137
std::unique_ptr< Private_Key > load_private_key(const AlgorithmIdentifier &alg_id, const secure_vector< uint8_t > &key_bits)
Definition: pk_algs.cpp:133
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:274