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 if ( ! PathInfo(signature).isFile() )
538 ZYPP_THROW(Exception("Signature file " + signature.asString() + " not found"));
540 MIL << "Determining key id if signature " << signature << endl;
541 // HACK create a tmp keyring with no keys
542 TmpDir dir(_base_dir, "fake-keyring");
543 TmpFile fakeData(_base_dir, "fake-data");
548 "--no-default-keyring",
556 dir.path().asString().c_str(),
558 signature.asString().c_str(),
559 fakeData.path().asString().c_str(),
563 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
568 str::regex rxNoKey("^\\[GNUPG:\\] NO_PUBKEY (.+)\n$");
570 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
572 //MIL << "[" << line << "]" << endl;
574 if(str::regex_match(line, what, rxNoKey))
576 if ( what.size() >= 1 )
578 //dumpRegexpResults(what);
582 MIL << "'" << line << "'" << endl;
588 MIL << "no output" << endl;
591 MIL << "Determined key id [" << id << "] for signature " << signature << endl;
596 bool KeyRing::Impl::verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring)
601 "--no-default-keyring",
609 keyring.asString().c_str(),
611 signature.asString().c_str(),
612 file.asString().c_str(),
616 // no need to parse output for now
617 // [GNUPG:] SIG_ID yCc4u223XRJnLnVAIllvYbUd8mQ 2006-03-29 1143618744
618 // [GNUPG:] GOODSIG A84EDAE89C800ACA SuSE Package Signing Key <build@suse.de>
619 // gpg: Good signature from "SuSE Package Signing Key <build@suse.de>"
620 // [GNUPG:] VALIDSIG 79C179B2E1C820C1890F9994A84EDAE89C800ACA 2006-03-29 1143618744 0 3 0 17 2 00 79C179B2E1C820C1890F9994A84EDAE89C800ACA
621 // [GNUPG:] TRUST_UNDEFINED
623 // [GNUPG:] ERRSIG A84EDAE89C800ACA 17 2 00 1143618744 9
624 // [GNUPG:] NO_PUBKEY A84EDAE89C800ACA
626 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
628 return (prog.close() == 0) ? true : false;
631 ///////////////////////////////////////////////////////////////////
633 ///////////////////////////////////////////////////////////////////
635 // CLASS NAME : KeyRing
637 ///////////////////////////////////////////////////////////////////
639 ///////////////////////////////////////////////////////////////////
641 // METHOD NAME : KeyRing::KeyRing
642 // METHOD TYPE : Ctor
644 KeyRing::KeyRing(const Pathname &baseTmpDir)
645 : _pimpl( new Impl(baseTmpDir) )
648 ///////////////////////////////////////////////////////////////////
650 // METHOD NAME : KeyRing::KeyRing
651 // METHOD TYPE : Ctor
653 //KeyRing::KeyRing( const Pathname &general_kr, const Pathname &trusted_kr )
654 //: _pimpl( new Impl(general_kr, trusted_kr) )
657 ///////////////////////////////////////////////////////////////////
659 // METHOD NAME : KeyRing::~KeyRing
660 // METHOD TYPE : Dtor
665 ///////////////////////////////////////////////////////////////////
667 // Forward to implementation:
669 ///////////////////////////////////////////////////////////////////
672 void KeyRing::importKey( const PublicKey &key, bool trusted )
674 _pimpl->importKey( key.path(), trusted );
677 string KeyRing::readSignatureKeyId( const Pathname &signature )
679 return _pimpl->readSignatureKeyId(signature);
682 void KeyRing::deleteKey( const string &id, bool trusted )
684 _pimpl->deleteKey(id, trusted);
687 list<PublicKey> KeyRing::publicKeys()
689 return _pimpl->publicKeys();
692 list<PublicKey> KeyRing::trustedPublicKeys()
694 return _pimpl->trustedPublicKeys();
697 list<string> KeyRing::publicKeyIds()
699 return _pimpl->publicKeyIds();
702 list<string> KeyRing::trustedPublicKeyIds()
704 return _pimpl->trustedPublicKeyIds();
707 bool KeyRing::verifyFileSignatureWorkflow( const Pathname &file, const string filedesc, const Pathname &signature)
709 return _pimpl->verifyFileSignatureWorkflow(file, filedesc, signature);
712 bool KeyRing::verifyFileSignature( const Pathname &file, const Pathname &signature)
714 return _pimpl->verifyFileSignature(file, signature);
717 bool KeyRing::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
719 return _pimpl->verifyFileTrustedSignature(file, signature);
722 void KeyRing::dumpPublicKey( const string &id, bool trusted, ostream &stream )
724 _pimpl->dumpPublicKey( id, trusted, stream);
727 bool KeyRing::isKeyTrusted( const string &id )
729 return _pimpl->isKeyTrusted(id);
732 bool KeyRing::isKeyKnown( const string &id )
734 return _pimpl->isKeyKnown(id);
737 /////////////////////////////////////////////////////////////////
739 ///////////////////////////////////////////////////////////////////