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
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)
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 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
94 User_Interface::UI_Result result = User_Interface::OK;
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)
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 */
134 SecureVector<byte> BER_encode(const Private_Key& key)
135 {
136 const size_t PKCS8_VERSION = 0;
137
138 return DER_Encoder()
139 .start_cons(SEQUENCE)
140 .encode(PKCS8_VERSION)
141 .encode(key.pkcs8_algorithm_identifier())
142 .encode(key.pkcs8_private_key(), OCTET_STRING)
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 */
158 SecureVector<byte> BER_encode(const Private_Key& key,
159 RandomNumberGenerator& rng,
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()
176 .start_cons(SEQUENCE)
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,
187 RandomNumberGenerator& rng,
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 */
201 Private_Key* load_key(DataSource& source,
202 RandomNumberGenerator& rng,
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,
220 RandomNumberGenerator& rng,
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 */
230 Private_Key* load_key(DataSource& source,
231 RandomNumberGenerator& rng,
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,
241 RandomNumberGenerator& rng,
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 */
250 Private_Key* copy_key(const Private_Key& key,
251 RandomNumberGenerator& rng)
252 {
253 DataSource_Memory source(PEM_encode(key));
254 return PKCS8::load_key(source, rng);
255 }
256
257 }
258
259 }
Botan::Private_Key::pkcs8_private_key
virtual MemoryVector< byte > pkcs8_private_key() const =0
Botan::DataSource_Stream
Definition: data_src.h:128
Botan::DER_Encoder::get_contents
SecureVector< byte > get_contents()
Definition: der_enc.cpp:122
Botan::User_Interface
Definition: ui.h:20
Botan::User_Interface::OK
Definition: ui.h:23
Botan::PKCS8::BER_encode
SecureVector< byte > BER_encode(const Private_Key &key)
Definition: pkcs8.cpp:134
Botan::RandomNumberGenerator
Definition: rng.h:20
Botan::Private_Key
Definition: pk_keys.h:86
Botan::BER_Decoder::decode
BER_Decoder & decode(bool &)
Definition: ber_dec.cpp:344
Botan::BER_Decoder::decode_and_check
BER_Decoder & decode_and_check(const T &expected, const std::string &error_msg)
Definition: ber_dec.h:62
Botan::OID::as_string
std::string as_string() const
Definition: asn1_oid.cpp:50
Botan::ASN1::maybe_BER
bool maybe_BER(DataSource &source)
Definition: asn1_int.cpp:55
Botan::AlgorithmIdentifier::parameters
SecureVector< byte > parameters
Definition: alg_id.h:36
Botan::PKCS8::PEM_encode
std::string PEM_encode(const Private_Key &key)
Definition: pkcs8.cpp:150
Botan::DataSource
Definition: data_src.h:20
Botan::make_private_key
Private_Key * make_private_key(const AlgorithmIdentifier &alg_id, const MemoryRegion< byte > &key_bits, RandomNumberGenerator &rng)
Definition: pk_algs.cpp:104
Botan::BER_Decoder::start_cons
BER_Decoder start_cons(ASN1_Tag, ASN1_Tag=UNIVERSAL)
Definition: ber_dec.cpp:238
Botan::PEM_Code::decode
SecureVector< byte > decode(DataSource &source, std::string &label)
Definition: pem.cpp:56
Botan::MemoryRegion::empty
bool empty() const
Definition: secmem.h:35
Botan::DER_Encoder::encode
DER_Encoder & encode(bool b)
Definition: der_enc.cpp:209
Botan::OCTET_STRING
Definition: asn1_int.h:31
Botan::DER_Encoder
Definition: der_enc.h:22
Botan::User_Interface::UI_Result
UI_Result
Definition: ui.h:23
Botan::PKCS8::encode
void encode(const Private_Key &key, Pipe &pipe, X509_Encoding encoding=PEM)
Definition: pkcs8.h:85
Botan::OIDS::lookup
std::string lookup(const OID &oid)
Definition: oids.cpp:31
Botan::AlgorithmIdentifier::oid
OID oid
Definition: alg_id.h:35
Botan::Decoding_Error
Definition: exceptn.h:138
Botan::SEQUENCE
Definition: asn1_int.h:35
Botan::PKCS8::copy_key
Private_Key * copy_key(const Private_Key &key, RandomNumberGenerator &rng)
Definition: pkcs8.cpp:250
Botan
Definition: algo_base.h:14
Botan::PEM_Code::matches
bool matches(DataSource &source, const std::string &extra, size_t search_range)
Definition: pem.cpp:116
Botan::DataSource::id
virtual std::string id() const
Definition: data_src.h:57
Botan::PKCS8_Exception
Definition: pkcs8.h:19
Botan::PEM_Code::encode
std::string encode(const byte der[], size_t length, const std::string &label, size_t width)
Definition: pem.cpp:19
Botan::User_Interface::CANCEL_ACTION
Definition: ui.h:23
Botan::BER_Decoder::verify_end
BER_Decoder & verify_end()
Definition: ber_dec.cpp:163
Botan::DataSource_Memory
Definition: data_src.h:94
Botan::get_pbe
PBE * get_pbe(const std::string &algo_spec)
Definition: get_pbe.cpp:27
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:135
Botan::User_Interface::get_passphrase
virtual std::string get_passphrase(const std::string &, const std::string &, UI_Result &) const
Definition: ui.cpp:15
Botan::SecureVector< byte >
Botan::Pipe
Definition: pipe.h:25
Botan::PKCS8::load_key
Private_Key * load_key(DataSource &source, RandomNumberGenerator &rng, const User_Interface &ui)
Definition: pkcs8.cpp:201
Botan::BER_Decoder
Definition: ber_dec.h:19
Botan::Pipe::process_msg
void process_msg(const byte in[], size_t length)
Definition: pipe.cpp:116
Botan::Private_Key::pkcs8_algorithm_identifier
virtual AlgorithmIdentifier pkcs8_algorithm_identifier() const
Definition: pk_keys.h:98