libzypp: zypp-common/private/keyring_p.cc Source File

libzypp 17.38.5

keyring_p.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
12
13#include "keyring_p.h"
14
15#include <iostream>
16#include <fstream>
17#include <optional>
18#include <sys/file.h>
19#include <unistd.h>
20
21#include <zypp/TmpPath.h>
22#include <zypp/ZYppFactory.h>
23#include <zypp/ZYpp.h>
24
25#include <zypp-core/base/LogTools.h>
26#include <zypp-core/base/IOStream.h>
27#include <zypp-core/base/String.h>
28#include <zypp-core/base/Regex.h>
29#include <zypp-core/base/Gettext.h>
30#include <zypp-core/fs/WatchFile>
31#include <zypp/PathInfo.h>
32#include <zypp-core/ExternalProgram.h>
33#include <zypp/TmpPath.h>
34#include <zypp-common/KeyManager.h>
35
36using std::endl;
37
38#undef ZYPP_BASE_LOGGER_LOGGROUP
39#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::KeyRing"
40
42namespace zypp
43{
44 CachedPublicKeyData::Manip::Manip(CachedPublicKeyData &cache_r, filesystem::Pathname keyring_r)
45 : _cache { cache_r }
46 , _keyring { std::move(keyring_r) }
47 {}
48
49 KeyManagerCtx &CachedPublicKeyData::Manip::keyManagerCtx() {
50 if ( not _context ) {
51 _context = KeyManagerCtx::createForOpenPGP( _keyring );
52 }
53 // frankly: don't remember why an explicit setDirty was introduced and
54 // why WatchFile was not enough. Maybe some corner case when the keyrings
55 // are created?
56 _cache.setDirty( _keyring );
57 return _context.value();
58 }
59
60 CachedPublicKeyData::Cache::Cache() {}
61
62 void CachedPublicKeyData::Cache::setDirty()
63 {
64 _keyringK.reset();
65 _keyringP.reset();
66 }
67
68 void CachedPublicKeyData::Cache::assertCache(const filesystem::Pathname &keyring_r)
69 {
70 // .kbx since gpg2-2.1
71 if ( !_keyringK )
72 _keyringK.reset( new WatchFile( keyring_r/"pubring.kbx", WatchFile::NO_INIT ) );
73 if ( !_keyringP )
74 _keyringP.reset( new WatchFile( keyring_r/"pubring.gpg", WatchFile::NO_INIT ) );
75 }
76
77 bool CachedPublicKeyData::Cache::hasChanged() const
78 {
79 bool k = _keyringK->hasChanged(); // be sure both files are checked
80 bool p = _keyringP->hasChanged();
81 return k || p;
82 }
83
84 const std::list<PublicKeyData> &CachedPublicKeyData::operator()(const filesystem::Pathname &keyring_r) const
85 { return getData( keyring_r ); }
86
87 void CachedPublicKeyData::setDirty(const filesystem::Pathname &keyring_r)
88 { _cacheMap[keyring_r].setDirty(); }
89
90 CachedPublicKeyData::Manip CachedPublicKeyData::manip(filesystem::Pathname keyring_r) { return Manip( *this, std::move(keyring_r) ); }
91
92 const std::list<PublicKeyData> &CachedPublicKeyData::getData(const filesystem::Pathname &keyring_r) const
93 {
94 Cache & cache( _cacheMap[keyring_r] );
95 // init new cache entry
96 cache.assertCache( keyring_r );
97 return getData( keyring_r, cache );
98 }
99
100 const std::list<PublicKeyData> &CachedPublicKeyData::getData(const filesystem::Pathname &keyring_r, Cache &cache_r) const
101 {
102 if ( cache_r.hasChanged() ) {
103 cache_r._data = KeyManagerCtx::createForOpenPGP( keyring_r ).listKeys();
104 MIL << "Found keys: " << cache_r._data << std::endl;
105 }
106 return cache_r._data;
107 }
108
109
110 KeyRingImpl::KeyRingImpl(const filesystem::Pathname &baseTmpDir)
111 : _trusted_tmp_dir( baseTmpDir, "zypp-trusted-kr" )
112 , _general_tmp_dir( baseTmpDir, "zypp-general-kr" )
113 , _base_dir( baseTmpDir )
114 {
115 }
116
117 void KeyRingImpl::importKey( const PublicKey & key, bool trusted )
118 {
119 importKey( key.path(), trusted ? trustedKeyRing() : generalKeyRing() );
120 MIL << "Imported key " << key << " to " << (trusted ? "trustedKeyRing" : "generalKeyRing" ) << endl;
121
122 if ( trusted )
123 {
124 if ( key.hiddenKeys().empty() )
125 {
126 _sigTrustedKeyAdded.emit( key );
127 }
128 else
129 {
130 // multiple keys: Export individual keys ascii armored to import in rpmdb
131 _sigTrustedKeyAdded.emit( exportKey( key, trustedKeyRing() ) );
132 for ( const PublicKeyData & hkey : key.hiddenKeys() )
133 _sigTrustedKeyAdded.emit( exportKey( hkey, trustedKeyRing() ) );
134 }
135 }
136 }
137
138 void KeyRingImpl::multiKeyImport( const Pathname & keyfile_r, bool trusted_r )
139 {
140 importKey( keyfile_r, trusted_r ? trustedKeyRing() : generalKeyRing() );
141 }
142
143 void KeyRingImpl::deleteKey( const std::string & id, bool trusted )
144 {
145 PublicKeyData keyDataToDel( publicKeyExists( id, trusted ? trustedKeyRing() : generalKeyRing() ) );
146 if ( ! keyDataToDel )
147 {
148 WAR << "Key to delete [" << id << "] is not in " << (trusted ? "trustedKeyRing" : "generalKeyRing" ) << endl;
149 return;
150 }
151
152 deleteKey( id, trusted ? trustedKeyRing() : generalKeyRing() );
153 MIL << "Deleted key [" << id << "] from " << (trusted ? "trustedKeyRing" : "generalKeyRing" ) << endl;
154
155 if ( trusted ) {
156 _sigTrustedKeyAdded.emit ( PublicKey( keyDataToDel ) );
157 }
158 }
159
160 PublicKeyData KeyRingImpl::publicKeyExists( const std::string & id, const Pathname & keyring )
161 {
162 if ( _allowPreload && keyring == generalKeyRing() ) {
163 _allowPreload = false;
164 preloadCachedKeys();
165 }
166
167 PublicKeyData ret;
168 for ( const PublicKeyData & key : publicKeyData( keyring ) )
169 {
170 if ( key.providesKey( id ) )
171 {
172 ret = key;
173 break;
174 }
175 }
176 DBG << (ret ? "Found" : "No") << " key [" << id << "] in keyring " << keyring << endl;
177 return ret;
178 }
179
180 void KeyRingImpl::preloadCachedKeys()
181 {
182 MIL << "preloadCachedKeys into general keyring..." << endl;
183 CachedPublicKeyData::Manip manip { keyRingManip( generalKeyRing() ) }; // Provides the context if we want to manip a cached keyring.
184
185 // For now just load the 'gpg-pubkey-*.{asc,key}' files into the general keyring,
186 // if their id (derived from the filename) is not in the trusted ring.
187 // TODO: Head for a persistent general keyring.
188 std::set<Pathname> cachedirs;
189 ZConfig & conf { ZConfig::instance() };
190 cachedirs.insert( conf.pubkeyCachePath() );
191 cachedirs.insert( "/usr/lib/rpm/gnupg/keys" );
192 if ( Pathname r = conf.systemRoot(); r != "/" && not r.empty() ) {
193 cachedirs.insert( r / conf.pubkeyCachePath() );
194 cachedirs.insert( r / "/usr/lib/rpm/gnupg/keys" );
195 }
196 if ( Pathname r = conf.repoManagerRoot(); r != "/" && not r.empty() ) {
197 cachedirs.insert( r / conf.pubkeyCachePath() );
198 cachedirs.insert( r / "/usr/lib/rpm/gnupg/keys" );
199 }
200
201 std::map<std::string,Pathname> keyCandidates; // Collect one file path per keyid
202 const str::regex rx { "^gpg-pubkey-([[:xdigit:]]{8,})(-[[:xdigit:]]{8,})?\\.(asc|key)$" };
203 for ( const auto & cache : cachedirs ) {
204 dirForEach( cache,
205 [&rx,&keyCandidates]( const Pathname & dir_r, const char *const file_r )->bool {
206 str::smatch what;
207 if ( str::regex_match( file_r, what, rx ) ) {
208 Pathname & remember { keyCandidates[what[1]] };
209 if ( remember.empty() ) {
210 remember = dir_r / file_r;
211 }
212 }
213 return true;
214 }
215 );
216 }
217
218 for ( const auto & p : keyCandidates ) {
219 // Avoid checking the general keyring while it is flagged dirty.
220 // Checking the trusted ring is ok, and most keys will be there anyway.
221 const std::string & id { p.first };
222 const Pathname & path { p.second };
223 if ( isKeyTrusted(id) )
224 continue;
225 if ( manip.keyManagerCtx().importKey( path ) ) {
226 DBG << "preload key file " << path << endl;
227 }
228 else {
229 WAR << "Skipping: Can't preload key file " << path << endl;
230 }
231 }
232 }
233
234 PublicKey KeyRingImpl::exportKey( const PublicKeyData & keyData, const Pathname & keyring )
235 {
236 return PublicKey( dumpPublicKeyToTmp( keyData.id(), keyring ), keyData );
237 }
238
239 PublicKey KeyRingImpl::exportKey( const std::string & id, const Pathname & keyring )
240 {
241 PublicKeyData keyData( publicKeyExists( id, keyring ) );
242 if ( keyData )
243 return PublicKey( dumpPublicKeyToTmp( keyData.id(), keyring ), keyData );
244
245 // Here: key not found
246 WAR << "No key [" << id << "] to export from " << keyring << endl;
247 return PublicKey();
248 }
249
250
251 void KeyRingImpl::dumpPublicKey( const std::string & id, const Pathname & keyring, std::ostream & stream )
252 {
253 KeyManagerCtx::createForOpenPGP( keyring ).exportKey(id, stream);
254 }
255
256 filesystem::TmpFile KeyRingImpl::dumpPublicKeyToTmp( const std::string & id, const Pathname & keyring )
257 {
258 filesystem::TmpFile tmpFile( _base_dir, "pubkey-"+id+"-" );
259 MIL << "Going to export key [" << id << "] from " << keyring << " to " << tmpFile.path() << endl;
260
261 std::ofstream os( tmpFile.path().c_str() );
262 dumpPublicKey( id, keyring, os );
263 os.close();
264 return tmpFile;
265 }
266
267 std::list<PublicKey> KeyRingImpl::publicKeys( const Pathname & keyring )
268 {
269 const std::list<PublicKeyData> & keys( publicKeyData( keyring ) );
270 std::list<PublicKey> ret;
271
272 for ( const PublicKeyData& keyData : keys )
273 {
274 PublicKey key( exportKey( keyData, keyring ) );
275 ret.push_back( key );
276 MIL << "Found key " << key << endl;
277 }
278 return ret;
279 }
280
281 void KeyRingImpl::importKey( const Pathname & keyfile, const Pathname & keyring )
282 {
283 if ( ! PathInfo( keyfile ).isExist() )
284 // TranslatorExplanation first %s is key name, second is keyring name
285 ZYPP_THROW(KeyRingException( str::Format(_("Tried to import not existent key %s into keyring %s"))
286 % keyfile.asString()
287 % keyring.asString() ));
288
289 CachedPublicKeyData::Manip manip { keyRingManip( keyring ) }; // Provides the context if we want to manip a cached keyring.
290 if ( ! manip.keyManagerCtx().importKey( keyfile ) )
291 ZYPP_THROW(KeyRingException(_("Failed to import key.")));
292 }
293
294 void KeyRingImpl::deleteKey( const std::string & id, const Pathname & keyring )
295 {
296 CachedPublicKeyData::Manip manip { keyRingManip( keyring ) }; // Provides the context if we want to manip a cached keyring.
297 if ( ! manip.keyManagerCtx().deleteKey( id ) )
298 ZYPP_THROW(KeyRingException(_("Failed to delete key.")));
299 }
300
301 std::string KeyRingImpl::readSignatureKeyId( const Pathname & signature )
302 {
303 if ( ! PathInfo( signature ).isFile() )
304 ZYPP_THROW(KeyRingException( str::Format(_("Signature file %s not found")) % signature.asString() ));
305
306 MIL << "Determining key id of signature " << signature << endl;
307
308 std::list<std::string> fprs = KeyManagerCtx::createForOpenPGP().readSignatureFingerprints( signature );
309 if ( ! fprs.empty() ) {
310 std::string &id = fprs.back();
311 MIL << "Determined key id [" << id << "] for signature " << signature << endl;
312 return id;
313 }
314 return std::string();
315 }
316
317 bool KeyRingImpl::verifyFile( const Pathname & file, const Pathname & signature, const Pathname & keyring )
318 {
319 return KeyManagerCtx::createForOpenPGP( keyring ).verify( file, signature );
320 }
321
322} // namespace zypp
323
ZYPP_THROW
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition Exception.h:459
ExternalProgram.h
Gettext.h
_
#define _(MSG)
Definition Gettext.h:39
IOStream.h
KeyManager.h
LogTools.h
DBG
#define DBG
Definition Logger.h:99
MIL
#define MIL
Definition Logger.h:100
WAR
#define WAR
Definition Logger.h:101
Regex.h
String.h
ZYppFactory.h
ZYpp.h
zypp::KeyManagerCtx
Definition KeyManager.h:31
zypp::KeyManagerCtx::exportKey
bool exportKey(const std::string &id, std::ostream &stream)
Exports the key with id into the given stream, returns true on success.
Definition KeyManager.cc:433
zypp::KeyManagerCtx::listKeys
std::list< PublicKeyData > listKeys()
Returns a list of all public keys found in the current keyring.
Definition KeyManager.cc:375
zypp::KeyManagerCtx::verify
bool verify(const Pathname &file, const Pathname &signature)
Tries to verify file using signature, returns true on success.
Definition KeyManager.cc:428
zypp::KeyManagerCtx::createForOpenPGP
static KeyManagerCtx createForOpenPGP()
Creates a new KeyManagerCtx for PGP using a volatile temp.
Definition KeyManager.cc:320
zypp::KeyManagerCtx::readSignatureFingerprints
std::list< std::string > readSignatureFingerprints(const Pathname &signature)
Reads all fingerprints from the signature file , returns a list of all found fingerprints.
Definition KeyManager.cc:588
zypp::KeyManagerCtx::deleteKey
bool deleteKey(const std::string &id)
Tries to delete a key specified by id, returns true on success.
Definition KeyManager.cc:560
zypp::KeyManagerCtx::importKey
bool importKey(const Pathname &keyfile)
Tries to import a key from keyfile, returns true on success.
Definition KeyManager.cc:502
zypp::KeyRingException
Definition KeyRingException.h:21
zypp::KeyRingImpl::_sigTrustedKeyAdded
zyppng::Signal< void(const PublicKey &)> _sigTrustedKeyAdded
Definition keyring_p.h:190
zypp::KeyRingImpl::publicKeyExists
PublicKeyData publicKeyExists(const std::string &id)
Definition keyring_p.h:129
zypp::KeyRingImpl::importKey
void importKey(const PublicKey &key, bool trusted=false)
Definition keyring_p.cc:117
zypp::KeyRingImpl::_general_tmp_dir
filesystem::TmpDir _general_tmp_dir
Definition keyring_p.h:179
zypp::KeyRingImpl::KeyRingImpl
KeyRingImpl(const Pathname &baseTmpDir)
Definition keyring_p.cc:110
zypp::KeyRingImpl::publicKeyData
const std::list< PublicKeyData > & publicKeyData()
Definition keyring_p.h:113
zypp::KeyRingImpl::multiKeyImport
void multiKeyImport(const Pathname &keyfile_r, bool trusted_r=false)
Definition keyring_p.cc:138
zypp::KeyRingImpl::_allowPreload
bool _allowPreload
Definition keyring_p.h:181
zypp::KeyRingImpl::publicKeys
std::list< PublicKey > publicKeys()
Definition keyring_p.h:108
zypp::KeyRingImpl::preloadCachedKeys
void preloadCachedKeys()
Load key files cached on the system into the generalKeyRing.
Definition keyring_p.cc:180
zypp::KeyRingImpl::dumpPublicKey
void dumpPublicKey(const std::string &id, bool trusted, std::ostream &stream)
Definition keyring_p.h:116
zypp::KeyRingImpl::generalKeyRing
const Pathname generalKeyRing() const
Definition keyring_p.h:163
zypp::KeyRingImpl::_base_dir
Pathname _base_dir
Definition keyring_p.h:180
zypp::KeyRingImpl::trustedKeyRing
const Pathname trustedKeyRing() const
Definition keyring_p.h:165
zypp::KeyRingImpl::readSignatureKeyId
std::string readSignatureKeyId(const Pathname &signature)
Definition keyring_p.cc:301
zypp::KeyRingImpl::keyRingManip
CachedPublicKeyData::Manip keyRingManip(const Pathname &keyring)
Impl helper providing on demand a KeyManagerCtx to manip a cached keyring.
Definition keyring_p.h:138
zypp::KeyRingImpl::exportKey
PublicKey exportKey(const std::string &id, const Pathname &keyring)
Definition keyring_p.cc:239
zypp::KeyRingImpl::isKeyTrusted
bool isKeyTrusted(const std::string &id)
Definition keyring_p.h:101
zypp::KeyRingImpl::verifyFile
bool verifyFile(const Pathname &file, const Pathname &signature, const Pathname &keyring)
Definition keyring_p.cc:317
zypp::KeyRingImpl::deleteKey
void deleteKey(const std::string &id, bool trusted)
Definition keyring_p.cc:143
zypp::KeyRingImpl::_trusted_tmp_dir
filesystem::TmpDir _trusted_tmp_dir
Definition keyring_p.h:178
zypp::KeyRingImpl::dumpPublicKeyToTmp
filesystem::TmpFile dumpPublicKeyToTmp(const std::string &id, const Pathname &keyring)
Definition keyring_p.cc:256
zypp::PublicKeyData
Class representing one GPG Public Keys data.
Definition PublicKey.h:201
zypp::PublicKeyData::id
std::string id() const
Key ID.
Definition PublicKey.cc:412
zypp::PublicKey
Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile).
Definition PublicKey.h:358
zypp::PublicKey::path
Pathname path() const
File containing the ASCII armored key.
Definition PublicKey.cc:640
zypp::PublicKey::hiddenKeys
const std::list< PublicKeyData > & hiddenKeys() const
Additional keys data in case the ASCII armored blob contains multiple keys.
Definition PublicKey.cc:643
zypp::WatchFile
Remember a files attributes to detect content changes.
Definition watchfile.h:50
zypp::WatchFile::NO_INIT
@ NO_INIT
Definition watchfile.h:52
zypp::ZConfig
Interim helper class to collect global options and settings.
Definition ZConfig.h:82
zypp::ZConfig::repoManagerRoot
Pathname repoManagerRoot() const
The RepoManager root directory.
Definition ZConfig.cc:1011
zypp::ZConfig::systemRoot
Pathname systemRoot() const
The target root directory.
Definition ZConfig.cc:1008
zypp::ZConfig::instance
static ZConfig & instance()
Singleton ctor.
Definition ZConfig.cc:971
zypp::ZConfig::pubkeyCachePath
Pathname pubkeyCachePath() const
Path where the pubkey caches.
Definition ZConfig.cc:1106
zypp::filesystem::PathInfo
Wrapper class for stat/lstat.
Definition PathInfo.h:226
zypp::filesystem::Pathname
Pathname.
Definition Pathname.h:48
zypp::filesystem::Pathname::c_str
const char * c_str() const
String representation.
Definition Pathname.h:113
zypp::filesystem::Pathname::asString
const std::string & asString() const
String representation.
Definition Pathname.h:94
zypp::filesystem::Pathname::empty
bool empty() const
Test for an empty path.
Definition Pathname.h:117
zypp::filesystem::TmpFile
Provide a new empty temporary file and delete it when no longer needed.
Definition TmpPath.h:118
zypp::filesystem::TmpPath::path
Pathname path() const
Definition TmpPath.cc:124
zypp::str::regex
Regular expression.
Definition Regex.h:95
zypp::str::smatch
Regular expression match result.
Definition Regex.h:168
std
Definition ansi.h:855
zypp::keyring
Definition KeyRingContexts.cc:18
zypp::str::regex_match
bool regex_match(const std::string &s, smatch &matches, const regex &regex)
\relates regex \ingroup ZYPP_STR_REGEX \relates regex \ingroup ZYPP_STR_REGEX
Definition Regex.h:70
zypp
Easy-to use interface to the ZYPP dependency resolver.
Definition CodePitfalls.doc:2
zypp::CachedPublicKeyData::Cache
Definition keyring_p.h:61
zypp::CachedPublicKeyData::Cache::_keyringP
scoped_ptr< WatchFile > _keyringP
Definition keyring_p.h:75
zypp::CachedPublicKeyData::Cache::setDirty
void setDirty()
Definition keyring_p.cc:62
zypp::CachedPublicKeyData::Cache::assertCache
void assertCache(const Pathname &keyring_r)
Definition keyring_p.cc:68
zypp::CachedPublicKeyData::Cache::hasChanged
bool hasChanged() const
Definition keyring_p.cc:77
zypp::CachedPublicKeyData::Cache::_data
std::list< PublicKeyData > _data
Definition keyring_p.h:70
zypp::CachedPublicKeyData::Cache::Cache
Cache()
Definition keyring_p.cc:60
zypp::CachedPublicKeyData::Cache::_keyringK
scoped_ptr< WatchFile > _keyringK
Definition keyring_p.h:74
zypp::CachedPublicKeyData::Manip
Helper providing on demand a KeyManagerCtx to manip the cached keyring.
Definition keyring_p.h:44
zypp::CachedPublicKeyData::Manip::_context
std::optional< KeyManagerCtx > _context
Definition keyring_p.h:52
zypp::CachedPublicKeyData::Manip::_keyring
Pathname _keyring
Definition keyring_p.h:51
zypp::CachedPublicKeyData::Manip::keyManagerCtx
KeyManagerCtx & keyManagerCtx()
Definition keyring_p.cc:49
zypp::CachedPublicKeyData::Manip::Manip
Manip(CachedPublicKeyData &cache_r, Pathname keyring_r)
Definition keyring_p.cc:44
zypp::CachedPublicKeyData::Manip::_cache
CachedPublicKeyData & _cache
Definition keyring_p.h:50
zypp::CachedPublicKeyData
Functor returning the keyrings data (cached).
Definition keyring_p.h:33
zypp::CachedPublicKeyData::setDirty
void setDirty(const Pathname &keyring_r)
Definition keyring_p.cc:87
zypp::CachedPublicKeyData::_cacheMap
CacheMap _cacheMap
Definition keyring_p.h:84
zypp::CachedPublicKeyData::operator()
const std::list< PublicKeyData > & operator()(const Pathname &keyring_r) const
Definition keyring_p.cc:84
zypp::CachedPublicKeyData::getData
const std::list< PublicKeyData > & getData(const Pathname &keyring_r) const
Definition keyring_p.cc:92
zypp::CachedPublicKeyData::manip
Manip manip(Pathname keyring_r)
Helper providing on demand a KeyManagerCtx to manip the cached keyring.
Definition keyring_p.cc:90
zypp::str::Format
Convenient building of std::string with boost::format.
Definition String.h:254
keyring_p.h
PathInfo.h
TmpPath.h