Botan  1.10.9
pkcs8.cpp
Go to the documentation of this file.
1 /*
2 * PKCS #8
3 * (C) 1999-2010 Jack Lloyd
4 *
5 * Distributed under the terms of the Botan license
6 */
7 
8 #include <botan/pkcs8.h>
9 #include <botan/get_pbe.h>
10 #include <botan/der_enc.h>
11 #include <botan/ber_dec.h>
12 #include <botan/asn1_obj.h>
13 #include <botan/oids.h>
14 #include <botan/pem.h>
15 #include <botan/internal/pk_algs.h>
16 #include <memory>
17 
18 namespace Botan {
19 
20 namespace PKCS8 {
21 
22 namespace {
23 
24 /*
25 * Get info from an EncryptedPrivateKeyInfo
26 */
27 SecureVector<byte> PKCS8_extract(DataSource& source,
28  AlgorithmIdentifier& pbe_alg_id)
29  {
30  SecureVector<byte> 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 SecureVector<byte> PKCS8_decode(DataSource& source, const User_Interface& ui,
45  AlgorithmIdentifier& pk_alg_id)
46  {
47  AlgorithmIdentifier pbe_alg_id;
48  SecureVector<byte> key_data, key;
49  bool is_encrypted = true;
50 
51  try {
52  if(ASN1::maybe_BER(source) && !PEM_Code::matches(source))
53  key_data = PKCS8_extract(source, pbe_alg_id);
54  else
55  {
56  std::string label;
57  key_data = PEM_Code::decode(source, label);
58  if(label == "PRIVATE KEY")
59  is_encrypted = false;
60  else if(label == "ENCRYPTED PRIVATE KEY")
61  {
62  DataSource_Memory key_source(key_data);
63  key_data = PKCS8_extract(key_source, pbe_alg_id);
64  }
65  else
66  throw PKCS8_Exception("Unknown PEM label " + label);
67  }
68 
69  if(key_data.empty())
70  throw PKCS8_Exception("No key data found");
71  }
72  catch(Decoding_Error)
73  {
74  throw Decoding_Error("PKCS #8 private key decoding failed");
75  }
76 
77  if(!is_encrypted)
78  key = key_data;
79 
80  const size_t MAX_TRIES = 3;
81 
82  size_t tries = 0;
83  while(true)
84  {
85  try {
86  if(MAX_TRIES && tries >= MAX_TRIES)
87  break;
88 
89  if(is_encrypted)
90  {
91  DataSource_Memory params(pbe_alg_id.parameters);
92  std::auto_ptr<PBE> pbe(get_pbe(pbe_alg_id.oid, params));
93 
95  const std::string passphrase =
96  ui.get_passphrase("PKCS #8 private key", source.id(), result);
97 
98  if(result == User_Interface::CANCEL_ACTION)
99  break;
100 
101  pbe->set_key(passphrase);
102  Pipe decryptor(pbe.release());
103 
104  decryptor.process_msg(key_data);
105  key = decryptor.read_all();
106  }
107 
108  BER_Decoder(key)
110  .decode_and_check<size_t>(0, "Unknown PKCS #8 version number")
111  .decode(pk_alg_id)
112  .decode(key, OCTET_STRING)
113  .discard_remaining()
114  .end_cons();
115 
116  break;
117  }
118  catch(Decoding_Error)
119  {
120  ++tries;
121  }
122  }
123 
124  if(key.empty())
125  throw Decoding_Error("PKCS #8 private key decoding failed");
126  return key;
127  }
128 
129 }
130 
131 /*
132 * BER encode a PKCS #8 private key, unencrypted
133 */
135  {
136  const size_t PKCS8_VERSION = 0;
137 
138  return DER_Encoder()
140  .encode(PKCS8_VERSION)
143  .end_cons()
144  .get_contents();
145  }
146 
147 /*
148 * PEM encode a PKCS #8 private key, unencrypted
149 */
150 std::string PEM_encode(const Private_Key& key)
151  {
152  return PEM_Code::encode(PKCS8::BER_encode(key), "PRIVATE KEY");
153  }
154 
155 /*
156 * BER encode a PKCS #8 private key, encrypted
157 */
160  const std::string& pass,
161  const std::string& pbe_algo)
162  {
163  const std::string DEFAULT_PBE = "PBE-PKCS5v20(SHA-1,AES-256/CBC)";
164 
165  std::auto_ptr<PBE> pbe(get_pbe(((pbe_algo != "") ? pbe_algo : DEFAULT_PBE)));
166 
167  pbe->new_params(rng);
168  pbe->set_key(pass);
169 
170  AlgorithmIdentifier pbe_algid(pbe->get_oid(), pbe->encode_params());
171 
172  Pipe key_encrytor(pbe.release());
173  key_encrytor.process_msg(PKCS8::BER_encode(key));
174 
175  return DER_Encoder()
177  .encode(pbe_algid)
178  .encode(key_encrytor.read_all(), OCTET_STRING)
179  .end_cons()
180  .get_contents();
181  }
182 
183 /*
184 * PEM encode a PKCS #8 private key, encrypted
185 */
186 std::string PEM_encode(const Private_Key& key,
188  const std::string& pass,
189  const std::string& pbe_algo)
190  {
191  if(pass == "")
192  return PEM_encode(key);
193 
194  return PEM_Code::encode(PKCS8::BER_encode(key, rng, pass, pbe_algo),
195  "ENCRYPTED PRIVATE KEY");
196  }
197 
198 /*
199 * Extract a private key and return it
200 */
203  const User_Interface& ui)
204  {
205  AlgorithmIdentifier alg_id;
206  SecureVector<byte> pkcs8_key = PKCS8_decode(source, ui, alg_id);
207 
208  const std::string alg_name = OIDS::lookup(alg_id.oid);
209  if(alg_name == "" || alg_name == alg_id.oid.as_string())
210  throw PKCS8_Exception("Unknown algorithm OID: " +
211  alg_id.oid.as_string());
212 
213  return make_private_key(alg_id, pkcs8_key, rng);
214  }
215 
216 /*
217 * Extract a private key and return it
218 */
219 Private_Key* load_key(const std::string& fsname,
221  const User_Interface& ui)
222  {
223  DataSource_Stream source(fsname, true);
224  return PKCS8::load_key(source, rng, ui);
225  }
226 
227 /*
228 * Extract a private key and return it
229 */
232  const std::string& pass)
233  {
234  return PKCS8::load_key(source, rng, User_Interface(pass));
235  }
236 
237 /*
238 * Extract a private key and return it
239 */
240 Private_Key* load_key(const std::string& fsname,
242  const std::string& pass)
243  {
244  return PKCS8::load_key(fsname, rng, User_Interface(pass));
245  }
246 
247 /*
248 * Make a copy of this private key
249 */
252  {
253  DataSource_Memory source(PEM_encode(key));
254  return PKCS8::load_key(source, rng);
255  }
256 
257 }
258 
259 }
virtual MemoryVector< byte > pkcs8_private_key() const =0
SecureVector< byte > get_contents()
Definition: der_enc.cpp:122
SecureVector< byte > BER_encode(const Private_Key &key)
Definition: pkcs8.cpp:134
BER_Decoder & decode(bool &)
Definition: ber_dec.cpp:338
BER_Decoder & decode_and_check(const T &expected, const std::string &error_msg)
Definition: ber_dec.h:62
bool maybe_BER(DataSource &source)
Definition: asn1_int.cpp:55
SecureVector< byte > parameters
Definition: alg_id.h:36
std::string PEM_encode(const Private_Key &key)
Definition: pkcs8.cpp:150
Private_Key * make_private_key(const AlgorithmIdentifier &alg_id, const MemoryRegion< byte > &key_bits, RandomNumberGenerator &rng)
Definition: pk_algs.cpp:104
BER_Decoder start_cons(ASN1_Tag, ASN1_Tag=UNIVERSAL)
Definition: ber_dec.cpp:232
SecureVector< byte > decode(DataSource &source, std::string &label)
Definition: pem.cpp:56
DER_Encoder & encode(bool b)
Definition: der_enc.cpp:209
RandomNumberGenerator * rng
Definition: global_rng.cpp:165
virtual std::string id() const
Definition: data_src.h:57
void encode(const Private_Key &key, Pipe &pipe, X509_Encoding encoding=PEM)
Definition: pkcs8.h:85
std::string lookup(const OID &oid)
Definition: oids.cpp:31
bool empty() const
Definition: secmem.h:35
virtual AlgorithmIdentifier pkcs8_algorithm_identifier() const
Definition: pk_keys.h:98
Private_Key * copy_key(const Private_Key &key, RandomNumberGenerator &rng)
Definition: pkcs8.cpp:250
bool matches(DataSource &source, const std::string &extra, size_t search_range)
Definition: pem.cpp:116
std::string encode(const byte der[], size_t length, const std::string &label, size_t width)
Definition: pem.cpp:19
BER_Decoder & verify_end()
Definition: ber_dec.cpp:160
std::string as_string() const
Definition: asn1_oid.cpp:50
PBE * get_pbe(const std::string &algo_spec)
Definition: get_pbe.cpp:27
DER_Encoder & start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: der_enc.cpp:135
Private_Key * load_key(DataSource &source, RandomNumberGenerator &rng, const User_Interface &ui)
Definition: pkcs8.cpp:201
virtual std::string get_passphrase(const std::string &, const std::string &, UI_Result &) const
Definition: ui.cpp:15
void process_msg(const byte in[], size_t length)
Definition: pipe.cpp:116