1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/KeyRing.cc
18 #include "zypp/TmpPath.h"
19 #include "zypp/ZYppFactory.h"
20 #include "zypp/ZYpp.h"
22 #include "zypp/base/Logger.h"
23 #include "zypp/base/IOStream.h"
24 #include "zypp/base/String.h"
25 #include "zypp/base/Regex.h"
26 #include "zypp/PathInfo.h"
27 #include "zypp/KeyRing.h"
28 #include "zypp/ExternalProgram.h"
29 #include "zypp/TmpPath.h"
32 using namespace zypp::filesystem;
34 #undef ZYPP_BASE_LOGGER_LOGGROUP
35 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::KeyRing"
37 #define GPG_BINARY "/usr/bin/gpg2"
39 ///////////////////////////////////////////////////////////////////
41 { /////////////////////////////////////////////////////////////////
43 IMPL_PTR_TYPE(KeyRing);
45 static bool printLine( const string &line )
53 bool _keyRingDefaultAccept( getenv("ZYPP_KEYRING_DEFAULT_ACCEPT_ALL") );
56 bool KeyRingReport::askUserToAcceptUnsignedFile( const string &file )
57 { return _keyRingDefaultAccept; }
59 bool KeyRingReport::askUserToAcceptUnknownKey( const string &file, const string &id )
60 { return _keyRingDefaultAccept; }
62 bool KeyRingReport::askUserToTrustKey( const PublicKey &key )
63 { return _keyRingDefaultAccept; }
65 bool KeyRingReport::askUserToImportKey( const PublicKey &key)
66 { return _keyRingDefaultAccept; }
68 bool KeyRingReport::askUserToAcceptVerificationFailed( const string &file, const PublicKey &key )
69 { return _keyRingDefaultAccept; }
71 ///////////////////////////////////////////////////////////////////
73 // CLASS NAME : KeyRing::Impl
75 /** KeyRing implementation. */
78 Impl(const Pathname &baseTmpDir)
79 : _trusted_tmp_dir(baseTmpDir, "zypp-trusted-kr")
80 , _general_tmp_dir(baseTmpDir, "zypp-general-kr")
81 , _base_dir( baseTmpDir )
87 Impl( const Pathname &general_kr, const Pathname &trusted_kr )
89 filesystem::assert_dir(general_kr);
90 filesystem::assert_dir(trusted_kr);
92 generalKeyRing() = general_kr;
93 trustedKeyRing() = trusted_kr;
97 void importKey( const PublicKey &key, bool trusted = 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( const Pathname &file, const string filedesc, const Pathname &signature);
115 bool verifyFileSignature( const Pathname &file, const Pathname &signature);
116 bool verifyFileTrustedSignature( const Pathname &file, const Pathname &signature);
118 //mutable map<Locale, string> translations;
119 bool verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring);
120 void importKey( const Pathname &keyfile, const Pathname &keyring);
121 PublicKey exportKey( string id, const Pathname &keyring);
122 void dumpPublicKey( const string &id, const Pathname &keyring, ostream &stream );
123 void deleteKey( const string &id, const Pathname &keyring );
125 list<PublicKey> publicKeys(const Pathname &keyring);
126 list<string> publicKeyIds(const Pathname &keyring);
128 bool publicKeyExists( string id, const Pathname &keyring);
130 const Pathname generalKeyRing() const;
131 const Pathname trustedKeyRing() const;
133 // Used for trusted and untrusted keyrings
134 TmpDir _trusted_tmp_dir;
135 TmpDir _general_tmp_dir;
138 /** Offer default Impl. */
139 static shared_ptr<Impl> nullimpl()
141 static shared_ptr<Impl> _nullimpl( new Impl( TmpPath::defaultLocation() ) );
146 friend Impl * rwcowClone<Impl>( const Impl * rhs );
147 /** clone for RWCOW_pointer */
149 { return new Impl( *this ); }
153 const Pathname KeyRing::Impl::generalKeyRing() const
155 return _general_tmp_dir.path();
158 const Pathname KeyRing::Impl::trustedKeyRing() const
160 return _trusted_tmp_dir.path();
163 void KeyRing::Impl::importKey( const PublicKey &key, bool trusted)
165 callback::SendReport<KeyRingSignals> emitSignal;
167 importKey( key.path(), trusted ? trustedKeyRing() : generalKeyRing() );
170 emitSignal->trustedKeyAdded( key );
174 void KeyRing::Impl::deleteKey( const string &id, bool trusted)
176 deleteKey( id, trusted ? trustedKeyRing() : generalKeyRing() );
179 list<PublicKey> KeyRing::Impl::publicKeys()
181 return publicKeys( generalKeyRing() );
184 list<PublicKey> KeyRing::Impl::trustedPublicKeys()
186 return publicKeys( trustedKeyRing() );
189 list<string> KeyRing::Impl::publicKeyIds()
191 return publicKeyIds( generalKeyRing() );
194 list<string> KeyRing::Impl::trustedPublicKeyIds()
196 return publicKeyIds( trustedKeyRing() );
199 bool KeyRing::Impl::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
201 return verifyFile( file, signature, trustedKeyRing() );
204 bool KeyRing::Impl::verifyFileSignature( const Pathname &file, const Pathname &signature)
206 return verifyFile( file, signature, generalKeyRing() );
209 bool KeyRing::Impl::isKeyTrusted( const string &id)
211 return publicKeyExists( id, trustedKeyRing() );
214 bool KeyRing::Impl::isKeyKnown( const string &id )
217 if ( publicKeyExists( id, trustedKeyRing() ) )
220 return publicKeyExists( id, generalKeyRing() );
223 bool KeyRing::Impl::publicKeyExists( string id, const Pathname &keyring)
225 MIL << "Searching key [" << id << "] in keyring " << keyring << endl;
226 list<PublicKey> keys = publicKeys(keyring);
227 for (list<PublicKey>::const_iterator it = keys.begin(); it != keys.end(); it++)
229 if ( id == (*it).id() )
235 PublicKey KeyRing::Impl::exportKey( string id, const Pathname &keyring)
237 TmpFile tmp_file( _base_dir, "pubkey-"+id+"-" );
238 Pathname keyfile = tmp_file.path();
239 MIL << "Going to export key " << id << " from " << keyring << " to " << keyfile << endl;
242 ofstream os(keyfile.asString().c_str());
243 dumpPublicKey( id, keyring, os );
245 PublicKey key(keyfile);
248 catch (BadKeyException &e)
250 ERR << "Cannot create public key " << id << " from " << keyring << " keyring to file " << e.keyFile() << endl;
251 ZYPP_THROW(Exception("Cannot create public key " + id + " from " + keyring.asString() + " keyring to file " + e.keyFile().asString() ) );
255 ERR << "Cannot export key " << id << " from " << keyring << " keyring to file " << keyfile << endl;
260 void KeyRing::Impl::dumpPublicKey( const string &id, bool trusted, ostream &stream )
262 dumpPublicKey( id, ( trusted ? trustedKeyRing() : generalKeyRing() ), stream );
265 void KeyRing::Impl::dumpPublicKey( const string &id, const Pathname &keyring, ostream &stream )
270 "--no-default-keyring",
274 "--no-permission-warning",
277 keyring.asString().c_str(),
283 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
286 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
294 bool KeyRing::Impl::verifyFileSignatureWorkflow( const Pathname &file, const string filedesc, const Pathname &signature)
296 callback::SendReport<KeyRingReport> report;
297 //callback::SendReport<KeyRingSignals> emitSignal;
298 MIL << "Going to verify signature for " << file << " with " << signature << endl;
300 // if signature does not exists, ask user if he wants to accept unsigned file.
301 if( signature.empty() || (!PathInfo(signature).isExist()) )
303 bool res = report->askUserToAcceptUnsignedFile( filedesc );
304 MIL << "User decision on unsigned file: " << res << endl;
308 // get the id of the signature
309 string id = readSignatureKeyId(signature);
311 // doeskey exists in trusted keyring
312 if ( publicKeyExists( id, trustedKeyRing() ) )
314 PublicKey key = exportKey( id, trustedKeyRing() );
316 MIL << "Key " << id << " " << key.name() << " is trusted" << endl;
317 // it exists, is trusted, does it validates?
318 if ( verifyFile( file, signature, trustedKeyRing() ) )
321 return report->askUserToAcceptVerificationFailed( filedesc, key );
325 if ( publicKeyExists( id, generalKeyRing() ) )
327 PublicKey key = exportKey( id, generalKeyRing());
328 MIL << "Exported key " << id << " to " << key.path() << endl;
329 MIL << "Key " << id << " " << key.name() << " is not trusted" << endl;
330 // ok the key is not trusted, ask the user to trust it or not
331 #warning We need the key details passed to the callback
332 if ( report->askUserToTrustKey( key ) )
334 MIL << "User wants to trust key " << id << " " << key.name() << endl;
335 //dumpFile(unKey.path());
337 Pathname which_keyring;
338 if ( report->askUserToImportKey( key ) )
340 MIL << "User wants to import key " << id << " " << key.name() << endl;
341 importKey( key, true );
342 which_keyring = trustedKeyRing();
346 which_keyring = generalKeyRing();
350 if ( verifyFile( file, signature, which_keyring ) )
352 MIL << "File signature is verified" << endl;
357 MIL << "File signature check fails" << endl;
358 if ( report->askUserToAcceptVerificationFailed( filedesc, key ) )
360 MIL << "User continues anyway." << endl;
365 MIL << "User does not want to continue" << endl;
372 MIL << "User does not want to trust key " << id << " " << key.name() << endl;
379 MIL << "File [" << file << "] ( " << filedesc << " ) signed with unknown key [" << id << "]" << endl;
380 if ( report->askUserToAcceptUnknownKey( filedesc, id ) )
382 MIL << "User wants to accept unknown key " << id << endl;
387 MIL << "User does not want to accept unknown key " << id << endl;
395 list<string> KeyRing::Impl::publicKeyIds(const Pathname &keyring)
397 static str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
398 static str::regex rxColonsFpr("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
405 "--no-default-keyring",
407 "--list-public-keys",
409 "--with-fingerprint",
416 keyring.asString().c_str(),
420 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
424 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
426 //MIL << line << endl;
428 if(str::regex_match(line, what, rxColons))
432 if ( what[1] == "pub" )
437 for(line2 = prog.receiveLine(); !line2.empty(); line2 = prog.receiveLine(), count++ )
440 if (str::regex_match(line2, what2, rxColonsFpr))
442 if ( (what2[1] == "fpr") && (what2[1] != "pub") && (what2[1] !="sub"))
444 fingerprint = what2[10];
451 MIL << "Found key " << "[" << id << "]" << endl;
453 //dumpRegexpResults(what);
460 list<PublicKey> KeyRing::Impl::publicKeys(const Pathname &keyring)
463 list<PublicKey> keys;
465 list<string> ids = publicKeyIds(keyring);
467 for ( list<string>::const_iterator it = ids.begin(); it != ids.end(); ++it )
469 PublicKey key(exportKey( *it, keyring ));
471 MIL << "Found key " << "[" << key.id() << "]" << " [" << key.name() << "]" << " [" << key.fingerprint() << "]" << endl;
476 void KeyRing::Impl::importKey( const Pathname &keyfile, const Pathname &keyring)
478 if ( ! PathInfo(keyfile).isExist() )
479 ZYPP_THROW(KeyRingException("Tried to import not existant key " + keyfile.asString() + " into keyring " + keyring.asString()));
484 "--no-default-keyring",
488 "--no-permission-warning",
492 keyring.asString().c_str(),
494 keyfile.asString().c_str(),
499 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
503 // ZYPP_THROW(Exception("failed to import key"));
506 void KeyRing::Impl::deleteKey( const string &id, const Pathname &keyring )
511 "--no-default-keyring",
519 keyring.asString().c_str(),
525 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
527 int code = prog.close();
529 ZYPP_THROW(Exception("Failed to delete key."));
531 MIL << "Deleted key " << id << " from keyring " << keyring << endl;
535 string KeyRing::Impl::readSignatureKeyId(const Pathname &signature )
537 MIL << "Deetermining key id if signature " << signature << endl;
538 // HACK create a tmp keyring with no keys
539 TmpDir dir(_base_dir, "fake-keyring");
540 TmpFile fakeData(_base_dir, "fake-data");
545 "--no-default-keyring",
553 dir.path().asString().c_str(),
555 signature.asString().c_str(),
556 fakeData.path().asString().c_str(),
560 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
565 str::regex rxNoKey("^\\[GNUPG:\\] NO_PUBKEY (.+)\n$");
567 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
569 //MIL << "[" << line << "]" << endl;
571 if(str::regex_search(line, what, rxNoKey))
573 if ( what.size() > 1 )
575 //dumpRegexpResults(what);
578 MIL << "Determined key id [" << id << "] for signature " << signature << endl;
583 bool KeyRing::Impl::verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring)
588 "--no-default-keyring",
596 keyring.asString().c_str(),
598 signature.asString().c_str(),
599 file.asString().c_str(),
603 // no need to parse output for now
604 // [GNUPG:] SIG_ID yCc4u223XRJnLnVAIllvYbUd8mQ 2006-03-29 1143618744
605 // [GNUPG:] GOODSIG A84EDAE89C800ACA SuSE Package Signing Key <build@suse.de>
606 // gpg: Good signature from "SuSE Package Signing Key <build@suse.de>"
607 // [GNUPG:] VALIDSIG 79C179B2E1C820C1890F9994A84EDAE89C800ACA 2006-03-29 1143618744 0 3 0 17 2 00 79C179B2E1C820C1890F9994A84EDAE89C800ACA
608 // [GNUPG:] TRUST_UNDEFINED
610 // [GNUPG:] ERRSIG A84EDAE89C800ACA 17 2 00 1143618744 9
611 // [GNUPG:] NO_PUBKEY A84EDAE89C800ACA
613 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
615 return (prog.close() == 0) ? true : false;
618 ///////////////////////////////////////////////////////////////////
620 ///////////////////////////////////////////////////////////////////
622 // CLASS NAME : KeyRing
624 ///////////////////////////////////////////////////////////////////
626 ///////////////////////////////////////////////////////////////////
628 // METHOD NAME : KeyRing::KeyRing
629 // METHOD TYPE : Ctor
631 KeyRing::KeyRing(const Pathname &baseTmpDir)
632 : _pimpl( new Impl(baseTmpDir) )
635 ///////////////////////////////////////////////////////////////////
637 // METHOD NAME : KeyRing::KeyRing
638 // METHOD TYPE : Ctor
640 //KeyRing::KeyRing( const Pathname &general_kr, const Pathname &trusted_kr )
641 //: _pimpl( new Impl(general_kr, trusted_kr) )
644 ///////////////////////////////////////////////////////////////////
646 // METHOD NAME : KeyRing::~KeyRing
647 // METHOD TYPE : Dtor
652 ///////////////////////////////////////////////////////////////////
654 // Forward to implementation:
656 ///////////////////////////////////////////////////////////////////
659 void KeyRing::importKey( const PublicKey &key, bool trusted )
661 _pimpl->importKey( key.path(), trusted );
664 string KeyRing::readSignatureKeyId( const Pathname &signature )
666 return _pimpl->readSignatureKeyId(signature);
669 void KeyRing::deleteKey( const string &id, bool trusted )
671 _pimpl->deleteKey(id, trusted);
674 list<PublicKey> KeyRing::publicKeys()
676 return _pimpl->publicKeys();
679 list<PublicKey> KeyRing::trustedPublicKeys()
681 return _pimpl->trustedPublicKeys();
684 list<string> KeyRing::publicKeyIds()
686 return _pimpl->publicKeyIds();
689 list<string> KeyRing::trustedPublicKeyIds()
691 return _pimpl->trustedPublicKeyIds();
694 bool KeyRing::verifyFileSignatureWorkflow( const Pathname &file, const string filedesc, const Pathname &signature)
696 return _pimpl->verifyFileSignatureWorkflow(file, filedesc, signature);
699 bool KeyRing::verifyFileSignature( const Pathname &file, const Pathname &signature)
701 return _pimpl->verifyFileSignature(file, signature);
704 bool KeyRing::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
706 return _pimpl->verifyFileTrustedSignature(file, signature);
709 void KeyRing::dumpPublicKey( const string &id, bool trusted, ostream &stream )
711 _pimpl->dumpPublicKey( id, trusted, stream);
714 bool KeyRing::isKeyTrusted( const string &id )
716 return _pimpl->isKeyTrusted(id);
719 bool KeyRing::isKeyKnown( const string &id )
721 return _pimpl->isKeyKnown(id);
724 /////////////////////////////////////////////////////////////////
726 ///////////////////////////////////////////////////////////////////