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;
56 static void dumpFile(const Pathname &file)
58 std::ifstream is(file.asString().c_str());
59 iostr::forEachLine( is, printLine);
64 bool _keyRingDefaultAccept( getenv("ZYPP_KEYRING_DEFAULT_ACCEPT_ALL") );
67 bool KeyRingReport::askUserToAcceptUnsignedFile( const std::string &file )
68 { return _keyRingDefaultAccept; }
70 bool KeyRingReport::askUserToAcceptUnknownKey( const std::string &file, const std::string &id )
71 { return _keyRingDefaultAccept; }
73 bool KeyRingReport::askUserToTrustKey( const PublicKey &key )
74 { return _keyRingDefaultAccept; }
76 bool KeyRingReport::askUserToImportKey( const PublicKey &key)
77 { return _keyRingDefaultAccept; }
79 bool KeyRingReport::askUserToAcceptVerificationFailed( const std::string &file, const PublicKey &key )
80 { return _keyRingDefaultAccept; }
82 ///////////////////////////////////////////////////////////////////
84 // CLASS NAME : KeyRing::Impl
86 /** KeyRing implementation. */
89 Impl(const Pathname &baseTmpDir)
90 : _trusted_tmp_dir(baseTmpDir, "zypp-trusted-kr")
91 , _general_tmp_dir(baseTmpDir, "zypp-general-kr")
92 , _base_dir( baseTmpDir )
98 Impl( const Pathname &general_kr, const Pathname &trusted_kr )
100 filesystem::assert_dir(general_kr);
101 filesystem::assert_dir(trusted_kr);
103 generalKeyRing() = general_kr;
104 trustedKeyRing() = trusted_kr;
108 void importKey( const PublicKey &key, bool trusted = false);
109 void deleteKey( const std::string &id, bool trusted );
111 std::string readSignatureKeyId( const Pathname &signature );
113 std::list<PublicKey> trustedPublicKeys();
114 std::list<PublicKey> publicKeys();
116 void dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream );
118 bool verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature);
120 bool verifyFileSignature( const Pathname &file, const Pathname &signature);
121 bool verifyFileTrustedSignature( const Pathname &file, const Pathname &signature);
123 //mutable std::map<Locale, std::string> translations;
124 bool verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring);
125 void importKey( const Pathname &keyfile, const Pathname &keyring);
126 PublicKey exportKey( std::string id, const Pathname &keyring);
127 void dumpPublicKey( const std::string &id, const Pathname &keyring, std::ostream &stream );
128 void deleteKey( const std::string &id, const Pathname &keyring );
129 std::list<PublicKey> publicKeys(const Pathname &keyring);
131 bool publicKeyExists( std::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( Pathname("/var/tmp") ) );
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<KeyRingSignals> emitSignal;
170 importKey( key.path(), trusted ? trustedKeyRing() : generalKeyRing() );
173 void KeyRing::Impl::deleteKey( const std::string &id, bool trusted)
175 deleteKey( id, trusted ? trustedKeyRing() : generalKeyRing() );
178 std::list<PublicKey> KeyRing::Impl::publicKeys()
180 return publicKeys( generalKeyRing() );
183 std::list<PublicKey> KeyRing::Impl::trustedPublicKeys()
185 return publicKeys( trustedKeyRing() );
188 bool KeyRing::Impl::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
190 return verifyFile( file, signature, trustedKeyRing() );
193 bool KeyRing::Impl::verifyFileSignature( const Pathname &file, const Pathname &signature)
195 return verifyFile( file, signature, generalKeyRing() );
198 bool KeyRing::Impl::publicKeyExists( std::string id, const Pathname &keyring)
200 MIL << "Searching key [" << id << "] in keyring " << keyring << std::endl;
201 std::list<PublicKey> keys = publicKeys(keyring);
202 for (std::list<PublicKey>::const_iterator it = keys.begin(); it != keys.end(); it++)
204 if ( id == (*it).id() )
210 PublicKey KeyRing::Impl::exportKey( std::string id, const Pathname &keyring)
212 TmpFile tmp_file( _base_dir, "pubkey-"+id+"-" );
213 Pathname keyfile = tmp_file.path();
214 MIL << "Going to export key " << id << " from " << keyring << " to " << keyfile << endl;
217 std::ofstream os(keyfile.asString().c_str());
218 dumpPublicKey( id, keyring, os );
220 PublicKey key(keyfile);
223 catch (BadKeyException &e)
225 ERR << "Cannot create public key " << id << " from " << keyring << " keyring to file " << e.keyFile() << std::endl;
226 ZYPP_THROW(Exception("Cannot create public key " + id + " from " + keyring.asString() + " keyring to file " + e.keyFile().asString() ) );
228 catch (std::exception &e)
230 ERR << "Cannot export key " << id << " from " << keyring << " keyring to file " << keyfile << std::endl;
235 void KeyRing::Impl::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
237 dumpPublicKey( id, ( trusted ? trustedKeyRing() : generalKeyRing() ), stream );
240 void KeyRing::Impl::dumpPublicKey( const std::string &id, const Pathname &keyring, std::ostream &stream )
245 "--no-default-keyring",
249 "--no-permission-warning",
252 keyring.asString().c_str(),
258 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
261 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
269 bool KeyRing::Impl::verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature)
271 callback::SendReport<KeyRingReport> report;
272 callback::SendReport<KeyRingSignals> emitSignal;
273 MIL << "Going to verify signature for " << file << " with " << signature << std::endl;
275 // if signature does not exists, ask user if he wants to accept unsigned file.
276 if( signature.empty() || (!PathInfo(signature).isExist()) )
278 bool res = report->askUserToAcceptUnsignedFile( filedesc );
279 MIL << "User decision on unsigned file: " << res << endl;
283 // get the id of the signature
284 std::string id = readSignatureKeyId(signature);
286 // doeskey exists in trusted keyring
287 if ( publicKeyExists( id, trustedKeyRing() ) )
289 PublicKey key = exportKey( id, trustedKeyRing() );
291 MIL << "Key " << id << " " << key.name() << " is trusted" << std::endl;
292 // it exists, is trusted, does it validates?
293 if ( verifyFile( file, signature, trustedKeyRing() ) )
296 return report->askUserToAcceptVerificationFailed( filedesc, key );
300 if ( publicKeyExists( id, generalKeyRing() ) )
302 PublicKey key = exportKey( id, generalKeyRing());
303 MIL << "Exported key " << id << " to " << key.path() << std::endl;
304 MIL << "Key " << id << " " << key.name() << " is not trusted" << std::endl;
305 // ok the key is not trusted, ask the user to trust it or not
306 #warning We need the key details passed to the callback
307 if ( report->askUserToTrustKey( key ) )
309 MIL << "User wants to trust key " << id << " " << key.name() << std::endl;
310 //dumpFile(unKey.path());
312 Pathname which_keyring;
313 if ( report->askUserToImportKey( key ) )
315 MIL << "User wants to import key " << id << " " << key.name() << std::endl;
316 importKey( key.path(), trustedKeyRing() );
317 emitSignal->trustedKeyAdded( (const KeyRing &)(*this), key );
318 which_keyring = trustedKeyRing();
322 which_keyring = generalKeyRing();
326 if ( verifyFile( file, signature, which_keyring ) )
328 MIL << "File signature is verified" << std::endl;
333 MIL << "File signature check fails" << std::endl;
334 if ( report->askUserToAcceptVerificationFailed( filedesc, key ) )
336 MIL << "User continues anyway." << std::endl;
341 MIL << "User does not want to continue" << std::endl;
348 MIL << "User does not want to trust key " << id << " " << key.name() << std::endl;
355 MIL << "File [" << file << "] ( " << filedesc << " ) signed with unknown key [" << id << "]" << std::endl;
356 if ( report->askUserToAcceptUnknownKey( filedesc, id ) )
358 MIL << "User wants to accept unknown key " << id << std::endl;
363 MIL << "User does not want to accept unknown key " << id << std::endl;
371 std::list<PublicKey> KeyRing::Impl::publicKeys(const Pathname &keyring)
376 "--no-default-keyring",
378 "--list-public-keys",
380 "--with-fingerprint",
387 keyring.asString().c_str(),
390 std::list<PublicKey> keys;
392 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
396 str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
397 str::regex rxColonsFpr("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
399 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
401 //MIL << line << std::endl;
403 if(str::regex_match(line, what, rxColons, str::match_extra))
406 if ( what[1] == "pub" )
411 for(line2 = prog.receiveLine(); !line2.empty(); line2 = prog.receiveLine(), count++ )
414 if (str::regex_match(line2, what2, rxColonsFpr, str::match_extra))
416 if ( (what2[1] == "fpr") && (what2[1] != "pub") && (what2[1] !="sub"))
418 //key.fingerprint = what2[10];
423 PublicKey key(exportKey( id, keyring ));
425 MIL << "Found key " << "[" << key.id() << "]" << " [" << key.name() << "]" << " [" << key.fingerprint() << "]" << std::endl;
427 //dumpRegexpResults(what);
434 void KeyRing::Impl::importKey( const Pathname &keyfile, const Pathname &keyring)
436 if ( ! PathInfo(keyfile).isExist() )
437 ZYPP_THROW(KeyRingException("Tried to import not existant key " + keyfile.asString() + " into keyring " + keyring.asString()));
442 "--no-default-keyring",
446 "--no-permission-warning",
450 keyring.asString().c_str(),
452 keyfile.asString().c_str(),
457 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
461 // ZYPP_THROW(Exception("failed to import key"));
464 void KeyRing::Impl::deleteKey( const std::string &id, const Pathname &keyring )
469 "--no-default-keyring",
477 keyring.asString().c_str(),
483 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
485 int code = prog.close();
487 ZYPP_THROW(Exception("Failed to delete key."));
489 MIL << "Deleted key " << id << " from keyring " << keyring << std::endl;
493 std::string KeyRing::Impl::readSignatureKeyId(const Pathname &signature )
495 MIL << "Deetermining key id if signature " << signature << std::endl;
496 // HACK create a tmp keyring with no keys
497 TmpDir dir(_base_dir, "fake-keyring");
498 TmpFile fakeData(_base_dir, "fake-data");
503 "--no-default-keyring",
511 dir.path().asString().c_str(),
513 signature.asString().c_str(),
514 fakeData.path().asString().c_str(),
518 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
523 str::regex rxNoKey("^\\[GNUPG:\\] NO_PUBKEY (.+)\n$");
525 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
527 //MIL << "[" << line << "]" << std::endl;
529 if(str::regex_match(line, what, rxNoKey, str::match_extra))
531 if ( what.size() > 1 )
533 //dumpRegexpResults(what);
536 MIL << "Determined key id [" << id << "] for signature " << signature << std::endl;
541 bool KeyRing::Impl::verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring)
546 "--no-default-keyring",
554 keyring.asString().c_str(),
556 signature.asString().c_str(),
557 file.asString().c_str(),
561 // no need to parse output for now
562 // [GNUPG:] SIG_ID yCc4u223XRJnLnVAIllvYbUd8mQ 2006-03-29 1143618744
563 // [GNUPG:] GOODSIG A84EDAE89C800ACA SuSE Package Signing Key <build@suse.de>
564 // gpg: Good signature from "SuSE Package Signing Key <build@suse.de>"
565 // [GNUPG:] VALIDSIG 79C179B2E1C820C1890F9994A84EDAE89C800ACA 2006-03-29 1143618744 0 3 0 17 2 00 79C179B2E1C820C1890F9994A84EDAE89C800ACA
566 // [GNUPG:] TRUST_UNDEFINED
568 // [GNUPG:] ERRSIG A84EDAE89C800ACA 17 2 00 1143618744 9
569 // [GNUPG:] NO_PUBKEY A84EDAE89C800ACA
571 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
573 return (prog.close() == 0) ? true : false;
576 ///////////////////////////////////////////////////////////////////
578 ///////////////////////////////////////////////////////////////////
580 // CLASS NAME : KeyRing
582 ///////////////////////////////////////////////////////////////////
584 ///////////////////////////////////////////////////////////////////
586 // METHOD NAME : KeyRing::KeyRing
587 // METHOD TYPE : Ctor
589 KeyRing::KeyRing(const Pathname &baseTmpDir)
590 : _pimpl( new Impl(baseTmpDir) )
593 ///////////////////////////////////////////////////////////////////
595 // METHOD NAME : KeyRing::KeyRing
596 // METHOD TYPE : Ctor
598 //KeyRing::KeyRing( const Pathname &general_kr, const Pathname &trusted_kr )
599 //: _pimpl( new Impl(general_kr, trusted_kr) )
602 ///////////////////////////////////////////////////////////////////
604 // METHOD NAME : KeyRing::~KeyRing
605 // METHOD TYPE : Dtor
610 ///////////////////////////////////////////////////////////////////
612 // Forward to implementation:
614 ///////////////////////////////////////////////////////////////////
617 void KeyRing::importKey( const PublicKey &key, bool trusted )
619 _pimpl->importKey( key.path(), trusted );
622 std::string KeyRing::readSignatureKeyId( const Pathname &signature )
624 return _pimpl->readSignatureKeyId(signature);
627 void KeyRing::deleteKey( const std::string &id, bool trusted )
629 _pimpl->deleteKey(id, trusted);
632 std::list<PublicKey> KeyRing::publicKeys()
634 return _pimpl->publicKeys();
637 std::list<PublicKey> KeyRing::trustedPublicKeys()
639 return _pimpl->trustedPublicKeys();
642 bool KeyRing::verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature)
644 return _pimpl->verifyFileSignatureWorkflow(file, filedesc, signature);
647 bool KeyRing::verifyFileSignature( const Pathname &file, const Pathname &signature)
649 return _pimpl->verifyFileSignature(file, signature);
652 bool KeyRing::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
654 return _pimpl->verifyFileTrustedSignature(file, signature);
657 void KeyRing::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
659 _pimpl->dumpPublicKey( id, trusted, stream);
662 /////////////////////////////////////////////////////////////////
664 ///////////////////////////////////////////////////////////////////