19#include <zypp/TmpPath.h>
23#include <zypp/base/LogTools.h>
24#include <zypp/base/IOStream.h>
25#include <zypp/base/String.h>
26#include <zypp/base/Regex.h>
27#include <zypp/base/Gettext.h>
28#include <zypp-core/fs/WatchFile>
29#include <zypp/PathInfo.h>
31#include <zypp/ExternalProgram.h>
32#include <zypp/TmpPath.h>
38#undef ZYPP_BASE_LOGGER_LOGGROUP
39#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::KeyRing"
53 {
return _keyRingDefaultAccept; }
57 MIL <<
"Set new KeyRing::DefaultAccept: " << value_r << endl;
58 _keyRingDefaultAccept = value_r;
86 data.
set(
"PublicKey", key_r);
87 data.
set(
"KeyContext", keycontext_r);
91 return data.
get<
bool>(
"TrustKey");
98 data.
set(
"Keys", keys_r);
107 data.set(
"KeyDataList", keyDataList_r );
108 data.set(
"KeySigning", keySigning_r );
109 data.set(
"KeyContext", keyContext_r );
124 const std::list<PublicKeyData> & operator()(
const Pathname & keyring_r )
const
125 {
return getData( keyring_r ); }
127 void setDirty(
const Pathname & keyring_r )
138 Manip( CachedPublicKeyData & cache_r, Pathname keyring_r )
144 if ( not _context ) {
150 _cache.setDirty( _keyring );
162 Manip manip( Pathname keyring_r ) {
return Manip( *
this, std::move(keyring_r) ); }
175 void assertCache(
const Pathname & keyring_r )
184 bool hasChanged()
const
199 typedef std::map<Pathname,Cache> CacheMap;
201 const std::list<PublicKeyData> & getData(
const Pathname & keyring_r )
const
205 cache.assertCache( keyring_r );
206 return getData( keyring_r, cache );
209 const std::list<PublicKeyData> & getData(
const Pathname & keyring_r, Cache & cache_r )
const
211 if ( cache_r.hasChanged() ) {
213 MIL <<
"Found keys: " << cache_r._data << endl;
215 return cache_r._data;
237 MIL <<
"Current KeyRing::DefaultAccept: " << _keyRingDefaultAccept << endl;
242 void deleteKey(
const std::string &
id,
bool trusted );
261 void dumpPublicKey(
const std::string &
id,
bool trusted, std::ostream & stream )
343 struct ImportKeyCBHelper
345 void operator()(
const PublicKey & key_r )
353 ERR <<
"Could not import key into rpmdb: " << excp << endl;
369 MIL <<
"Imported key " << key <<
" to " << (trusted ?
"trustedKeyRing" :
"generalKeyRing" ) << endl;
373 ImportKeyCBHelper emitSignal;
390 importKey( keyfile_r, trusted_r ? trustedKeyRing() : generalKeyRing() );
395 PublicKeyData keyDataToDel( publicKeyExists(
id, trusted ? trustedKeyRing() : generalKeyRing() ) );
396 if ( ! keyDataToDel )
398 WAR <<
"Key to delete [" <<
id <<
"] is not in " << (trusted ?
"trustedKeyRing" :
"generalKeyRing" ) << endl;
401 deleteKey(
id, trusted ? trustedKeyRing() : generalKeyRing() );
402 MIL <<
"Deleted key [" <<
id <<
"] from " << (trusted ?
"trustedKeyRing" :
"generalKeyRing" ) << endl;
409 rpmdbEmitSignal->trustedKeyRemoved( key );
412 emitSignal->trustedKeyRemoved( key );
416 ERR <<
"Could not delete key from rpmmdb: " << excp << endl;
424 if ( _allowPreload && keyring == generalKeyRing() ) {
425 _allowPreload =
false;
432 if ( key.providesKey(
id ) )
438 DBG << (ret ?
"Found" :
"No") <<
" key [" <<
id <<
"] in keyring " << keyring << endl;
444 MIL <<
"preloadCachedKeys into general keyring..." << endl;
445 CachedPublicKeyData::Manip manip { keyRingManip( generalKeyRing() ) };
450 std::set<Pathname> cachedirs;
452 cachedirs.insert( conf.pubkeyCachePath() );
453 cachedirs.insert(
"/usr/lib/rpm/gnupg/keys" );
454 if (
Pathname r = conf.systemRoot(); r !=
"/" && not r.
empty() ) {
455 cachedirs.insert( r / conf.pubkeyCachePath() );
456 cachedirs.insert( r /
"/usr/lib/rpm/gnupg/keys" );
458 if (
Pathname r = conf.repoManagerRoot(); r !=
"/" && not r.
empty() ) {
459 cachedirs.insert( r / conf.pubkeyCachePath() );
460 cachedirs.insert( r /
"/usr/lib/rpm/gnupg/keys" );
463 std::map<std::string,Pathname> keyCandidates;
464 const str::regex rx {
"^gpg-pubkey-([[:xdigit:]]{8,})(-[[:xdigit:]]{8,})?\\.(asc|key)$" };
465 for (
const auto & cache : cachedirs ) {
467 [&rx,&keyCandidates](
const Pathname & dir_r,
const char *
const file_r )->
bool {
470 Pathname & remember { keyCandidates[what[1]] };
471 if ( remember.empty() ) {
472 remember = dir_r / file_r;
480 for (
const auto & p : keyCandidates ) {
483 const std::string &
id { p.first };
487 if ( manip.keyManagerCtx().importKey( path ) ) {
488 DBG <<
"preload key file " << path << endl;
491 WAR <<
"Skipping: Can't preload key file " << path << endl;
498 return PublicKey( dumpPublicKeyToTmp( keyData.
id(), keyring ), keyData );
505 return PublicKey( dumpPublicKeyToTmp( keyData.
id(), keyring ), keyData );
508 WAR <<
"No key [" <<
id <<
"] to export from " << keyring << endl;
521 MIL <<
"Going to export key [" <<
id <<
"] from " << keyring <<
" to " << tmpFile.
path() << endl;
523 std::ofstream os( tmpFile.
path().
c_str() );
534 const std::string & filedesc { context_r.
shortFile() };
538 MIL <<
"Going to verify signature for " << filedesc <<
" ( " << file <<
" ) with " << signature << endl;
541 if( signature.empty() || (!
PathInfo( signature ).isExist()) )
543 bool res = report->askUserToAcceptUnsignedFile( filedesc, keyContext );
544 MIL <<
"askUserToAcceptUnsignedFile: " << res << endl;
554 std::list<PublicKeyData> buddies;
555 for (
const auto & sid : context_r.
buddyKeys() ) {
557 WAR <<
"buddy " << sid <<
": key id is too short to safely identify a gpg key. Skipping it." << endl;
560 if ( trustedPublicKeyExists( sid ) ) {
561 MIL <<
"buddy " << sid <<
": already in trusted key ring. Not needed." << endl;
564 auto pk = publicKeyExists( sid );
566 WAR <<
"buddy " << sid <<
": not available in the public key ring. Skipping it." << endl;
569 if ( pk.providesKey(
id) ) {
570 MIL <<
"buddy " << sid <<
": is the signing key. Handled separately." << endl;
573 MIL <<
"buddy " << sid <<
": candidate for auto import. Remeber it." << endl;
574 buddies.push_back( pk );
580 PublicKeyData trustedKeyData( publicKeyExists(
id, trustedKeyRing() ) );
581 if ( trustedKeyData )
583 MIL <<
"Key is trusted: " << trustedKeyData << endl;
587 PublicKeyData generalKeyData( publicKeyExists(
id, generalKeyRing() ) );
588 if ( generalKeyData )
601 MIL <<
"Key was updated. Saving new version into trusted keyring: " << generalKeyData << endl;
602 importKey( exportKey( generalKeyData, generalKeyRing() ),
true );
603 trustedKeyData = publicKeyExists(
id, trustedKeyRing() );
607 foundKey = trustedKeyData;
608 whichKeyring = trustedKeyRing();
612 PublicKeyData generalKeyData( publicKeyExists(
id, generalKeyRing() ) );
613 if ( generalKeyData )
615 PublicKey key( exportKey( generalKeyData, generalKeyRing() ) );
616 MIL <<
"Key [" <<
id <<
"] " << key.
name() <<
" is not trusted" << endl;
623 MIL <<
"User wants to trust key [" <<
id <<
"] " << key.
name() << endl;
627 MIL <<
"User wants to import key [" <<
id <<
"] " << key.
name() << endl;
629 whichKeyring = trustedKeyRing();
632 whichKeyring = generalKeyRing();
634 foundKey = generalKeyData;
638 MIL <<
"User does not want to trust key [" <<
id <<
"] " << key.
name() << endl;
642 else if ( ! keyContext.empty() )
646 whichKeyring = trustedKeyRing();
647 foundKey =
PublicKeyData( publicKeyExists(
id, trustedKeyRing() ) );
656 report->infoVerify( filedesc, foundKey, keyContext );
657 if ( verifyFile( file, signature, whichKeyring ) )
662 MIL <<
"Validated with trusted key: importing buddy list..." << endl;
663 report->reportAutoImportKey( buddies, foundKey, keyContext );
664 for (
const auto & kd : buddies ) {
665 importKey( exportKey( kd, generalKeyRing() ),
true );
672 bool res = report->askUserToAcceptVerificationFailed( filedesc, exportKey( foundKey, whichKeyring ), keyContext );
673 MIL <<
"askUserToAcceptVerificationFailed: " << res << endl;
678 MIL <<
"File [" << file <<
"] ( " << filedesc <<
" ) signed with unknown key [" <<
id <<
"]" << endl;
679 bool res = report->askUserToAcceptUnknownKey( filedesc,
id, keyContext );
680 MIL <<
"askUserToAcceptUnknownKey: " << res << endl;
711 ERR <<
"Key [" << id_r <<
"] from cache: " << cacheDir <<
" is not valid" << endl;
715 MIL <<
"Key [" << id_r <<
"] " << key.
name() <<
" loaded from cache" << endl;
719 if ( ! report->askUserToAcceptPackageKey( key, context ) ) {
723 MIL <<
"User wants to import key [" << id_r <<
"] " << key.
name() <<
" from cache" << endl;
728 ERR <<
"Failed to import key: "<<id_r;
737 const std::list<PublicKeyData> & keys(
publicKeyData( keyring ) );
738 std::list<PublicKey> ret;
740 for_( it, keys.begin(), keys.end() )
742 PublicKey key( exportKey( *it, keyring ) );
743 ret.push_back( key );
744 MIL <<
"Found key " << key << endl;
751 if ( !
PathInfo( keyfile ).isExist() )
757 CachedPublicKeyData::Manip manip { keyRingManip( keyring ) };
758 if ( ! manip.keyManagerCtx().importKey( keyfile ) )
764 CachedPublicKeyData::Manip manip { keyRingManip( keyring ) };
765 if ( ! manip.keyManagerCtx().deleteKey(
id ) )
771 if ( !
PathInfo( signature ).isFile() )
774 MIL <<
"Determining key id of signature " << signature << endl;
777 if ( ! fprs.empty() ) {
778 std::string &
id = fprs.back();
779 MIL <<
"Determined key id [" <<
id <<
"] for signature " << signature << endl;
782 return std::string();
806 {
_pimpl->allowPreload( yesno_r ); }
810 {
_pimpl->importKey( key, trusted ); }
813 {
_pimpl->multiKeyImport( keyfile_r, trusted_r ); }
816 {
return _pimpl->readSignatureKeyId( signature ); }
819 {
_pimpl->deleteKey(
id, trusted ); }
822 {
return _pimpl->publicKeys(); }
825 {
return _pimpl->trustedPublicKeys(); }
828 {
return _pimpl->publicKeyData(); }
831 {
return _pimpl->trustedPublicKeyData(); }
834 {
return _pimpl->publicKeyExists( id_r ); }
837 {
return _pimpl->trustedPublicKeyExists( id_r ); }
860 {
return _pimpl->verifyFileSignatureWorkflow( context_r ); }
863 {
return _pimpl->verifyFileSignature( file, signature ); }
866 {
return _pimpl->verifyFileTrustedSignature( file, signature ); }
870 return _pimpl->provideAndImportKeyFromRepositoryWorkflow(
id, info );
874 {
_pimpl->dumpPublicKey(
id, trusted, stream ); }
877 {
return _pimpl->exportPublicKey( keyData ); }
880 {
return _pimpl->exportTrustedPublicKey( keyData ); }
883 {
return _pimpl->isKeyTrusted(
id ); }
886 {
return _pimpl->isKeyKnown(
id ); }
callback::SendReport< KeyRingSignals > _emitSignal
std::list< PublicKeyData > _data
scoped_ptr< WatchFile > _keyringK
CachedPublicKeyData & _cache
scoped_ptr< WatchFile > _keyringP
std::optional< KeyManagerCtx > _context
callback::SendReport< target::rpm::KeyRingSignals > _rpmdbEmitSignal
Base class for Exception.
std::string asUserHistory() const
A single (multiline) string composed of asUserString and historyAsString.
bool exportKey(const std::string &id, std::ostream &stream)
Exports the key with id into the given stream, returns true on success.
std::list< PublicKeyData > listKeys()
Returns a list of all public keys found in the current keyring.
bool verify(const Pathname &file, const Pathname &signature)
Tries to verify file using signature, returns true on success.
static KeyManagerCtx createForOpenPGP()
Creates a new KeyManagerCtx for PGP using a volatile temp.
std::list< std::string > readSignatureFingerprints(const Pathname &signature)
Reads all fingerprints from the signature file , returns a list of all found fingerprints.
bool provideAndImportKeyFromRepositoryWorkflow(const std::string &id, const RepoInfo &info)
Try to find the id in key cache or repository specified in info.
bool isKeyKnown(const std::string &id)
true if the key id is knows, that means at least exist on the untrusted keyring
std::list< PublicKey > publicKeys()
Get a list of public keys in the keyring (incl.
std::list< PublicKey > trustedPublicKeys()
Get a list of trusted public keys in the keyring (incl.
static DefaultAccept defaultAccept()
Get the active accept bits.
void dumpPublicKey(const std::string &id, bool trusted, std::ostream &stream)
bool verifyFileSignature(const Pathname &file, const Pathname &signature)
Verifies a file against a signature, with no user interaction.
void multiKeyImport(const Pathname &keyfile_r, bool trusted_r=false)
Initial import from RpmDb.
KeyRing(const Pathname &baseTmpDir)
Default ctor.
PublicKey exportPublicKey(const PublicKeyData &keyData)
Export a public key identified by its key data.
std::string readSignatureKeyId(const Pathname &signature)
reads the public key id from a signature
void allowPreload(bool yesno_r)
The general keyring may be populated with known keys stored on the system.
bool verifyFileTrustedSignature(const Pathname &file, const Pathname &signature)
void importKey(const PublicKey &key, bool trusted=false)
imports a key from a file.
bool verifyFileSignatureWorkflow(const Pathname &file, const std::string &filedesc, const Pathname &signature, bool &sigValid_r, const KeyContext &keycontext=KeyContext())
Follows a signature verification interacting with the user.
RW_pointer< Impl > _pimpl
Pointer to implementation.
void deleteKey(const std::string &id, bool trusted=false)
removes a key from the keyring.
std::list< PublicKeyData > trustedPublicKeyData()
Get a list of trusted public key data in the keyring (key data only)
static void setDefaultAccept(DefaultAccept value_r)
Set the active accept bits.
std::list< PublicKeyData > publicKeyData()
Get a list of public key data in the keyring (key data only)
@ ACCEPT_VERIFICATION_FAILED
PublicKey exportTrustedPublicKey(const PublicKeyData &keyData)
Export a trusted public key identified by its key data.
bool isKeyTrusted(const std::string &id)
true if the key id is trusted
Class representing one GPG Public Keys data.
Date created() const
Creation / last modification date (latest selfsig).
static bool isSafeKeyId(const std::string &id_r)
Whether this is a long id (64bit/16byte) or even better a fingerprint.
std::string id() const
Key ID.
std::string fingerprint() const
Key fingerprint.
Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile).
Pathname path() const
File containing the ASCII armored key.
const std::list< PublicKeyData > & hiddenKeys() const
Additional keys data in case the ASCII armored blob contains multiple keys.
const PublicKeyData & keyData() const
The public keys data (.
What is known about a repository.
Pathname provideKey(const std::string &keyID_r, const Pathname &targetDirectory_r) const
downloads all configured gpg keys into the defined directory
Interim helper class to collect global options and settings.
Pathname repoManagerRoot() const
The RepoManager root directory.
static ZConfig & instance()
Singleton ctor.
Pathname pubkeyCachePath() const
Path where the pubkey caches.
Typesafe passing of user data via callbacks.
const Tp & get(const std::string &key_r) const
Pass back a const Tp & reference to key_r value.
bool hasvalue(const std::string &key_r) const
Whether key_r is in data and value is not empty.
bool set(const std::string &key_r, AnyType val_r)
Set the value for key (nonconst version always returns true).
Wrapper class for stat/lstat.
const char * c_str() const
String representation.
const std::string & asString() const
String representation.
bool empty() const
Test for an empty path.
Provide a new empty temporary directory and recursively delete it when no longer needed.
Provide a new empty temporary file and delete it when no longer needed.
I/O context for KeyRing::verifyFileSignatureWorkflow.
bool fileValidated() const
Whether the signature was actually successfully verified.
const KeyContext & keyContext() const
KeyContext passed to callbacks
std::string shortFile() const
Short name for file (default: basename).
const Pathname & file() const
File to verify.
const BuddyKeys & buddyKeys() const
bool signatureIdTrusted() const
Whether the SignatureId is in the trusted keyring (not temp.
const Pathname & signature() const
Detached signature or empty.
void resetResults()
Reset all result values to safe defaults.
const std::string & signatureId() const
The id of the gpg key which signed the file.
bool fileAccepted() const
May return true due to user interaction or global defaults even if the signature was not actually ver...
Regular expression match result.
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
bool regex_match(const std::string &s, smatch &matches, const regex ®ex)
\relates regex \ingroup ZYPP_STR_REGEX \relates regex \ingroup ZYPP_STR_REGEX
Easy-to use interface to the ZYPP dependency resolver.
static bool error(const std::string &msg_r, const UserData &userData_r=UserData())
send error text
void setRepoInfo(const RepoInfo &repoinfo)
virtual void infoVerify(const std::string &file_r, const PublicKeyData &keyData_r, const KeyContext &keycontext=KeyContext())
Informal callback showing the trusted key that will be used for verification.
void reportNonImportedKeys(const std::set< Edition > &keys_r)
Notify the user about keys that were not imported from the rpm key database into zypp keyring.
KeyTrust
User reply options for the askUserToTrustKey callback.
@ KEY_TRUST_AND_IMPORT
Import the key.
@ KEY_DONT_TRUST
User has chosen not to trust the key.
@ KEY_TRUST_TEMPORARILY
This basically means, we knew the key, but it was not trusted.
static constexpr const char * REPORT_AUTO_IMPORT_KEY
generic reports UserData::type
virtual bool askUserToAcceptUnsignedFile(const std::string &file, const KeyContext &keycontext=KeyContext())
bool askUserToAcceptPackageKey(const PublicKey &key_r, const KeyContext &keycontext_r=KeyContext())
Ask user to trust and/or import the package key to trusted keyring, using ReportBase::report.
static constexpr const char * ACCEPT_PACKAGE_KEY_REQUEST
generic reports UserData::type
static constexpr const char * KEYS_NOT_IMPORTED_REPORT
generic reports UserData::type
void reportAutoImportKey(const std::list< PublicKeyData > &keyDataList_r, const PublicKeyData &keySigning_r, const KeyContext &keyContext_r)
Notify that a repository auto imported new package signing keys.
virtual KeyTrust askUserToAcceptKey(const PublicKey &key, const KeyContext &keycontext=KeyContext())
Ask user to trust and/or import the key to trusted keyring.
virtual bool askUserToAcceptUnknownKey(const std::string &file, const std::string &id, const KeyContext &keycontext=KeyContext())
we DONT know the key, only its id, but we have never seen it, the difference with trust key is that i...
virtual bool askUserToAcceptVerificationFailed(const std::string &file, const PublicKey &key, const KeyContext &keycontext=KeyContext())
The file filedesc is signed but the verification failed.
void importKey(const PublicKey &key, bool trusted=false)
PublicKeyData trustedPublicKeyExists(const std::string &id)
void preloadCachedKeys()
Load key files cached on the system into the generalKeyRing.
bool provideAndImportKeyFromRepositoryWorkflow(const std::string &id_r, const RepoInfo &info_r)
std::list< PublicKey > trustedPublicKeys()
CachedPublicKeyData::Manip keyRingManip(const Pathname &keyring)
Impl helper providing on demand a KeyManagerCtx to manip a cached keyring.
PublicKeyData publicKeyExists(const std::string &id)
PublicKey exportKey(const std::string &id, const Pathname &keyring)
PublicKey exportPublicKey(const PublicKeyData &keyData)
bool verifyFileSignatureWorkflow(keyring::VerifyFileContext &context_r)
bool isKeyKnown(const std::string &id)
const std::list< PublicKeyData > & publicKeyData()
bool verifyFileTrustedSignature(const Pathname &file, const Pathname &signature)
void allowPreload(bool yesno_r)
PublicKey exportTrustedPublicKey(const PublicKeyData &keyData)
Impl(const Pathname &baseTmpDir)
bool verifyFile(const Pathname &file, const Pathname &signature, const Pathname &keyring)
const Pathname generalKeyRing() const
const std::list< PublicKeyData > & trustedPublicKeyData()
filesystem::TmpDir _general_tmp_dir
bool verifyFileSignature(const Pathname &file, const Pathname &signature)
CachedPublicKeyData cachedPublicKeyData
Functor returning the keyrings data (cached).
std::string readSignatureKeyId(const Pathname &signature)
void multiKeyImport(const Pathname &keyfile_r, bool trusted_r=false)
std::list< PublicKey > publicKeys()
const std::list< PublicKeyData > & publicKeyData(const Pathname &keyring)
void deleteKey(const std::string &id, bool trusted)
const Pathname trustedKeyRing() const
bool _verifyFileSignatureWorkflow(keyring::VerifyFileContext &context_r)
filesystem::TmpFile dumpPublicKeyToTmp(const std::string &id, const Pathname &keyring)
PublicKey exportKey(const PublicKey &key, const Pathname &keyring)
filesystem::TmpDir _trusted_tmp_dir
bool isKeyTrusted(const std::string &id)
void dumpPublicKey(const std::string &id, bool trusted, std::ostream &stream)
virtual void report(const UserData &userData_r=UserData())
The most generic way of sending/receiving data.
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
#define NON_COPYABLE_BUT_MOVE(CLASS)
Delete copy ctor and copy assign but enable default move.
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
#define IMPL_PTR_TYPE(NAME)