Botan 1.10.17
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
18namespace Botan {
19
20namespace PKCS8 {
21
22namespace {
23
24/*
25* Get info from an EncryptedPrivateKeyInfo
26*/
27SecureVector<byte> PKCS8_extract(DataSource& source,
28 AlgorithmIdentifier& pbe_alg_id)
29 {
30 SecureVector<byte> 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*/
44SecureVector<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
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)
109 .start_cons(SEQUENCE)
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*/
150std::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*/
186std::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*/
219Private_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*/
240Private_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}
SecureVector< byte > parameters
Definition alg_id.h:36
BER_Decoder(DataSource &)
Definition ber_dec.cpp:264
DER_Encoder & start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition der_enc.cpp:135
SecureVector< byte > get_contents()
Definition der_enc.cpp:122
DER_Encoder & end_cons()
Definition der_enc.cpp:145
DER_Encoder & encode(bool b)
Definition der_enc.cpp:209
virtual std::string id() const
Definition data_src.h:57
bool empty() const
Definition secmem.h:35
std::string as_string() const
Definition asn1_oid.cpp:50
SecureVector< byte > read_all(message_id msg=DEFAULT_MESSAGE)
Definition pipe_rw.cpp:105
void process_msg(const byte in[], size_t length)
Definition pipe.cpp:116
virtual MemoryVector< byte > pkcs8_private_key() const =0
virtual AlgorithmIdentifier pkcs8_algorithm_identifier() const
Definition pk_keys.h:98
virtual std::string get_passphrase(const std::string &, const std::string &, UI_Result &) const
Definition ui.cpp:15
User_Interface(const std::string &="")
Definition ui.cpp:30
bool maybe_BER(DataSource &source)
Definition asn1_int.cpp:55
std::string lookup(const OID &oid)
Definition oids.cpp:31
std::string encode(const byte der[], size_t length, const std::string &label, size_t width)
Definition pem.cpp:19
bool matches(DataSource &source, const std::string &extra, size_t search_range)
Definition pem.cpp:116
SecureVector< byte > decode(DataSource &source, std::string &label)
Definition pem.cpp:56
SecureVector< byte > BER_encode(const Private_Key &key)
Definition pkcs8.cpp:134
Private_Key * copy_key(const Private_Key &key, RandomNumberGenerator &rng)
Definition pkcs8.cpp:250
Private_Key * load_key(DataSource &source, RandomNumberGenerator &rng, const User_Interface &ui)
Definition pkcs8.cpp:201
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
@ SEQUENCE
Definition asn1_int.h:35
@ OCTET_STRING
Definition asn1_int.h:31
PBE * get_pbe(const std::string &algo_spec)
Definition get_pbe.cpp:27
Decoding_Error(const std::string &name)
Definition exceptn.h:140
PKCS8_Exception(const std::string &error)
Definition pkcs8.h:21