monotone

monotone Mtn Source Tree

Root/key_store.cc

1#include "base.hh"
2#include <sstream>
3
4#include "key_store.hh"
5#include "file_io.hh"
6#include "packet.hh"
7#include "database.hh"
8#include "keys.hh"
9#include "globish.hh"
10#include "app_state.hh"
11#include "transforms.hh"
12#include "constants.hh"
13#include "ssh_agent.hh"
14#include "safe_map.hh"
15
16#include "botan/botan.h"
17#include "botan/rsa.h"
18#include "botan/keypair.h"
19#include "botan/pem.h"
20#include "botan_pipe_cache.hh"
21
22using std::make_pair;
23using std::istringstream;
24using std::map;
25using std::ostringstream;
26using std::pair;
27using std::string;
28using std::vector;
29
30using boost::scoped_ptr;
31using boost::shared_ptr;
32using boost::shared_dynamic_cast;
33
34using Botan::RSA_PrivateKey;
35using Botan::RSA_PublicKey;
36using Botan::SecureVector;
37using Botan::X509_PublicKey;
38using Botan::PKCS8_PrivateKey;
39using Botan::PK_Decryptor;
40using Botan::PK_Signer;
41using Botan::Pipe;
42
43struct key_store_state
44{
45 system_path const key_dir;
46 string const ssh_sign_mode;
47 bool have_read;
48 lua_hooks & lua;
49 map<rsa_keypair_id, keypair> keys;
50 map<id, rsa_keypair_id> hashes;
51
52 // These are used to cache keys and signers (if the hook allows).
53 map<rsa_keypair_id, shared_ptr<RSA_PrivateKey> > privkey_cache;
54 map<rsa_keypair_id, shared_ptr<PK_Signer> > signer_cache;
55
56 // Initialized when first required.
57 scoped_ptr<ssh_agent> agent;
58
59 key_store_state(app_state & app)
60 : key_dir(app.opts.key_dir), ssh_sign_mode(app.opts.ssh_sign),
61 have_read(false), lua(app.lua)
62 {
63 N(app.opts.key_dir_given
64 || app.opts.conf_dir_given
65 || !app.opts.no_default_confdir,
66 F("No available keystore found"));
67 }
68
69 // internal methods
70 void get_key_file(rsa_keypair_id const & ident, system_path & file);
71 void write_key(rsa_keypair_id const & ident, keypair const & kp);
72 void maybe_read_key_dir();
73 shared_ptr<RSA_PrivateKey> decrypt_private_key(rsa_keypair_id const & id,
74 bool force_from_user = false);
75
76 // just like put_key_pair except that the key is _not_ written to disk.
77 // for internal use in reading keys back from disk.
78 bool put_key_pair_memory(rsa_keypair_id const & ident,
79 keypair const & kp);
80
81 // wrapper around accesses to agent, initializes as needed
82 ssh_agent & get_agent()
83 {
84 if (!agent)
85 agent.reset(new ssh_agent);
86 return *agent;
87 }
88
89 // duplicates of key_store interfaces for use by key_store_state methods
90 // and the keyreader.
91 bool maybe_get_key_pair(rsa_keypair_id const & ident,
92 keypair & kp);
93 bool put_key_pair(rsa_keypair_id const & ident,
94 keypair const & kp);
95 void migrate_old_key_pair(rsa_keypair_id const & id,
96 old_arc4_rsa_priv_key const & old_priv,
97 rsa_pub_key const & pub);
98};
99
100namespace
101{
102 struct keyreader : public packet_consumer
103 {
104 key_store_state & kss;
105
106 keyreader(key_store_state & kss): kss(kss) {}
107 virtual void consume_file_data(file_id const & ident,
108 file_data const & dat)
109 {E(false, F("Extraneous data in key store."));}
110 virtual void consume_file_delta(file_id const & id_old,
111 file_id const & id_new,
112 file_delta const & del)
113 {E(false, F("Extraneous data in key store."));}
114
115 virtual void consume_revision_data(revision_id const & ident,
116 revision_data const & dat)
117 {E(false, F("Extraneous data in key store."));}
118 virtual void consume_revision_cert(revision<cert> const & t)
119 {E(false, F("Extraneous data in key store."));}
120
121
122 virtual void consume_public_key(rsa_keypair_id const & ident,
123 rsa_pub_key const & k)
124 {E(false, F("Extraneous data in key store."));}
125
126 virtual void consume_key_pair(rsa_keypair_id const & ident,
127 keypair const & kp)
128 {
129 L(FL("reading key pair '%s' from key store") % ident);
130
131 E(kss.put_key_pair_memory(ident, kp),
132 F("Key store has multiple keys with id '%s'.") % ident);
133
134 L(FL("successfully read key pair '%s' from key store") % ident);
135 }
136
137 // for backward compatibility
138 virtual void consume_old_private_key(rsa_keypair_id const & ident,
139 old_arc4_rsa_priv_key const & k)
140 {
141 W(F("converting old-format private key '%s'") % ident);
142
143 rsa_pub_key dummy;
144 kss.migrate_old_key_pair(ident, k, dummy);
145
146 L(FL("successfully read key pair '%s' from key store") % ident);
147 }
148 };
149}
150
151key_store::key_store(app_state & a)
152 : s(new key_store_state(a))
153{}
154
155key_store::~key_store()
156{}
157
158system_path const &
159key_store::get_key_dir()
160{
161 return s->key_dir;
162}
163
164void
165key_store_state::maybe_read_key_dir()
166{
167 if (have_read)
168 return;
169 have_read = true;
170
171 vector<path_component> key_files, dirs;
172 if (directory_exists(key_dir))
173 {
174 L(FL("reading key dir '%s'") % key_dir);
175 read_directory(key_dir, key_files, dirs);
176 }
177 else
178 {
179 L(FL("key dir '%s' does not exist") % key_dir);
180 return;
181 }
182
183 keyreader kr(*this);
184 for (vector<path_component>::const_iterator i = key_files.begin();
185 i != key_files.end(); ++i)
186 {
187 L(FL("reading keys from file '%s'") % (*i));
188 data dat;
189 read_data(key_dir / *i, dat);
190 istringstream is(dat());
191 read_packets(is, kr);
192 }
193}
194
195void
196key_store::get_key_ids(globish const & pattern,
197 vector<rsa_keypair_id> & priv)
198{
199 s->maybe_read_key_dir();
200 priv.clear();
201 for (map<rsa_keypair_id, keypair>::const_iterator
202 i = s->keys.begin(); i != s->keys.end(); ++i)
203 if (pattern.matches((i->first)()))
204 priv.push_back(i->first);
205}
206
207void
208key_store::get_key_ids(vector<rsa_keypair_id> & priv)
209{
210 s->maybe_read_key_dir();
211 priv.clear();
212 for (map<rsa_keypair_id, keypair>::const_iterator
213 i = s->keys.begin(); i != s->keys.end(); ++i)
214 priv.push_back(i->first);
215}
216
217bool
218key_store::key_pair_exists(rsa_keypair_id const & ident)
219{
220 s->maybe_read_key_dir();
221 return s->keys.find(ident) != s->keys.end();
222}
223
224bool
225key_store_state::maybe_get_key_pair(rsa_keypair_id const & ident,
226 keypair & kp)
227{
228 maybe_read_key_dir();
229 map<rsa_keypair_id, keypair>::const_iterator i = keys.find(ident);
230 if (i == keys.end())
231 return false;
232 kp = i->second;
233 return true;
234}
235
236bool
237key_store::maybe_get_key_pair(rsa_keypair_id const & ident,
238 keypair & kp)
239{
240 return s->maybe_get_key_pair(ident, kp);
241}
242
243void
244key_store::get_key_pair(rsa_keypair_id const & ident,
245 keypair & kp)
246{
247 bool found = maybe_get_key_pair(ident, kp);
248 I(found);
249}
250
251bool
252key_store::maybe_get_key_pair(id const & hash,
253 rsa_keypair_id & keyid,
254 keypair & kp)
255{
256 s->maybe_read_key_dir();
257 map<id, rsa_keypair_id>::const_iterator hi = s->hashes.find(hash);
258 if (hi == s->hashes.end())
259 return false;
260
261 map<rsa_keypair_id, keypair>::const_iterator ki = s->keys.find(hi->second);
262 if (ki == s->keys.end())
263 return false;
264 keyid = hi->second;
265 kp = ki->second;
266 return true;
267}
268
269void
270key_store_state::get_key_file(rsa_keypair_id const & ident,
271 system_path & file)
272{
273 // filename is the keypair id, except that some characters can't be put in
274 // filenames (especially on windows).
275 string leaf = ident();
276 for (unsigned int i = 0; i < leaf.size(); ++i)
277 if (leaf.at(i) == '+')
278 leaf.at(i) = '_';
279
280 file = key_dir / path_component(leaf);
281}
282
283void
284key_store_state::write_key(rsa_keypair_id const & ident,
285 keypair const & kp)
286{
287 ostringstream oss;
288 packet_writer pw(oss);
289 pw.consume_key_pair(ident, kp);
290 data dat(oss.str());
291
292 system_path file;
293 get_key_file(ident, file);
294
295 // Make sure the private key is not readable by anyone other than the user.
296 L(FL("writing key '%s' to file '%s' in dir '%s'") % ident % file % key_dir);
297 write_data_userprivate(file, dat, key_dir);
298}
299
300bool
301key_store_state::put_key_pair(rsa_keypair_id const & ident,
302 keypair const & kp)
303{
304 maybe_read_key_dir();
305 bool newkey = put_key_pair_memory(ident, kp);
306 if (newkey)
307 write_key(ident, kp);
308 return newkey;
309}
310
311bool
312key_store::put_key_pair(rsa_keypair_id const & ident,
313 keypair const & kp)
314{
315 return s->put_key_pair(ident, kp);
316}
317
318bool
319key_store_state::put_key_pair_memory(rsa_keypair_id const & ident,
320 keypair const & kp)
321{
322 L(FL("putting key pair '%s'") % ident);
323 pair<map<rsa_keypair_id, keypair>::iterator, bool> res;
324 res = keys.insert(make_pair(ident, kp));
325 if (res.second)
326 {
327 id hash;
328 key_hash_code(ident, kp.pub, hash);
329 I(hashes.insert(make_pair(hash, ident)).second);
330 return true;
331 }
332 else
333 {
334 E(keys_match(ident, res.first->second.pub, ident, kp.pub),
335 F("Cannot store key '%s': a different key by that name exists.")
336 % ident);
337 L(FL("skipping existing key pair %s") % ident);
338 return false;
339 }
340}
341
342void
343key_store::delete_key(rsa_keypair_id const & ident)
344{
345 s->maybe_read_key_dir();
346 map<rsa_keypair_id, keypair>::iterator i = s->keys.find(ident);
347 if (i != s->keys.end())
348 {
349 id hash;
350 key_hash_code(ident, i->second.pub, hash);
351 map<id, rsa_keypair_id>::iterator j = s->hashes.find(hash);
352 I(j != s->hashes.end());
353 s->hashes.erase(j);
354 s->keys.erase(i);
355 s->signer_cache.erase(ident);
356 s->privkey_cache.erase(ident);
357 }
358 system_path file;
359 s->get_key_file(ident, file);
360 delete_file(file);
361}
362
363//
364// Crypto operations
365//
366
367shared_ptr<RSA_PrivateKey>
368key_store_state::decrypt_private_key(rsa_keypair_id const & id,
369 bool force_from_user)
370{
371 // See if we have this key in the decrypted key cache.
372 map<rsa_keypair_id, shared_ptr<RSA_PrivateKey> >::const_iterator
373 cpk = privkey_cache.find(id);
374 if (cpk != privkey_cache.end())
375 return cpk->second;
376
377 keypair kp;
378 N(maybe_get_key_pair(id, kp),
379 F("no key pair '%s' found in key store '%s'") % id % key_dir);
380
381 L(FL("%d-byte private key") % kp.priv().size());
382
383 shared_ptr<PKCS8_PrivateKey> pkcs8_key;
384 try // with empty passphrase
385 {
386 Botan::DataSource_Memory ds(kp.priv());
387 pkcs8_key.reset(Botan::PKCS8::load_key(ds, ""));
388 }
389 catch (Botan::Exception & e)
390 {
391 L(FL("failed to load key with no passphrase: %s") % e.what());
392
393 utf8 phrase;
394 string lua_phrase;
395 // See whether a lua hook will tell us the passphrase.
396 if (!force_from_user && lua.hook_get_passphrase(id, lua_phrase))
397 phrase = utf8(lua_phrase);
398 else
399 get_passphrase(phrase, id, false, false);
400
401 int cycles = 1;
402 for (;;)
403 try
404 {
405 Botan::DataSource_Memory ds(kp.priv());
406 pkcs8_key.reset(Botan::PKCS8::load_key(ds, phrase()));
407 break;
408 }
409 catch (Botan::Exception & e)
410 {
411 L(FL("decrypt_private_key: failure %d to load encrypted key: %s")
412 % cycles % e.what());
413 E(cycles <= 3,
414 F("failed to decrypt old private RSA key, "
415 "probably incorrect passphrase"));
416
417 get_passphrase(phrase, id, false, false);
418 cycles++;
419 continue;
420 }
421 }
422
423 I(pkcs8_key);
424
425 shared_ptr<RSA_PrivateKey> priv_key;
426 priv_key = shared_dynamic_cast<RSA_PrivateKey>(pkcs8_key);
427 E(priv_key,
428 F("failed to extract RSA private key from PKCS#8 keypair"));
429
430 // Cache the decrypted key if we're allowed.
431 if (lua.hook_persist_phrase_ok())
432 safe_insert(privkey_cache, make_pair(id, priv_key));
433
434 return priv_key;
435}
436
437void
438key_store::cache_decrypted_key(const rsa_keypair_id & id)
439{
440 signing_key = id;
441 if (s->lua.hook_persist_phrase_ok())
442 s->decrypt_private_key(id);
443}
444
445void
446key_store::create_key_pair(database & db,
447 rsa_keypair_id const & id,
448 utf8 const * maybe_passphrase,
449 id * maybe_pubhash,
450 id * maybe_privhash)
451{
452 conditional_transaction_guard guard(db);
453
454 bool exists = key_pair_exists(id);
455 if (db.database_specified())
456 {
457 guard.acquire();
458 exists = exists || db.public_key_exists(id);
459 }
460 N(!exists, F("key '%s' already exists") % id);
461
462 utf8 prompted_passphrase;
463 if (!maybe_passphrase)
464 {
465 get_passphrase(prompted_passphrase, id, true, true);
466 maybe_passphrase = &prompted_passphrase;
467 }
468
469 // okay, now we can create the key
470 P(F("generating key-pair '%s'") % id);
471 RSA_PrivateKey priv(constants::keylen);
472
473 // serialize and maybe encrypt the private key
474 keypair kp;
475 SecureVector<Botan::byte> pubkey, privkey;
476
477 unfiltered_pipe->start_msg();
478 if ((*maybe_passphrase)().length())
479 Botan::PKCS8::encrypt_key(priv, *unfiltered_pipe,
480 (*maybe_passphrase)(),
481 "PBE-PKCS5v20(SHA-1,TripleDES/CBC)",
482 Botan::RAW_BER);
483 else
484 Botan::PKCS8::encode(priv, *unfiltered_pipe);
485 unfiltered_pipe->end_msg();
486 kp.priv = rsa_priv_key(unfiltered_pipe->read_all_as_string(Pipe::LAST_MESSAGE));
487
488 // serialize the public key
489 unfiltered_pipe->start_msg();
490 Botan::X509::encode(priv, *unfiltered_pipe, Botan::RAW_BER);
491 unfiltered_pipe->end_msg();
492 kp.pub = rsa_pub_key(unfiltered_pipe->read_all_as_string(Pipe::LAST_MESSAGE));
493
494 // convert to storage format
495 L(FL("generated %d-byte public key\n"
496 "generated %d-byte (encrypted) private key\n")
497 % kp.pub().size()
498 % kp.priv().size());
499
500 // and save it.
501 P(F("storing key-pair '%s' in %s/") % id % get_key_dir());
502 put_key_pair(id, kp);
503
504 if (db.database_specified())
505 {
506 P(F("storing public key '%s' in %s") % id % db.get_filename());
507 db.put_key(id, kp.pub);
508 guard.commit();
509 }
510
511 if (maybe_pubhash)
512 key_hash_code(id, kp.pub, *maybe_pubhash);
513 if (maybe_privhash)
514 key_hash_code(id, kp.priv, *maybe_privhash);
515}
516
517void
518key_store::change_key_passphrase(rsa_keypair_id const & id)
519{
520 keypair kp;
521 load_key_pair(*this, id, kp);
522 shared_ptr<RSA_PrivateKey> priv = s->decrypt_private_key(id, true);
523
524 utf8 new_phrase;
525 get_passphrase(new_phrase, id, true, false);
526
527 unfiltered_pipe->start_msg();
528 Botan::PKCS8::encrypt_key(*priv, *unfiltered_pipe, new_phrase(),
529 "PBE-PKCS5v20(SHA-1,TripleDES/CBC)",
530 Botan::RAW_BER);
531 unfiltered_pipe->end_msg();
532 kp.priv = rsa_priv_key(unfiltered_pipe->read_all_as_string(Pipe::LAST_MESSAGE));
533
534 delete_key(id);
535 put_key_pair(id, kp);
536}
537
538void
539key_store::decrypt_rsa(rsa_keypair_id const & id,
540 rsa_oaep_sha_data const & ciphertext,
541 string & plaintext)
542{
543 keypair kp;
544 load_key_pair(*this, id, kp);
545 shared_ptr<RSA_PrivateKey> priv_key = s->decrypt_private_key(id);
546
547 shared_ptr<PK_Decryptor>
548 decryptor(get_pk_decryptor(*priv_key, "EME1(SHA-1)"));
549
550 SecureVector<Botan::byte> plain = decryptor->decrypt(
551 reinterpret_cast<Botan::byte const *>(ciphertext().data()),
552 ciphertext().size());
553 plaintext = string(reinterpret_cast<char const*>(plain.begin()),
554 plain.size());
555}
556
557void
558key_store::make_signature(database & db,
559 rsa_keypair_id const & id,
560 string const & tosign,
561 rsa_sha1_signature & signature)
562{
563 keypair key;
564 get_key_pair(id, key);
565
566 // If the database doesn't have this public key, add it now.
567 if (!db.public_key_exists(id))
568 db.put_key(id, key.pub);
569
570 string sig_string;
571 ssh_agent & agent = s->get_agent();
572
573 //sign with ssh-agent (if connected)
574 N(agent.connected() || s->ssh_sign_mode != "only",
575 F("You have chosen to sign only with ssh-agent but ssh-agent"
576 " does not seem to be running."));
577 if (s->ssh_sign_mode == "yes"
578 || s->ssh_sign_mode == "check"
579 || s->ssh_sign_mode == "only")
580 {
581 if (agent.connected()) {
582 //grab the monotone public key as an RSA_PublicKey
583 SecureVector<Botan::byte> pub_block;
584 pub_block.set(reinterpret_cast<Botan::byte const *>(key.pub().data()),
585 key.pub().size());
586 L(FL("make_signature: building %d-byte pub key") % pub_block.size());
587 shared_ptr<X509_PublicKey> x509_key =
588 shared_ptr<X509_PublicKey>(Botan::X509::load_key(pub_block));
589 shared_ptr<RSA_PublicKey> pub_key = shared_dynamic_cast<RSA_PublicKey>(x509_key);
590
591 if (!pub_key)
592 throw informative_failure("Failed to get monotone RSA public key");
593
594 agent.sign_data(*pub_key, tosign, sig_string);
595 }
596 if (sig_string.length() <= 0)
597 L(FL("make_signature: monotone and ssh-agent keys do not match, will"
598 " use monotone signing"));
599 }
600
601 string ssh_sig = sig_string;
602
603 N(ssh_sig.length() > 0 || s->ssh_sign_mode != "only",
604 F("You don't seem to have your monotone key imported "));
605
606 if (ssh_sig.length() <= 0
607 || s->ssh_sign_mode == "check"
608 || s->ssh_sign_mode == "no")
609 {
610 SecureVector<Botan::byte> sig;
611
612 // we permit the user to relax security here, by caching a decrypted key
613 // (if they permit it) through the life of a program run. this helps when
614 // you're making a half-dozen certs during a commit or merge or
615 // something.
616
617 bool persist_phrase = (!s->signer_cache.empty()
618 || s->lua.hook_persist_phrase_ok());
619
620 shared_ptr<PK_Signer> signer;
621 shared_ptr<RSA_PrivateKey> priv_key;
622 if (persist_phrase && s->signer_cache.find(id) != s->signer_cache.end())
623 signer = s->signer_cache[id];
624
625 else
626 {
627 priv_key = s->decrypt_private_key(id);
628 if (agent.connected()
629 && s->ssh_sign_mode != "only"
630 && s->ssh_sign_mode != "no") {
631 L(FL("make_signature: adding private key (%s) to ssh-agent") % id());
632 agent.add_identity(*priv_key, id());
633 }
634 signer = shared_ptr<PK_Signer>(get_pk_signer(*priv_key, "EMSA3(SHA-1)"));
635
636 /* If persist_phrase is true, the RSA_PrivateKey object is
637 cached in s->active_keys and will survive as long as the
638 PK_Signer object does. */
639 if (persist_phrase)
640 s->signer_cache.insert(make_pair(id, signer));
641 }
642
643 sig = signer->sign_message(reinterpret_cast<Botan::byte const *>(tosign.data()), tosign.size());
644 sig_string = string(reinterpret_cast<char const*>(sig.begin()), sig.size());
645 }
646
647 if (s->ssh_sign_mode == "check" && ssh_sig.length() > 0)
648 {
649 E(ssh_sig == sig_string,
650 F("make_signature: ssh signature (%i) != monotone signature (%i)\n"
651 "ssh signature : %s\n"
652 "monotone signature: %s")
653 % ssh_sig.length()
654 % sig_string.length()
655 % encode_hexenc(ssh_sig)
656 % encode_hexenc(sig_string));
657 L(FL("make_signature: signatures from ssh-agent and monotone"
658 " are the same"));
659 }
660
661 L(FL("make_signature: produced %d-byte signature") % sig_string.size());
662 signature = rsa_sha1_signature(sig_string);
663
664 cert_status s = db.check_signature(id, tosign, signature);
665 I(s != cert_unknown);
666 E(s == cert_ok, F("make_signature: signature is not valid"));
667}
668
669//
670// Interoperation with ssh-agent (see also above)
671//
672
673void
674key_store::add_key_to_agent(rsa_keypair_id const & id)
675{
676 ssh_agent & agent = s->get_agent();
677 N(agent.connected(),
678 F("no ssh-agent is available, cannot add key '%s'") % id);
679
680 shared_ptr<RSA_PrivateKey> priv = s->decrypt_private_key(id);
681 agent.add_identity(*priv, id());
682}
683
684void
685key_store::export_key_for_agent(rsa_keypair_id const & id,
686 std::ostream & os)
687{
688 shared_ptr<RSA_PrivateKey> priv = s->decrypt_private_key(id);
689 utf8 new_phrase;
690 get_passphrase(new_phrase, id, true, false);
691
692 // This pipe cannot sensibly be recycled.
693 Pipe p(new Botan::DataSink_Stream(os));
694 p.start_msg();
695 if (new_phrase().length())
696 Botan::PKCS8::encrypt_key(*priv,
697 p,
698 new_phrase(),
699 "PBE-PKCS5v20(SHA-1,TripleDES/CBC)");
700 else
701 Botan::PKCS8::encode(*priv, p);
702 p.end_msg();
703}
704
705
706//
707// Migration from old databases
708//
709
710void
711key_store_state::migrate_old_key_pair
712 (rsa_keypair_id const & id,
713 old_arc4_rsa_priv_key const & old_priv,
714 rsa_pub_key const & pub)
715{
716 keypair kp;
717 SecureVector<Botan::byte> arc4_key;
718 utf8 phrase;
719 shared_ptr<PKCS8_PrivateKey> pkcs8_key;
720 shared_ptr<RSA_PrivateKey> priv_key;
721
722 // See whether a lua hook will tell us the passphrase.
723 string lua_phrase;
724 if (lua.hook_get_passphrase(id, lua_phrase))
725 phrase = utf8(lua_phrase);
726 else
727 get_passphrase(phrase, id, false, false);
728
729 int cycles = 1;
730 for (;;)
731 try
732 {
733 arc4_key.set(reinterpret_cast<Botan::byte const *>(phrase().data()),
734 phrase().size());
735
736 Pipe arc4_decryptor(get_cipher("ARC4", arc4_key, Botan::DECRYPTION));
737 arc4_decryptor.process_msg(old_priv());
738
739 // This is necessary because PKCS8::load_key() cannot currently
740 // recognize an unencrypted, raw-BER blob as such, but gets it
741 // right if it's PEM-coded.
742 SecureVector<Botan::byte> arc4_decrypt(arc4_decryptor.read_all());
743 Botan::DataSource_Memory ds(Botan::PEM_Code::encode(arc4_decrypt,
744 "PRIVATE KEY"));
745 pkcs8_key.reset(Botan::PKCS8::load_key(ds));
746 break;
747 }
748 catch (Botan::Exception & e)
749 {
750 L(FL("migrate_old_key_pair: failure %d to load old private key: %s")
751 % cycles % e.what());
752
753 E(cycles <= 3,
754 F("failed to decrypt old private RSA key, "
755 "probably incorrect passphrase"));
756
757 get_passphrase(phrase, id, false, false);
758 cycles++;
759 continue;
760 }
761
762 priv_key = shared_dynamic_cast<RSA_PrivateKey>(pkcs8_key);
763 I(priv_key);
764
765 // now we can write out the new key
766 unfiltered_pipe->start_msg();
767 Botan::PKCS8::encrypt_key(*priv_key, *unfiltered_pipe, phrase(),
768 "PBE-PKCS5v20(SHA-1,TripleDES/CBC)",
769 Botan::RAW_BER);
770 unfiltered_pipe->end_msg();
771 kp.priv = rsa_priv_key(unfiltered_pipe->read_all_as_string(Pipe::LAST_MESSAGE));
772
773 // also the public key (which is derivable from the private key; asking
774 // Botan for the X.509 encoding of the private key implies that we want
775 // it to derive and produce the public key)
776 unfiltered_pipe->start_msg();
777 Botan::X509::encode(*priv_key, *unfiltered_pipe, Botan::RAW_BER);
778 unfiltered_pipe->end_msg();
779 kp.pub = rsa_pub_key(unfiltered_pipe->read_all_as_string(Pipe::LAST_MESSAGE));
780
781 // if the database had a public key entry for this key, make sure it
782 // matches what we derived from the private key entry, but don't abort the
783 // whole migration if it doesn't.
784 if (!pub().empty() && !keys_match(id, pub, id, kp.pub))
785 W(F("public and private keys for %s don't match") % id);
786
787 put_key_pair(id, kp);
788}
789
790void
791key_store::migrate_old_key_pair
792 (rsa_keypair_id const & id,
793 old_arc4_rsa_priv_key const & old_priv,
794 rsa_pub_key const & pub)
795{
796 s->migrate_old_key_pair(id, old_priv, pub);
797}
798
799// Local Variables:
800// mode: C++
801// fill-column: 76
802// c-file-style: "gnu"
803// indent-tabs-mode: nil
804// End:
805// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status