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 deleteKey( const string &id, bool trusted );
99 string readSignatureKeyId( const Pathname &signature );
101 bool isKeyTrusted( const string &id);
102 bool isKeyKnown( const string &id );
104 list<PublicKey> trustedPublicKeys();
105 list<PublicKey> publicKeys();
107 list<string> trustedPublicKeyIds();
108 list<string> publicKeyIds();
110 void dumpPublicKey( const string &id, bool trusted, ostream &stream );
112 bool verifyFileSignatureWorkflow(
113 const Pathname &file,
114 const string filedesc,
115 const Pathname &signature,
116 const KeyContext &keycontext = KeyContext());
118 bool verifyFileSignature( const Pathname &file, const Pathname &signature);
119 bool verifyFileTrustedSignature( const Pathname &file, const Pathname &signature);
121 //mutable map<Locale, string> translations;
122 bool verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring);
123 void importKey( const Pathname &keyfile, const Pathname &keyring);
124 PublicKey exportKey( string id, const Pathname &keyring);
125 void dumpPublicKey( const string &id, const Pathname &keyring, ostream &stream );
126 void deleteKey( const string &id, const Pathname &keyring );
128 list<PublicKey> publicKeys(const Pathname &keyring);
129 list<string> publicKeyIds(const Pathname &keyring);
131 bool publicKeyExists( string id, const Pathname &keyring);
133 const Pathname generalKeyRing() const;
134 const Pathname trustedKeyRing() const;
136 // Used for trusted and untrusted keyrings
137 TmpDir _trusted_tmp_dir;
138 TmpDir _general_tmp_dir;
141 /** Offer default Impl. */
142 static shared_ptr<Impl> nullimpl()
144 static shared_ptr<Impl> _nullimpl( new Impl( TmpPath::defaultLocation() ) );
149 friend Impl * rwcowClone<Impl>( const Impl * rhs );
150 /** clone for RWCOW_pointer */
152 { return new Impl( *this ); }
156 const Pathname KeyRing::Impl::generalKeyRing() const
158 return _general_tmp_dir.path();
161 const Pathname KeyRing::Impl::trustedKeyRing() const
163 return _trusted_tmp_dir.path();
166 void KeyRing::Impl::importKey( const PublicKey &key, bool trusted)
168 callback::SendReport<target::rpm::KeyRingSignals> rpmdbEmitSignal;
169 callback::SendReport<KeyRingSignals> emitSignal;
171 importKey( key.path(), trusted ? trustedKeyRing() : generalKeyRing() );
175 rpmdbEmitSignal->trustedKeyAdded( key );
176 emitSignal->trustedKeyAdded( key );
180 void KeyRing::Impl::deleteKey( const string &id, bool trusted)
186 key = exportKey(id, trustedKeyRing());
189 deleteKey( id, trusted ? trustedKeyRing() : generalKeyRing() );
193 callback::SendReport<target::rpm::KeyRingSignals> rpmdbEmitSignal;
194 callback::SendReport<KeyRingSignals> emitSignal;
196 rpmdbEmitSignal->trustedKeyRemoved( key );
197 emitSignal->trustedKeyRemoved( key );
201 list<PublicKey> KeyRing::Impl::publicKeys()
203 return publicKeys( generalKeyRing() );
206 list<PublicKey> KeyRing::Impl::trustedPublicKeys()
208 return publicKeys( trustedKeyRing() );
211 list<string> KeyRing::Impl::publicKeyIds()
213 return publicKeyIds( generalKeyRing() );
216 list<string> KeyRing::Impl::trustedPublicKeyIds()
218 return publicKeyIds( trustedKeyRing() );
221 bool KeyRing::Impl::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
223 return verifyFile( file, signature, trustedKeyRing() );
226 bool KeyRing::Impl::verifyFileSignature( const Pathname &file, const Pathname &signature)
228 return verifyFile( file, signature, generalKeyRing() );
231 bool KeyRing::Impl::isKeyTrusted( const string &id)
233 return publicKeyExists( id, trustedKeyRing() );
236 bool KeyRing::Impl::isKeyKnown( const string &id )
239 if ( publicKeyExists( id, trustedKeyRing() ) )
242 return publicKeyExists( id, generalKeyRing() );
245 bool KeyRing::Impl::publicKeyExists( string id, const Pathname &keyring)
247 MIL << "Searching key [" << id << "] in keyring " << keyring << endl;
248 list<PublicKey> keys = publicKeys(keyring);
249 for (list<PublicKey>::const_iterator it = keys.begin(); it != keys.end(); it++)
251 if ( id == (*it).id() )
258 PublicKey KeyRing::Impl::exportKey( string id, const Pathname &keyring)
260 TmpFile tmp_file( _base_dir, "pubkey-"+id+"-" );
261 MIL << "Going to export key " << id << " from " << keyring << " to " << tmp_file.path() << endl;
264 ofstream os(tmp_file.path().c_str());
265 dumpPublicKey( id, keyring, os );
267 return PublicKey( tmp_file );
269 catch (BadKeyException &e)
271 ERR << "Cannot create public key " << id << " from " << keyring << " keyring to file " << e.keyFile() << endl;
272 // TranslatorExplanation first %s is key name, second is keyring name
273 // and third is keyfile name
274 ZYPP_THROW(Exception(boost::str(boost::format(
275 _("Cannot create public key %s from %s keyring to file %s"))
276 % id % keyring.asString() % e.keyFile().asString())));
280 ERR << "Cannot export key " << id << " from " << keyring << " keyring to file " << tmp_file.path() << endl;
285 void KeyRing::Impl::dumpPublicKey( const string &id, bool trusted, ostream &stream )
287 dumpPublicKey( id, ( trusted ? trustedKeyRing() : generalKeyRing() ), stream );
290 void KeyRing::Impl::dumpPublicKey( const string &id, const Pathname &keyring, ostream &stream )
295 "--no-default-keyring",
299 "--no-permission-warning",
302 keyring.asString().c_str(),
308 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
311 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
319 bool KeyRing::Impl::verifyFileSignatureWorkflow(
320 const Pathname &file,
321 const string filedesc,
322 const Pathname &signature,
323 const KeyContext &context)
325 callback::SendReport<KeyRingReport> report;
326 //callback::SendReport<KeyRingSignals> emitSignal;
327 MIL << "Going to verify signature for " << filedesc << " ( " << file << " ) with " << signature << endl;
329 // if signature does not exists, ask user if he wants to accept unsigned file.
330 if( signature.empty() || (!PathInfo(signature).isExist()) )
332 bool res = report->askUserToAcceptUnsignedFile( filedesc, context );
333 MIL << "User decision on unsigned file: " << res << endl;
337 // get the id of the signature
338 string id = readSignatureKeyId(signature);
340 // doeskey exists in trusted keyring
341 if ( publicKeyExists( id, trustedKeyRing() ) )
343 PublicKey key = exportKey( id, trustedKeyRing() );
345 // lets look if there is an updated key in the
347 if ( publicKeyExists( id, generalKeyRing() ) )
349 // bnc #393160: Comment #30: Compare at least the fingerprint
350 // in case an attacker created a key the the same id.
351 PublicKey untkey = exportKey( id, generalKeyRing() );
352 if ( untkey.fingerprint() == key.fingerprint()
353 && untkey.created() > key.created() )
355 MIL << "Key " << key << " was updated. Saving new version into trusted keyring." << endl;
356 importKey( untkey, true );
361 MIL << "Key " << id << " " << key.name() << " is trusted" << endl;
362 // it exists, is trusted, does it validates?
363 if ( verifyFile( file, signature, trustedKeyRing() ) )
366 return report->askUserToAcceptVerificationFailed( filedesc, key, context );
370 if ( publicKeyExists( id, generalKeyRing() ) )
372 PublicKey key = exportKey( id, generalKeyRing());
373 MIL << "Exported key " << id << " to " << key.path() << endl;
374 MIL << "Key " << id << " " << key.name() << " is not trusted" << endl;
376 // ok the key is not trusted, ask the user to trust it or not
377 KeyRingReport::KeyTrust reply = report->askUserToAcceptKey(key, context);
378 if (reply == KeyRingReport::KEY_TRUST_TEMPORARILY ||
379 reply == KeyRingReport::KEY_TRUST_AND_IMPORT)
381 MIL << "User wants to trust key " << id << " " << key.name() << endl;
382 //dumpFile(unKey.path());
384 Pathname which_keyring;
385 if (reply == KeyRingReport::KEY_TRUST_AND_IMPORT)
387 MIL << "User wants to import key " << id << " " << key.name() << endl;
388 importKey( key, true );
389 which_keyring = trustedKeyRing();
392 which_keyring = generalKeyRing();
395 if ( verifyFile( file, signature, which_keyring ) )
397 MIL << "File signature is verified" << endl;
402 MIL << "File signature check fails" << endl;
403 if ( report->askUserToAcceptVerificationFailed( filedesc, key, context ) )
405 MIL << "User continues anyway." << endl;
410 MIL << "User does not want to continue" << endl;
417 MIL << "User does not want to trust key " << id << " " << key.name() << endl;
424 MIL << "File [" << file << "] ( " << filedesc << " ) signed with unknown key [" << id << "]" << endl;
425 if ( report->askUserToAcceptUnknownKey( filedesc, id, context ) )
427 MIL << "User wants to accept unknown key " << id << endl;
432 MIL << "User does not want to accept unknown key " << id << endl;
440 list<string> KeyRing::Impl::publicKeyIds(const Pathname &keyring)
442 static str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
443 static str::regex rxColonsFpr("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
450 "--no-default-keyring",
452 "--list-public-keys",
454 "--with-fingerprint",
461 keyring.asString().c_str(),
465 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
469 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
471 //MIL << line << endl;
473 if(str::regex_match(line, what, rxColons))
477 if ( what[1] == "pub" )
482 for(line2 = prog.receiveLine(); !line2.empty(); line2 = prog.receiveLine(), count++ )
485 if (str::regex_match(line2, what2, rxColonsFpr))
487 if ( (what2[1] == "fpr") && (what2[1] != "pub") && (what2[1] !="sub"))
489 fingerprint = what2[10];
496 MIL << "Found key " << "[" << id << "]" << endl;
498 //dumpRegexpResults(what);
505 list<PublicKey> KeyRing::Impl::publicKeys(const Pathname &keyring)
508 list<PublicKey> keys;
510 list<string> ids = publicKeyIds(keyring);
512 for ( list<string>::const_iterator it = ids.begin(); it != ids.end(); ++it )
514 PublicKey key(exportKey( *it, keyring ));
516 MIL << "Found key " << "[" << key.id() << "]" << " [" << key.name() << "]" << " [" << key.fingerprint() << "]" << endl;
521 void KeyRing::Impl::importKey( const Pathname &keyfile, const Pathname &keyring)
523 if ( ! PathInfo(keyfile).isExist() )
524 // TranslatorExplanation first %s is key name, second is keyring name
525 ZYPP_THROW(KeyRingException(boost::str(boost::format(
526 _("Tried to import not existant key %s into keyring %s"))
527 % keyfile.asString() % keyring.asString())));
532 "--no-default-keyring",
536 "--no-permission-warning",
540 keyring.asString().c_str(),
542 keyfile.asString().c_str(),
547 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
551 // ZYPP_THROW(Exception("failed to import key"));
554 void KeyRing::Impl::deleteKey( const string &id, const Pathname &keyring )
559 "--no-default-keyring",
567 keyring.asString().c_str(),
573 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
575 int code = prog.close();
577 ZYPP_THROW(Exception(_("Failed to delete key.")));
579 MIL << "Deleted key " << id << " from keyring " << keyring << endl;
583 string KeyRing::Impl::readSignatureKeyId(const Pathname &signature )
585 if ( ! PathInfo(signature).isFile() )
586 ZYPP_THROW(Exception(boost::str(boost::format(
587 _("Signature file %s not found"))% signature.asString())));
589 MIL << "Determining key id if signature " << signature << endl;
590 // HACK create a tmp keyring with no keys
591 TmpDir dir(_base_dir, "fake-keyring");
596 "--no-default-keyring",
604 dir.path().asString().c_str(),
605 signature.asString().c_str(),
609 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
614 str::regex rxNoKey("^\\[GNUPG:\\] NO_PUBKEY (.+)\n$");
616 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
618 //MIL << "[" << line << "]" << endl;
620 if(str::regex_match(line, what, rxNoKey))
622 if ( what.size() >= 1 )
624 //dumpRegexpResults(what);
628 MIL << "'" << line << "'" << endl;
634 MIL << "no output" << endl;
637 MIL << "Determined key id [" << id << "] for signature " << signature << endl;
642 bool KeyRing::Impl::verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring)
647 "--no-default-keyring",
655 keyring.asString().c_str(),
657 signature.asString().c_str(),
658 file.asString().c_str(),
662 // no need to parse output for now
663 // [GNUPG:] SIG_ID yCc4u223XRJnLnVAIllvYbUd8mQ 2006-03-29 1143618744
664 // [GNUPG:] GOODSIG A84EDAE89C800ACA SuSE Package Signing Key <build@suse.de>
665 // gpg: Good signature from "SuSE Package Signing Key <build@suse.de>"
666 // [GNUPG:] VALIDSIG 79C179B2E1C820C1890F9994A84EDAE89C800ACA 2006-03-29 1143618744 0 3 0 17 2 00 79C179B2E1C820C1890F9994A84EDAE89C800ACA
667 // [GNUPG:] TRUST_UNDEFINED
669 // [GNUPG:] ERRSIG A84EDAE89C800ACA 17 2 00 1143618744 9
670 // [GNUPG:] NO_PUBKEY A84EDAE89C800ACA
672 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
674 return (prog.close() == 0) ? true : false;
677 ///////////////////////////////////////////////////////////////////
679 ///////////////////////////////////////////////////////////////////
681 // CLASS NAME : KeyRing
683 ///////////////////////////////////////////////////////////////////
685 ///////////////////////////////////////////////////////////////////
687 // METHOD NAME : KeyRing::KeyRing
688 // METHOD TYPE : Ctor
690 KeyRing::KeyRing(const Pathname &baseTmpDir)
691 : _pimpl( new Impl(baseTmpDir) )
694 ///////////////////////////////////////////////////////////////////
696 // METHOD NAME : KeyRing::KeyRing
697 // METHOD TYPE : Ctor
699 //KeyRing::KeyRing( const Pathname &general_kr, const Pathname &trusted_kr )
700 //: _pimpl( new Impl(general_kr, trusted_kr) )
703 ///////////////////////////////////////////////////////////////////
705 // METHOD NAME : KeyRing::~KeyRing
706 // METHOD TYPE : Dtor
711 ///////////////////////////////////////////////////////////////////
713 // Forward to implementation:
715 ///////////////////////////////////////////////////////////////////
718 void KeyRing::importKey( const PublicKey &key, bool trusted )
720 _pimpl->importKey( key, trusted );
723 string KeyRing::readSignatureKeyId( const Pathname &signature )
725 return _pimpl->readSignatureKeyId(signature);
728 void KeyRing::deleteKey( const string &id, bool trusted )
730 _pimpl->deleteKey(id, trusted);
733 list<PublicKey> KeyRing::publicKeys()
735 return _pimpl->publicKeys();
738 list<PublicKey> KeyRing::trustedPublicKeys()
740 return _pimpl->trustedPublicKeys();
743 list<string> KeyRing::publicKeyIds()
745 return _pimpl->publicKeyIds();
748 list<string> KeyRing::trustedPublicKeyIds()
750 return _pimpl->trustedPublicKeyIds();
753 bool KeyRing::verifyFileSignatureWorkflow(
754 const Pathname &file,
755 const string filedesc,
756 const Pathname &signature,
757 const KeyContext &keycontext)
759 return _pimpl->verifyFileSignatureWorkflow(file, filedesc, signature, keycontext);
762 bool KeyRing::verifyFileSignature( const Pathname &file, const Pathname &signature)
764 return _pimpl->verifyFileSignature(file, signature);
767 bool KeyRing::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
769 return _pimpl->verifyFileTrustedSignature(file, signature);
772 void KeyRing::dumpPublicKey( const string &id, bool trusted, ostream &stream )
774 _pimpl->dumpPublicKey( id, trusted, stream);
777 bool KeyRing::isKeyTrusted( const string &id )
779 return _pimpl->isKeyTrusted(id);
782 bool KeyRing::isKeyKnown( const string &id )
784 return _pimpl->isKeyKnown(id);
787 /////////////////////////////////////////////////////////////////
789 ///////////////////////////////////////////////////////////////////