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/KeyRing.h"
25 #include "zypp/ExternalProgram.h"
26 #include "zypp/TmpPath.h"
29 using namespace zypp::filesystem;
32 #undef ZYPP_BASE_LOGGER_LOGGROUP
33 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::KeyRing"
35 ///////////////////////////////////////////////////////////////////
37 { /////////////////////////////////////////////////////////////////
39 IMPL_PTR_TYPE(KeyRing);
41 static void dumpRegexpResults( const str::smatch &what )
43 for ( unsigned int k=0; k < what.size(); k++)
45 XXX << "[match "<< k << "] [" << what[k] << "]" << std::endl;
49 static bool printLine( const std::string &line )
51 MIL << line << std::endl;
54 static void dumpFile(const Pathname &file)
56 std::ifstream is(file.asString().c_str());
57 iostr::forEachLine( is, printLine);
62 bool _keyRingDefaultAccept( getenv("ZYPP_KEYRING_DEFAULT_ACCEPT_ALL") );
65 bool KeyRingReport::askUserToAcceptUnsignedFile( const Pathname &file )
66 { return _keyRingDefaultAccept; }
68 bool KeyRingReport::askUserToAcceptUnknownKey( const Pathname &file, const std::string &keyid, const std::string &keyname )
69 { return _keyRingDefaultAccept; }
71 bool KeyRingReport::askUserToTrustKey( const std::string &keyid, const std::string &keyname, const std::string &keydetails )
72 { return _keyRingDefaultAccept; }
74 bool KeyRingReport::askUserToAcceptVerificationFailed( const Pathname &file, const std::string &keyid, const std::string &keyname )
75 { return _keyRingDefaultAccept; }
77 ///////////////////////////////////////////////////////////////////
79 // CLASS NAME : KeyRing::Impl
81 /** KeyRing implementation. */
86 _general_kr = _general_tmp_dir.path();
87 _trusted_kr = _trusted_tmp_dir.path();
91 Impl( const Pathname &general_kr, const Pathname &trusted_kr )
93 filesystem::assert_dir(general_kr);
94 filesystem::assert_dir(trusted_kr);
96 _general_kr = general_kr;
97 _trusted_kr = trusted_kr;
101 void importKey( const Pathname &keyfile, bool trusted = false);
102 PublicKey readPublicKey( const Pathname &keyfile );
103 std::string readSignatureKeyId( const Pathname &data, const Pathname &keyfile );
105 void deleteKey( const std::string &id, bool trusted );
106 std::list<PublicKey> trustedPublicKeys();
107 std::list<PublicKey> publicKeys();
109 void dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream );
111 bool verifyFileSignatureWorkflow( const Pathname &file, const Pathname &signature);
113 bool verifyFileSignature( const Pathname &file, const Pathname &signature);
114 bool verifyFileTrustedSignature( const Pathname &file, const Pathname &signature);
116 //mutable std::map<Locale, std::string> translations;
117 bool verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring);
118 void importKey( const Pathname &keyfile, const Pathname &keyring);
120 void exportKey( std::string id, const Pathname &keyfile, bool trusted);
122 void deleteKey( const std::string &id, const Pathname &keyring );
123 std::list<PublicKey> publicKeys(const Pathname &keyring);
125 bool publicKeyExists( std::string id, const Pathname &keyring);
127 Pathname _general_kr;
128 Pathname _trusted_kr;
130 // Used for trusted and untrusted keyrings
131 TmpDir _trusted_tmp_dir;
132 TmpDir _general_tmp_dir;
134 /** Offer default Impl. */
135 static shared_ptr<Impl> nullimpl()
137 static shared_ptr<Impl> _nullimpl( new Impl );
142 friend Impl * rwcowClone<Impl>( const Impl * rhs );
143 /** clone for RWCOW_pointer */
145 { return new Impl( *this ); }
148 void KeyRing::Impl::importKey( const Pathname &keyfile, bool trusted)
150 importKey( keyfile, trusted ? _trusted_kr : _general_kr );
153 void KeyRing::Impl::deleteKey( const std::string &id, bool trusted)
155 deleteKey( id, trusted ? _trusted_kr : _general_kr );
158 std::list<PublicKey> KeyRing::Impl::publicKeys()
160 return publicKeys( _general_kr );
163 std::list<PublicKey> KeyRing::Impl::trustedPublicKeys()
165 return publicKeys( _trusted_kr );
168 bool KeyRing::Impl::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
170 return verifyFile( file, signature, _trusted_kr );
173 bool KeyRing::Impl::verifyFileSignature( const Pathname &file, const Pathname &signature)
175 return verifyFile( file, signature, _general_kr );
178 bool KeyRing::Impl::publicKeyExists( std::string id, const Pathname &keyring)
180 std::list<PublicKey> keys = publicKeys(keyring);
181 for (std::list<PublicKey>::const_iterator it = keys.begin(); it != keys.end(); it++)
183 if ( id == (*it).id )
189 void KeyRing::Impl::exportKey( std::string id, const Pathname &keyfile, bool trusted)
192 std::ofstream os(keyfile.asString().c_str());
193 dumpPublicKey( id, trusted, os );
196 catch (std::exception &e)
198 ERR << "Cannot export key " << id << " from " << (trusted ? "trusted" : "untrusted ") << " keyring to file " << keyfile << std::endl;
202 void KeyRing::Impl::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
204 Pathname keyring = trusted ? _trusted_kr : _general_kr;
211 "--no-permission-warning",
214 keyring.asString().c_str(),
220 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
223 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
231 bool KeyRing::Impl::verifyFileSignatureWorkflow( const Pathname &file, const Pathname &signature)
233 if ( ! getenv("ZYPP_CHECKSIG") )
235 MIL << "Digital signature check disabled. Accepting source." << std::endl;
239 callback::SendReport<KeyRingReport> report;
240 callback::SendReport<KeyRingSignals> emitSignal;
241 MIL << "Going to verify signature for " << file << " with " << signature << std::endl;
243 // if signature does not exists, ask user if he wants to accept unsigned file.
244 if( signature.empty() || (!PathInfo(signature).isExist()) )
246 bool res = report->askUserToAcceptUnsignedFile( file );
247 MIL << "User decision on unsigned file: " << res << endl;
251 // get the id of the signature
252 std::string id = readSignatureKeyId(file, signature);
254 // doeskey exists in trusted keyring
255 if ( publicKeyExists( id, _trusted_kr ) )
258 exportKey( id, trustedKey.path(), true);
259 PublicKey key = readPublicKey(trustedKey.path());
260 MIL << "Key " << id << " " << key.name << " is trusted" << std::endl;
261 // it exists, is trusted, does it validates?
262 if ( verifyFile( file, signature, _trusted_kr ) )
265 return report->askUserToAcceptVerificationFailed( file, key.id, key.name );
269 if ( publicKeyExists( id, _general_kr ) )
272 exportKey( id, unKey.path(), false);
273 MIL << "Exported key " << id << " to " << unKey << std::endl;
275 PublicKey key = readPublicKey(unKey.path());
276 MIL << "Key " << id << " " << key.name << " is not trusted" << std::endl;
277 // ok the key is not trusted, ask the user to trust it or not
278 #warning We need the key details passed to the callback
279 if ( report->askUserToTrustKey(key.id, key.name, "") )
281 MIL << "User wants to trust key " << id << " " << key.name << std::endl;
282 //dumpFile(unKey.path());
284 importKey( unKey.path(), _trusted_kr );
285 emitSignal->trustedKeyAdded( (const KeyRing &)(*this), id, key.name );
288 if ( verifyFile( file, signature, _trusted_kr ) )
290 MIL << "File signature is verified" << std::endl;
295 MIL << "File signature check fails" << std::endl;
296 if ( report->askUserToAcceptVerificationFailed( file, key.id, key.name ) )
298 MIL << "User continues anyway." << std::endl;
303 MIL << "User does not want to continue" << std::endl;
310 MIL << "User does not want to trust key " << id << " " << key.name << std::endl;
317 if ( report->askUserToAcceptUnknownKey( file, id, "Unknown Key" ) )
319 MIL << "User wants to accept unknown key " << id << std::endl;
324 MIL << "User does not want to accept unknown key " << id << std::endl;
333 PublicKey KeyRing::Impl::readPublicKey( const Pathname &keyfile )
338 "--with-fingerprint",
346 keyfile.asString().c_str(),
350 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
355 str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
357 // pub:-:1024:17:A84EDAE89C800ACA:2000-10-19:2008-06-21::-:SuSE Package Signing Key <build@suse.de>:
360 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
362 //MIL << "[" << line << "]" << std::endl;
364 if(str::regex_match(line, what, rxColons, str::match_extra))
366 if ( what[1] == "pub" )
372 //dumpRegexpResults(what);
379 std::list<PublicKey> KeyRing::Impl::publicKeys(const Pathname &keyring)
385 "--list-public-keys",
387 "--with-fingerprint",
389 keyring.asString().c_str(),
392 std::list<PublicKey> keys;
394 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
398 str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\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))
405 if ( what[1] == "pub" )
410 MIL << "Found key " << key.id << " [" << key.name << "]" << std::endl;
413 //dumpRegexpResults(what);
420 void KeyRing::Impl::importKey( const Pathname &keyfile, const Pathname &keyring)
428 "--no-permission-warning",
432 keyring.asString().c_str(),
434 keyfile.asString().c_str(),
439 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
443 // ZYPP_THROW(Exception("failed to import key"));
446 void KeyRing::Impl::deleteKey( const std::string &id, const Pathname &keyring )
458 keyring.asString().c_str(),
464 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
466 int code = prog.close();
468 ZYPP_THROW(Exception("Failed to delete key."));
470 MIL << "Deleted key " << id << " from keyring " << keyring << std::endl;
474 std::string KeyRing::Impl::readSignatureKeyId( const Pathname &data, const Pathname &keyfile )
476 // HACK create a tmp keyring with no keys
489 dir.path().asString().c_str(),
491 keyfile.asString().c_str(),
492 data.asString().c_str(),
496 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
501 str::regex rxNoKey("^\\[GNUPG:\\] NO_PUBKEY (.+)\n$");
503 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
505 //MIL << "[" << line << "]" << std::endl;
507 if(str::regex_match(line, what, rxNoKey, str::match_extra))
509 if ( what.size() > 1 )
511 //dumpRegexpResults(what);
518 bool KeyRing::Impl::verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring)
530 keyring.asString().c_str(),
532 signature.asString().c_str(),
533 file.asString().c_str(),
537 // no need to parse output for now
538 // [GNUPG:] SIG_ID yCc4u223XRJnLnVAIllvYbUd8mQ 2006-03-29 1143618744
539 // [GNUPG:] GOODSIG A84EDAE89C800ACA SuSE Package Signing Key <build@suse.de>
540 // gpg: Good signature from "SuSE Package Signing Key <build@suse.de>"
541 // [GNUPG:] VALIDSIG 79C179B2E1C820C1890F9994A84EDAE89C800ACA 2006-03-29 1143618744 0 3 0 17 2 00 79C179B2E1C820C1890F9994A84EDAE89C800ACA
542 // [GNUPG:] TRUST_UNDEFINED
544 // [GNUPG:] ERRSIG A84EDAE89C800ACA 17 2 00 1143618744 9
545 // [GNUPG:] NO_PUBKEY A84EDAE89C800ACA
547 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
549 return (prog.close() == 0) ? true : false;
552 ///////////////////////////////////////////////////////////////////
554 ///////////////////////////////////////////////////////////////////
556 // CLASS NAME : KeyRing
558 ///////////////////////////////////////////////////////////////////
560 ///////////////////////////////////////////////////////////////////
562 // METHOD NAME : KeyRing::KeyRing
563 // METHOD TYPE : Ctor
566 : _pimpl( new Impl() )
569 ///////////////////////////////////////////////////////////////////
571 // METHOD NAME : KeyRing::KeyRing
572 // METHOD TYPE : Ctor
574 //KeyRing::KeyRing( const Pathname &general_kr, const Pathname &trusted_kr )
575 //: _pimpl( new Impl(general_kr, trusted_kr) )
578 ///////////////////////////////////////////////////////////////////
580 // METHOD NAME : KeyRing::~KeyRing
581 // METHOD TYPE : Dtor
586 ///////////////////////////////////////////////////////////////////
588 // Forward to implementation:
590 ///////////////////////////////////////////////////////////////////
592 void KeyRing::importKey( const Pathname &keyfile, bool trusted)
594 _pimpl->importKey(keyfile, trusted);
597 PublicKey KeyRing::readPublicKey( const Pathname &keyfile )
599 return _pimpl->readPublicKey(keyfile);
602 std::string KeyRing::readSignatureKeyId( const Pathname &data, const Pathname &keyfile )
604 return _pimpl->readSignatureKeyId(data, keyfile);
607 void KeyRing::deleteKey( const std::string &id, bool trusted )
609 _pimpl->deleteKey(id, trusted);
612 std::list<PublicKey> KeyRing::publicKeys()
614 return _pimpl->publicKeys();
617 std::list<PublicKey> KeyRing::trustedPublicKeys()
619 return _pimpl->trustedPublicKeys();
622 bool KeyRing::verifyFileSignatureWorkflow( const Pathname &file, const Pathname &signature)
624 return _pimpl->verifyFileSignatureWorkflow(file, signature);
627 bool KeyRing::verifyFileSignature( const Pathname &file, const Pathname &signature)
629 return _pimpl->verifyFileSignature(file, signature);
632 bool KeyRing::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
634 return _pimpl->verifyFileTrustedSignature(file, signature);
637 void KeyRing::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
639 _pimpl->dumpPublicKey( id, trusted, stream);
642 /////////////////////////////////////////////////////////////////
644 ///////////////////////////////////////////////////////////////////