1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/KeyRing.cc
18 #include "zypp/TmpPath.h"
19 #include "zypp/ZYppFactory.h"
20 #include "zypp/ZYpp.h"
22 #include "zypp/base/LogTools.h"
23 #include "zypp/base/IOStream.h"
24 #include "zypp/base/String.h"
25 #include "zypp/base/Regex.h"
26 #include "zypp/base/Gettext.h"
27 #include "zypp/base/WatchFile.h"
28 #include "zypp/PathInfo.h"
29 #include "zypp/KeyRing.h"
30 #include "zypp/ExternalProgram.h"
31 #include "zypp/TmpPath.h"
35 #undef ZYPP_BASE_LOGGER_LOGGROUP
36 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::KeyRing"
38 /** \todo Fix duplicate define in PublicKey/KeyRing */
39 #define GPG_BINARY "/usr/bin/gpg2"
41 ///////////////////////////////////////////////////////////////////
43 { /////////////////////////////////////////////////////////////////
45 IMPL_PTR_TYPE(KeyRing);
49 KeyRing::DefaultAccept _keyRingDefaultAccept( KeyRing::ACCEPT_NOTHING );
52 KeyRing::DefaultAccept KeyRing::defaultAccept()
53 { return _keyRingDefaultAccept; }
55 void KeyRing::setDefaultAccept( DefaultAccept value_r )
57 MIL << "Set new KeyRing::DefaultAccept: " << value_r << endl;
58 _keyRingDefaultAccept = value_r;
61 void KeyRingReport::infoVerify( const std::string & file_r, const PublicKeyData & keyData_r, const KeyContext & keycontext )
64 bool KeyRingReport::askUserToAcceptUnsignedFile( const std::string & file, const KeyContext & keycontext )
65 { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_UNSIGNED_FILE ); }
67 KeyRingReport::KeyTrust
68 KeyRingReport::askUserToAcceptKey( const PublicKey & key, const KeyContext & keycontext )
70 if ( _keyRingDefaultAccept.testFlag( KeyRing::TRUST_KEY_TEMPORARILY ) )
71 return KEY_TRUST_TEMPORARILY;
72 if ( _keyRingDefaultAccept.testFlag( KeyRing::TRUST_AND_IMPORT_KEY ) )
73 return KEY_TRUST_AND_IMPORT;
74 return KEY_DONT_TRUST;
77 bool KeyRingReport::askUserToAcceptUnknownKey( const std::string & file, const std::string & id, const KeyContext & keycontext )
78 { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_UNKNOWNKEY ); }
80 bool KeyRingReport::askUserToAcceptVerificationFailed( const std::string & file, const PublicKey & key, const KeyContext & keycontext )
81 { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_VERIFICATION_FAILED ); }
85 ///////////////////////////////////////////////////////////////////
86 /// \class CachedPublicKeyData
87 /// \brief Functor returning the keyrings data (cached).
89 /// const std::list<PublicKeyData> & cachedPublicKeyData( const Pathname & keyring );
91 ///////////////////////////////////////////////////////////////////
92 struct CachedPublicKeyData // : private base::NonCopyable - but KeyRing uses RWCOW though also NonCopyable :(
94 const std::list<PublicKeyData> & operator()( const Pathname & keyring_r ) const
95 { return getData( keyring_r ); }
100 // Empty copy ctor to allow insert into std::map as
101 // scoped_ptr is noncopyable.
103 Cache( const Cache & rhs ) {}
105 void assertCache( const Pathname & keyring_r )
107 // .kbx since gpg2-2.1
109 _keyringK.reset( new WatchFile( keyring_r/"pubring.kbx", WatchFile::NO_INIT ) );
111 _keyringP.reset( new WatchFile( keyring_r/"pubring.gpg", WatchFile::NO_INIT ) );
114 bool hasChanged() const
116 bool k = _keyringK->hasChanged(); // be sure both files are checked
117 bool p = _keyringP->hasChanged();
121 std::list<PublicKeyData> _data;
124 scoped_ptr<WatchFile> _keyringK;
125 scoped_ptr<WatchFile> _keyringP;
128 typedef std::map<Pathname,Cache> CacheMap;
130 const std::list<PublicKeyData> & getData( const Pathname & keyring_r ) const
132 Cache & cache( _cacheMap[keyring_r] );
133 // init new cache entry
134 cache.assertCache( keyring_r );
135 return getData( keyring_r, cache );
138 const std::list<PublicKeyData> & getData( const Pathname & keyring_r, Cache & cache_r ) const
140 if ( cache_r.hasChanged() )
145 "--list-public-keys",
146 "--homedir", keyring_r.c_str(),
147 "--no-default-keyring",
151 "--with-fingerprint",
160 PublicKeyScanner scanner;
161 ExternalProgram prog( argv ,ExternalProgram::Discard_Stderr, false, -1, true );
162 for( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
164 scanner.scan( line );
168 cache_r._data.swap( scanner._keys );
169 MIL << "Found keys: " << cache_r._data << endl;
171 return cache_r._data;
174 mutable CacheMap _cacheMap;
176 ///////////////////////////////////////////////////////////////////
179 ///////////////////////////////////////////////////////////////////
181 // CLASS NAME : KeyRing::Impl
183 /** KeyRing implementation. */
186 Impl( const Pathname & baseTmpDir )
187 : _trusted_tmp_dir( baseTmpDir, "zypp-trusted-kr" )
188 , _general_tmp_dir( baseTmpDir, "zypp-general-kr" )
189 , _base_dir( baseTmpDir )
191 MIL << "Current KeyRing::DefaultAccept: " << _keyRingDefaultAccept << endl;
194 void importKey( const PublicKey & key, bool trusted = false );
195 void multiKeyImport( const Pathname & keyfile_r, bool trusted_r = false );
196 void deleteKey( const std::string & id, bool trusted );
198 std::string readSignatureKeyId( const Pathname & signature );
200 bool isKeyTrusted( const std::string & id )
201 { return bool(publicKeyExists( id, trustedKeyRing() )); }
202 bool isKeyKnown( const std::string & id )
203 { return publicKeyExists( id, trustedKeyRing() ) || publicKeyExists( id, generalKeyRing() ); }
205 std::list<PublicKey> trustedPublicKeys()
206 { return publicKeys( trustedKeyRing() ); }
207 std::list<PublicKey> publicKeys()
208 { return publicKeys( generalKeyRing() ); }
210 const std::list<PublicKeyData> & trustedPublicKeyData()
211 { return publicKeyData( trustedKeyRing() ); }
212 const std::list<PublicKeyData> & publicKeyData()
213 { return publicKeyData( generalKeyRing() ); }
215 void dumpPublicKey( const std::string & id, bool trusted, std::ostream & stream )
216 { dumpPublicKey( id, ( trusted ? trustedKeyRing() : generalKeyRing() ), stream ); }
218 PublicKey exportPublicKey( const PublicKeyData & keyData )
219 { return exportKey( keyData, generalKeyRing() ); }
220 PublicKey exportTrustedPublicKey( const PublicKeyData & keyData )
221 { return exportKey( keyData, trustedKeyRing() ); }
223 bool verifyFileSignatureWorkflow( const Pathname & file, const std::string & filedesc, const Pathname & signature, bool & sigValid_r, const KeyContext & keycontext = KeyContext());
225 bool verifyFileSignature( const Pathname & file, const Pathname & signature )
226 { return verifyFile( file, signature, generalKeyRing() ); }
227 bool verifyFileTrustedSignature( const Pathname & file, const Pathname & signature )
228 { return verifyFile( file, signature, trustedKeyRing() ); }
231 bool verifyFile( const Pathname & file, const Pathname & signature, const Pathname & keyring );
232 void importKey( const Pathname & keyfile, const Pathname & keyring );
234 PublicKey exportKey( const std::string & id, const Pathname & keyring );
235 PublicKey exportKey( const PublicKeyData & keyData, const Pathname & keyring );
237 void dumpPublicKey( const std::string & id, const Pathname & keyring, std::ostream & stream );
238 filesystem::TmpFile dumpPublicKeyToTmp( const std::string & id, const Pathname & keyring );
240 void deleteKey( const std::string & id, const Pathname & keyring );
242 std::list<PublicKey> publicKeys( const Pathname & keyring);
243 const std::list<PublicKeyData> & publicKeyData( const Pathname & keyring )
244 { return cachedPublicKeyData( keyring ); }
246 /** Get \ref PublicKeyData for ID (\c false if ID is not found). */
247 PublicKeyData publicKeyExists( const std::string & id, const Pathname & keyring );
249 const Pathname generalKeyRing() const
250 { return _general_tmp_dir.path(); }
251 const Pathname trustedKeyRing() const
252 { return _trusted_tmp_dir.path(); }
254 // Used for trusted and untrusted keyrings
255 filesystem::TmpDir _trusted_tmp_dir;
256 filesystem::TmpDir _general_tmp_dir;
260 /** Functor returning the keyrings data (cached).
262 * const std::list<PublicKeyData> & cachedPublicKeyData( const Pathname & keyring );
265 CachedPublicKeyData cachedPublicKeyData;
267 ///////////////////////////////////////////////////////////////////
270 void KeyRing::Impl::importKey( const PublicKey & key, bool trusted )
272 importKey( key.path(), trusted ? trustedKeyRing() : generalKeyRing() );
276 callback::SendReport<target::rpm::KeyRingSignals> rpmdbEmitSignal;
277 callback::SendReport<KeyRingSignals> emitSignal;
279 rpmdbEmitSignal->trustedKeyAdded( key );
280 emitSignal->trustedKeyAdded( key );
284 void KeyRing::Impl::multiKeyImport( const Pathname & keyfile_r, bool trusted_r )
286 importKey( keyfile_r, trusted_r ? trustedKeyRing() : generalKeyRing() );
289 void KeyRing::Impl::deleteKey( const std::string & id, bool trusted )
295 key = exportKey( id, trustedKeyRing() );
298 deleteKey( id, trusted ? trustedKeyRing() : generalKeyRing() );
302 callback::SendReport<target::rpm::KeyRingSignals> rpmdbEmitSignal;
303 callback::SendReport<KeyRingSignals> emitSignal;
305 rpmdbEmitSignal->trustedKeyRemoved( key );
306 emitSignal->trustedKeyRemoved( key );
310 PublicKeyData KeyRing::Impl::publicKeyExists( const std::string & id, const Pathname & keyring )
312 MIL << "Searching key [" << id << "] in keyring " << keyring << endl;
314 for ( const PublicKeyData & key : publicKeyData( keyring ) )
316 if ( key.providesKey( id ) )
325 PublicKey KeyRing::Impl::exportKey( const PublicKeyData & keyData, const Pathname & keyring )
327 return PublicKey( dumpPublicKeyToTmp( keyData.id(), keyring ), keyData );
330 PublicKey KeyRing::Impl::exportKey( const std::string & id, const Pathname & keyring )
332 PublicKeyData keyData( publicKeyExists( id, keyring ) );
334 return PublicKey( dumpPublicKeyToTmp( keyData.id(), keyring ), keyData );
336 // Here: key not found
337 WAR << "No key " << id << " to export from " << keyring << endl;
342 void KeyRing::Impl::dumpPublicKey( const std::string & id, const Pathname & keyring, std::ostream & stream )
349 "--homedir", keyring.asString().c_str(),
350 "--no-default-keyring",
354 "--no-permission-warning",
359 ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true );
360 for ( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
367 filesystem::TmpFile KeyRing::Impl::dumpPublicKeyToTmp( const std::string & id, const Pathname & keyring )
369 filesystem::TmpFile tmpFile( _base_dir, "pubkey-"+id+"-" );
370 MIL << "Going to export key " << id << " from " << keyring << " to " << tmpFile.path() << endl;
372 std::ofstream os( tmpFile.path().c_str() );
373 dumpPublicKey( id, keyring, os );
378 bool KeyRing::Impl::verifyFileSignatureWorkflow( const Pathname & file, const std::string & filedesc, const Pathname & signature, bool & sigValid_r, const KeyContext & context )
380 sigValid_r = false; // set true if signature is actually successfully validated!
382 callback::SendReport<KeyRingReport> report;
383 MIL << "Going to verify signature for " << filedesc << " ( " << file << " ) with " << signature << endl;
385 // if signature does not exists, ask user if he wants to accept unsigned file.
386 if( signature.empty() || (!PathInfo( signature ).isExist()) )
388 bool res = report->askUserToAcceptUnsignedFile( filedesc, context );
389 MIL << "askUserToAcceptUnsignedFile: " << res << endl;
393 // get the id of the signature (it might be a subkey id!)
394 std::string id = readSignatureKeyId( signature );
396 // does key exists in trusted keyring
397 PublicKeyData trustedKeyData( publicKeyExists( id, trustedKeyRing() ) );
398 if ( trustedKeyData )
400 MIL << "Key is trusted: " << trustedKeyData << endl;
402 // lets look if there is an updated key in the
404 PublicKeyData generalKeyData( publicKeyExists( id, generalKeyRing() ) );
405 if ( generalKeyData )
407 // bnc #393160: Comment #30: Compare at least the fingerprint
408 // in case an attacker created a key the the same id.
410 // FIXME: bsc#1008325: For keys using subkeys, we'd actually need
411 // to compare the subkey sets, to tell whether a key was updated.
412 // because created() remains unchanged if the primary key is not touched.
413 // For now we wait until a new subkey signs the data and treat it as a
414 // new key (else part below).
415 if ( trustedKeyData.fingerprint() == generalKeyData.fingerprint()
416 && trustedKeyData.created() < generalKeyData.created() )
418 MIL << "Key was updated. Saving new version into trusted keyring: " << generalKeyData << endl;
419 importKey( exportKey( generalKeyData, generalKeyRing() ), true );
420 trustedKeyData = publicKeyExists( id, trustedKeyRing() ); // re-read: invalidated by import?
424 // it exists, is trusted, does it validate?
425 report->infoVerify( filedesc, trustedKeyData, context );
426 if ( verifyFile( file, signature, trustedKeyRing() ) )
428 return (sigValid_r=true); // signature is actually successfully validated!
432 bool res = report->askUserToAcceptVerificationFailed( filedesc, exportKey( trustedKeyData, trustedKeyRing() ), context );
433 MIL << "askUserToAcceptVerificationFailed: " << res << endl;
439 PublicKeyData generalKeyData( publicKeyExists( id, generalKeyRing() ) );
440 if ( generalKeyData )
442 PublicKey key( exportKey( generalKeyData, generalKeyRing() ) );
443 MIL << "Exported key " << id << " to " << key.path() << endl;
444 MIL << "Key " << id << " " << key.name() << " is not trusted" << endl;
446 // ok the key is not trusted, ask the user to trust it or not
447 KeyRingReport::KeyTrust reply = report->askUserToAcceptKey( key, context );
448 if ( reply == KeyRingReport::KEY_TRUST_TEMPORARILY ||
449 reply == KeyRingReport::KEY_TRUST_AND_IMPORT )
451 MIL << "User wants to trust key " << id << " " << key.name() << endl;
453 Pathname whichKeyring;
454 if ( reply == KeyRingReport::KEY_TRUST_AND_IMPORT )
456 MIL << "User wants to import key " << id << " " << key.name() << endl;
457 importKey( key, true );
458 whichKeyring = trustedKeyRing();
461 whichKeyring = generalKeyRing();
464 report->infoVerify( filedesc, generalKeyData, context );
465 if ( verifyFile( file, signature, whichKeyring ) )
467 return (sigValid_r=true); // signature is actually successfully validated!
471 bool res = report->askUserToAcceptVerificationFailed( filedesc, key, context );
472 MIL << "askUserToAcceptVerificationFailed: " << res << endl;
478 MIL << "User does not want to trust key " << id << " " << key.name() << endl;
484 // signed with an unknown key...
485 MIL << "File [" << file << "] ( " << filedesc << " ) signed with unknown key [" << id << "]" << endl;
486 bool res = report->askUserToAcceptUnknownKey( filedesc, id, context );
487 MIL << "askUserToAcceptUnknownKey: " << res << endl;
494 std::list<PublicKey> KeyRing::Impl::publicKeys( const Pathname & keyring )
496 const std::list<PublicKeyData> & keys( publicKeyData( keyring ) );
497 std::list<PublicKey> ret;
499 for_( it, keys.begin(), keys.end() )
501 PublicKey key( exportKey( *it, keyring ) );
502 ret.push_back( key );
503 MIL << "Found key " << key << endl;
508 void KeyRing::Impl::importKey( const Pathname & keyfile, const Pathname & keyring )
510 if ( ! PathInfo( keyfile ).isExist() )
511 // TranslatorExplanation first %s is key name, second is keyring name
512 ZYPP_THROW(KeyRingException( str::Format(_("Tried to import not existent key %s into keyring %s"))
514 % keyring.asString() ));
520 "--homedir", keyring.asString().c_str(),
521 "--no-default-keyring",
525 "--no-permission-warning",
527 keyfile.asString().c_str(),
531 ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true );
535 void KeyRing::Impl::deleteKey( const std::string & id, const Pathname & keyring )
541 "--homedir", keyring.asString().c_str(),
542 "--no-default-keyring",
552 ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true );
554 int code = prog.close();
556 ZYPP_THROW(Exception(_("Failed to delete key.")));
558 MIL << "Deleted key " << id << " from keyring " << keyring << endl;
561 std::string KeyRing::Impl::readSignatureKeyId( const Pathname & signature )
563 if ( ! PathInfo( signature ).isFile() )
564 ZYPP_THROW(Exception( str::Format(_("Signature file %s not found")) % signature.asString() ));
566 MIL << "Determining key id of signature " << signature << endl;
571 signature.asString().c_str(),
574 ExternalProgram prog( argv ,ExternalProgram::Discard_Stderr, false, -1, true );
576 // :signature packet: algo 1, keyid 1397BC53640DB551
577 // version 4, created 1501094968, md5len 0, sigclass 0x00
578 // digest algo 8, begin of digest 15 89
579 // hashed subpkt 2 len 4 (sig created 2017-07-26)
580 // subpkt 16 len 8 (issuer key ID 1397BC53640DB551)
583 for( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
585 if ( id.empty() && str::startsWith( line, ":signature packet:" ) )
587 static const str::regex rxKeyId( " keyid +([0-9A-Z]+)" );
589 if( str::regex_match( line, what, rxKeyId ) )
594 MIL << "Determined key id [" << id << "] for signature " << signature << endl;
599 bool KeyRing::Impl::verifyFile( const Pathname & file, const Pathname & signature, const Pathname & keyring )
605 "--homedir", keyring.asString().c_str(),
606 "--no-default-keyring",
612 signature.asString().c_str(),
613 file.asString().c_str(),
617 // no need to parse output for now
618 // [GNUPG:] SIG_ID yCc4u223XRJnLnVAIllvYbUd8mQ 2006-03-29 1143618744
619 // [GNUPG:] GOODSIG A84EDAE89C800ACA SuSE Package Signing Key <build@suse.de>
620 // gpg: Good signature from "SuSE Package Signing Key <build@suse.de>"
621 // [GNUPG:] VALIDSIG 79C179B2E1C820C1890F9994A84EDAE89C800ACA 2006-03-29 1143618744 0 3 0 17 2 00 79C179B2E1C820C1890F9994A84EDAE89C800ACA
622 // [GNUPG:] TRUST_UNDEFINED
624 // [GNUPG:] ERRSIG A84EDAE89C800ACA 17 2 00 1143618744 9
625 // [GNUPG:] NO_PUBKEY A84EDAE89C800ACA
627 ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true );
629 return ( prog.close() == 0 ) ? true : false;
632 ///////////////////////////////////////////////////////////////////
634 ///////////////////////////////////////////////////////////////////
636 // CLASS NAME : KeyRing
638 ///////////////////////////////////////////////////////////////////
640 KeyRing::KeyRing( const Pathname & baseTmpDir )
641 : _pimpl( new Impl( baseTmpDir ) )
648 void KeyRing::importKey( const PublicKey & key, bool trusted )
649 { _pimpl->importKey( key, trusted ); }
651 void KeyRing::multiKeyImport( const Pathname & keyfile_r, bool trusted_r )
652 { _pimpl->multiKeyImport( keyfile_r, trusted_r ); }
654 std::string KeyRing::readSignatureKeyId( const Pathname & signature )
655 { return _pimpl->readSignatureKeyId( signature ); }
657 void KeyRing::deleteKey( const std::string & id, bool trusted )
658 { _pimpl->deleteKey( id, trusted ); }
660 std::list<PublicKey> KeyRing::publicKeys()
661 { return _pimpl->publicKeys(); }
663 std:: list<PublicKey> KeyRing::trustedPublicKeys()
664 { return _pimpl->trustedPublicKeys(); }
666 std::list<PublicKeyData> KeyRing::publicKeyData()
667 { return _pimpl->publicKeyData(); }
669 std::list<PublicKeyData> KeyRing::trustedPublicKeyData()
670 { return _pimpl->trustedPublicKeyData(); }
672 bool KeyRing::verifyFileSignatureWorkflow( const Pathname & file, const std::string & filedesc, const Pathname & signature, bool & sigValid_r, const KeyContext & keycontext )
673 { return _pimpl->verifyFileSignatureWorkflow( file, filedesc, signature, sigValid_r, keycontext ); }
675 bool KeyRing::verifyFileSignatureWorkflow( const Pathname & file, const std::string filedesc, const Pathname & signature, const KeyContext & keycontext )
676 { bool unused; return _pimpl->verifyFileSignatureWorkflow( file, filedesc, signature, unused, keycontext ); }
678 bool KeyRing::verifyFileSignature( const Pathname & file, const Pathname & signature )
679 { return _pimpl->verifyFileSignature( file, signature ); }
681 bool KeyRing::verifyFileTrustedSignature( const Pathname & file, const Pathname & signature )
682 { return _pimpl->verifyFileTrustedSignature( file, signature ); }
684 void KeyRing::dumpPublicKey( const std::string & id, bool trusted, std::ostream & stream )
685 { _pimpl->dumpPublicKey( id, trusted, stream ); }
687 PublicKey KeyRing::exportPublicKey( const PublicKeyData & keyData )
688 { return _pimpl->exportPublicKey( keyData ); }
690 PublicKey KeyRing::exportTrustedPublicKey( const PublicKeyData & keyData )
691 { return _pimpl->exportTrustedPublicKey( keyData ); }
693 bool KeyRing::isKeyTrusted( const std::string & id )
694 { return _pimpl->isKeyTrusted( id ); }
696 bool KeyRing::isKeyKnown( const std::string & id )
697 { return _pimpl->isKeyKnown( id ); }
699 /////////////////////////////////////////////////////////////////
701 ///////////////////////////////////////////////////////////////////