~ubuntu-branches/ubuntu/precise/botan1.8/precise

« back to all changes in this revision

Viewing changes to src/pubkey/pk_codecs/pkcs8.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Baumann
  • Date: 2009-08-04 00:47:32 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20090804004732-bmf7f33nfoctocbz
Tags: 1.8.5-1
* Merging upstream version 1.8.5.
* Adding old changelog entries for separately uploaded botan packages
  in the past.
* Using correct rfc-2822 date formats in changelog.
* Wrapping build depends.
* Adding misc depends.
* Renaming local manpages directory to common name.
* Minimizing rules file.
* Doing some minor cosmetical updates in the manpage.
* Updating copyright file to reflect changes of upstream version
  1.8.0.
* Using new configure.py instread of configure.pl, updating necessary
  things to cope with that.
* Updating.
* Tidy debhelper install files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
* PKCS #8
 
3
* (C) 1999-2008 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/pk_algs.h>
 
14
#include <botan/oids.h>
 
15
#include <botan/pem.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.is_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 u32bit MAX_TRIES = 3;
 
81
 
 
82
   u32bit 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, key_data.size());
 
105
            key = decryptor.read_all();
 
106
            }
 
107
 
 
108
         u32bit version;
 
109
 
 
110
         BER_Decoder(key)
 
111
            .start_cons(SEQUENCE)
 
112
               .decode(version)
 
113
               .decode(pk_alg_id)
 
114
               .decode(key, OCTET_STRING)
 
115
               .discard_remaining()
 
116
            .end_cons();
 
117
 
 
118
         if(version != 0)
 
119
            throw Decoding_Error("PKCS #8: Unknown version number");
 
120
 
 
121
         break;
 
122
         }
 
123
      catch(Decoding_Error)
 
124
         {
 
125
         ++tries;
 
126
         }
 
127
      }
 
128
 
 
129
   if(key.is_empty())
 
130
      throw Decoding_Error("PKCS #8 private key decoding failed");
 
131
   return key;
 
132
   }
 
133
 
 
134
}
 
135
 
 
136
/*
 
137
* DER or PEM encode a PKCS #8 private key
 
138
*/
 
139
void encode(const Private_Key& key, Pipe& pipe, X509_Encoding encoding)
 
140
   {
 
141
   std::auto_ptr<PKCS8_Encoder> encoder(key.pkcs8_encoder());
 
142
   if(!encoder.get())
 
143
      throw Encoding_Error("PKCS8::encode: Key does not support encoding");
 
144
 
 
145
   const u32bit PKCS8_VERSION = 0;
 
146
 
 
147
   SecureVector<byte> contents =
 
148
      DER_Encoder()
 
149
         .start_cons(SEQUENCE)
 
150
            .encode(PKCS8_VERSION)
 
151
            .encode(encoder->alg_id())
 
152
            .encode(encoder->key_bits(), OCTET_STRING)
 
153
         .end_cons()
 
154
      .get_contents();
 
155
 
 
156
   if(encoding == PEM)
 
157
      pipe.write(PEM_Code::encode(contents, "PRIVATE KEY"));
 
158
   else
 
159
      pipe.write(contents);
 
160
   }
 
161
 
 
162
/*
 
163
* Encode and encrypt a PKCS #8 private key
 
164
*/
 
165
void encrypt_key(const Private_Key& key,
 
166
                 Pipe& pipe,
 
167
                 RandomNumberGenerator& rng,
 
168
                 const std::string& pass, const std::string& pbe_algo,
 
169
                 X509_Encoding encoding)
 
170
   {
 
171
   const std::string DEFAULT_PBE = "PBE-PKCS5v20(SHA-1,TripleDES/CBC)";
 
172
 
 
173
   Pipe raw_key;
 
174
   raw_key.start_msg();
 
175
   encode(key, raw_key, RAW_BER);
 
176
   raw_key.end_msg();
 
177
 
 
178
   std::auto_ptr<PBE> pbe(get_pbe(((pbe_algo != "") ? pbe_algo : DEFAULT_PBE)));
 
179
 
 
180
   pbe->new_params(rng);
 
181
   pbe->set_key(pass);
 
182
 
 
183
   AlgorithmIdentifier pbe_algid(pbe->get_oid(), pbe->encode_params());
 
184
 
 
185
   Pipe key_encrytor(pbe.release());
 
186
   key_encrytor.process_msg(raw_key);
 
187
 
 
188
   SecureVector<byte> enc_key =
 
189
      DER_Encoder()
 
190
         .start_cons(SEQUENCE)
 
191
            .encode(pbe_algid)
 
192
            .encode(key_encrytor.read_all(), OCTET_STRING)
 
193
         .end_cons()
 
194
      .get_contents();
 
195
 
 
196
   if(encoding == PEM)
 
197
      pipe.write(PEM_Code::encode(enc_key, "ENCRYPTED PRIVATE KEY"));
 
198
   else
 
199
      pipe.write(enc_key);
 
200
   }
 
