1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/KeyRing.cc
18 #include <boost/format.hpp>
20 #include "zypp/TmpPath.h"
21 #include "zypp/ZYppFactory.h"
22 #include "zypp/ZYpp.h"
24 #include "zypp/base/Logger.h"
25 #include "zypp/base/IOStream.h"
26 #include "zypp/base/String.h"
27 #include "zypp/base/Regex.h"
28 #include "zypp/base/Gettext.h"
29 #include "zypp/PathInfo.h"
30 #include "zypp/KeyRing.h"
31 #include "zypp/ExternalProgram.h"
32 #include "zypp/TmpPath.h"
35 using namespace zypp::filesystem;
37 #undef ZYPP_BASE_LOGGER_LOGGROUP
38 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::KeyRing"
40 #define GPG_BINARY "/usr/bin/gpg2"
42 ///////////////////////////////////////////////////////////////////
44 { /////////////////////////////////////////////////////////////////
46 IMPL_PTR_TYPE(KeyRing);
50 KeyRing::DefaultAccept _keyRingDefaultAccept( KeyRing::ACCEPT_NOTHING );
53 KeyRing::DefaultAccept KeyRing::defaultAccept()
54 { return _keyRingDefaultAccept; }
56 void KeyRing::setDefaultAccept( DefaultAccept value_r )
58 MIL << "Set new KeyRing::DefaultAccept: " << value_r << endl;
59 _keyRingDefaultAccept = value_r;
62 bool KeyRingReport::askUserToAcceptUnsignedFile( const string &file, const KeyContext &keycontext )
63 { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_UNSIGNED_FILE ); }
65 KeyRingReport::KeyTrust
66 KeyRingReport::askUserToAcceptKey( const PublicKey &key, const KeyContext &keycontext )
68 if ( _keyRingDefaultAccept.testFlag( KeyRing::TRUST_KEY_TEMPORARILY ) )
69 return KEY_TRUST_TEMPORARILY;
70 if ( _keyRingDefaultAccept.testFlag( KeyRing::TRUST_AND_IMPORT_KEY ) )
71 return KEY_TRUST_AND_IMPORT;
72 return KEY_DONT_TRUST;
75 bool KeyRingReport::askUserToAcceptUnknownKey( const string &file, const string &id, const KeyContext &keycontext )
76 { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_UNKNOWNKEY ); }
78 bool KeyRingReport::askUserToAcceptVerificationFailed( const string &file, const PublicKey &key, const KeyContext &keycontext )
79 { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_VERIFICATION_FAILED ); }
81 ///////////////////////////////////////////////////////////////////
83 // CLASS NAME : KeyRing::Impl
85 /** KeyRing implementation. */
88 Impl( const Pathname & baseTmpDir )
89 : _trusted_tmp_dir( baseTmpDir, "zypp-trusted-kr" )
90 , _general_tmp_dir( baseTmpDir, "zypp-general-kr" )
91 , _base_dir( baseTmpDir )
93 MIL << "Current KeyRing::DefaultAccept: " << _keyRingDefaultAccept << endl;
96 void importKey( const PublicKey &key, bool trusted = false);
97 void multiKeyImport( const Pathname & keyfile_r, bool trusted_r = false);
98 void deleteKey( const string &id, bool trusted );
100 string readSignatureKeyId( const Pathname &signature );
102 bool isKeyTrusted( const string &id);
103 bool isKeyKnown( const string &id );
105 list<PublicKey> trustedPublicKeys();
106 list<PublicKey> publicKeys();
108 list<string> trustedPublicKeyIds();
109 list<string> publicKeyIds();
111 void dumpPublicKey( const string &id, bool trusted, ostream &stream );
113 bool verifyFileSignatureWorkflow(
114 const Pathname &file,
115 const string filedesc,
116 const Pathname &signature,
117 const KeyContext &keycontext = KeyContext());
119 bool verifyFileSignature( const Pathname &file, const Pathname &signature);
120 bool verifyFileTrustedSignature( const Pathname &file, const Pathname &signature);
122 //mutable map<Locale, string> translations;
123 bool verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring);
124 void importKey( const Pathname &keyfile, const Pathname &keyring);
125 PublicKey exportKey( string id, const Pathname &keyring);
126 void dumpPublicKey( const string &id, const Pathname &keyring, ostream &stream );
127 void deleteKey( const string &id, const Pathname &keyring );
129 list<PublicKey> publicKeys(const Pathname &keyring);
130 list<string> publicKeyIds(const Pathname &keyring);
132 bool publicKeyExists( string id, const Pathname &keyring);
134 const Pathname generalKeyRing() const;
135 const Pathname trustedKeyRing() const;
137 // Used for trusted and untrusted keyrings
138 TmpDir _trusted_tmp_dir;
139 TmpDir _general_tmp_dir;
142 /** Offer default Impl. */
143 static shared_ptr<Impl> nullimpl()
145 static shared_ptr<Impl> _nullimpl( new Impl( TmpPath::defaultLocation() ) );
150 friend Impl * rwcowClone<Impl>( const Impl * rhs );
151 /** clone for RWCOW_pointer */
153 { return new Impl( *this ); }
157 const Pathname KeyRing::Impl::generalKeyRing() const
159 return _general_tmp_dir.path();
162 const Pathname KeyRing::Impl::trustedKeyRing() const
164 return _trusted_tmp_dir.path();
167 void KeyRing::Impl::importKey( const PublicKey &key, bool trusted)
169 callback::SendReport<target::rpm::KeyRingSignals> rpmdbEmitSignal;
170 callback::SendReport<KeyRingSignals> emitSignal;
172 importKey( key.path(), trusted ? trustedKeyRing() : generalKeyRing() );
176 rpmdbEmitSignal->trustedKeyAdded( key );
177 emitSignal->trustedKeyAdded( key );
181 void KeyRing::Impl::multiKeyImport( const Pathname & keyfile_r, bool trusted_r )
183 importKey( keyfile_r, trusted_r ? trustedKeyRing() : generalKeyRing() );
186 void KeyRing::Impl::deleteKey( const string &id, bool trusted)
192 key = exportKey(id, trustedKeyRing());
195 deleteKey( id, trusted ? trustedKeyRing() : generalKeyRing() );
199 callback::SendReport<target::rpm::KeyRingSignals> rpmdbEmitSignal;
200 callback::SendReport<KeyRingSignals> emitSignal;
202 rpmdbEmitSignal->trustedKeyRemoved( key );
203 emitSignal->trustedKeyRemoved( key );
207 list<PublicKey> KeyRing::Impl::publicKeys()
209 return publicKeys( generalKeyRing() );
212 list<PublicKey> KeyRing::Impl::trustedPublicKeys()
214 return publicKeys( trustedKeyRing() );
217 list<string> KeyRing::Impl::publicKeyIds()
219 return publicKeyIds( generalKeyRing() );
222 list<string> KeyRing::Impl::trustedPublicKeyIds()
224 return publicKeyIds( trustedKeyRing() );
227 bool KeyRing::Impl::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
229 return verifyFile( file, signature, trustedKeyRing() );
232 bool KeyRing::Impl::verifyFileSignature( const Pathname &file, const Pathname &signature)
234 return verifyFile( file, signature, generalKeyRing() );
237 bool KeyRing::Impl::isKeyTrusted( const string &id)
239 return publicKeyExists( id, trustedKeyRing() );
242 bool KeyRing::Impl::isKeyKnown( const string &id )
245 if ( publicKeyExists( id, trustedKeyRing() ) )
248 return publicKeyExists( id, generalKeyRing() );
251 bool KeyRing::Impl::publicKeyExists( string id, const Pathname &keyring)
253 MIL << "Searching key [" << id << "] in keyring " << keyring << endl;
254 list<PublicKey> keys = publicKeys(keyring);
255 for (list<PublicKey>::const_iterator it = keys.begin(); it != keys.end(); it++)
257 if ( id == (*it).id() )
264 PublicKey KeyRing::Impl::exportKey( string id, const Pathname &keyring)
266 TmpFile tmp_file( _base_dir, "pubkey-"+id+"-" );
267 MIL << "Going to export key " << id << " from " << keyring << " to " << tmp_file.path() << endl;
270 ofstream os(tmp_file.path().c_str());
271 dumpPublicKey( id, keyring, os );
273 return PublicKey( tmp_file );
275 catch (BadKeyException &e)
277 ERR << "Cannot create public key " << id << " from " << keyring << " keyring to file " << e.keyFile() << endl;
278 // TranslatorExplanation first %s is key name, second is keyring name
279 // and third is keyfile name
280 ZYPP_THROW(Exception(boost::str(boost::format(
281 _("Cannot create public key %s from %s keyring to file %s"))
282 % id % keyring.asString() % e.keyFile().asString())));
286 ERR << "Cannot export key " << id << " from " << keyring << " keyring to file " << tmp_file.path() << endl;
291 void KeyRing::Impl::dumpPublicKey( const string &id, bool trusted, ostream &stream )
293 dumpPublicKey( id, ( trusted ? trustedKeyRing() : generalKeyRing() ), stream );
296 void KeyRing::Impl::dumpPublicKey( const string &id, const Pathname &keyring, ostream &stream )
301 "--no-default-keyring",
305 "--no-permission-warning",
308 keyring.asString().c_str(),
314 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
317 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
325 bool KeyRing::Impl::verifyFileSignatureWorkflow(
326 const Pathname &file,
327 const string filedesc,
328 const Pathname &signature,
329 const KeyContext &context)
331 callback::SendReport<KeyRingReport> report;
332 //callback::SendReport<KeyRingSignals> emitSignal;
333 MIL << "Going to verify signature for " << filedesc << " ( " << file << " ) with " << signature << endl;
335 // if signature does not exists, ask user if he wants to accept unsigned file.
336 if( signature.empty() || (!PathInfo(signature).isExist()) )
338 bool res = report->askUserToAcceptUnsignedFile( filedesc, context );
339 MIL << "User decision on unsigned file: " << res << endl;
343 // get the id of the signature
344 string id = readSignatureKeyId(signature);
346 // doeskey exists in trusted keyring
347 if ( publicKeyExists( id, trustedKeyRing() ) )
349 PublicKey key = exportKey( id, trustedKeyRing() );
351 // lets look if there is an updated key in the
353 if ( publicKeyExists( id, generalKeyRing() ) )
355 // bnc #393160: Comment #30: Compare at least the fingerprint
356 // in case an attacker created a key the the same id.
357 PublicKey untkey = exportKey( id, generalKeyRing() );
358 if ( untkey.fingerprint() == key.fingerprint()
359 && untkey.created() > key.created() )
361 MIL << "Key " << key << " was updated. Saving new version into trusted keyring." << endl;
362 importKey( untkey, true );
367 MIL << "Key " << id << " " << key.name() << " is trusted" << endl;
368 // it exists, is trusted, does it validates?
369 if ( verifyFile( file, signature, trustedKeyRing() ) )
372 return report->askUserToAcceptVerificationFailed( filedesc, key, context );
376 if ( publicKeyExists( id, generalKeyRing() ) )
378 PublicKey key = exportKey( id, generalKeyRing());
379 MIL << "Exported key " << id << " to " << key.path() << endl;
380 MIL << "Key " << id << " " << key.name() << " is not trusted" << endl;
382 // ok the key is not trusted, ask the user to trust it or not
383 KeyRingReport::KeyTrust reply = report->askUserToAcceptKey(key, context);
384 if (reply == KeyRingReport::KEY_TRUST_TEMPORARILY ||
385 reply == KeyRingReport::KEY_TRUST_AND_IMPORT)
387 MIL << "User wants to trust key " << id << " " << key.name() << endl;
388 //dumpFile(unKey.path());
390 Pathname which_keyring;
391 if (reply == KeyRingReport::KEY_TRUST_AND_IMPORT)
393 MIL << "User wants to import key " << id << " " << key.name() << endl;
394 importKey( key, true );
395 which_keyring = trustedKeyRing();
398 which_keyring = generalKeyRing();
401 if ( verifyFile( file, signature, which_keyring ) )
403 MIL << "File signature is verified" << endl;
408 MIL << "File signature check fails" << endl;
409 if ( report->askUserToAcceptVerificationFailed( filedesc, key, context ) )
411 MIL << "User continues anyway." << endl;
416 MIL << "User does not want to continue" << endl;
423 MIL << "User does not want to trust key " << id << " " << key.name() << endl;
430 MIL << "File [" << file << "] ( " << filedesc << " ) signed with unknown key [" << id << "]" << endl;
431 if ( report->askUserToAcceptUnknownKey( filedesc, id, context ) )
433 MIL << "User wants to accept unknown key " << id << endl;
438 MIL << "User does not want to accept unknown key " << id << endl;
446 list<string> KeyRing::Impl::publicKeyIds(const Pathname &keyring)
448 static str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
449 static str::regex rxColonsFpr("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
456 "--no-default-keyring",
458 "--list-public-keys",
460 "--with-fingerprint",
467 keyring.asString().c_str(),
471 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
475 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
477 //MIL << line << endl;
479 if(str::regex_match(line, what, rxColons))
483 if ( what[1] == "pub" )
488 for(line2 = prog.receiveLine(); !line2.empty(); line2 = prog.receiveLine(), count++ )
491 if (str::regex_match(line2, what2, rxColonsFpr))
493 if ( (what2[1] == "fpr") && (what2[1] != "pub") && (what2[1] !="sub"))
495 fingerprint = what2[10];
502 MIL << "Found key " << "[" << id << "]" << endl;
504 //dumpRegexpResults(what);
511 list<PublicKey> KeyRing::Impl::publicKeys(const Pathname &keyring)
514 list<PublicKey> keys;
516 list<string> ids = publicKeyIds(keyring);
518 for ( list<string>::const_iterator it = ids.begin(); it != ids.end(); ++it )
520 PublicKey key(exportKey( *it, keyring ));
522 MIL << "Found key " << "[" << key.id() << "]" << " [" << key.name() << "]" << " [" << key.fingerprint() << "]" << endl;
527 void KeyRing::Impl::importKey( const Pathname &keyfile, const Pathname &keyring)
529 if ( ! PathInfo(keyfile).isExist() )
530 // TranslatorExplanation first %s is key name, second is keyring name
531 ZYPP_THROW(KeyRingException(boost::str(boost::format(
532 _("Tried to import not existant key %s into keyring %s"))
533 % keyfile.asString() % keyring.asString())));
538 "--no-default-keyring",
542 "--no-permission-warning",
546 keyring.asString().c_str(),
548 keyfile.asString().c_str(),
553 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
557 // ZYPP_THROW(Exception("failed to import key"));
560 void KeyRing::Impl::deleteKey( const string &id, const Pathname &keyring )
565 "--no-default-keyring",
573 keyring.asString().c_str(),
579 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
581 int code = prog.close();
583 ZYPP_THROW(Exception(_("Failed to delete key.")));
585 MIL << "Deleted key " << id << " from keyring " << keyring << endl;
589 string KeyRing::Impl::readSignatureKeyId(const Pathname &signature )
591 if ( ! PathInfo(signature).isFile() )
592 ZYPP_THROW(Exception(boost::str(boost::format(
593 _("Signature file %s not found"))% signature.asString())));
595 MIL << "Determining key id if signature " << signature << endl;
596 // HACK create a tmp keyring with no keys
597 TmpDir dir(_base_dir, "fake-keyring");
602 "--no-default-keyring",
610 dir.path().asString().c_str(),
611 signature.asString().c_str(),
615 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
620 str::regex rxNoKey("^\\[GNUPG:\\] NO_PUBKEY (.+)\n$");
622 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
624 //MIL << "[" << line << "]" << endl;
626 if(str::regex_match(line, what, rxNoKey))
628 if ( what.size() >= 1 )
633 //dumpRegexpResults(what);
639 MIL << "no output" << endl;
642 MIL << "Determined key id [" << id << "] for signature " << signature << endl;
647 bool KeyRing::Impl::verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring)
652 "--no-default-keyring",
660 keyring.asString().c_str(),
662 signature.asString().c_str(),
663 file.asString().c_str(),
667 // no need to parse output for now
668 // [GNUPG:] SIG_ID yCc4u223XRJnLnVAIllvYbUd8mQ 2006-03-29 1143618744
669 // [GNUPG:] GOODSIG A84EDAE89C800ACA SuSE Package Signing Key <build@suse.de>
670 // gpg: Good signature from "SuSE Package Signing Key <build@suse.de>"
671 // [GNUPG:] VALIDSIG 79C179B2E1C820C1890F9994A84EDAE89C800ACA 2006-03-29 1143618744 0 3 0 17 2 00 79C179B2E1C820C1890F9994A84EDAE89C800ACA
672 // [GNUPG:] TRUST_UNDEFINED
674 // [GNUPG:] ERRSIG A84EDAE89C800ACA 17 2 00 1143618744 9
675 // [GNUPG:] NO_PUBKEY A84EDAE89C800ACA
677 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
679 return (prog.close() == 0) ? true : false;
682 ///////////////////////////////////////////////////////////////////
684 ///////////////////////////////////////////////////////////////////
686 // CLASS NAME : KeyRing
688 ///////////////////////////////////////////////////////////////////
690 ///////////////////////////////////////////////////////////////////
692 // METHOD NAME : KeyRing::KeyRing
693 // METHOD TYPE : Ctor
695 KeyRing::KeyRing(const Pathname &baseTmpDir)
696 : _pimpl( new Impl(baseTmpDir) )
699 ///////////////////////////////////////////////////////////////////
701 // METHOD NAME : KeyRing::KeyRing
702 // METHOD TYPE : Ctor
704 //KeyRing::KeyRing( const Pathname &general_kr, const Pathname &trusted_kr )
705 //: _pimpl( new Impl(general_kr, trusted_kr) )
708 ///////////////////////////////////////////////////////////////////
710 // METHOD NAME : KeyRing::~KeyRing
711 // METHOD TYPE : Dtor
716 ///////////////////////////////////////////////////////////////////
718 // Forward to implementation:
720 ///////////////////////////////////////////////////////////////////
723 void KeyRing::importKey( const PublicKey &key, bool trusted )
725 _pimpl->importKey( key, trusted );
728 void KeyRing::multiKeyImport( const Pathname & keyfile_r, bool trusted_r )
730 _pimpl->multiKeyImport( keyfile_r, trusted_r );
733 string KeyRing::readSignatureKeyId( const Pathname &signature )
735 return _pimpl->readSignatureKeyId(signature);
738 void KeyRing::deleteKey( const string &id, bool trusted )
740 _pimpl->deleteKey(id, trusted);
743 list<PublicKey> KeyRing::publicKeys()
745 return _pimpl->publicKeys();
748 list<PublicKey> KeyRing::trustedPublicKeys()
750 return _pimpl->trustedPublicKeys();
753 list<string> KeyRing::publicKeyIds()
755 return _pimpl->publicKeyIds();
758 list<string> KeyRing::trustedPublicKeyIds()
760 return _pimpl->trustedPublicKeyIds();
763 bool KeyRing::verifyFileSignatureWorkflow(
764 const Pathname &file,
765 const string filedesc,
766 const Pathname &signature,
767 const KeyContext &keycontext)
769 return _pimpl->verifyFileSignatureWorkflow(file, filedesc, signature, keycontext);
772 bool KeyRing::verifyFileSignature( const Pathname &file, const Pathname &signature)
774 return _pimpl->verifyFileSignature(file, signature);
777 bool KeyRing::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
779 return _pimpl->verifyFileTrustedSignature(file, signature);
782 void KeyRing::dumpPublicKey( const string &id, bool trusted, ostream &stream )
784 _pimpl->dumpPublicKey( id, trusted, stream);
787 bool KeyRing::isKeyTrusted( const string &id )
789 return _pimpl->isKeyTrusted(id);
792 bool KeyRing::isKeyKnown( const string &id )
794 return _pimpl->isKeyKnown(id);
797 /////////////////////////////////////////////////////////////////
799 ///////////////////////////////////////////////////////////////////