Botan 2.1.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 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)
33 .start_cons(SEQUENCE)
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)
111 .start_cons(SEQUENCE)
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 */
130 secure_vector<uint8_t> BER_encode(const Private_Key& key)
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,
170 RandomNumberGenerator& rng,
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()
182 .start_cons(SEQUENCE)
183 .encode(pbe_info.first)
184 .encode(pbe_info.second, OCTET_STRING)
185 .end_cons()
186 .get_contents_unlocked();
187 }
188
189 /*
190 * PEM encode a PKCS #8 private key, encrypted
191 */
192 std::string PEM_encode(const Private_Key& key,
193 RandomNumberGenerator& rng,
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,
209 RandomNumberGenerator& rng,
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 =
216 pbes2_encrypt_iter(key.private_key_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()
223 .start_cons(SEQUENCE)
224 .encode(pbe_info.first)
225 .encode(pbe_info.second, OCTET_STRING)
226 .end_cons()
227 .get_contents_unlocked();
228 }
229
230 /*
231 * PEM encode a PKCS #8 private key, encrypted
232 */
233 std::string PEM_encode_encrypted_pbkdf_iter(const Private_Key& key,
234 RandomNumberGenerator& rng,
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,
249 RandomNumberGenerator& rng,
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 =
257 pbes2_encrypt_msec(key.private_key_info(), pass,
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()
264 .start_cons(SEQUENCE)
265 .encode(pbe_info.first)
266 .encode(pbe_info.second, OCTET_STRING)
267 .end_cons()
268 .get_contents_unlocked();
269 }
270
271 /*
272 * PEM encode a PKCS #8 private key, encrypted
273 */
274 std::string PEM_encode_encrypted_pbkdf_msec(const Private_Key& key,
275 RandomNumberGenerator& rng,
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 */
292 Private_Key* load_key(DataSource& source,
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 */
313 Private_Key* load_key(DataSource& source,
314 RandomNumberGenerator& rng,
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 */
323 Private_Key* load_key(DataSource& source,
324 RandomNumberGenerator& rng,
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 */
333 Private_Key* load_key(DataSource& source,
334 RandomNumberGenerator& rng)
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,
346 RandomNumberGenerator& rng,
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 */
378 Private_Key* copy_key(const Private_Key& key,
379 RandomNumberGenerator& rng)
380 {
381 DataSource_Memory source(PEM_encode(key));
382 return PKCS8::load_key(source, rng);
383 }
384
385 }
386
387 }
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:208
Botan::DataSource_Stream
Definition: data_src.h:143
Botan::PEM_Code::decode
secure_vector< uint8_t > decode(DataSource &source, std::string &label)
Definition: pem.cpp:68
Botan::Exception
Definition: exceptn.h:21
Botan::DER_Encoder::get_contents_unlocked
std::vector< uint8_t > get_contents_unlocked()
Definition: der_enc.h:27
Botan::RandomNumberGenerator
Definition: rng.h:25
Botan::AlgorithmIdentifier::parameters
std::vector< uint8_t > parameters
Definition: alg_id.h:39
Botan::Private_Key
Definition: pk_keys.h:166
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::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:153
Botan::BER_Decoder::decode_and_check
BER_Decoder & decode_and_check(const T &expected, const std::string &error_msg)
Definition: ber_dec.h:146
Botan::PKCS8::BER_encode
secure_vector< uint8_t > BER_encode(const Private_Key &key)
Definition: pkcs8.cpp:130
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:233
Botan::Public_Key::algo_name
virtual std::string algo_name() const =0
Botan::BER_Decoder::decode
BER_Decoder & decode(bool &v)
Definition: ber_dec.cpp:376
Botan::ASN1::maybe_BER
bool maybe_BER(DataSource &source)
Definition: asn1_obj.cpp:55
Botan::PKCS8::PEM_encode
std::string PEM_encode(const Private_Key &key)
Definition: pkcs8.cpp:139
Botan::DER_Encoder::end_cons
DER_Encoder & end_cons()
Definition: der_enc.cpp:147
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:134
Botan::DataSource
Definition: data_src.h:21
Botan::PKCS8::load_key
Private_Key * load_key(DataSource &source, RandomNumberGenerator &rng, std::function< std::string()> get_pass)
Definition: pkcs8.cpp:313
Botan::DER_Encoder::encode
DER_Encoder & encode(bool b)
Definition: der_enc.cpp:216
Botan::OCTET_STRING
Definition: asn1_obj.h:35
Botan::DER_Encoder
Definition: der_enc.h:22
Botan::secure_vector
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:121
Botan::OIDS::lookup
std::string lookup(const OID &oid)
Definition: oids.cpp:18
Botan::DataSource::end_of_data
virtual bool end_of_data() const =0
Botan::AlgorithmIdentifier::oid
OID oid
Definition: alg_id.h:36
Botan::Decoding_Error
Definition: exceptn.h:189
Botan::Exception::what
const char * what() const BOTAN_NOEXCEPT override
Definition: exceptn.h:26
Botan::SEQUENCE
Definition: asn1_obj.h:39
Botan::BER_Decoder::start_cons
BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: ber_dec.cpp:258
Botan::PKCS8::copy_key
Private_Key * copy_key(const Private_Key &key, RandomNumberGenerator &rng)
Definition: pkcs8.cpp:378
Botan
Definition: alg_id.cpp:13
Botan::DataSource::read_byte
size_t read_byte(uint8_t &out)
Definition: data_src.cpp:22
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:164
Botan::PEM_Code::matches
bool matches(DataSource &source, const std::string &extra, size_t search_range)
Definition: pem.cpp:140
Botan::Private_Key::private_key_info
secure_vector< uint8_t > private_key_info() const
Definition: pk_keys.cpp:41
Botan::PKCS8_Exception
Definition: pkcs8.h:20
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:248
Botan::BER_Decoder::verify_end
BER_Decoder & verify_end()
Definition: ber_dec.cpp:168
Botan::DataSource_Memory
Definition: data_src.h:98
Botan::OID::as_string
std::string as_string() const
Definition: asn1_oid.cpp:50
Botan::AlgorithmIdentifier
Definition: alg_id.h:20
Botan::DER_Encoder::start_cons
DER_Encoder & start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: der_enc.cpp:137
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:133
Botan::BER_Decoder
Definition: ber_dec.h:19
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:274