libzypp 17.38.15

KeyManager.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
9#include <iostream>
10#include <fstream>
11#include <optional>
12
13#include "KeyManager.h"
14#include "KeyRingException.h"
15
16#include <zypp-core/fs/PathInfo.h>
17#include <zypp-core/base/LogTools.h>
18#include <zypp-core/base/LogControl.h>
19#include <zypp-core/fs/TmpPath.h>
20#include <zypp-core/base/String.h>
21#include <zypp-core/AutoDispose.h>
22
23#include <boost/thread/once.hpp>
24#include <boost/interprocess/smart_ptr/scoped_ptr.hpp>
25#include <gpgme.h>
26
27#include <stdio.h>
28 using std::endl;
29
30#undef ZYPP_BASE_LOGGER_LOGGROUP
31#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::gpg"
32
34 namespace zypp
35{
37 namespace
38 {
39 // Name of the gpg.conf file inside a keyring.
40 static const std::string gpgconfName { "gpg.conf" };
41
42 // @TODO [threading]
43 // make sure to call the init code of gpgme only once
44 // this might need to be moved to a different location when
45 // threads are introduced into libzypp
46 boost::once_flag gpgme_init_once = BOOST_ONCE_INIT;
47
48 void initGpgme ()
49 {
50 const char *version = gpgme_check_version(NULL);
51 if ( version )
52 {
53 MIL << "Initialized libgpgme version: " << version << endl;
54 }
55 else
56 {
57 MIL << "Initialized libgpgme with unknown version" << endl;
58 }
59 }
60
61 //using boost::interprocess pointer because it allows a custom deleter
62 using GpgmeDataPtr = boost::interprocess::scoped_ptr<gpgme_data, boost::function<void (gpgme_data_t)>>;
63 using GpgmeKeyPtr = boost::interprocess::scoped_ptr<_gpgme_key, boost::function<void (gpgme_key_t)>>;
64 using FILEPtr = boost::interprocess::scoped_ptr<FILE, boost::function<int (FILE *)>>;
65
66 struct GpgmeErr
67 {
68 GpgmeErr( gpgme_error_t err_r = GPG_ERR_NO_ERROR )
69 : _err( err_r )
70 {}
71 operator gpgme_error_t() const { return _err; }
72 private:
73 gpgme_error_t _err;
74 };
75
76 std::ostream & operator<<( std::ostream & str, const GpgmeErr & obj )
77 { return str << "<" << gpgme_strsource(obj) << "> " << gpgme_strerror(obj); }
78
79 bool findKeyById( gpgme_ctx_t ctx, const std::string & id, GpgmeKeyPtr & foundKey )
80 {
81 GpgmeErr err = GPG_ERR_NO_ERROR;
82
83 gpgme_key_t key = nullptr;
84 gpgme_op_keylist_start( ctx, NULL, 0 );
85 while ( !( err = gpgme_op_keylist_next( ctx, &key ) ) ) {
86 if ( key->subkeys && id == str::asString( key->subkeys->keyid ) ) {
87 GpgmeKeyPtr( key, gpgme_key_release ).swap( foundKey );
88 break;
89 }
90 gpgme_key_release( key );
91 }
92 gpgme_op_keylist_end( ctx );
93
94 return foundKey.get() != nullptr;
95 }
96
97 bool exportKeyData( gpgme_ctx_t ctx, const std::string & id, ByteArray & keydata )
98 {
99 GpgmeKeyPtr foundKey( nullptr, gpgme_key_release );
100 if ( ! findKeyById( ctx, id, foundKey ) ) {
101 WAR << "Key " << id << "not found" << endl;
102 return false;
103 }
104
105 gpgme_key_t keyarray[2];
106 keyarray[0] = foundKey.get();
107 keyarray[1] = NULL;
108
109 GpgmeDataPtr out( nullptr, gpgme_data_release );
110 GpgmeErr err = gpgme_data_new( &out.get() );
111 if ( err ) {
112 ERR << err << endl;
113 return false;
114 }
115
116 // bsc#1179222: Remove outdated self signatures when exporting the key.
117 // The keyring does not order the signatures when multiple versions of the
118 // same key are imported. Rpm however uses the 1st to compute the -release
119 // of the gpg-pubkey. So we export only the latest to get a proper-release.
120 gpgme_set_armor( ctx, 1 );
121 err = gpgme_op_export_keys( ctx, keyarray, GPGME_EXPORT_MODE_MINIMAL, out.get() );
122 if ( err ) {
123 ERR << "Error exporting key: "<< err << endl;
124 return false;
125 }
126
127 int ret = gpgme_data_seek( out.get(), 0, SEEK_SET );
128 if ( ret ) {
129 ERR << "Unable to seek in exported key data" << endl;
130 return false;
131 }
132
133 keydata.clear();
134 const int bufsize = 512;
135 char buf[bufsize];
136 while ( ( ret = gpgme_data_read( out.get(), buf, bufsize ) ) > 0 ) {
137 keydata.insert( keydata.end(), buf, buf + ret );
138 }
139
140 if ( ret < 0 ) {
141 ERR << "Unable to read exported key data" << endl;
142 return false;
143 }
144
145 return true;
146 }
147
149 [[maybe_unused]] std::ostream & operator<<( std::ostream & str, const _gpgme_op_import_result & obj )
150 {
151 str << "gpgme_op_import_result {" << endl;
152 str << " " << obj.considered << " The total number of considered keys." << endl;
153 str << " " << obj.no_user_id << " The number of keys without user ID." << endl;
154 str << " " << obj.imported << " The total number of imported keys." << endl;
155 str << " " << obj.imported_rsa << " imported RSA keys." << endl;
156 str << " " << obj.unchanged << " unchanged keys." << endl;
157 str << " " << obj.new_user_ids << " new user IDs." << endl;
158 str << " " << obj.new_sub_keys << " new sub keys." << endl;
159 str << " " << obj.new_signatures << " new signatures." << endl;
160 str << " " << obj.new_revocations << " new revocations." << endl;
161 str << " " << obj.secret_read << " secret keys read." << endl;
162 str << " " << obj.secret_imported << " imported secret keys." << endl;
163 str << " " << obj.secret_unchanged << " unchanged secret keys." << endl;
164 str << " " << obj.not_imported << " keys not imported." << endl;
165 for ( gpgme_import_status_t p = obj.imports; p; p = p->next )
166 {
167 str << " - " << p->fpr << ": " << p->result << endl;
168 }
169 // In V.1.11: str << " " << obj.skipped_v3_keys << " skipped v3 keys." << endl;
170 return str << "}";
171 }
172
173 [[maybe_unused]] std::ostream & operator<<( std::ostream & str, const gpgme_sigsum_t & obj )
174 {
175 str << ((int)obj&(int)0xffff) << ":";
176#define OSC(V) if ( V & (unsigned)obj ) str << " " << #V;
177 OSC(GPGME_SIGSUM_VALID );
178 OSC(GPGME_SIGSUM_GREEN );
179 OSC(GPGME_SIGSUM_RED );
180 OSC(GPGME_SIGSUM_KEY_REVOKED );
181 OSC(GPGME_SIGSUM_KEY_EXPIRED );
182 OSC(GPGME_SIGSUM_SIG_EXPIRED );
183 OSC(GPGME_SIGSUM_KEY_MISSING );
184 OSC(GPGME_SIGSUM_CRL_MISSING );
185 OSC(GPGME_SIGSUM_CRL_TOO_OLD );
186 OSC(GPGME_SIGSUM_BAD_POLICY );
187 OSC(GPGME_SIGSUM_SYS_ERROR );
188 OSC(GPGME_SIGSUM_TOFU_CONFLICT);
189#undef OSC
190 return str;
191 }
192
193 [[maybe_unused]] std::ostream & operator<<( std::ostream & str, const gpgme_signature_t & obj )
194 {
195 str << "gpgme_signature_t " << (void *)obj << " {" << endl;
196 str << " next: " << (void *)obj->next << endl;
197 str << " summary: " << obj->summary << endl;
198 str << " fpr: " << obj->fpr << endl;
199 str << " status: " << obj->status << " " << GpgmeErr(obj->status) << endl;
200 str << " timestamp: " << obj->timestamp << endl;
201 str << " exp_timestamp: " << obj->exp_timestamp << endl;
202 str << " wrong_key_usage: " << obj->wrong_key_usage << endl;
203 str << " pka_trust: " << obj->pka_trust << endl;
204 str << " chain_model: " << obj->chain_model << endl;
205 str << " is_de_vs: " << obj->is_de_vs << endl;
206 str << " validity: " << obj->validity << endl;
207 str << " validity_reason: " << obj->validity_reason << " " << GpgmeErr(obj->validity_reason) << endl;
208 str << " pubkey_algo: " << obj->pubkey_algo << endl;
209 str << " hash_algo: " << obj->hash_algo << endl;
210 str << " pka_address: " << (obj->pka_address ? obj->pka_address : "") << endl;
211 return str;
212 }
213
214 } // namespace
216
217 struct GpgmeException : public KeyRingException
218 {
219 GpgmeException( const std::string & in_r, const GpgmeErr & err_r )
220 : KeyRingException( str::Format( "libgpgme error in '%1%': %2%" ) % in_r % err_r )
221 {}
222 };
223
224 class KeyManagerCtx::Impl
225 {
226 public:
227 Impl()
228 { boost::call_once( gpgme_init_once, initGpgme ); }
229
230 Impl(const Impl &) = delete;
231 Impl(Impl &&) = delete;
232 Impl &operator=(const Impl &) = delete;
233 Impl &operator=(Impl &&) = delete;
234
235 ~Impl() {
236 if (_ctx)
237 gpgme_release(_ctx);
238 }
239
241 std::list<std::string> readSignaturesFprs( const Pathname & signature_r )
242 { return readSignaturesFprsOptVerify( signature_r ); }
243
245 std::list<std::string> readSignaturesFprs( const ByteArray & signature_r )
246 { return readSignaturesFprsOptVerify( signature_r ); }
247
249 bool verifySignaturesFprs( const Pathname & file_r, const Pathname & signature_r )
250 {
251 bool verify = false;
252 readSignaturesFprsOptVerify( signature_r, file_r, &verify );
253 return verify;
254 }
255
256 template< typename Callback >
257 bool importKey(GpgmeDataPtr &data, Callback &&calcDataSize );
258
259 bool isVolatile() const
260 { return _tmpDir.has_value(); }
261
262 gpgme_ctx_t _ctx { nullptr };
263 std::optional<filesystem::TmpDir> _tmpDir;
264
265 private:
271 std::list<std::string> readSignaturesFprsOptVerify( const Pathname & signature_r, const Pathname & file_r = "/dev/null", bool * verify_r = nullptr );
272 std::list<std::string> readSignaturesFprsOptVerify( const ByteArray& keyData_r, const Pathname & file_r = "/dev/null", bool * verify_r = nullptr );
273 std::list<std::string> readSignaturesFprsOptVerify( GpgmeDataPtr &sigData, const Pathname & file_r = "/dev/null", bool * verify_r = nullptr );
274 };
275
276std::list<std::string> KeyManagerCtx::Impl::readSignaturesFprsOptVerify( const Pathname & signature_r, const Pathname & file_r, bool * verify_r )
277{
278 //lets be pessimistic
279 if ( verify_r )
280 *verify_r = false;
281
282 if (!PathInfo( signature_r ).isExist())
283 return std::list<std::string>();
284
285 FILEPtr sigFile(fopen(signature_r.c_str(), "rb"), fclose);
286 if (!sigFile) {
287 ERR << "Unable to open signature file '" << signature_r << "'" <<endl;
288 return std::list<std::string>();
289 }
290
291 GpgmeDataPtr sigData(nullptr, gpgme_data_release);
292 GpgmeErr err = gpgme_data_new_from_stream (&sigData.get(), sigFile.get());
293 if (err) {
294 ERR << err << endl;
295 return std::list<std::string>();
296 }
297
298 return readSignaturesFprsOptVerify( sigData, file_r, verify_r );
299}
300
301std::list<std::string> KeyManagerCtx::Impl::readSignaturesFprsOptVerify( const ByteArray &keyData_r, const filesystem::Pathname &file_r, bool *verify_r )
302{
303 //lets be pessimistic
304 if ( verify_r )
305 *verify_r = false;
306
307 GpgmeDataPtr sigData(nullptr, gpgme_data_release);
308 GpgmeErr err = gpgme_data_new_from_mem(&sigData.get(), keyData_r.data(), keyData_r.size(), 1 );
309 if (err) {
310 ERR << err << endl;
311 return std::list<std::string>();
312 }
313
314 return readSignaturesFprsOptVerify( sigData, file_r, verify_r );
315}
316
317std::list<std::string> KeyManagerCtx::Impl::readSignaturesFprsOptVerify(GpgmeDataPtr &sigData, const filesystem::Pathname &file_r, bool *verify_r)
318{
319 //lets be pessimistic
320 if ( verify_r )
321 *verify_r = false;
322
323 FILEPtr dataFile(fopen(file_r.c_str(), "rb"), fclose);
324 if (!dataFile)
325 return std::list<std::string>();
326
327 GpgmeDataPtr fileData(nullptr, gpgme_data_release);
328 GpgmeErr err = gpgme_data_new_from_stream (&fileData.get(), dataFile.get());
329 if (err) {
330 ERR << err << endl;
331 return std::list<std::string>();
332 }
333
334 err = gpgme_op_verify(_ctx, sigData.get(), fileData.get(), NULL);
335 if (err != GPG_ERR_NO_ERROR) {
336 ERR << err << endl;
337 return std::list<std::string>();
338 }
339
340 gpgme_verify_result_t res = gpgme_op_verify_result(_ctx);
341 if (!res || !res->signatures) {
342 ERR << "Unable to read signature fingerprints" <<endl;
343 return std::list<std::string>();
344 }
345
346 bool foundBadSignature = false;
347 bool foundGoodSignature = false;
348 std::list<std::string> signatures;
349 for ( gpgme_signature_t sig = res->signatures; sig; sig = sig->next ) {
350 //DBG << "- " << sig << std::endl;
351 if ( sig->fpr )
352 {
353 // bsc#1100427: With libgpgme11-1.11.0 and if a recent gpg version was used
354 // to create the signature, the field may contain the full fingerprint, but
355 // we're expected to return the ID.
356 // [https://github.com/gpg/gpgme/commit/478d1650bbef84958ccce439fac982ef57b16cd0]
357 std::string id( sig->fpr );
358 if ( id.size() > 16 )
359 id = id.substr( id.size()-16 );
360
361 DBG << "Found signature with ID: " << id << " in " << file_r << std::endl;
362 signatures.push_back( std::move(id) );
363 }
364
365 if ( verify_r && sig->status != GPG_ERR_NO_ERROR ) {
366 const auto status = gpgme_err_code(sig->status);
367
368 // bsc#1180721: libgpgme started to return signatures of unknown keys, which breaks
369 // our workflow when verifying files that have multiple signatures, including some that are
370 // not in the trusted keyring. We should not fail if we have unknown or expired keys and at least a good one.
371 // We will however keep the behaviour of failing if we find a bad signatures even if others are good.
372 switch ( status ) {
373 case GPG_ERR_KEY_EXPIRED:
374 // for now treat expired keys as good signature
375 foundGoodSignature = true;
376 WAR << "Accept good signature from expired key: " << file_r << " " << GpgmeErr(sig->status) << endl;
377 break;
378
379 case GPG_ERR_NO_PUBKEY:
380 WAR << "Legacy: Ignore unknown key: " << file_r << " " << GpgmeErr(sig->status) << endl;
381 break;
382
383 default:
384 WAR << "Failed signature check: " << file_r << " " << GpgmeErr(sig->status) << endl;
385 if ( !foundBadSignature )
386 foundBadSignature = true;
387 break;
388 }
389 } else {
390 foundGoodSignature = true;
391 }
392 }
393
394 if ( verify_r )
395 *verify_r = (!foundBadSignature) && foundGoodSignature;
396 return signatures;
397}
398
399 KeyManagerCtx::KeyManagerCtx()
400: _pimpl( new Impl )
401{}
402
403 KeyManagerCtx KeyManagerCtx::createForOpenPGP()
404{
405 filesystem::TmpDir tmppath( zypp::myTmpDir(), "PublicKey." );
406 if ( not tmppath )
407 ZYPP_THROW( KeyRingException( "Failed to create temporary keyring directory." ) );
408
409 KeyManagerCtx ret { createForOpenPGP( tmppath ) };
410 ret._pimpl->_tmpDir = tmppath;
411 return ret;
412}
413
414 KeyManagerCtx KeyManagerCtx::createForOpenPGP( const Pathname & keyring_r )
415{
416 // DBG << "createForOpenPGP(" << keyring_r << ")" << endl;
417
418 KeyManagerCtx ret;
419 gpgme_ctx_t & ctx { ret._pimpl->_ctx };
420
421 // create the context
422 GpgmeErr err = gpgme_new( &ctx );
423 if ( err != GPG_ERR_NO_ERROR )
424 ZYPP_THROW( GpgmeException( "gpgme_new", err ) );
425
426 // use OpenPGP
427 err = gpgme_set_protocol( ctx, GPGME_PROTOCOL_OpenPGP );
428 if ( err != GPG_ERR_NO_ERROR )
429 ZYPP_THROW( GpgmeException( "gpgme_set_protocol", err ) );
430
431 if ( !keyring_r.empty() ) {
432 // Prevent launching a gpg-agent; we don't need one.
433 {
434 PathInfo pi { keyring_r / gpgconfName };
435 if ( not pi.isExist() ) {
436 std::ofstream file { pi.path().c_str() };
437 file << "no-autostart" << std::endl;
438 }
439 }
440 // get engine information to read current state
441 gpgme_engine_info_t enginfo = gpgme_ctx_get_engine_info( ctx );
442 if ( !enginfo )
443 ZYPP_THROW( GpgmeException( "gpgme_ctx_get_engine_info", err ) );
444
445 err = gpgme_ctx_set_engine_info( ctx, GPGME_PROTOCOL_OpenPGP, enginfo->file_name, keyring_r.c_str() );
446 if ( err != GPG_ERR_NO_ERROR )
447 ZYPP_THROW( GpgmeException( "gpgme_ctx_set_engine_info", err ) );
448 }
449#if 0
450 DBG << "createForOpenPGP {" << endl;
451 for ( const auto & key : ret.listKeys() ) {
452 DBG << " " << key << endl;
453 }
454 DBG << "}" << endl;
455#endif
456 return ret;
457}
458
459 Pathname KeyManagerCtx::homedir() const
460{
461 Pathname ret;
462 if ( gpgme_engine_info_t enginfo = gpgme_ctx_get_engine_info( _pimpl->_ctx ) )
463 ret = enginfo->home_dir;
464 return ret;
465}
466
467std::list<PublicKeyData> KeyManagerCtx::listKeys()
468{
469 std::list<PublicKeyData> ret;
470 GpgmeErr err = GPG_ERR_NO_ERROR;
471
472 // Reset gpgme_keylist_mode on return!
473 AutoDispose<gpgme_keylist_mode_t> guard { gpgme_get_keylist_mode( _pimpl->_ctx ), bind( &gpgme_set_keylist_mode, _pimpl->_ctx, _1 ) };
474 // Let listed keys include signatures (required if PublicKeyData are created from the key)
475 if ( (err = gpgme_set_keylist_mode( _pimpl->_ctx, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_SIGS )) != GPG_ERR_NO_ERROR ) {
476 ERR << "gpgme_set_keylist_mode: " << err << endl;
477 return ret;
478 }
479
480 if ( (err = gpgme_op_keylist_start( _pimpl->_ctx, NULL, 0 )) != GPG_ERR_NO_ERROR ) {
481 ERR << "gpgme_op_keylist_start: " << err << endl;
482 return ret;
483 }
484 // Close list operation on return!
485 AutoDispose<gpgme_ctx_t> guard2 { _pimpl->_ctx, &gpgme_op_keylist_end };
486
487 AutoDispose<gpgme_key_t> key { nullptr, &gpgme_key_release };
488 for ( ; gpgme_op_keylist_next( _pimpl->_ctx, &(*key) ) == GPG_ERR_NO_ERROR; key.getDispose()( key ) ) {
489 PublicKeyData data { PublicKeyData::fromGpgmeKey( key ) };
490 if ( data )
491 ret.push_back( data );
492 }
493
494 return ret;
495}
496
497std::list<PublicKeyData> KeyManagerCtx::readKeyFromFile( const Pathname & keyfile_r )
498{
499 // bsc#1140670: GPGME does not support reading keys from a keyfile using
500 // gpgme_data_t and gpgme_op_keylist_from_data_start. Despite GPGME_KEYLIST_MODE_SIGS
501 // the signatures are missing, but we need them to create proper PublicKeyData objects.
502 // While this is not resolved, we read into a temp. keyring. Volatile contexts own
503 // a private temp. homedir and can therefore clear and reuse their keyring without
504 // affecting other contexts. Non-volatile contexts delegate to a volatile one.
505 std::list<PublicKeyData> ret;
506
507 if ( _pimpl->isVolatile() ) {
508 // in a volatile context we can simply clear the keyring...
509 base::LogControl::TmpLineWriter shutUp; // be quiet
510 filesystem::dirForEach( homedir(), []( const Pathname & dir, const char *const name ) {
511 if ( name != gpgconfName ) {
512 filesystem::unlink( dir / name );
513 }
514 return true;
515 } );
516 if ( importKey( keyfile_r ) )
517 ret = listKeys();
518 } else {
519 // read in a volatile context
520 ret = createForOpenPGP().readKeyFromFile( keyfile_r );
521 }
522
523 return ret;
524}
525
526 bool KeyManagerCtx::verify(const Pathname &file, const Pathname &signature)
527{
528 return _pimpl->verifySignaturesFprs(file, signature);
529}
530
531 bool KeyManagerCtx::exportKey(const std::string &id, std::ostream &stream)
532{
533 ByteArray keydata;
534 if ( ! exportKey( id, keydata ) )
535 return false;
536
537 stream.write( keydata.data(), keydata.size() );
538 return bool( stream );
539}
540
541 bool KeyManagerCtx::exportKey(const std::string &id, ByteArray &keydata)
542{
543 return exportKeyData( _pimpl->_ctx, id, keydata );
544}
545
546 bool KeyManagerCtx::importKey(const Pathname &keyfile)
547{
548 if ( !PathInfo( keyfile ).isExist() ) {
549 ERR << "Keyfile '" << keyfile << "' does not exist.";
550 return false;
551 }
552
553 GpgmeDataPtr data(nullptr, gpgme_data_release);
554 GpgmeErr err;
555
556 err = gpgme_data_new_from_file(&data.get(), keyfile.c_str(), 1);
557 if (err) {
558 ERR << "Error importing key: "<< err << endl;
559 return false;
560 }
561
562 return _pimpl->importKey( data, [&](){ return PathInfo(keyfile).size(); } );
563}
564
565 bool KeyManagerCtx::importKey( std::istream & stream )
566{
567 ByteArray keydata;
568
569 constexpr size_t bufSize = 4096;
570 char buf[bufSize];
571 while ( stream.read( buf, sizeof(buf) ) || stream.gcount() ) {
572 keydata.insert( keydata.end(), buf, buf + stream.gcount() );
573 }
574
575 if ( stream.bad() ) {
576 ERR << "Error importing key: failed to read key stream" << endl;
577 return false;
578 }
579
580 return importKey( keydata );
581}
582
583 bool KeyManagerCtx::importKey( const ByteArray &keydata )
584{
585 GpgmeDataPtr data(nullptr, gpgme_data_release);
586 GpgmeErr err;
587
588 err = gpgme_data_new_from_mem( &data.get(), keydata.data(), keydata.size(), 1);
589 if (err) {
590 ERR << "Error importing key: "<< err << endl;
591 return false;
592 }
593
594 return _pimpl->importKey( data, [&](){ return keydata.size(); } );
595}
596
597 template<typename Callback>
598 bool KeyManagerCtx::Impl::importKey(GpgmeDataPtr &data, Callback &&calcDataSize)
599{
600 GpgmeErr err;
601 err = gpgme_op_import( _ctx, data.get() );
602 if (err) {
603 ERR << "Error importing key: "<< err << endl;
604 return false;
605 }
606
607 // Work around bsc#1127220 [libgpgme] no error upon incomplete import due to signal received.
608 // We need this error, otherwise RpmDb will report the missing keys as 'probably v3'.
609 if ( gpgme_import_result_t res = gpgme_op_import_result(_ctx) )
610 {
611 if ( ! res->considered && std::forward<Callback>(calcDataSize)() )
612 {
613 DBG << *res << endl;
614 ERR << "Error importing key: No keys considered (bsc#1127220, [libgpgme] signal received?)" << endl;
615 return false;
616 }
617 }
618
619 return (err == GPG_ERR_NO_ERROR);
620}
621
622 bool KeyManagerCtx::deleteKey(const std::string &id)
623{
624 gpgme_key_t key = nullptr;
625 GpgmeErr err = GPG_ERR_NO_ERROR;
626
627 gpgme_op_keylist_start(_pimpl->_ctx, NULL, 0);
628
629 while (!(err = gpgme_op_keylist_next(_pimpl->_ctx, &key))) {
630 if (key->subkeys && id == str::asString(key->subkeys->keyid)) {
631 err = gpgme_op_delete(_pimpl->_ctx, key, 0);
632
633 gpgme_key_release(key);
634 gpgme_op_keylist_end(_pimpl->_ctx);
635
636 if (err) {
637 ERR << "Error deleting key: "<< err << endl;
638 return false;
639 }
640 return true;
641 }
642 gpgme_key_release(key);
643 }
644
645 gpgme_op_keylist_end(_pimpl->_ctx);
646 WAR << "Key: '"<< id << "' not found." << endl;
647 return false;
648}
649
650std::list<std::string> KeyManagerCtx::readSignatureFingerprints(const Pathname &signature)
651{ return _pimpl->readSignaturesFprs(signature); }
652
653std::list<std::string> KeyManagerCtx::readSignatureFingerprints(const ByteArray &keyData)
654{ return _pimpl->readSignaturesFprs(keyData); }
655
656} // namespace zypp
AutoDispose.h
ZYPP_THROW
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition Exception.h:459
OSC
#define OSC(V)
KeyManager.h
KeyRingException.h
LogControl.h
LogTools.h
DBG
#define DBG
Definition Logger.h:129
MIL
#define MIL
Definition Logger.h:130
ERR
#define ERR
Definition Logger.h:132
WAR
#define WAR
Definition Logger.h:131
operator<<
std::ostream & operator<<(std::ostream &str, const zypp::sat::detail::CDataiterator *obj)
relates: zypp::sat::LookupAttr::iterator Stream output of the underlying iterator for debug.
Definition LookupAttr.cc:808
String.h
bool
zypp::AutoDispose
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition AutoDispose.h:95
zypp::AutoDispose::getDispose
const Dispose & getDispose() const
Return the current dispose function.
Definition AutoDispose.h:163
zypp::ByteArray
Definition ByteArray.h:20
zypp::KeyManagerCtx::Impl
Definition KeyManager.cc:225
zypp::KeyManagerCtx::Impl::operator=
Impl & operator=(const Impl &)=delete
zypp::KeyManagerCtx::Impl::Impl
Impl()
Definition KeyManager.cc:227
zypp::KeyManagerCtx::Impl::_ctx
gpgme_ctx_t _ctx
Definition KeyManager.cc:262
zypp::KeyManagerCtx::Impl::readSignaturesFprs
std::list< std::string > readSignaturesFprs(const Pathname &signature_r)
Return all fingerprints found in signature_r.
Definition KeyManager.cc:241
zypp::KeyManagerCtx::Impl::Impl
Impl(const Impl &)=delete
zypp::KeyManagerCtx::Impl::_tmpDir
std::optional< filesystem::TmpDir > _tmpDir
volatile contexts own their private temp homedir
Definition KeyManager.cc:263
zypp::KeyManagerCtx::Impl::Impl
Impl(Impl &&)=delete
zypp::KeyManagerCtx::Impl::~Impl
~Impl()
Definition KeyManager.cc:235
zypp::KeyManagerCtx::Impl::operator=
Impl & operator=(Impl &&)=delete
zypp::KeyManagerCtx::Impl::readSignaturesFprs
std::list< std::string > readSignaturesFprs(const ByteArray &signature_r)
Return all fingerprints found in signature_r.
Definition KeyManager.cc:245
zypp::KeyManagerCtx::Impl::isVolatile
bool isVolatile() const
Definition KeyManager.cc:259
zypp::KeyManagerCtx::Impl::readSignaturesFprsOptVerify
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:276
zypp::KeyManagerCtx::Impl::verifySignaturesFprs
bool verifySignaturesFprs(const Pathname &file_r, const Pathname &signature_r)
Tries to verify the file_r using signature_r.
Definition KeyManager.cc:249
zypp::KeyManagerCtx::Impl::importKey
bool importKey(GpgmeDataPtr &data, Callback &&calcDataSize)
Definition KeyManager.cc:598
zypp::KeyManagerCtx::KeyManagerCtx
KeyManagerCtx()
Definition KeyManager.cc:399
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:531
zypp::KeyManagerCtx::listKeys
std::list< PublicKeyData > listKeys()
Returns a list of all public keys found in the current keyring.
Definition KeyManager.cc:467
zypp::KeyManagerCtx::verify
bool verify(const Pathname &file, const Pathname &signature)
Tries to verify file using signature, returns true on success.
Definition KeyManager.cc:526
zypp::KeyManagerCtx::createForOpenPGP
static KeyManagerCtx createForOpenPGP()
Creates a new KeyManagerCtx for PGP using a volatile temp.
Definition KeyManager.cc:403
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:650
zypp::KeyManagerCtx::readKeyFromFile
std::list< PublicKeyData > readKeyFromFile(const Pathname &file)
Returns a list of all PublicKeyData found in file.
Definition KeyManager.cc:497
zypp::KeyManagerCtx::_pimpl
RW_pointer< Impl > _pimpl
Pointer to implementation.
Definition KeyManager.h:95
zypp::KeyManagerCtx::deleteKey
bool deleteKey(const std::string &id)
Tries to delete a key specified by id, returns true on success.
Definition KeyManager.cc:622
zypp::KeyManagerCtx::homedir
Pathname homedir() const
Return the homedir/keyring.
Definition KeyManager.cc:459
zypp::KeyManagerCtx::importKey
bool importKey(const Pathname &keyfile)
Tries to import a key from keyfile, returns true on success.
Definition KeyManager.cc:546
zypp::KeyRingException::KeyRingException
KeyRingException()
Ctor taking message.
Definition KeyRingException.h:26
zypp::PathInfo::PathInfo
PathInfo()
Definition PathInfo.cc:131
zypp::PublicKeyData
Class representing one GPG Public Keys data.
Definition PublicKey.h:201
zypp::PublicKeyData::fromGpgmeKey
static PublicKeyData fromGpgmeKey(_gpgme_key *data)
Definition PublicKey.cc:406
zypp::filesystem::PathInfo
Wrapper class for stat/lstat.
Definition PathInfo.h:226
zypp::filesystem::PathInfo::path
const Pathname & path() const
Return current Pathname.
Definition PathInfo.h:251
zypp::filesystem::PathInfo::isExist
bool isExist() const
Return whether valid stat info exists.
Definition PathInfo.h:286
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::empty
bool empty() const
Test for an empty path.
Definition Pathname.h:117
zypp::filesystem::TmpDir
Provide a new empty temporary directory and recursively delete it when no longer needed.
Definition TmpPath.h:173
str
String related utilities and Regular expression matching.
zypp::filesystem::unlink
int unlink(const Pathname &path)
Like 'unlink'.
Definition PathInfo.cc:719
zypp::filesystem::dirForEach
int dirForEach(const Pathname &dir_r, const StrMatcher &matcher_r, function< bool(const Pathname &, const char *const)> fnc_r)
Definition PathInfo.cc:32
zypp::str::asString
const std::string & asString(const std::string &t)
Global asString() that works with std::string too.
Definition String.h:140
zypp
Easy-to use interface to the ZYPP dependency resolver.
Definition CodePitfalls.doc:2
zypp::myTmpDir
Pathname myTmpDir()
Global access to the zypp.TMPDIR (created on demand, deleted when libzypp is unloaded).
Definition TmpPath.cc:276
zypp::GpgmeException::GpgmeException
GpgmeException(const std::string &in_r, const GpgmeErr &err_r)
Definition KeyManager.cc:219
zypp::base::LogControl::TmpLineWriter
Exchange LineWriter for the lifetime of this object.
Definition LogControl.h:204
PathInfo.h
TmpPath.h