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 &id )
70 { return _keyRingDefaultAccept; }
72 bool KeyRingReport::askUserToTrustKey( const PublicKey &key )
73 { return _keyRingDefaultAccept; }
75 bool KeyRingReport::askUserToImportKey( const PublicKey &key)
76 { return _keyRingDefaultAccept; }
78 bool KeyRingReport::askUserToAcceptVerificationFailed( const std::string &file, const PublicKey &key )
79 { return _keyRingDefaultAccept; }
81 ///////////////////////////////////////////////////////////////////
83 // CLASS NAME : KeyRing::Impl
85 /** KeyRing implementation. */
88 Impl(const Pathname &baseTmpDir)
89 : _trusted_tmp_dir(baseTmpDir, "zypp-trusted-kr")
90 , _general_tmp_dir(baseTmpDir, "zypp-general-kr")
91 , _base_dir( baseTmpDir )
97 Impl( const Pathname &general_kr, const Pathname &trusted_kr )
99 filesystem::assert_dir(general_kr);
100 filesystem::assert_dir(trusted_kr);
102 generalKeyRing() = general_kr;
103 trustedKeyRing() = trusted_kr;
107 void importKey( const PublicKey &key, bool trusted = false);
108 void deleteKey( const std::string &id, bool trusted );
110 std::string readSignatureKeyId( const Pathname &signature );
112 std::list<PublicKey> trustedPublicKeys();
113 std::list<PublicKey> publicKeys();
115 void dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream );
117 bool verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature);
119 bool verifyFileSignature( const Pathname &file, const Pathname &signature);
120 bool verifyFileTrustedSignature( const Pathname &file, const Pathname &signature);
122 //mutable std::map<Locale, std::string> translations;
123 bool verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring);
124 void importKey( const Pathname &keyfile, const Pathname &keyring);
125 PublicKey exportKey( std::string id, const Pathname &keyring);
126 void dumpPublicKey( const std::string &id, const Pathname &keyring, std::ostream &stream );
127 void deleteKey( const std::string &id, const Pathname &keyring );
128 std::list<PublicKey> publicKeys(const Pathname &keyring);
130 bool publicKeyExists( std::string id, const Pathname &keyring);
132 const Pathname generalKeyRing() const;
133 const Pathname trustedKeyRing() const;
135 // Used for trusted and untrusted keyrings
136 TmpDir _trusted_tmp_dir;
137 TmpDir _general_tmp_dir;
140 /** Offer default Impl. */
141 static shared_ptr<Impl> nullimpl()
143 static shared_ptr<Impl> _nullimpl( new Impl( Pathname("/var/tmp") ) );
148 friend Impl * rwcowClone<Impl>( const Impl * rhs );
149 /** clone for RWCOW_pointer */
151 { return new Impl( *this ); }
155 const Pathname KeyRing::Impl::generalKeyRing() const
157 return _general_tmp_dir.path();
160 const Pathname KeyRing::Impl::trustedKeyRing() const
162 return _trusted_tmp_dir.path();
165 void KeyRing::Impl::importKey( const PublicKey &key, bool trusted)
167 importKey( key.path(), trusted ? trustedKeyRing() : generalKeyRing() );
170 void KeyRing::Impl::deleteKey( const std::string &id, bool trusted)
172 deleteKey( id, trusted ? trustedKeyRing() : generalKeyRing() );
175 std::list<PublicKey> KeyRing::Impl::publicKeys()
177 return publicKeys( generalKeyRing() );
180 std::list<PublicKey> KeyRing::Impl::trustedPublicKeys()
182 return publicKeys( trustedKeyRing() );
185 bool KeyRing::Impl::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
187 return verifyFile( file, signature, trustedKeyRing() );
190 bool KeyRing::Impl::verifyFileSignature( const Pathname &file, const Pathname &signature)
192 return verifyFile( file, signature, generalKeyRing() );
195 bool KeyRing::Impl::publicKeyExists( std::string id, const Pathname &keyring)
197 MIL << "Searching key [" << id << "] in keyring " << keyring << std::endl;
198 std::list<PublicKey> keys = publicKeys(keyring);
199 for (std::list<PublicKey>::const_iterator it = keys.begin(); it != keys.end(); it++)
201 if ( id == (*it).id() )
207 PublicKey KeyRing::Impl::exportKey( std::string id, const Pathname &keyring)
209 TmpFile tmp_file( _base_dir, "pubkey-"+id+"-" );
210 Pathname keyfile = tmp_file.path();
211 MIL << "Going to export key " << id << " from " << keyring << " to " << keyfile << endl;
214 std::ofstream os(keyfile.asString().c_str());
215 dumpPublicKey( id, keyring, os );
217 PublicKey key(keyfile);
220 catch (BadKeyException &e)
222 ERR << "Cannot create public key " << id << " from " << keyring << " keyring to file " << e.keyFile() << std::endl;
223 ZYPP_THROW(Exception("Cannot create public key " + id + " from " + keyring.asString() + " keyring to file " + e.keyFile().asString() ) );
225 catch (std::exception &e)
227 ERR << "Cannot export key " << id << " from " << keyring << " keyring to file " << keyfile << std::endl;
232 void KeyRing::Impl::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
234 dumpPublicKey( id, ( trusted ? trustedKeyRing() : generalKeyRing() ), stream );
237 void KeyRing::Impl::dumpPublicKey( const std::string &id, const Pathname &keyring, std::ostream &stream )
242 "--no-default-keyring",
246 "--no-permission-warning",
249 keyring.asString().c_str(),
255 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
258 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
266 bool KeyRing::Impl::verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature)
268 callback::SendReport<KeyRingReport> report;
269 callback::SendReport<KeyRingSignals> emitSignal;
270 MIL << "Going to verify signature for " << file << " with " << signature << std::endl;
272 // if signature does not exists, ask user if he wants to accept unsigned file.
273 if( signature.empty() || (!PathInfo(signature).isExist()) )
275 bool res = report->askUserToAcceptUnsignedFile( filedesc );
276 MIL << "User decision on unsigned file: " << res << endl;
280 // get the id of the signature
281 std::string id = readSignatureKeyId(signature);
283 // doeskey exists in trusted keyring
284 if ( publicKeyExists( id, trustedKeyRing() ) )
286 PublicKey key = exportKey( id, trustedKeyRing() );
288 MIL << "Key " << id << " " << key.name() << " is trusted" << std::endl;
289 // it exists, is trusted, does it validates?
290 if ( verifyFile( file, signature, trustedKeyRing() ) )
293 return report->askUserToAcceptVerificationFailed( filedesc, key );
297 if ( publicKeyExists( id, generalKeyRing() ) )
299 PublicKey key = exportKey( id, generalKeyRing());
300 MIL << "Exported key " << id << " to " << key.path() << std::endl;
301 MIL << "Key " << id << " " << key.name() << " is not trusted" << std::endl;
302 // ok the key is not trusted, ask the user to trust it or not
303 #warning We need the key details passed to the callback
304 if ( report->askUserToTrustKey( key ) )
306 MIL << "User wants to trust key " << id << " " << key.name() << std::endl;
307 //dumpFile(unKey.path());
309 Pathname which_keyring;
310 if ( report->askUserToImportKey( key ) )
312 MIL << "User wants to import key " << id << " " << key.name() << std::endl;
313 importKey( key.path(), trustedKeyRing() );
314 emitSignal->trustedKeyAdded( (const KeyRing &)(*this), key );
315 which_keyring = trustedKeyRing();
319 which_keyring = generalKeyRing();
323 if ( verifyFile( file, signature, which_keyring ) )
325 MIL << "File signature is verified" << std::endl;
330 MIL << "File signature check fails" << std::endl;
331 if ( report->askUserToAcceptVerificationFailed( filedesc, key ) )
333 MIL << "User continues anyway." << std::endl;
338 MIL << "User does not want to continue" << std::endl;
345 MIL << "User does not want to trust key " << id << " " << key.name() << std::endl;
352 MIL << "File [" << file << "] ( " << filedesc << " ) signed with unknown key [" << id << "]" << std::endl;
353 if ( report->askUserToAcceptUnknownKey( filedesc, id ) )
355 MIL << "User wants to accept unknown key " << id << std::endl;
360 MIL << "User does not want to accept unknown key " << id << std::endl;
368 std::list<PublicKey> KeyRing::Impl::publicKeys(const Pathname &keyring)
373 "--no-default-keyring",
375 "--list-public-keys",
377 "--with-fingerprint",
384 keyring.asString().c_str(),
387 std::list<PublicKey> keys;
389 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
393 str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
394 str::regex rxColonsFpr("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
396 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
398 //MIL << line << std::endl;
400 if(str::regex_match(line, what, rxColons, str::match_extra))
403 if ( what[1] == "pub" )
408 for(line2 = prog.receiveLine(); !line2.empty(); line2 = prog.receiveLine(), count++ )
411 if (str::regex_match(line2, what2, rxColonsFpr, str::match_extra))
413 if ( (what2[1] == "fpr") && (what2[1] != "pub") && (what2[1] !="sub"))
415 //key.fingerprint = what2[10];
420 PublicKey key(exportKey( id, keyring ));
422 MIL << "Found key " << "[" << key.id() << "]" << " [" << key.name() << "]" << " [" << key.fingerprint() << "]" << std::endl;
424 //dumpRegexpResults(what);
431 void KeyRing::Impl::importKey( const Pathname &keyfile, const Pathname &keyring)
433 if ( ! PathInfo(keyfile).isExist() )
434 ZYPP_THROW(KeyRingException("Tried to import not existant key " + keyfile.asString() + " into keyring " + keyring.asString()));
439 "--no-default-keyring",
443 "--no-permission-warning",
447 keyring.asString().c_str(),
449 keyfile.asString().c_str(),
454 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
458 // ZYPP_THROW(Exception("failed to import key"));
461 void KeyRing::Impl::deleteKey( const std::string &id, const Pathname &keyring )
466 "--no-default-keyring",
474 keyring.asString().c_str(),
480 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
482 int code = prog.close();
484 ZYPP_THROW(Exception("Failed to delete key."));
486 MIL << "Deleted key " << id << " from keyring " << keyring << std::endl;
490 std::string KeyRing::Impl::readSignatureKeyId(const Pathname &signature )
492 MIL << "Deetermining key id if signature " << signature << std::endl;
493 // HACK create a tmp keyring with no keys
494 TmpDir dir(_base_dir, "fake-keyring");
495 TmpFile fakeData(_base_dir, "fake-data");
500 "--no-default-keyring",
508 dir.path().asString().c_str(),
510 signature.asString().c_str(),
511 fakeData.path().asString().c_str(),
515 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
520 str::regex rxNoKey("^\\[GNUPG:\\] NO_PUBKEY (.+)\n$");
522 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
524 //MIL << "[" << line << "]" << std::endl;
526 if(str::regex_match(line, what, rxNoKey, str::match_extra))
528 if ( what.size() > 1 )
530 //dumpRegexpResults(what);
533 MIL << "Determined key id [" << id << "] for signature " << signature << std::endl;
538 bool KeyRing::Impl::verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring)
543 "--no-default-keyring",
551 keyring.asString().c_str(),
553 signature.asString().c_str(),
554 file.asString().c_str(),
558 // no need to parse output for now
559 // [GNUPG:] SIG_ID yCc4u223XRJnLnVAIllvYbUd8mQ 2006-03-29 1143618744
560 // [GNUPG:] GOODSIG A84EDAE89C800ACA SuSE Package Signing Key <build@suse.de>
561 // gpg: Good signature from "SuSE Package Signing Key <build@suse.de>"
562 // [GNUPG:] VALIDSIG 79C179B2E1C820C1890F9994A84EDAE89C800ACA 2006-03-29 1143618744 0 3 0 17 2 00 79C179B2E1C820C1890F9994A84EDAE89C800ACA
563 // [GNUPG:] TRUST_UNDEFINED
565 // [GNUPG:] ERRSIG A84EDAE89C800ACA 17 2 00 1143618744 9
566 // [GNUPG:] NO_PUBKEY A84EDAE89C800ACA
568 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
570 return (prog.close() == 0) ? true : false;
573 ///////////////////////////////////////////////////////////////////
575 ///////////////////////////////////////////////////////////////////
577 // CLASS NAME : KeyRing
579 ///////////////////////////////////////////////////////////////////
581 ///////////////////////////////////////////////////////////////////
583 // METHOD NAME : KeyRing::KeyRing
584 // METHOD TYPE : Ctor
586 KeyRing::KeyRing(const Pathname &baseTmpDir)
587 : _pimpl( new Impl(baseTmpDir) )
590 ///////////////////////////////////////////////////////////////////
592 // METHOD NAME : KeyRing::KeyRing
593 // METHOD TYPE : Ctor
595 //KeyRing::KeyRing( const Pathname &general_kr, const Pathname &trusted_kr )
596 //: _pimpl( new Impl(general_kr, trusted_kr) )
599 ///////////////////////////////////////////////////////////////////
601 // METHOD NAME : KeyRing::~KeyRing
602 // METHOD TYPE : Dtor
607 ///////////////////////////////////////////////////////////////////
609 // Forward to implementation:
611 ///////////////////////////////////////////////////////////////////
614 void KeyRing::importKey( const PublicKey &key, bool trusted )
616 _pimpl->importKey( key.path(), trusted );
619 std::string KeyRing::readSignatureKeyId( const Pathname &signature )
621 return _pimpl->readSignatureKeyId(signature);
624 void KeyRing::deleteKey( const std::string &id, bool trusted )
626 _pimpl->deleteKey(id, trusted);
629 std::list<PublicKey> KeyRing::publicKeys()
631 return _pimpl->publicKeys();
634 std::list<PublicKey> KeyRing::trustedPublicKeys()
636 return _pimpl->trustedPublicKeys();
639 bool KeyRing::verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature)
641 return _pimpl->verifyFileSignatureWorkflow(file, filedesc, signature);
644 bool KeyRing::verifyFileSignature( const Pathname &file, const Pathname &signature)
646 return _pimpl->verifyFileSignature(file, signature);
649 bool KeyRing::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
651 return _pimpl->verifyFileTrustedSignature(file, signature);
654 void KeyRing::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
656 _pimpl->dumpPublicKey( id, trusted, stream);
659 /////////////////////////////////////////////////////////////////
661 ///////////////////////////////////////////////////////////////////