libzypp  17.32.4
KeyManager.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
9 #include <zypp/KeyManager.h>
10 #include <zypp/KeyRing.h>
11 #include <zypp/PathInfo.h>
12 #include <zypp/base/Logger.h>
13 #include <zypp/TmpPath.h>
14 #include <zypp/base/String.h>
15 #include <zypp/AutoDispose.h>
16 
17 #include <boost/thread/once.hpp>
18 #include <boost/interprocess/smart_ptr/scoped_ptr.hpp>
19 #include <gpgme.h>
20 
21 #include <stdio.h>
22 using std::endl;
23 
24 #undef ZYPP_BASE_LOGGER_LOGGROUP
25 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::gpg"
26 
28 namespace zypp
29 {
31  namespace
32  {
33  // @TODO [threading]
34  // make sure to call the init code of gpgme only once
35  // this might need to be moved to a different location when
36  // threads are introduced into libzypp
37  boost::once_flag gpgme_init_once = BOOST_ONCE_INIT;
38 
39  void initGpgme ()
40  {
41  const char *version = gpgme_check_version(NULL);
42  if ( version )
43  {
44  MIL << "Initialized libgpgme version: " << version << endl;
45  }
46  else
47  {
48  MIL << "Initialized libgpgme with unknown version" << endl;
49  }
50  }
51 
52  //using boost::interprocess pointer because it allows a custom deleter
53  using GpgmeDataPtr = boost::interprocess::scoped_ptr<gpgme_data, boost::function<void (gpgme_data_t)>>;
54  using GpgmeKeyPtr = boost::interprocess::scoped_ptr<_gpgme_key, boost::function<void (gpgme_key_t)>>;
55  using FILEPtr = boost::interprocess::scoped_ptr<FILE, boost::function<int (FILE *)>>;
56 
57  struct GpgmeErr
58  {
59  GpgmeErr( gpgme_error_t err_r = GPG_ERR_NO_ERROR )
60  : _err( err_r )
61  {}
62  operator gpgme_error_t() const { return _err; }
63  private:
64  gpgme_error_t _err;
65  };
66 
67  std::ostream & operator<<( std::ostream & str, const GpgmeErr & obj )
68  { return str << "<" << gpgme_strsource(obj) << "> " << gpgme_strerror(obj); }
69 
71  std::ostream & operator<<( std::ostream & str, const _gpgme_op_import_result & obj )
72  {
73  str << "gpgme_op_import_result {" << endl;
74  str << " " << obj.considered << " The total number of considered keys." << endl;
75  str << " " << obj.no_user_id << " The number of keys without user ID." << endl;
76  str << " " << obj.imported << " The total number of imported keys." << endl;
77  str << " " << obj.imported_rsa << " imported RSA keys." << endl;
78  str << " " << obj.unchanged << " unchanged keys." << endl;
79  str << " " << obj.new_user_ids << " new user IDs." << endl;
80  str << " " << obj.new_sub_keys << " new sub keys." << endl;
81  str << " " << obj.new_signatures << " new signatures." << endl;
82  str << " " << obj.new_revocations << " new revocations." << endl;
83  str << " " << obj.secret_read << " secret keys read." << endl;
84  str << " " << obj.secret_imported << " imported secret keys." << endl;
85  str << " " << obj.secret_unchanged << " unchanged secret keys." << endl;
86  str << " " << obj.not_imported << " keys not imported." << endl;
87  for ( gpgme_import_status_t p = obj.imports; p; p = p->next )
88  {
89  str << " - " << p->fpr << ": " << p->result << endl;
90  }
91  // In V.1.11: str << " " << obj.skipped_v3_keys << " skipped v3 keys." << endl;
92  return str << "}";
93  }
94  } // namespace
96 
98  {
99  GpgmeException( const std::string & in_r, const GpgmeErr & err_r )
100  : KeyRingException( str::Format( "libgpgme error in '%1%': %2%" ) % in_r % err_r )
101  {}
102  };
103 
105  {
106  public:
108  { boost::call_once( gpgme_init_once, initGpgme ); }
109 
110  Impl(const Impl &) = delete;
111  Impl(Impl &&) = delete;
112  Impl &operator=(const Impl &) = delete;
113  Impl &operator=(Impl &&) = delete;
114 
115  ~Impl() {
116  if (_ctx)
117  gpgme_release(_ctx);
118  }
119 
121  std::list<std::string> readSignaturesFprs( const Pathname & signature_r )
122  { return readSignaturesFprsOptVerify( signature_r ); }
123 
125  std::list<std::string> readSignaturesFprs( const ByteArray & signature_r )
126  { return readSignaturesFprsOptVerify( signature_r ); }
127 
129  bool verifySignaturesFprs( const Pathname & file_r, const Pathname & signature_r )
130  {
131  bool verify = false;
132  readSignaturesFprsOptVerify( signature_r, file_r, &verify );
133  return verify;
134  }
135 
136  template< typename Callback >
137  bool importKey(GpgmeDataPtr &data, Callback &&calcDataSize );
138 
139  gpgme_ctx_t _ctx { nullptr };
140  bool _volatile { false };
141 
142  private:
148  std::list<std::string> readSignaturesFprsOptVerify( const Pathname & signature_r, const Pathname & file_r = "/dev/null", bool * verify_r = nullptr );
149  std::list<std::string> readSignaturesFprsOptVerify( const ByteArray& keyData_r, const Pathname & file_r = "/dev/null", bool * verify_r = nullptr );
150  std::list<std::string> readSignaturesFprsOptVerify( GpgmeDataPtr &sigData, const Pathname & file_r = "/dev/null", bool * verify_r = nullptr );
151  };
152 
153 std::list<std::string> KeyManagerCtx::Impl::readSignaturesFprsOptVerify( const Pathname & signature_r, const Pathname & file_r, bool * verify_r )
154 {
155  //lets be pessimistic
156  if ( verify_r )
157  *verify_r = false;
158 
159  if (!PathInfo( signature_r ).isExist())
160  return std::list<std::string>();
161 
162  FILEPtr sigFile(fopen(signature_r.c_str(), "rb"), fclose);
163  if (!sigFile) {
164  ERR << "Unable to open signature file '" << signature_r << "'" <<endl;
165  return std::list<std::string>();
166  }
167 
168  GpgmeDataPtr sigData(nullptr, gpgme_data_release);
169  GpgmeErr err = gpgme_data_new_from_stream (&sigData.get(), sigFile.get());
170  if (err) {
171  ERR << err << endl;
172  return std::list<std::string>();
173  }
174 
175  return readSignaturesFprsOptVerify( sigData, file_r, verify_r );
176 }
177 
178 std::list<std::string> KeyManagerCtx::Impl::readSignaturesFprsOptVerify( const ByteArray &keyData_r, const filesystem::Pathname &file_r, bool *verify_r )
179 {
180  //lets be pessimistic
181  if ( verify_r )
182  *verify_r = false;
183 
184  GpgmeDataPtr sigData(nullptr, gpgme_data_release);
185  GpgmeErr err = gpgme_data_new_from_mem(&sigData.get(), keyData_r.data(), keyData_r.size(), 1 );
186  if (err) {
187  ERR << err << endl;
188  return std::list<std::string>();
189  }
190 
191  return readSignaturesFprsOptVerify( sigData, file_r, verify_r );
192 }
193 
194 std::list<std::string> KeyManagerCtx::Impl::readSignaturesFprsOptVerify(GpgmeDataPtr &sigData, const filesystem::Pathname &file_r, bool *verify_r)
195 {
196  //lets be pessimistic
197  if ( verify_r )
198  *verify_r = false;
199 
200  FILEPtr dataFile(fopen(file_r.c_str(), "rb"), fclose);
201  if (!dataFile)
202  return std::list<std::string>();
203 
204  GpgmeDataPtr fileData(nullptr, gpgme_data_release);
205  GpgmeErr err = gpgme_data_new_from_stream (&fileData.get(), dataFile.get());
206  if (err) {
207  ERR << err << endl;
208  return std::list<std::string>();
209  }
210 
211  err = gpgme_op_verify(_ctx, sigData.get(), fileData.get(), NULL);
212  if (err != GPG_ERR_NO_ERROR) {
213  ERR << err << endl;
214  return std::list<std::string>();
215  }
216 
217  gpgme_verify_result_t res = gpgme_op_verify_result(_ctx);
218  if (!res || !res->signatures) {
219  ERR << "Unable to read signature fingerprints" <<endl;
220  return std::list<std::string>();
221  }
222 
223  bool foundBadSignature = false;
224  bool foundGoodSignature = false;
225  std::list<std::string> signatures;
226  for ( gpgme_signature_t sig = res->signatures; sig; sig = sig->next ) {
227 
228  if ( sig->fpr )
229  {
230  // bsc#1100427: With libgpgme11-1.11.0 and if a recent gpg version was used
231  // to create the signature, the field may contain the full fingerprint, but
232  // we're expected to return the ID.
233  // [https://github.com/gpg/gpgme/commit/478d1650bbef84958ccce439fac982ef57b16cd0]
234  std::string id( sig->fpr );
235  if ( id.size() > 16 )
236  id = id.substr( id.size()-16 );
237 
238  DBG << "Found signature with ID: " << id << " in " << file_r << std::endl;
239  signatures.push_back( std::move(id) );
240  }
241 
242  if ( verify_r && sig->status != GPG_ERR_NO_ERROR ) {
243  const auto status = gpgme_err_code(sig->status);
244 
245  // bsc#1180721: libgpgme started to return signatures of unknown keys, which breaks
246  // our workflow when verifying files that have multiple signatures, including some that are
247  // not in the trusted keyring. We should not fail if we have unknown or expired keys and at least a good one.
248  // We will however keep the behaviour of failing if we find a bad signatures even if others are good.
249  if ( status != GPG_ERR_KEY_EXPIRED && status != GPG_ERR_NO_PUBKEY )
250  {
251  WAR << "Failed signature check: " << file_r << " " << GpgmeErr(sig->status) << endl;
252  if ( !foundBadSignature )
253  foundBadSignature = true;
254  }
255  else
256  {
257  WAR << "Legacy: Ignore expired or unknown key: " << file_r << " " << GpgmeErr(sig->status) << endl;
258  // for now treat expired keys as good signature
259  if ( status == GPG_ERR_KEY_EXPIRED )
260  foundGoodSignature = true;
261  }
262  } else {
263  foundGoodSignature = true;
264  }
265  }
266 
267  if ( verify_r )
268  *verify_r = (!foundBadSignature) && foundGoodSignature;
269  return signatures;
270 }
271 
273 : _pimpl( new Impl )
274 {}
275 
277 {
278  static Pathname tmppath( zypp::myTmpDir() / "PublicKey" );
279  filesystem::assert_dir( tmppath );
280 
281  KeyManagerCtx ret { createForOpenPGP( tmppath ) };
282  ret._pimpl->_volatile = true; // readKeyFromFile workaround bsc#1140670
283  return ret;
284 }
285 
287 {
288  DBG << "createForOpenPGP(" << keyring_r << ")" << endl;
289 
290  KeyManagerCtx ret;
291  gpgme_ctx_t & ctx { ret._pimpl->_ctx };
292 
293  // create the context
294  GpgmeErr err = gpgme_new( &ctx );
295  if ( err != GPG_ERR_NO_ERROR )
296  ZYPP_THROW( GpgmeException( "gpgme_new", err ) );
297 
298  // use OpenPGP
299  err = gpgme_set_protocol( ctx, GPGME_PROTOCOL_OpenPGP );
300  if ( err != GPG_ERR_NO_ERROR )
301  ZYPP_THROW( GpgmeException( "gpgme_set_protocol", err ) );
302 
303  if ( !keyring_r.empty() ) {
304  // get engine information to read current state
305  gpgme_engine_info_t enginfo = gpgme_ctx_get_engine_info( ctx );
306  if ( !enginfo )
307  ZYPP_THROW( GpgmeException( "gpgme_ctx_get_engine_info", err ) );
308 
309  err = gpgme_ctx_set_engine_info( ctx, GPGME_PROTOCOL_OpenPGP, enginfo->file_name, keyring_r.c_str() );
310  if ( err != GPG_ERR_NO_ERROR )
311  ZYPP_THROW( GpgmeException( "gpgme_ctx_set_engine_info", err ) );
312  }
313 
314  return ret;
315 }
316 
318 {
319  Pathname ret;
320  if ( gpgme_engine_info_t enginfo = gpgme_ctx_get_engine_info( _pimpl->_ctx ) )
321  ret = enginfo->home_dir;
322  return ret;
323 }
324 
325 std::list<PublicKeyData> KeyManagerCtx::listKeys()
326 {
327  std::list<PublicKeyData> ret;
328  GpgmeErr err = GPG_ERR_NO_ERROR;
329 
330  // Reset gpgme_keylist_mode on return!
331  AutoDispose<gpgme_keylist_mode_t> guard { gpgme_get_keylist_mode( _pimpl->_ctx ), bind( &gpgme_set_keylist_mode, _pimpl->_ctx, _1 ) };
332  // Let listed keys include signatures (required if PublicKeyData are created from the key)
333  if ( (err = gpgme_set_keylist_mode( _pimpl->_ctx, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_SIGS )) != GPG_ERR_NO_ERROR ) {
334  ERR << "gpgme_set_keylist_mode: " << err << endl;
335  return ret;
336  }
337 
338  if ( (err = gpgme_op_keylist_start( _pimpl->_ctx, NULL, 0 )) != GPG_ERR_NO_ERROR ) {
339  ERR << "gpgme_op_keylist_start: " << err << endl;
340  return ret;
341  }
342  // Close list operation on return!
343  AutoDispose<gpgme_ctx_t> guard2 { _pimpl->_ctx, &gpgme_op_keylist_end };
344 
345  AutoDispose<gpgme_key_t> key { nullptr, &gpgme_key_release };
346  for ( ; gpgme_op_keylist_next( _pimpl->_ctx, &(*key) ) == GPG_ERR_NO_ERROR; key.getDispose()( key ) ) {
348  if ( data )
349  ret.push_back( data );
350  }
351 
352  return ret;
353 }
354 
355 std::list<PublicKeyData> KeyManagerCtx::readKeyFromFile( const Pathname & keyfile_r )
356 {
357  // bsc#1140670: GPGME does not support reading keys from a keyfile using
358  // gpgme_data_t and gpgme_op_keylist_from_data_start. Despite GPGME_KEYLIST_MODE_SIGS
359  // the signatures are missing, but we need them to create proper PublicKeyData objects.
360  // While this is not resolved, we read into a temp. keyring. Impl::_volatile helps
361  // to detect whether we can clear and import into the current context or need to
362  // create a temp. one.
363  std::list<PublicKeyData> ret;
364 
365  if ( _pimpl->_volatile ) {
366  // in a volatile context we can simple clear the keyring...
368  if ( importKey( keyfile_r ) )
369  ret = listKeys();
370  } else {
371  // read in a volatile context
372  ret = createForOpenPGP().readKeyFromFile( keyfile_r );
373  }
374 
375  return ret;
376 }
377 
378 bool KeyManagerCtx::verify(const Pathname &file, const Pathname &signature)
379 {
380  return _pimpl->verifySignaturesFprs(file, signature);
381 }
382 
383 bool KeyManagerCtx::exportKey(const std::string &id, std::ostream &stream)
384 {
385  GpgmeErr err = GPG_ERR_NO_ERROR;
386 
387  GpgmeKeyPtr foundKey;
388 
389  //search for requested key id
390  gpgme_key_t key = nullptr;
391  gpgme_op_keylist_start(_pimpl->_ctx, NULL, 0);
392  while (!(err = gpgme_op_keylist_next(_pimpl->_ctx, &key))) {
393  if (key->subkeys && id == str::asString(key->subkeys->keyid)) {
394  GpgmeKeyPtr(key, gpgme_key_release).swap(foundKey);
395  break;
396  }
397  gpgme_key_release(key);
398  }
399  gpgme_op_keylist_end(_pimpl->_ctx);
400 
401  if (!foundKey) {
402  WAR << "Key " << id << "not found" << endl;
403  return false;
404  }
405 
406  //function needs a array of keys to export
407  gpgme_key_t keyarray[2];
408  keyarray[0] = foundKey.get();
409  keyarray[1] = NULL;
410 
411  GpgmeDataPtr out(nullptr, gpgme_data_release);
412  err = gpgme_data_new (&out.get());
413  if (err) {
414  ERR << err << endl;
415  return false;
416  }
417 
418  //format as ascii armored
419  gpgme_set_armor (_pimpl->_ctx, 1);
420  // bsc#1179222: Remove outdated self signatures when exporting the key.
421  // The keyring does not order the signatures when multiple versions of the
422  // same key are imported. Rpm however uses the 1st to compute the -release
423  // of the gpg-pubkey. So we export only the latest to get a proper-release.
424  err = gpgme_op_export_keys (_pimpl->_ctx, keyarray, GPGME_EXPORT_MODE_MINIMAL, out.get());
425  if (!err) {
426  int ret = gpgme_data_seek (out.get(), 0, SEEK_SET);
427  if (ret) {
428  ERR << "Unable to seek in exported key data" << endl;
429  return false;
430  }
431 
432  const int bufsize = 512;
433  char buf[bufsize + 1];
434  while ((ret = gpgme_data_read(out.get(), buf, bufsize)) > 0) {
435  stream.write(buf, ret);
436  }
437 
438  //failed to read from buffer
439  if (ret < 0) {
440  ERR << "Unable to read exported key data" << endl;
441  return false;
442  }
443  } else {
444  ERR << "Error exporting key: "<< err << endl;
445  return false;
446  }
447 
448  //if we reach this point export was successful
449  return true;
450 }
451 
452 bool KeyManagerCtx::importKey(const Pathname &keyfile)
453 {
454  if ( !PathInfo( keyfile ).isExist() ) {
455  ERR << "Keyfile '" << keyfile << "' does not exist.";
456  return false;
457  }
458 
459  GpgmeDataPtr data(nullptr, gpgme_data_release);
460  GpgmeErr err;
461 
462  err = gpgme_data_new_from_file(&data.get(), keyfile.c_str(), 1);
463  if (err) {
464  ERR << "Error importing key: "<< err << endl;
465  return false;
466  }
467 
468  return _pimpl->importKey( data, [&](){ return PathInfo(keyfile).size(); } );
469 }
470 
471 bool KeyManagerCtx::importKey( const ByteArray &keydata )
472 {
473  GpgmeDataPtr data(nullptr, gpgme_data_release);
474  GpgmeErr err;
475 
476  err = gpgme_data_new_from_mem( &data.get(), keydata.data(), keydata.size(), 1);
477  if (err) {
478  ERR << "Error importing key: "<< err << endl;
479  return false;
480  }
481 
482  return _pimpl->importKey( data, [&](){ return keydata.size(); } );
483 }
484 
485 template<typename Callback>
486 bool KeyManagerCtx::Impl::importKey(GpgmeDataPtr &data, Callback &&calcDataSize)
487 {
488  GpgmeErr err;
489  err = gpgme_op_import( _ctx, data.get() );
490  if (err) {
491  ERR << "Error importing key: "<< err << endl;
492  return false;
493  }
494 
495  // Work around bsc#1127220 [libgpgme] no error upon incomplete import due to signal received.
496  // We need this error, otherwise RpmDb will report the missing keys as 'probably v3'.
497  if ( gpgme_import_result_t res = gpgme_op_import_result(_ctx) )
498  {
499  if ( ! res->considered && std::forward<Callback>(calcDataSize)() )
500  {
501  DBG << *res << endl;
502  ERR << "Error importing key: No keys considered (bsc#1127220, [libgpgme] signal received?)" << endl;
503  return false;
504  }
505  }
506 
507  return (err == GPG_ERR_NO_ERROR);
508 }
509 
510 bool KeyManagerCtx::deleteKey(const std::string &id)
511 {
512  gpgme_key_t key = nullptr;
513  GpgmeErr err = GPG_ERR_NO_ERROR;
514 
515  gpgme_op_keylist_start(_pimpl->_ctx, NULL, 0);
516 
517  while (!(err = gpgme_op_keylist_next(_pimpl->_ctx, &key))) {
518  if (key->subkeys && id == str::asString(key->subkeys->keyid)) {
519  err = gpgme_op_delete(_pimpl->_ctx, key, 0);
520 
521  gpgme_key_release(key);
522  gpgme_op_keylist_end(_pimpl->_ctx);
523 
524  if (err) {
525  ERR << "Error deleting key: "<< err << endl;
526  return false;
527  }
528  return true;
529  }
530  gpgme_key_release(key);
531  }
532 
533  gpgme_op_keylist_end(_pimpl->_ctx);
534  WAR << "Key: '"<< id << "' not found." << endl;
535  return false;
536 }
537 
538 std::list<std::string> KeyManagerCtx::readSignatureFingerprints(const Pathname &signature)
539 { return _pimpl->readSignaturesFprs(signature); }
540 
541 std::list<std::string> KeyManagerCtx::readSignatureFingerprints(const ByteArray &keyData)
542 { return _pimpl->readSignaturesFprs(keyData); }
543 
544 } // namespace zypp
DlContextRefType _ctx
Definition: rpmmd.cc:66
int assert_dir(const Pathname &path, unsigned mode)
Like &#39;mkdir -p&#39;.
Definition: PathInfo.cc:320
#define MIL
Definition: Logger.h:96
Impl & operator=(const Impl &)=delete
std::list< PublicKeyData > readKeyFromFile(const Pathname &file)
Returns a list of all PublicKeyData found in file.
Definition: KeyManager.cc:355
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:429
std::list< std::string > readSignaturesFprs(const Pathname &signature_r)
Return all fingerprints found in signature_r.
Definition: KeyManager.cc:121
gpgme_error_t _err
Definition: KeyManager.cc:64
Class representing one GPG Public Keys data.
Definition: PublicKey.h:207
int clean_dir(const Pathname &path)
Like &#39;rm -r DIR/ *&#39;.
Definition: PathInfo.cc:443
const char * c_str() const
String representation.
Definition: Pathname.h:110
String related utilities and Regular expression matching.
const std::string & asString(const std::string &t)
Global asString() that works with std::string too.
Definition: String.h:139
std::ostream & operator<<(std::ostream &str, const SerialNumber &obj)
Definition: SerialNumber.cc:52
bool verify(const Pathname &file, const Pathname &signature)
Tries to verify file using signature, returns true on success.
Definition: KeyManager.cc:378
static KeyManagerCtx createForOpenPGP()
Creates a new KeyManagerCtx for PGP using a volatile temp.
Definition: KeyManager.cc:276
#define ERR
Definition: Logger.h:98
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:383
RW_pointer< Impl > _pimpl
Pointer to implementation.
Definition: KeyManager.h:89
Pathname homedir() const
Return the homedir/keyring.
Definition: KeyManager.cc:317
bool empty() const
Test for an empty path.
Definition: Pathname.h:114
bool importKey(const Pathname &keyfile)
Tries to import a key from keyfile, returns true on success.
Definition: KeyManager.cc:452
std::list< std::string > readSignaturesFprs(const ByteArray &signature_r)
Return all fingerprints found in signature_r.
Definition: KeyManager.cc:125
bool verifySignaturesFprs(const Pathname &file_r, const Pathname &signature_r)
Tries to verify the file_r using signature_r.
Definition: KeyManager.cc:129
#define WAR
Definition: Logger.h:97
Pathname myTmpDir()
Global access to the zypp.TMPDIR (created on demand, deleted when libzypp is unloaded) ...
Definition: ZYppImpl.cc:343
bool deleteKey(const std::string &id)
Tries to delete a key specified by id, returns true on success.
Definition: KeyManager.cc:510
bool importKey(GpgmeDataPtr &data, Callback &&calcDataSize)
Definition: KeyManager.cc:486
std::list< PublicKeyData > listKeys()
Returns a list of all public keys found in the current keyring.
Definition: KeyManager.cc:325
GpgmeException(const std::string &in_r, const GpgmeErr &err_r)
Definition: KeyManager.cc:99
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:94
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
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:538
std::list< std::string > readSignaturesFprsOptVerify(const Pathname &signature_r, const Pathname &file_r="/dev/null", bool *verify_r=nullptr)
Return all fingerprints found in signature_r and optionally verify the file_r on the fly...
Definition: KeyManager.cc:153
static PublicKeyData fromGpgmeKey(_gpgme_key *data)
Definition: PublicKey.cc:412
Easy-to use interface to the ZYPP dependency resolver.
Definition: Application.cc:19
bool _volatile
readKeyFromFile workaround bsc#1140670
Definition: KeyManager.cc:140
#define DBG
Definition: Logger.h:95