201
 
 
202
/*
 
203
* PEM encode a PKCS #8 private key
 
204
*/
 
205
std::string PEM_encode(const Private_Key& key)
 
206
   {
 
207
   Pipe pem;
 
208
   pem.start_msg();
 
209
   encode(key, pem, PEM);
 
210
   pem.end_msg();
 
211
   return pem.read_all_as_string();
 
212
   }
 
213
 
 
214
/*
 
215
* Encrypt and PEM encode a PKCS #8 private key
 
216
*/
 
217
std::string PEM_encode(const Private_Key& key,
 
218
                       RandomNumberGenerator& rng,
 
219
                       const std::string& pass,
 
220
                       const std::string& pbe_algo)
 
221
   {
 
222
   if(pass == "")
 
223
      return PEM_encode(key);
 
224
 
 
225
   Pipe pem;
 
226
   pem.start_msg();
 
227
   encrypt_key(key, pem, rng, pass, pbe_algo, PEM);
 
228
   pem.end_msg();
 
229
   return pem.read_all_as_string();
 
230
   }
 
231
 
 
232
/*
 
233
* Extract a private key and return it
 
234
*/
 
235
Private_Key* load_key(DataSource& source,
 
236
                      RandomNumberGenerator& rng,
 
237
                      const User_Interface& ui)
 
238
   {
 
239
   AlgorithmIdentifier alg_id;
 
240
   SecureVector<byte> pkcs8_key = PKCS8_decode(source, ui, alg_id);
 
241
 
 
242
   const std::string alg_name = OIDS::lookup(alg_id.oid);
 
243
   if(alg_name == "" || alg_name == alg_id.oid.as_string())
 
244
      throw PKCS8_Exception("Unknown algorithm OID: " +
 
245
                            alg_id.oid.as_string());
 
246
 
 
247
   std::auto_ptr<Private_Key> key(get_private_key(alg_name));
 
248
 
 
249
   if(!key.get())
 
250
      throw PKCS8_Exception("Unknown PK algorithm/OID: " + alg_name + ", " +
 
251
                           alg_id.oid.as_string());
 
252
 
 
253
   std::auto_ptr<PKCS8_Decoder> decoder(key->pkcs8_decoder(rng));
 
254
 
 
255
   if(!decoder.get())
 
256
      throw Decoding_Error("Key does not support PKCS #8 decoding");
 
257
 
 
258
   decoder->alg_id(alg_id);
 
259
   decoder->key_bits(pkcs8_key);
 
260
 
 
261
   return key.release();
 
262
   }
 
263
 
 
264
/*
 
265
* Extract a private key and return it
 
266
*/
 
267
Private_Key* load_key(const std::string& fsname,
 
268
                      RandomNumberGenerator& rng,
 
269
                      const User_Interface& ui)
 
270
   {
 
271
   DataSource_Stream source(fsname, true);
 
272
   return PKCS8::load_key(source, rng, ui);
 
273
   }
 
274
 
 
275
/*
 
276
* Extract a private key and return it
 
277
*/
 
278
Private_Key* load_key(DataSource& source,
 
279
                      RandomNumberGenerator& rng,
 
280
                      const std::string& pass)
 
281
   {
 
282
   return PKCS8::load_key(source, rng, User_Interface(pass));
 
283
   }
 
284
 
 
285
/*
 
286
* Extract a private key and return it
 
287
*/
 
288
Private_Key* load_key(const std::string& fsname,
 
289
                      RandomNumberGenerator& rng,
 
290
                      const std::string& pass)
 
291
   {
 
292
   return PKCS8::load_key(fsname, rng, User_Interface(pass));
 
293
   }
 
294
 
 
295
/*
 
296
* Make a copy of this private key
 
297
*/
 
298
Private_Key* copy_key(const Private_Key& key,
 
299
                      RandomNumberGenerator& rng)
 
300
   {
 
301
   Pipe bits;
 
302
 
 
303
   bits.start_msg();
 
304
   PKCS8::encode(key, bits);
 
305
   bits.end_msg();
 
306
 
 
307
   DataSource_Memory source(bits.read_all());
 
308
   return PKCS8::load_key(source, rng);
 
309
   }
 
310
 
 
311
}
 
312
 
 
313
}