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 importKey( key.path(), trusted ? trustedKeyRing() : generalKeyRing() );
171 void KeyRing::Impl::deleteKey( const std::string &id, bool trusted)
173 deleteKey( id, trusted ? trustedKeyRing() : generalKeyRing() );
176 std::list<PublicKey> KeyRing::Impl::publicKeys()
178 return publicKeys( generalKeyRing() );
181 std::list<PublicKey> KeyRing::Impl::trustedPublicKeys()
183 return publicKeys( trustedKeyRing() );
186 bool KeyRing::Impl::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
188 return verifyFile( file, signature, trustedKeyRing() );
191 bool KeyRing::Impl::verifyFileSignature( const Pathname &file, const Pathname &signature)
193 return verifyFile( file, signature, generalKeyRing() );
196 bool KeyRing::Impl::publicKeyExists( std::string id, const Pathname &keyring)
198 MIL << "Searching key [" << id << "] in keyring " << keyring << std::endl;
199 std::list<PublicKey> keys = publicKeys(keyring);
200 for (std::list<PublicKey>::const_iterator it = keys.begin(); it != keys.end(); it++)
202 if ( id == (*it).id() )
208 PublicKey KeyRing::Impl::exportKey( std::string id, const Pathname &keyring)
210 TmpFile tmp_file( _base_dir, "pubkey-"+id+"-" );
211 Pathname keyfile = tmp_file.path();
212 MIL << "Going to export key " << id << " from " << keyring << " to " << keyfile << endl;
215 std::ofstream os(keyfile.asString().c_str());
216 dumpPublicKey( id, keyring, os );
218 PublicKey key(keyfile);
221 catch (BadKeyException &e)
223 ERR << "Cannot create public key " << id << " from " << keyring << " keyring to file " << e.keyFile() << std::endl;
224 ZYPP_THROW(Exception("Cannot create public key " + id + " from " + keyring.asString() + " keyring to file " + e.keyFile().asString() ) );
226 catch (std::exception &e)
228 ERR << "Cannot export key " << id << " from " << keyring << " keyring to file " << keyfile << std::endl;
233 void KeyRing::Impl::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
235 dumpPublicKey( id, ( trusted ? trustedKeyRing() : generalKeyRing() ), stream );
238 void KeyRing::Impl::dumpPublicKey( const std::string &id, const Pathname &keyring, std::ostream &stream )
243 "--no-default-keyring",
247 "--no-permission-warning",
250 keyring.asString().c_str(),
256 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
259 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
267 bool KeyRing::Impl::verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature)
269 callback::SendReport<KeyRingReport> report;
270 callback::SendReport<KeyRingSignals> emitSignal;
271 MIL << "Going to verify signature for " << file << " with " << signature << std::endl;
273 // if signature does not exists, ask user if he wants to accept unsigned file.
274 if( signature.empty() || (!PathInfo(signature).isExist()) )
276 bool res = report->askUserToAcceptUnsignedFile( filedesc );
277 MIL << "User decision on unsigned file: " << res << endl;
281 // get the id of the signature
282 std::string id = readSignatureKeyId(signature);
284 // doeskey exists in trusted keyring
285 if ( publicKeyExists( id, trustedKeyRing() ) )
287 PublicKey key = exportKey( id, trustedKeyRing() );
289 MIL << "Key " << id << " " << key.name() << " is trusted" << std::endl;
290 // it exists, is trusted, does it validates?
291 if ( verifyFile( file, signature, trustedKeyRing() ) )
294 return report->askUserToAcceptVerificationFailed( filedesc, key );
298 if ( publicKeyExists( id, generalKeyRing() ) )
300 PublicKey key = exportKey( id, generalKeyRing());
301 MIL << "Exported key " << id << " to " << key.path() << std::endl;
302 MIL << "Key " << id << " " << key.name() << " is not trusted" << std::endl;
303 // ok the key is not trusted, ask the user to trust it or not
304 #warning We need the key details passed to the callback
305 if ( report->askUserToTrustKey( key ) )
307 MIL << "User wants to trust key " << id << " " << key.name() << std::endl;
308 //dumpFile(unKey.path());
310 Pathname which_keyring;
311 if ( report->askUserToImportKey( key ) )
313 MIL << "User wants to import key " << id << " " << key.name() << std::endl;
314 importKey( key.path(), trustedKeyRing() );
315 emitSignal->trustedKeyAdded( (const KeyRing &)(*this), key );
316 which_keyring = trustedKeyRing();
320 which_keyring = generalKeyRing();
324 if ( verifyFile( file, signature, which_keyring ) )
326 MIL << "File signature is verified" << std::endl;
331 MIL << "File signature check fails" << std::endl;
332 if ( report->askUserToAcceptVerificationFailed( filedesc, key ) )
334 MIL << "User continues anyway." << std::endl;
339 MIL << "User does not want to continue" << std::endl;
346 MIL << "User does not want to trust key " << id << " " << key.name() << std::endl;
353 MIL << "File [" << file << "] ( " << filedesc << " ) signed with unknown key [" << id << "]" << std::endl;
354 if ( report->askUserToAcceptUnknownKey( filedesc, id ) )
356 MIL << "User wants to accept unknown key " << id << std::endl;
361 MIL << "User does not want to accept unknown key " << id << std::endl;
369 std::list<PublicKey> KeyRing::Impl::publicKeys(const Pathname &keyring)
374 "--no-default-keyring",
376 "--list-public-keys",
378 "--with-fingerprint",
385 keyring.asString().c_str(),
388 std::list<PublicKey> keys;
390 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
394 str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
395 str::regex rxColonsFpr("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
397 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
399 //MIL << line << std::endl;
401 if(str::regex_match(line, what, rxColons, str::match_extra))
404 if ( what[1] == "pub" )
409 for(line2 = prog.receiveLine(); !line2.empty(); line2 = prog.receiveLine(), count++ )
412 if (str::regex_match(line2, what2, rxColonsFpr, str::match_extra))
414 if ( (what2[1] == "fpr") && (what2[1] != "pub") && (what2[1] !="sub"))
416 //key.fingerprint = what2[10];
421 PublicKey key(exportKey( id, keyring ));
423 MIL << "Found key " << "[" << key.id() << "]" << " [" << key.name() << "]" << " [" << key.fingerprint() << "]" << std::endl;
425 //dumpRegexpResults(what);
432 void KeyRing::Impl::importKey( const Pathname &keyfile, const Pathname &keyring)
434 if ( ! PathInfo(keyfile).isExist() )
435 ZYPP_THROW(KeyRingException("Tried to import not existant key " + keyfile.asString() + " into keyring " + keyring.asString()));
440 "--no-default-keyring",
444 "--no-permission-warning",
448 keyring.asString().c_str(),
450 keyfile.asString().c_str(),
455 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
459 // ZYPP_THROW(Exception("failed to import key"));
462 void KeyRing::Impl::deleteKey( const std::string &id, const Pathname &keyring )
467 "--no-default-keyring",
475 keyring.asString().c_str(),
481 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
483 int code = prog.close();
485 ZYPP_THROW(Exception("Failed to delete key."));
487 MIL << "Deleted key " << id << " from keyring " << keyring << std::endl;
491 std::string KeyRing::Impl::readSignatureKeyId(const Pathname &signature )
493 MIL << "Deetermining key id if signature " << signature << std::endl;
494 // HACK create a tmp keyring with no keys
495 TmpDir dir(_base_dir, "fake-keyring");
496 TmpFile fakeData(_base_dir, "fake-data");
501 "--no-default-keyring",
509 dir.path().asString().c_str(),
511 signature.asString().c_str(),
512 fakeData.path().asString().c_str(),
516 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
521 str::regex rxNoKey("^\\[GNUPG:\\] NO_PUBKEY (.+)\n$");
523 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
525 //MIL << "[" << line << "]" << std::endl;
527 if(str::regex_match(line, what, rxNoKey, str::match_extra))
529 if ( what.size() > 1 )
531 //dumpRegexpResults(what);
534 MIL << "Determined key id [" << id << "] for signature " << signature << std::endl;
539 bool KeyRing::Impl::verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring)
544 "--no-default-keyring",
552 keyring.asString().c_str(),
554 signature.asString().c_str(),
555 file.asString().c_str(),
559 // no need to parse output for now
560 // [GNUPG:] SIG_ID yCc4u223XRJnLnVAIllvYbUd8mQ 2006-03-29 1143618744
561 // [GNUPG:] GOODSIG A84EDAE89C800ACA SuSE Package Signing Key <build@suse.de>
562 // gpg: Good signature from "SuSE Package Signing Key <build@suse.de>"
563 // [GNUPG:] VALIDSIG 79C179B2E1C820C1890F9994A84EDAE89C800ACA 2006-03-29 1143618744 0 3 0 17 2 00 79C179B2E1C820C1890F9994A84EDAE89C800ACA
564 // [GNUPG:] TRUST_UNDEFINED
566 // [GNUPG:] ERRSIG A84EDAE89C800ACA 17 2 00 1143618744 9
567 // [GNUPG:] NO_PUBKEY A84EDAE89C800ACA
569 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
571 return (prog.close() == 0) ? true : false;
574 ///////////////////////////////////////////////////////////////////
576 ///////////////////////////////////////////////////////////////////
578 // CLASS NAME : KeyRing
580 ///////////////////////////////////////////////////////////////////
582 ///////////////////////////////////////////////////////////////////
584 // METHOD NAME : KeyRing::KeyRing
585 // METHOD TYPE : Ctor
587 KeyRing::KeyRing(const Pathname &baseTmpDir)
588 : _pimpl( new Impl(baseTmpDir) )
591 ///////////////////////////////////////////////////////////////////
593 // METHOD NAME : KeyRing::KeyRing
594 // METHOD TYPE : Ctor
596 //KeyRing::KeyRing( const Pathname &general_kr, const Pathname &trusted_kr )
597 //: _pimpl( new Impl(general_kr, trusted_kr) )
600 ///////////////////////////////////////////////////////////////////
602 // METHOD NAME : KeyRing::~KeyRing
603 // METHOD TYPE : Dtor
608 ///////////////////////////////////////////////////////////////////
610 // Forward to implementation:
612 ///////////////////////////////////////////////////////////////////
615 void KeyRing::importKey( const PublicKey &key, bool trusted )
617 _pimpl->importKey( key.path(), trusted );
620 std::string KeyRing::readSignatureKeyId( const Pathname &signature )
622 return _pimpl->readSignatureKeyId(signature);
625 void KeyRing::deleteKey( const std::string &id, bool trusted )
627 _pimpl->deleteKey(id, trusted);
630 std::list<PublicKey> KeyRing::publicKeys()
632 return _pimpl->publicKeys();
635 std::list<PublicKey> KeyRing::trustedPublicKeys()
637 return _pimpl->trustedPublicKeys();
640 bool KeyRing::verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature)
642 return _pimpl->verifyFileSignatureWorkflow(file, filedesc, signature);
645 bool KeyRing::verifyFileSignature( const Pathname &file, const Pathname &signature)
647 return _pimpl->verifyFileSignature(file, signature);
650 bool KeyRing::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
652 return _pimpl->verifyFileTrustedSignature(file, signature);
655 void KeyRing::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
657 _pimpl->dumpPublicKey( id, trusted, stream);
660 /////////////////////////////////////////////////////////////////
662 ///////////////////////////////////////////////////////////////////