1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/KeyRing.cc
18 #include "zypp/ZYppFactory.h"
19 #include "zypp/ZYpp.h"
21 #include "zypp/base/Logger.h"
22 #include "zypp/base/IOStream.h"
23 #include "zypp/base/String.h"
24 #include "zypp/Pathname.h"
25 #include "zypp/KeyRing.h"
26 #include "zypp/ExternalProgram.h"
27 #include "zypp/TmpPath.h"
30 using namespace zypp::filesystem;
33 #undef ZYPP_BASE_LOGGER_LOGGROUP
34 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::KeyRing"
36 ///////////////////////////////////////////////////////////////////
38 { /////////////////////////////////////////////////////////////////
40 IMPL_PTR_TYPE(KeyRing);
42 static void dumpRegexpResults( const str::smatch &what )
44 for ( unsigned int k=0; k < what.size(); k++)
46 XXX << "[match "<< k << "] [" << what[k] << "]" << std::endl;
50 static bool printLine( const std::string &line )
52 MIL << line << std::endl;
55 static void dumpFile(const Pathname &file)
57 std::ifstream is(file.asString().c_str());
58 iostr::forEachLine( is, printLine);
63 bool _keyRingDefaultAccept( getenv("ZYPP_KEYRING_DEFAULT_ACCEPT_ALL") );
66 bool KeyRingReport::askUserToAcceptUnsignedFile( const std::string &file )
67 { return _keyRingDefaultAccept; }
69 bool KeyRingReport::askUserToAcceptUnknownKey( const std::string &file, const std::string &keyid, const std::string &keyname, const std::string &fingerprint )
70 { return _keyRingDefaultAccept; }
72 bool KeyRingReport::askUserToTrustKey( const std::string &keyid, const std::string &keyname, const std::string &fingerprint )
73 { return _keyRingDefaultAccept; }
75 bool KeyRingReport::askUserToAcceptVerificationFailed( const std::string &file, const std::string &keyid, const std::string &keyname, const std::string &fingerprint )
76 { return _keyRingDefaultAccept; }
78 ///////////////////////////////////////////////////////////////////
80 // CLASS NAME : KeyRing::Impl
82 /** KeyRing implementation. */
85 Impl(const Pathname &baseTmpDir)
86 : _trusted_tmp_dir(baseTmpDir)
87 , _general_tmp_dir(baseTmpDir)
90 _base_dir = baseTmpDir;
94 Impl( const Pathname &general_kr, const Pathname &trusted_kr )
96 filesystem::assert_dir(general_kr);
97 filesystem::assert_dir(trusted_kr);
99 generalKeyRing() = general_kr;
100 trustedKeyRing() = trusted_kr;
104 void importKey( const Pathname &keyfile, bool trusted = false);
105 PublicKey readPublicKey( const Pathname &keyfile );
106 std::string readSignatureKeyId( const Pathname &signature );
108 void deleteKey( const std::string &id, bool trusted );
109 std::list<PublicKey> trustedPublicKeys();
110 std::list<PublicKey> publicKeys();
112 void dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream );
114 bool verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature);
116 bool verifyFileSignature( const Pathname &file, const Pathname &signature);
117 bool verifyFileTrustedSignature( const Pathname &file, const Pathname &signature);
119 //mutable std::map<Locale, std::string> translations;
120 bool verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring);
121 void importKey( const Pathname &keyfile, const Pathname &keyring);
123 void exportKey( std::string id, const Pathname &keyfile, bool trusted);
125 void deleteKey( const std::string &id, const Pathname &keyring );
126 std::list<PublicKey> publicKeys(const Pathname &keyring);
128 bool publicKeyExists( std::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( Pathname("/var/tmp") ) );
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 Pathname &keyfile, bool trusted)
165 importKey( keyfile, trusted ? trustedKeyRing() : generalKeyRing() );
168 void KeyRing::Impl::deleteKey( const std::string &id, bool trusted)
170 deleteKey( id, trusted ? trustedKeyRing() : generalKeyRing() );
173 std::list<PublicKey> KeyRing::Impl::publicKeys()
175 return publicKeys( generalKeyRing() );
178 std::list<PublicKey> KeyRing::Impl::trustedPublicKeys()
180 return publicKeys( trustedKeyRing() );
183 bool KeyRing::Impl::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
185 return verifyFile( file, signature, trustedKeyRing() );
188 bool KeyRing::Impl::verifyFileSignature( const Pathname &file, const Pathname &signature)
190 return verifyFile( file, signature, generalKeyRing() );
193 bool KeyRing::Impl::publicKeyExists( std::string id, const Pathname &keyring)
195 MIL << "Searching key [" << id << "] in keyring " << keyring << std::endl;
196 std::list<PublicKey> keys = publicKeys(keyring);
197 for (std::list<PublicKey>::const_iterator it = keys.begin(); it != keys.end(); it++)
199 if ( id == (*it).id )
205 void KeyRing::Impl::exportKey( std::string id, const Pathname &keyfile, bool trusted)
208 std::ofstream os(keyfile.asString().c_str());
209 dumpPublicKey( id, trusted, os );
212 catch (std::exception &e)
214 ERR << "Cannot export key " << id << " from " << (trusted ? "trusted" : "untrusted ") << " keyring to file " << keyfile << std::endl;
218 void KeyRing::Impl::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
220 Pathname keyring = trusted ? trustedKeyRing() : generalKeyRing();
224 "--no-default-keyring",
228 "--no-permission-warning",
231 keyring.asString().c_str(),
237 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
240 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
248 bool KeyRing::Impl::verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature)
250 callback::SendReport<KeyRingReport> report;
251 callback::SendReport<KeyRingSignals> emitSignal;
252 MIL << "Going to verify signature for " << file << " with " << signature << std::endl;
254 // if signature does not exists, ask user if he wants to accept unsigned file.
255 if( signature.empty() || (!PathInfo(signature).isExist()) )
257 bool res = report->askUserToAcceptUnsignedFile( filedesc );
258 MIL << "User decision on unsigned file: " << res << endl;
262 // get the id of the signature
263 std::string id = readSignatureKeyId(signature);
265 // doeskey exists in trusted keyring
266 if ( publicKeyExists( id, trustedKeyRing() ) )
268 TmpFile trustedKey(_base_dir);
269 exportKey( id, trustedKey.path(), true);
270 PublicKey key = readPublicKey(trustedKey.path());
271 MIL << "Key " << id << " " << key.name << " is trusted" << std::endl;
272 // it exists, is trusted, does it validates?
273 if ( verifyFile( file, signature, trustedKeyRing() ) )
276 return report->askUserToAcceptVerificationFailed( filedesc, key.id, key.name, key.fingerprint );
280 if ( publicKeyExists( id, generalKeyRing() ) )
282 TmpFile unKey(_base_dir);
283 exportKey( id, unKey.path(), false);
284 MIL << "Exported key " << id << " to " << unKey << std::endl;
286 PublicKey key = readPublicKey(unKey.path());
287 MIL << "Key " << id << " " << key.name << " is not trusted" << std::endl;
288 // ok the key is not trusted, ask the user to trust it or not
289 #warning We need the key details passed to the callback
290 if ( report->askUserToTrustKey(key.id, key.name, key.fingerprint) )
292 MIL << "User wants to trust key " << id << " " << key.name << std::endl;
293 //dumpFile(unKey.path());
295 importKey( unKey.path(), trustedKeyRing() );
296 emitSignal->trustedKeyAdded( (const KeyRing &)(*this), id, key.name, key.fingerprint );
299 if ( verifyFile( file, signature, trustedKeyRing() ) )
301 MIL << "File signature is verified" << std::endl;
306 MIL << "File signature check fails" << std::endl;
307 if ( report->askUserToAcceptVerificationFailed( filedesc, key.id, key.name, key.fingerprint ) )
309 MIL << "User continues anyway." << std::endl;
314 MIL << "User does not want to continue" << std::endl;
321 MIL << "User does not want to trust key " << id << " " << key.name << std::endl;
328 MIL << "File [" << file << "] ( " << filedesc << " ) signed with unknown key [" << id << "]" << std::endl;
329 if ( report->askUserToAcceptUnknownKey( filedesc, id, "", "" ) )
331 MIL << "User wants to accept unknown key " << id << std::endl;
336 MIL << "User does not want to accept unknown key " << id << std::endl;
345 PublicKey KeyRing::Impl::readPublicKey( const Pathname &keyfile )
347 TmpDir dir(_base_dir);
352 "--no-default-keyring",
354 dir.path().asString().c_str(),
355 "--with-fingerprint",
363 keyfile.asString().c_str(),
367 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
372 str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
374 // pub:-:1024:17:A84EDAE89C800ACA:2000-10-19:2008-06-21::-:SuSE Package Signing Key <build@suse.de>:
377 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
379 //MIL << "[" << line << "]" << std::endl;
381 if(str::regex_match(line, what, rxColons, str::match_extra))
383 if ( what[1] == "pub" )
389 else if ( what[1] == "fpr" )
391 key.fingerprint = what[10];
393 //dumpRegexpResults(what);
400 std::list<PublicKey> KeyRing::Impl::publicKeys(const Pathname &keyring)
405 "--no-default-keyring",
407 "--list-public-keys",
409 "--with-fingerprint",
416 keyring.asString().c_str(),
419 std::list<PublicKey> keys;
421 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
425 str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
426 str::regex rxColonsFpr("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
428 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
430 //MIL << line << std::endl;
432 if(str::regex_match(line, what, rxColons, str::match_extra))
435 if ( what[1] == "pub" )
441 for(line2 = prog.receiveLine(); !line2.empty(); line2 = prog.receiveLine(), count++ )
444 if (str::regex_match(line2, what2, rxColonsFpr, str::match_extra))
446 if ( (what2[1] == "fpr") && (what2[1] != "pub") && (what2[1] !="sub"))
448 key.fingerprint = what2[10];
454 MIL << "Found key " << "[" << key.id << "]" << " [" << key.name << "]" << " [" << key.fingerprint << "]" << std::endl;
456 //dumpRegexpResults(what);
463 void KeyRing::Impl::importKey( const Pathname &keyfile, const Pathname &keyring)
468 "--no-default-keyring",
472 "--no-permission-warning",
476 keyring.asString().c_str(),
478 keyfile.asString().c_str(),
483 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
487 // ZYPP_THROW(Exception("failed to import key"));
490 void KeyRing::Impl::deleteKey( const std::string &id, const Pathname &keyring )
495 "--no-default-keyring",
503 keyring.asString().c_str(),
509 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
511 int code = prog.close();
513 ZYPP_THROW(Exception("Failed to delete key."));
515 MIL << "Deleted key " << id << " from keyring " << keyring << std::endl;
519 std::string KeyRing::Impl::readSignatureKeyId(const Pathname &signature )
521 MIL << "Deetermining key id if signature " << signature << std::endl;
522 // HACK create a tmp keyring with no keys
523 TmpDir dir(_base_dir);
524 TmpFile fakeData(_base_dir);
529 "--no-default-keyring",
537 dir.path().asString().c_str(),
539 signature.asString().c_str(),
540 fakeData.path().asString().c_str(),
544 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
549 str::regex rxNoKey("^\\[GNUPG:\\] NO_PUBKEY (.+)\n$");
551 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
553 //MIL << "[" << line << "]" << std::endl;
555 if(str::regex_match(line, what, rxNoKey, str::match_extra))
557 if ( what.size() > 1 )
559 //dumpRegexpResults(what);
562 MIL << "Determined key id [" << id << "] for signature " << signature << std::endl;
567 bool KeyRing::Impl::verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring)
572 "--no-default-keyring",
580 keyring.asString().c_str(),
582 signature.asString().c_str(),
583 file.asString().c_str(),
587 // no need to parse output for now
588 // [GNUPG:] SIG_ID yCc4u223XRJnLnVAIllvYbUd8mQ 2006-03-29 1143618744
589 // [GNUPG:] GOODSIG A84EDAE89C800ACA SuSE Package Signing Key <build@suse.de>
590 // gpg: Good signature from "SuSE Package Signing Key <build@suse.de>"
591 // [GNUPG:] VALIDSIG 79C179B2E1C820C1890F9994A84EDAE89C800ACA 2006-03-29 1143618744 0 3 0 17 2 00 79C179B2E1C820C1890F9994A84EDAE89C800ACA
592 // [GNUPG:] TRUST_UNDEFINED
594 // [GNUPG:] ERRSIG A84EDAE89C800ACA 17 2 00 1143618744 9
595 // [GNUPG:] NO_PUBKEY A84EDAE89C800ACA
597 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
599 return (prog.close() == 0) ? true : false;
602 ///////////////////////////////////////////////////////////////////
604 ///////////////////////////////////////////////////////////////////
606 // CLASS NAME : KeyRing
608 ///////////////////////////////////////////////////////////////////
610 ///////////////////////////////////////////////////////////////////
612 // METHOD NAME : KeyRing::KeyRing
613 // METHOD TYPE : Ctor
615 KeyRing::KeyRing(const Pathname &baseTmpDir)
616 : _pimpl( new Impl(baseTmpDir) )
619 ///////////////////////////////////////////////////////////////////
621 // METHOD NAME : KeyRing::KeyRing
622 // METHOD TYPE : Ctor
624 //KeyRing::KeyRing( const Pathname &general_kr, const Pathname &trusted_kr )
625 //: _pimpl( new Impl(general_kr, trusted_kr) )
628 ///////////////////////////////////////////////////////////////////
630 // METHOD NAME : KeyRing::~KeyRing
631 // METHOD TYPE : Dtor
636 ///////////////////////////////////////////////////////////////////
638 // Forward to implementation:
640 ///////////////////////////////////////////////////////////////////
642 void KeyRing::importKey( const Pathname &keyfile, bool trusted)
644 _pimpl->importKey(keyfile, trusted);
647 PublicKey KeyRing::readPublicKey( const Pathname &keyfile )
649 return _pimpl->readPublicKey(keyfile);
652 std::string KeyRing::readSignatureKeyId( const Pathname &signature )
654 return _pimpl->readSignatureKeyId(signature);
657 void KeyRing::deleteKey( const std::string &id, bool trusted )
659 _pimpl->deleteKey(id, trusted);
662 std::list<PublicKey> KeyRing::publicKeys()
664 return _pimpl->publicKeys();
667 std::list<PublicKey> KeyRing::trustedPublicKeys()
669 return _pimpl->trustedPublicKeys();
672 bool KeyRing::verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature)
674 return _pimpl->verifyFileSignatureWorkflow(file, filedesc, signature);
677 bool KeyRing::verifyFileSignature( const Pathname &file, const Pathname &signature)
679 return _pimpl->verifyFileSignature(file, signature);
682 bool KeyRing::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
684 return _pimpl->verifyFileTrustedSignature(file, signature);
687 void KeyRing::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
689 _pimpl->dumpPublicKey( id, trusted, stream);
692 /////////////////////////////////////////////////////////////////
694 ///////////////////////////////////////////////////////////////////