libzypp 17.38.3
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
30#include <zypp-core/fs/WatchFile>
31#include <zypp/PathInfo.h>
33#include <zypp/TmpPath.h>
35
36using std::endl;
37
38#undef ZYPP_BASE_LOGGER_LOGGROUP
39#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::KeyRing"
40
42namespace zypp
43{
45 : _cache { cache_r }
46 , _keyring { std::move(keyring_r) }
47 {}
48
50 if ( not _context ) {
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
61
63 {
64 _keyringK.reset();
65 _keyringP.reset();
66 }
67
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
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
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
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
132 for ( const PublicKeyData & hkey : key.hiddenKeys() )
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
161 {
162 if ( _allowPreload && keyring == generalKeyRing() ) {
163 _allowPreload = false;
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
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
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 {
254 }
255
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
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition Exception.h:459
#define _(MSG)
Definition Gettext.h:39
#define DBG
Definition Logger.h:99
#define MIL
Definition Logger.h:100
#define WAR
Definition Logger.h:101
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 deleteKey(const std::string &id)
Tries to delete a key specified by id, returns true on success.
bool importKey(const Pathname &keyfile)
Tries to import a key from keyfile, returns true on success.
zyppng::Signal< void(const PublicKey &)> _sigTrustedKeyAdded
Definition keyring_p.h:190
PublicKeyData publicKeyExists(const std::string &id)
Definition keyring_p.h:129
void importKey(const PublicKey &key, bool trusted=false)
Definition keyring_p.cc:117
filesystem::TmpDir _general_tmp_dir
Definition keyring_p.h:179
KeyRingImpl(const Pathname &baseTmpDir)
Definition keyring_p.cc:110
const std::list< PublicKeyData > & publicKeyData()
Definition keyring_p.h:113
void multiKeyImport(const Pathname &keyfile_r, bool trusted_r=false)
Definition keyring_p.cc:138
std::list< PublicKey > publicKeys()
Definition keyring_p.h:108
void preloadCachedKeys()
Load key files cached on the system into the generalKeyRing.
Definition keyring_p.cc:180
void dumpPublicKey(const std::string &id, bool trusted, std::ostream &stream)
Definition keyring_p.h:116
const Pathname generalKeyRing() const
Definition keyring_p.h:163
Pathname _base_dir
Definition keyring_p.h:180
const Pathname trustedKeyRing() const
Definition keyring_p.h:165
std::string readSignatureKeyId(const Pathname &signature)
Definition keyring_p.cc:301
CachedPublicKeyData::Manip keyRingManip(const Pathname &keyring)
Impl helper providing on demand a KeyManagerCtx to manip a cached keyring.
Definition keyring_p.h:138
PublicKey exportKey(const std::string &id, const Pathname &keyring)
Definition keyring_p.cc:239
bool isKeyTrusted(const std::string &id)
Definition keyring_p.h:101
bool verifyFile(const Pathname &file, const Pathname &signature, const Pathname &keyring)
Definition keyring_p.cc:317
void deleteKey(const std::string &id, bool trusted)
Definition keyring_p.cc:143
filesystem::TmpDir _trusted_tmp_dir
Definition keyring_p.h:178
filesystem::TmpFile dumpPublicKeyToTmp(const std::string &id, const Pathname &keyring)
Definition keyring_p.cc:256
Class representing one GPG Public Keys data.
Definition PublicKey.h:201
std::string id() const
Key ID.
Definition PublicKey.cc:412
Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile).
Definition PublicKey.h:358
Pathname path() const
File containing the ASCII armored key.
Definition PublicKey.cc:640
const std::list< PublicKeyData > & hiddenKeys() const
Additional keys data in case the ASCII armored blob contains multiple keys.
Definition PublicKey.cc:643
Remember a files attributes to detect content changes.
Definition watchfile.h:50
Interim helper class to collect global options and settings.
Definition ZConfig.h:82
Pathname repoManagerRoot() const
The RepoManager root directory.
Definition ZConfig.cc:1011
Pathname systemRoot() const
The target root directory.
Definition ZConfig.cc:1008
static ZConfig & instance()
Singleton ctor.
Definition ZConfig.cc:971
Pathname pubkeyCachePath() const
Path where the pubkey caches.
Definition ZConfig.cc:1106
Wrapper class for stat/lstat.
Definition PathInfo.h:226
const char * c_str() const
String representation.
Definition Pathname.h:113
const std::string & asString() const
String representation.
Definition Pathname.h:94
bool empty() const
Test for an empty path.
Definition Pathname.h:117
Provide a new empty temporary file and delete it when no longer needed.
Definition TmpPath.h:118
Pathname path() const
Definition TmpPath.cc:124
Regular expression.
Definition Regex.h:95
Regular expression match result.
Definition Regex.h:168
Definition ansi.h:855
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
Easy-to use interface to the ZYPP dependency resolver.
scoped_ptr< WatchFile > _keyringP
Definition keyring_p.h:75
void assertCache(const Pathname &keyring_r)
Definition keyring_p.cc:68
std::list< PublicKeyData > _data
Definition keyring_p.h:70
scoped_ptr< WatchFile > _keyringK
Definition keyring_p.h:74
Helper providing on demand a KeyManagerCtx to manip the cached keyring.
Definition keyring_p.h:44
std::optional< KeyManagerCtx > _context
Definition keyring_p.h:52
KeyManagerCtx & keyManagerCtx()
Definition keyring_p.cc:49
Manip(CachedPublicKeyData &cache_r, Pathname keyring_r)
Definition keyring_p.cc:44
CachedPublicKeyData & _cache
Definition keyring_p.h:50
Functor returning the keyrings data (cached).
Definition keyring_p.h:33
void setDirty(const Pathname &keyring_r)
Definition keyring_p.cc:87
const std::list< PublicKeyData > & operator()(const Pathname &keyring_r) const
Definition keyring_p.cc:84
const std::list< PublicKeyData > & getData(const Pathname &keyring_r) const
Definition keyring_p.cc:92
Manip manip(Pathname keyring_r)
Helper providing on demand a KeyManagerCtx to manip the cached keyring.
Definition keyring_p.cc:90
Convenient building of std::string with boost::format.
Definition String.h:254