libzypp 17.31.23
KeyRing.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
12#include <iostream>
13#include <fstream>
14#include <optional>
15#include <sys/file.h>
16#include <cstdio>
17#include <unistd.h>
18
19#include <zypp/TmpPath.h>
20#include <zypp/ZYppFactory.h>
21#include <zypp/ZYpp.h>
22
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>
30#include <zypp/KeyRing.h>
31#include <zypp/ExternalProgram.h>
32#include <zypp/TmpPath.h>
33#include <zypp/ZYppCallbacks.h> // JobReport::instance
34#include <zypp/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
46
47 namespace
48 {
49 KeyRing::DefaultAccept _keyRingDefaultAccept( KeyRing::ACCEPT_NOTHING );
50 }
51
52 KeyRing::DefaultAccept KeyRing::defaultAccept()
53 { return _keyRingDefaultAccept; }
54
55 void KeyRing::setDefaultAccept( DefaultAccept value_r )
56 {
57 MIL << "Set new KeyRing::DefaultAccept: " << value_r << endl;
58 _keyRingDefaultAccept = value_r;
59 }
60
61 void KeyRingReport::infoVerify( const std::string & file_r, const PublicKeyData & keyData_r, const KeyContext & keycontext )
62 {}
63
64 bool KeyRingReport::askUserToAcceptUnsignedFile( const std::string & file, const KeyContext & keycontext )
65 { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_UNSIGNED_FILE ); }
66
68 KeyRingReport::askUserToAcceptKey( const PublicKey & key, const KeyContext & keycontext )
69 {
70 if ( _keyRingDefaultAccept.testFlag( KeyRing::TRUST_KEY_TEMPORARILY ) )
72 if ( _keyRingDefaultAccept.testFlag( KeyRing::TRUST_AND_IMPORT_KEY ) )
74 return KEY_DONT_TRUST;
75 }
76
77 bool KeyRingReport::askUserToAcceptUnknownKey( const std::string & file, const std::string & id, const KeyContext & keycontext )
78 { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_UNKNOWNKEY ); }
79
80 bool KeyRingReport::askUserToAcceptVerificationFailed( const std::string & file, const PublicKey & key, const KeyContext & keycontext )
81 { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_VERIFICATION_FAILED ); }
82
83 bool KeyRingReport::askUserToAcceptPackageKey(const PublicKey &key_r, const KeyContext &keycontext_r)
84 {
86 data.set("PublicKey", key_r);
87 data.set("KeyContext", keycontext_r);
88 report(data);
89
90 if ( data.hasvalue("TrustKey") )
91 return data.get<bool>("TrustKey");
92 return false;
93 }
94
95 void KeyRingReport::reportNonImportedKeys(const std::set<Edition> &keys_r)
96 {
98 data.set("Keys", keys_r);
99 report(data);
100 }
101
102 void KeyRingReport::reportAutoImportKey( const std::list<PublicKeyData> & keyDataList_r,
103 const PublicKeyData & keySigning_r,
104 const KeyContext &keyContext_r )
105 {
107 data.set( "KeyDataList", keyDataList_r );
108 data.set( "KeySigning", keySigning_r );
109 data.set( "KeyContext", keyContext_r );
110 report( data );
111 }
112
113 namespace
114 {
122 struct CachedPublicKeyData : private base::NonCopyable
123 {
124 const std::list<PublicKeyData> & operator()( const Pathname & keyring_r ) const
125 { return getData( keyring_r ); }
126
127 void setDirty( const Pathname & keyring_r )
128 { _cacheMap[keyring_r].setDirty(); }
129
136 struct Manip {
137 NON_COPYABLE_BUT_MOVE( Manip );
138 Manip( CachedPublicKeyData & cache_r, Pathname keyring_r )
139 : _cache { cache_r }
140 , _keyring { std::move(keyring_r) }
141 {}
142
143 KeyManagerCtx & keyManagerCtx() {
144 if ( not _context ) {
146 }
147 // frankly: don't remember why an explicit setDirty was introduced and
148 // why WatchFile was not enough. Maybe some corner case when the keyrings
149 // are created?
150 _cache.setDirty( _keyring );
151 return _context.value();
152 }
153
154 private:
155 CachedPublicKeyData & _cache;
156 Pathname _keyring;
157 std::optional<KeyManagerCtx> _context;
158 };
160
162 Manip manip( Pathname keyring_r ) { return Manip( *this, std::move(keyring_r) ); }
163
164 private:
165 struct Cache
166 {
167 Cache() {}
168
169 void setDirty()
170 {
171 _keyringK.reset();
172 _keyringP.reset();
173 }
174
175 void assertCache( const Pathname & keyring_r )
176 {
177 // .kbx since gpg2-2.1
178 if ( !_keyringK )
179 _keyringK.reset( new WatchFile( keyring_r/"pubring.kbx", WatchFile::NO_INIT ) );
180 if ( !_keyringP )
181 _keyringP.reset( new WatchFile( keyring_r/"pubring.gpg", WatchFile::NO_INIT ) );
182 }
183
184 bool hasChanged() const
185 {
186 bool k = _keyringK->hasChanged(); // be sure both files are checked
187 bool p = _keyringP->hasChanged();
188 return k || p;
189 }
190
191 std::list<PublicKeyData> _data;
192
193 private:
194
197 };
198
199 typedef std::map<Pathname,Cache> CacheMap;
200
201 const std::list<PublicKeyData> & getData( const Pathname & keyring_r ) const
202 {
203 Cache & cache( _cacheMap[keyring_r] );
204 // init new cache entry
205 cache.assertCache( keyring_r );
206 return getData( keyring_r, cache );
207 }
208
209 const std::list<PublicKeyData> & getData( const Pathname & keyring_r, Cache & cache_r ) const
210 {
211 if ( cache_r.hasChanged() ) {
212 cache_r._data = KeyManagerCtx::createForOpenPGP( keyring_r ).listKeys();
213 MIL << "Found keys: " << cache_r._data << endl;
214 }
215 return cache_r._data;
216 }
217
218 mutable CacheMap _cacheMap;
219 };
221
222
223 }
224
226 //
227 // CLASS NAME : KeyRing::Impl
228 //
231 {
232 Impl( const Pathname & baseTmpDir )
233 : _trusted_tmp_dir( baseTmpDir, "zypp-trusted-kr" )
234 , _general_tmp_dir( baseTmpDir, "zypp-general-kr" )
235 , _base_dir( baseTmpDir )
236 {
237 MIL << "Current KeyRing::DefaultAccept: " << _keyRingDefaultAccept << endl;
238 }
239
240 void importKey( const PublicKey & key, bool trusted = false );
241 void multiKeyImport( const Pathname & keyfile_r, bool trusted_r = false );
242 void deleteKey( const std::string & id, bool trusted );
243
244 std::string readSignatureKeyId( const Pathname & signature );
245
246 bool isKeyTrusted( const std::string & id )
247 { return bool(publicKeyExists( id, trustedKeyRing() )); }
248 bool isKeyKnown( const std::string & id )
249 { return publicKeyExists( id, trustedKeyRing() ) || publicKeyExists( id, generalKeyRing() ); }
250
251 std::list<PublicKey> trustedPublicKeys()
252 { return publicKeys( trustedKeyRing() ); }
253 std::list<PublicKey> publicKeys()
254 { return publicKeys( generalKeyRing() ); }
255
256 const std::list<PublicKeyData> & trustedPublicKeyData()
257 { return publicKeyData( trustedKeyRing() ); }
258 const std::list<PublicKeyData> & publicKeyData()
259 { return publicKeyData( generalKeyRing() ); }
260
261 void dumpPublicKey( const std::string & id, bool trusted, std::ostream & stream )
262 { dumpPublicKey( id, ( trusted ? trustedKeyRing() : generalKeyRing() ), stream ); }
263
265 { return exportKey( keyData, generalKeyRing() ); }
267 { return exportKey( keyData, trustedKeyRing() ); }
268
270 {
271 // Assert result and return value are in sync
272 context_r.fileAccepted( _verifyFileSignatureWorkflow( context_r ) );
273 return context_r.fileAccepted();
274 }
276
277 bool verifyFileSignature( const Pathname & file, const Pathname & signature )
278 { return verifyFile( file, signature, generalKeyRing() ); }
279 bool verifyFileTrustedSignature( const Pathname & file, const Pathname & signature )
280 { return verifyFile( file, signature, trustedKeyRing() ); }
281
282 PublicKeyData publicKeyExists( const std::string & id )
283 { return publicKeyExists(id, generalKeyRing());}
284 PublicKeyData trustedPublicKeyExists( const std::string & id )
285 { return publicKeyExists(id, trustedKeyRing());}
286
287 bool provideAndImportKeyFromRepositoryWorkflow (const std::string &id_r , const RepoInfo &info_r );
288
289 void allowPreload( bool yesno_r )
290 { _allowPreload = yesno_r; }
291
292 private:
294 CachedPublicKeyData::Manip keyRingManip( const Pathname & keyring )
295 { return cachedPublicKeyData.manip( keyring ); }
296
297 bool verifyFile( const Pathname & file, const Pathname & signature, const Pathname & keyring );
298 void importKey( const Pathname & keyfile, const Pathname & keyring );
299
300 PublicKey exportKey( const std::string & id, const Pathname & keyring );
301 PublicKey exportKey( const PublicKeyData & keyData, const Pathname & keyring );
302 PublicKey exportKey( const PublicKey & key, const Pathname & keyring )
303 { return exportKey( key.keyData(), keyring ); }
304
305 void dumpPublicKey( const std::string & id, const Pathname & keyring, std::ostream & stream );
306 filesystem::TmpFile dumpPublicKeyToTmp( const std::string & id, const Pathname & keyring );
307
308 void deleteKey( const std::string & id, const Pathname & keyring );
309
310 std::list<PublicKey> publicKeys( const Pathname & keyring);
311 const std::list<PublicKeyData> & publicKeyData( const Pathname & keyring )
312 { return cachedPublicKeyData( keyring ); }
313
315 PublicKeyData publicKeyExists( const std::string & id, const Pathname & keyring );
317 void preloadCachedKeys();
318
320 { return _general_tmp_dir.path(); }
322 { return _trusted_tmp_dir.path(); }
323
324 // Used for trusted and untrusted keyrings
328 bool _allowPreload = false; //< General keyring may be preloaded with keys cached on the system.
329
330 private:
336 CachedPublicKeyData cachedPublicKeyData;
337 };
339
340 namespace
341 {
343 struct ImportKeyCBHelper
344 {
345 void operator()( const PublicKey & key_r )
346 {
347 try {
348 _rpmdbEmitSignal->trustedKeyAdded( key_r );
349 _emitSignal->trustedKeyAdded( key_r );
350 }
351 catch ( const Exception & excp )
352 {
353 ERR << "Could not import key into rpmdb: " << excp << endl;
354 // TODO: JobReport as hotfix for bsc#1057188; should bubble up and go through some callback
356 }
357 }
358
359 private:
360 callback::SendReport<target::rpm::KeyRingSignals> _rpmdbEmitSignal;
361 callback::SendReport<KeyRingSignals> _emitSignal;
362 };
363 } // namespace
364
365
366 void KeyRing::Impl::importKey( const PublicKey & key, bool trusted )
367 {
368 importKey( key.path(), trusted ? trustedKeyRing() : generalKeyRing() );
369 MIL << "Imported key " << key << " to " << (trusted ? "trustedKeyRing" : "generalKeyRing" ) << endl;
370
371 if ( trusted )
372 {
373 ImportKeyCBHelper emitSignal;
374 if ( key.hiddenKeys().empty() )
375 {
376 emitSignal( key );
377 }
378 else
379 {
380 // multiple keys: Export individual keys ascii armored to import in rpmdb
381 emitSignal( exportKey( key, trustedKeyRing() ) );
382 for ( const PublicKeyData & hkey : key.hiddenKeys() )
383 emitSignal( exportKey( hkey, trustedKeyRing() ) );
384 }
385 }
386 }
387
388 void KeyRing::Impl::multiKeyImport( const Pathname & keyfile_r, bool trusted_r )
389 {
390 importKey( keyfile_r, trusted_r ? trustedKeyRing() : generalKeyRing() );
391 }
392
393 void KeyRing::Impl::deleteKey( const std::string & id, bool trusted )
394 {
395 PublicKeyData keyDataToDel( publicKeyExists( id, trusted ? trustedKeyRing() : generalKeyRing() ) );
396 if ( ! keyDataToDel )
397 {
398 WAR << "Key to delete [" << id << "] is not in " << (trusted ? "trustedKeyRing" : "generalKeyRing" ) << endl;
399 return;
400 }
401 deleteKey( id, trusted ? trustedKeyRing() : generalKeyRing() );
402 MIL << "Deleted key [" << id << "] from " << (trusted ? "trustedKeyRing" : "generalKeyRing" ) << endl;
403
404 if ( trusted )
405 try {
406 PublicKey key( keyDataToDel );
407
409 rpmdbEmitSignal->trustedKeyRemoved( key );
410
412 emitSignal->trustedKeyRemoved( key );
413 }
414 catch ( const Exception & excp )
415 {
416 ERR << "Could not delete key from rpmmdb: " << excp << endl;
417 // TODO: JobReport as hotfix for bsc#1057188; should bubble up and go through some callback
419 }
420 }
421
422 PublicKeyData KeyRing::Impl::publicKeyExists( const std::string & id, const Pathname & keyring )
423 {
424 if ( _allowPreload && keyring == generalKeyRing() ) {
425 _allowPreload = false;
426 preloadCachedKeys();
427 }
428
429 PublicKeyData ret;
430 for ( const PublicKeyData & key : publicKeyData( keyring ) )
431 {
432 if ( key.providesKey( id ) )
433 {
434 ret = key;
435 break;
436 }
437 }
438 DBG << (ret ? "Found" : "No") << " key [" << id << "] in keyring " << keyring << endl;
439 return ret;
440 }
441
443 {
444 MIL << "preloadCachedKeys into general keyring..." << endl;
445 CachedPublicKeyData::Manip manip { keyRingManip( generalKeyRing() ) }; // Provides the context if we want to manip a cached keyring.
446
447 // For now just load the 'gpg-pubkey-*.{asc,key}' files into the general keyring,
448 // if their id (derived from the filename) is not in the trusted ring.
449 // TODO: Head for a persistent general keyring.
450 std::set<Pathname> cachedirs;
451 ZConfig & conf { ZConfig::instance() };
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" );
457 }
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" );
461 }
462
463 std::map<std::string,Pathname> keyCandidates; // Collect one file path per keyid
464 const str::regex rx { "^gpg-pubkey-([[:xdigit:]]{8,})(-[[:xdigit:]]{8,})?\\.(asc|key)$" };
465 for ( const auto & cache : cachedirs ) {
466 dirForEach( cache,
467 [&rx,&keyCandidates]( const Pathname & dir_r, const char *const file_r )->bool {
468 str::smatch what;
469 if ( str::regex_match( file_r, what, rx ) ) {
470 Pathname & remember { keyCandidates[what[1]] };
471 if ( remember.empty() ) {
472 remember = dir_r / file_r;
473 }
474 }
475 return true;
476 }
477 );
478 }
479
480 for ( const auto & p : keyCandidates ) {
481 // Avoid checking the general keyring while it is flagged dirty.
482 // Checking the trusted ring is ok, and most keys will be there anyway.
483 const std::string & id { p.first };
484 const Pathname & path { p.second };
485 if ( isKeyTrusted(id) )
486 continue;
487 if ( manip.keyManagerCtx().importKey( path ) ) {
488 DBG << "preload key file " << path << endl;
489 }
490 else {
491 WAR << "Skipping: Can't preload key file " << path << endl;
492 }
493 }
494 }
495
496 PublicKey KeyRing::Impl::exportKey( const PublicKeyData & keyData, const Pathname & keyring )
497 {
498 return PublicKey( dumpPublicKeyToTmp( keyData.id(), keyring ), keyData );
499 }
500
501 PublicKey KeyRing::Impl::exportKey( const std::string & id, const Pathname & keyring )
502 {
503 PublicKeyData keyData( publicKeyExists( id, keyring ) );
504 if ( keyData )
505 return PublicKey( dumpPublicKeyToTmp( keyData.id(), keyring ), keyData );
506
507 // Here: key not found
508 WAR << "No key [" << id << "] to export from " << keyring << endl;
509 return PublicKey();
510 }
511
512
513 void KeyRing::Impl::dumpPublicKey( const std::string & id, const Pathname & keyring, std::ostream & stream )
514 {
515 KeyManagerCtx::createForOpenPGP( keyring ).exportKey(id, stream);
516 }
517
518 filesystem::TmpFile KeyRing::Impl::dumpPublicKeyToTmp( const std::string & id, const Pathname & keyring )
519 {
520 filesystem::TmpFile tmpFile( _base_dir, "pubkey-"+id+"-" );
521 MIL << "Going to export key [" << id << "] from " << keyring << " to " << tmpFile.path() << endl;
522
523 std::ofstream os( tmpFile.path().c_str() );
524 dumpPublicKey( id, keyring, os );
525 os.close();
526 return tmpFile;
527 }
528
530 {
531 context_r.resetResults();
532 const Pathname & file { context_r.file() };
533 const Pathname & signature { context_r.signature() };
534 const std::string & filedesc { context_r.shortFile() };
535 const KeyContext & keyContext { context_r.keyContext() };
536
538 MIL << "Going to verify signature for " << filedesc << " ( " << file << " ) with " << signature << endl;
539
540 // if signature does not exists, ask user if they want to accept unsigned file.
541 if( signature.empty() || (!PathInfo( signature ).isExist()) )
542 {
543 bool res = report->askUserToAcceptUnsignedFile( filedesc, keyContext );
544 MIL << "askUserToAcceptUnsignedFile: " << res << endl;
545 return res;
546 }
547
548 // get the id of the signature (it might be a subkey id!)
549 context_r.signatureId( readSignatureKeyId( signature ) );
550 const std::string & id = context_r.signatureId();
551 PublicKeyData foundKey;
552 Pathname whichKeyring;
553
554 std::list<PublicKeyData> buddies; // Could be imported IFF the file is validated by a trusted key
555 for ( const auto & sid : context_r.buddyKeys() ) {
556 if ( not PublicKeyData::isSafeKeyId( sid ) ) {
557 WAR << "buddy " << sid << ": key id is too short to safely identify a gpg key. Skipping it." << endl;
558 continue;
559 }
560 if ( trustedPublicKeyExists( sid ) ) {
561 MIL << "buddy " << sid << ": already in trusted key ring. Not needed." << endl;
562 continue;
563 }
564 auto pk = publicKeyExists( sid );
565 if ( not pk ) {
566 WAR << "buddy " << sid << ": not available in the public key ring. Skipping it." << endl;
567 continue;
568 }
569 if ( pk.providesKey(id) ) {
570 MIL << "buddy " << sid << ": is the signing key. Handled separately." << endl;
571 continue;
572 }
573 MIL << "buddy " << sid << ": candidate for auto import. Remeber it." << endl;
574 buddies.push_back( pk );
575 }
576
577 if ( !id.empty() ) {
578
579 // does key exists in trusted keyring
580 PublicKeyData trustedKeyData( publicKeyExists( id, trustedKeyRing() ) );
581 if ( trustedKeyData )
582 {
583 MIL << "Key is trusted: " << trustedKeyData << endl;
584
585 // lets look if there is an updated key in the
586 // general keyring
587 PublicKeyData generalKeyData( publicKeyExists( id, generalKeyRing() ) );
588 if ( generalKeyData )
589 {
590 // bnc #393160: Comment #30: Compare at least the fingerprint
591 // in case an attacker created a key the the same id.
592 //
593 // FIXME: bsc#1008325: For keys using subkeys, we'd actually need
594 // to compare the subkey sets, to tell whether a key was updated.
595 // because created() remains unchanged if the primary key is not touched.
596 // For now we wait until a new subkey signs the data and treat it as a
597 // new key (else part below).
598 if ( trustedKeyData.fingerprint() == generalKeyData.fingerprint()
599 && trustedKeyData.created() < generalKeyData.created() )
600 {
601 MIL << "Key was updated. Saving new version into trusted keyring: " << generalKeyData << endl;
602 importKey( exportKey( generalKeyData, generalKeyRing() ), true );
603 trustedKeyData = publicKeyExists( id, trustedKeyRing() ); // re-read: invalidated by import?
604 }
605 }
606
607 foundKey = trustedKeyData;
608 whichKeyring = trustedKeyRing();
609 }
610 else
611 {
612 PublicKeyData generalKeyData( publicKeyExists( id, generalKeyRing() ) );
613 if ( generalKeyData )
614 {
615 PublicKey key( exportKey( generalKeyData, generalKeyRing() ) );
616 MIL << "Key [" << id << "] " << key.name() << " is not trusted" << endl;
617
618 // ok the key is not trusted, ask the user to trust it or not
619 KeyRingReport::KeyTrust reply = report->askUserToAcceptKey( key, keyContext );
622 {
623 MIL << "User wants to trust key [" << id << "] " << key.name() << endl;
624
626 {
627 MIL << "User wants to import key [" << id << "] " << key.name() << endl;
628 importKey( key, true );
629 whichKeyring = trustedKeyRing();
630 }
631 else
632 whichKeyring = generalKeyRing();
633
634 foundKey = generalKeyData;
635 }
636 else
637 {
638 MIL << "User does not want to trust key [" << id << "] " << key.name() << endl;
639 return false;
640 }
641 }
642 else if ( ! keyContext.empty() )
643 {
644 // try to find the key in the repository info
645 if ( provideAndImportKeyFromRepositoryWorkflow( id, keyContext.repoInfo() ) ) {
646 whichKeyring = trustedKeyRing();
647 foundKey = PublicKeyData( publicKeyExists( id, trustedKeyRing() ) );
648 }
649 }
650 }
651 }
652
653 if ( foundKey ) {
654 // it exists, is trusted, does it validate?
655 context_r.signatureIdTrusted( whichKeyring == trustedKeyRing() );
656 report->infoVerify( filedesc, foundKey, keyContext );
657 if ( verifyFile( file, signature, whichKeyring ) )
658 {
659 context_r.fileValidated( true );
660 if ( context_r.signatureIdTrusted() && not buddies.empty() ) {
661 // Check for buddy keys to be imported...
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 );
666 }
667 }
668 return context_r.fileValidated(); // signature is actually successfully validated!
669 }
670 else
671 {
672 bool res = report->askUserToAcceptVerificationFailed( filedesc, exportKey( foundKey, whichKeyring ), keyContext );
673 MIL << "askUserToAcceptVerificationFailed: " << res << endl;
674 return res;
675 }
676 } else {
677 // signed with an unknown key...
678 MIL << "File [" << file << "] ( " << filedesc << " ) signed with unknown key [" << id << "]" << endl;
679 bool res = report->askUserToAcceptUnknownKey( filedesc, id, keyContext );
680 MIL << "askUserToAcceptUnknownKey: " << res << endl;
681 return res;
682 }
683
684 return false;
685 }
686
687 bool KeyRing::Impl::provideAndImportKeyFromRepositoryWorkflow(const std::string &id_r, const RepoInfo &info_r)
688 {
689 if ( id_r.empty() )
690 return false;
691
692 const ZConfig &conf = ZConfig::instance();
693 Pathname cacheDir = conf.repoManagerRoot() / conf.pubkeyCachePath();
694
695 Pathname myKey = info_r.provideKey( id_r, cacheDir );
696 if ( myKey.empty() )
697 // if we did not find any keys, there is no point in checking again, break
698 return false;
699
701
702 PublicKey key;
703 try {
704 key = PublicKey( myKey );
705 } catch ( const Exception &e ) {
706 ZYPP_CAUGHT(e);
707 return false;
708 }
709
710 if ( !key.isValid() ) {
711 ERR << "Key [" << id_r << "] from cache: " << cacheDir << " is not valid" << endl;
712 return false;
713 }
714
715 MIL << "Key [" << id_r << "] " << key.name() << " loaded from cache" << endl;
716
717 KeyContext context;
718 context.setRepoInfo( info_r );
719 if ( ! report->askUserToAcceptPackageKey( key, context ) ) {
720 return false;
721 }
722
723 MIL << "User wants to import key [" << id_r << "] " << key.name() << " from cache" << endl;
724 try {
725 importKey( key, true );
726 } catch ( const KeyRingException &e ) {
727 ZYPP_CAUGHT(e);
728 ERR << "Failed to import key: "<<id_r;
729 return false;
730 }
731
732 return true;
733 }
734
735 std::list<PublicKey> KeyRing::Impl::publicKeys( const Pathname & keyring )
736 {
737 const std::list<PublicKeyData> & keys( publicKeyData( keyring ) );
738 std::list<PublicKey> ret;
739
740 for_( it, keys.begin(), keys.end() )
741 {
742 PublicKey key( exportKey( *it, keyring ) );
743 ret.push_back( key );
744 MIL << "Found key " << key << endl;
745 }
746 return ret;
747 }
748
749 void KeyRing::Impl::importKey( const Pathname & keyfile, const Pathname & keyring )
750 {
751 if ( ! PathInfo( keyfile ).isExist() )
752 // TranslatorExplanation first %s is key name, second is keyring name
753 ZYPP_THROW(KeyRingException( str::Format(_("Tried to import not existent key %s into keyring %s"))
754 % keyfile.asString()
755 % keyring.asString() ));
756
757 CachedPublicKeyData::Manip manip { keyRingManip( keyring ) }; // Provides the context if we want to manip a cached keyring.
758 if ( ! manip.keyManagerCtx().importKey( keyfile ) )
759 ZYPP_THROW(KeyRingException(_("Failed to import key.")));
760 }
761
762 void KeyRing::Impl::deleteKey( const std::string & id, const Pathname & keyring )
763 {
764 CachedPublicKeyData::Manip manip { keyRingManip( keyring ) }; // Provides the context if we want to manip a cached keyring.
765 if ( ! manip.keyManagerCtx().deleteKey( id ) )
766 ZYPP_THROW(KeyRingException(_("Failed to delete key.")));
767 }
768
769 std::string KeyRing::Impl::readSignatureKeyId( const Pathname & signature )
770 {
771 if ( ! PathInfo( signature ).isFile() )
772 ZYPP_THROW(KeyRingException( str::Format(_("Signature file %s not found")) % signature.asString() ));
773
774 MIL << "Determining key id of signature " << signature << endl;
775
776 std::list<std::string> fprs = KeyManagerCtx::createForOpenPGP().readSignatureFingerprints( signature );
777 if ( ! fprs.empty() ) {
778 std::string &id = fprs.back();
779 MIL << "Determined key id [" << id << "] for signature " << signature << endl;
780 return id;
781 }
782 return std::string();
783 }
784
785 bool KeyRing::Impl::verifyFile( const Pathname & file, const Pathname & signature, const Pathname & keyring )
786 {
787 return KeyManagerCtx::createForOpenPGP( keyring ).verify( file, signature );
788 }
789
791
793 //
794 // CLASS NAME : KeyRing
795 //
797
798 KeyRing::KeyRing( const Pathname & baseTmpDir )
799 : _pimpl( new Impl( baseTmpDir ) )
800 {}
801
803 {}
804
805 void KeyRing::allowPreload( bool yesno_r )
806 { _pimpl->allowPreload( yesno_r ); }
807
808
809 void KeyRing::importKey( const PublicKey & key, bool trusted )
810 { _pimpl->importKey( key, trusted ); }
811
812 void KeyRing::multiKeyImport( const Pathname & keyfile_r, bool trusted_r )
813 { _pimpl->multiKeyImport( keyfile_r, trusted_r ); }
814
815 std::string KeyRing::readSignatureKeyId( const Pathname & signature )
816 { return _pimpl->readSignatureKeyId( signature ); }
817
818 void KeyRing::deleteKey( const std::string & id, bool trusted )
819 { _pimpl->deleteKey( id, trusted ); }
820
821 std::list<PublicKey> KeyRing::publicKeys()
822 { return _pimpl->publicKeys(); }
823
824 std:: list<PublicKey> KeyRing::trustedPublicKeys()
825 { return _pimpl->trustedPublicKeys(); }
826
827 std::list<PublicKeyData> KeyRing::publicKeyData()
828 { return _pimpl->publicKeyData(); }
829
830 std::list<PublicKeyData> KeyRing::trustedPublicKeyData()
831 { return _pimpl->trustedPublicKeyData(); }
832
833 PublicKeyData KeyRing::publicKeyData( const std::string &id_r )
834 { return _pimpl->publicKeyExists( id_r ); }
835
837 { return _pimpl->trustedPublicKeyExists( id_r ); }
838
839 bool KeyRing::verifyFileSignatureWorkflow( const Pathname & file, const std::string & filedesc, const Pathname & signature, bool & sigValid_r, const KeyContext & keycontext )
840 {
841 sigValid_r = false; // just in case....
842 keyring::VerifyFileContext context( file, signature );
843 context.shortFile( filedesc );
844 context.keyContext( keycontext );
846 sigValid_r = context.fileValidated();
847 return context.fileAccepted();
848 }
849
850 bool KeyRing::verifyFileSignatureWorkflow( const Pathname & file, const std::string filedesc, const Pathname & signature, const KeyContext & keycontext )
851 {
852 keyring::VerifyFileContext context( file, signature );
853 context.shortFile( filedesc );
854 context.keyContext( keycontext );
856 return context.fileAccepted();
857 }
858
860 { return _pimpl->verifyFileSignatureWorkflow( context_r ); }
861
862 bool KeyRing::verifyFileSignature( const Pathname & file, const Pathname & signature )
863 { return _pimpl->verifyFileSignature( file, signature ); }
864
865 bool KeyRing::verifyFileTrustedSignature( const Pathname & file, const Pathname & signature )
866 { return _pimpl->verifyFileTrustedSignature( file, signature ); }
867
868 bool KeyRing::provideAndImportKeyFromRepositoryWorkflow(const std::string &id, const RepoInfo &info)
869 {
870 return _pimpl->provideAndImportKeyFromRepositoryWorkflow( id, info );
871 }
872
873 void KeyRing::dumpPublicKey( const std::string & id, bool trusted, std::ostream & stream )
874 { _pimpl->dumpPublicKey( id, trusted, stream ); }
875
877 { return _pimpl->exportPublicKey( keyData ); }
878
880 { return _pimpl->exportTrustedPublicKey( keyData ); }
881
882 bool KeyRing::isKeyTrusted( const std::string & id )
883 { return _pimpl->isKeyTrusted( id ); }
884
885 bool KeyRing::isKeyKnown( const std::string & id )
886 { return _pimpl->isKeyKnown( id ); }
887
889} // namespace zypp
callback::SendReport< KeyRingSignals > _emitSignal
Definition: KeyRing.cc:361
std::list< PublicKeyData > _data
Definition: KeyRing.cc:191
scoped_ptr< WatchFile > _keyringK
Definition: KeyRing.cc:195
CachedPublicKeyData & _cache
Definition: KeyRing.cc:155
Pathname _keyring
Definition: KeyRing.cc:156
scoped_ptr< WatchFile > _keyringP
Definition: KeyRing.cc:196
std::optional< KeyManagerCtx > _context
Definition: KeyRing.cc:157
callback::SendReport< target::rpm::KeyRingSignals > _rpmdbEmitSignal
Definition: KeyRing.cc:360
CacheMap _cacheMap
Definition: KeyRing.cc:218
Wrapper for GPGME.
Base class for Exception.
Definition: Exception.h:146
std::string asUserHistory() const
A single (multiline) string composed of asUserString and historyAsString.
Definition: Exception.cc:91
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:377
std::list< PublicKeyData > listKeys()
Returns a list of all public keys found in the current keyring.
Definition: KeyManager.cc:319
bool verify(const Pathname &file, const Pathname &signature)
Tries to verify file using signature, returns true on success.
Definition: KeyManager.cc:372
static KeyManagerCtx createForOpenPGP()
Creates a new KeyManagerCtx for PGP using a volatile temp.
Definition: KeyManager.cc:270
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:532
Gpg key handling.
Definition: KeyRing.h:187
bool provideAndImportKeyFromRepositoryWorkflow(const std::string &id, const RepoInfo &info)
Try to find the id in key cache or repository specified in info.
Definition: KeyRing.cc:868
bool isKeyKnown(const std::string &id)
true if the key id is knows, that means at least exist on the untrusted keyring
Definition: KeyRing.cc:885
std::list< PublicKey > publicKeys()
Get a list of public keys in the keyring (incl.
Definition: KeyRing.cc:821
std::list< PublicKey > trustedPublicKeys()
Get a list of trusted public keys in the keyring (incl.
Definition: KeyRing.cc:824
static DefaultAccept defaultAccept()
Get the active accept bits.
Definition: KeyRing.cc:52
void dumpPublicKey(const std::string &id, bool trusted, std::ostream &stream)
Definition: KeyRing.cc:873
bool verifyFileSignature(const Pathname &file, const Pathname &signature)
Verifies a file against a signature, with no user interaction.
Definition: KeyRing.cc:862
void multiKeyImport(const Pathname &keyfile_r, bool trusted_r=false)
Initial import from RpmDb.
Definition: KeyRing.cc:812
KeyRing(const Pathname &baseTmpDir)
Default ctor.
Definition: KeyRing.cc:798
~KeyRing()
Dtor.
Definition: KeyRing.cc:802
PublicKey exportPublicKey(const PublicKeyData &keyData)
Export a public key identified by its key data.
Definition: KeyRing.cc:876
std::string readSignatureKeyId(const Pathname &signature)
reads the public key id from a signature
Definition: KeyRing.cc:815
void allowPreload(bool yesno_r)
The general keyring may be populated with known keys stored on the system.
Definition: KeyRing.cc:805
bool verifyFileTrustedSignature(const Pathname &file, const Pathname &signature)
Definition: KeyRing.cc:865
void importKey(const PublicKey &key, bool trusted=false)
imports a key from a file.
Definition: KeyRing.cc:809
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.
Definition: KeyRing.cc:839
RW_pointer< Impl > _pimpl
Pointer to implementation.
Definition: KeyRing.h:366
void deleteKey(const std::string &id, bool trusted=false)
removes a key from the keyring.
Definition: KeyRing.cc:818
std::list< PublicKeyData > trustedPublicKeyData()
Get a list of trusted public key data in the keyring (key data only)
Definition: KeyRing.cc:830
static void setDefaultAccept(DefaultAccept value_r)
Set the active accept bits.
Definition: KeyRing.cc:55
std::list< PublicKeyData > publicKeyData()
Get a list of public key data in the keyring (key data only)
Definition: KeyRing.cc:827
@ TRUST_KEY_TEMPORARILY
Definition: KeyRing.h:207
@ ACCEPT_VERIFICATION_FAILED
Definition: KeyRing.h:209
@ ACCEPT_UNKNOWNKEY
Definition: KeyRing.h:206
@ ACCEPT_NOTHING
Definition: KeyRing.h:204
@ TRUST_AND_IMPORT_KEY
Definition: KeyRing.h:208
@ ACCEPT_UNSIGNED_FILE
Definition: KeyRing.h:205
PublicKey exportTrustedPublicKey(const PublicKeyData &keyData)
Export a trusted public key identified by its key data.
Definition: KeyRing.cc:879
bool isKeyTrusted(const std::string &id)
true if the key id is trusted
Definition: KeyRing.cc:882
Class representing one GPG Public Keys data.
Definition: PublicKey.h:207
Date created() const
Creation / last modification date (latest selfsig).
Definition: PublicKey.cc:429
static bool isSafeKeyId(const std::string &id_r)
Whether this is a long id (64bit/16byte) or even better a fingerprint.
Definition: PublicKey.h:302
std::string id() const
Key ID.
Definition: PublicKey.cc:417
std::string fingerprint() const
Key fingerprint.
Definition: PublicKey.cc:423
Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile).
Definition: PublicKey.h:359
Pathname path() const
File containing the ASCII armored key.
Definition: PublicKey.cc:645
const std::list< PublicKeyData > & hiddenKeys() const
Additional keys data in case the ASCII armored blob contains multiple keys.
Definition: PublicKey.cc:648
std::string name() const
Definition: PublicKey.cc:665
const PublicKeyData & keyData() const
The public keys data (.
Definition: PublicKey.cc:642
bool isValid() const
Definition: PublicKey.h:397
What is known about a repository.
Definition: RepoInfo.h:72
Pathname provideKey(const std::string &keyID_r, const Pathname &targetDirectory_r) const
downloads all configured gpg keys into the defined directory
Definition: RepoInfo.cc:536
Interim helper class to collect global options and settings.
Definition: ZConfig.h:64
Pathname repoManagerRoot() const
The RepoManager root directory.
Definition: ZConfig.cc:953
static ZConfig & instance()
Singleton ctor.
Definition: ZConfig.cc:922
Pathname pubkeyCachePath() const
Path where the pubkey caches.
Definition: ZConfig.cc:1045
Typesafe passing of user data via callbacks.
Definition: UserData.h:39
const Tp & get(const std::string &key_r) const
Pass back a const Tp & reference to key_r value.
Definition: UserData.h:175
bool hasvalue(const std::string &key_r) const
Whether key_r is in data and value is not empty.
Definition: UserData.h:101
bool set(const std::string &key_r, AnyType val_r)
Set the value for key (nonconst version always returns true).
Definition: UserData.h:118
Wrapper class for stat/lstat.
Definition: PathInfo.h:221
const char * c_str() const
String representation.
Definition: Pathname.h:110
const std::string & asString() const
String representation.
Definition: Pathname.h:91
bool empty() const
Test for an empty path.
Definition: Pathname.h:114
Provide a new empty temporary directory and recursively delete it when no longer needed.
Definition: TmpPath.h:178
Provide a new empty temporary file and delete it when no longer needed.
Definition: TmpPath.h:128
Pathname path() const
Definition: TmpPath.cc:146
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.
Definition: Regex.h:95
Regular expression match result.
Definition: Regex.h:168
Definition: Arch.h:361
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
Definition: NonCopyable.h:26
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.
Definition: CodePitfalls.doc:2
static bool error(const std::string &msg_r, const UserData &userData_r=UserData())
send error text
void setRepoInfo(const RepoInfo &repoinfo)
Definition: KeyContext.h:19
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.
Definition: KeyRing.cc:61
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.
Definition: KeyRing.cc:95
KeyTrust
User reply options for the askUserToTrustKey callback.
Definition: KeyRing.h:52
@ KEY_TRUST_AND_IMPORT
Import the key.
Definition: KeyRing.h:70
@ KEY_DONT_TRUST
User has chosen not to trust the key.
Definition: KeyRing.h:56
@ KEY_TRUST_TEMPORARILY
This basically means, we knew the key, but it was not trusted.
Definition: KeyRing.h:61
static constexpr const char * REPORT_AUTO_IMPORT_KEY
generic reports UserData::type
Definition: KeyRing.h:149
virtual bool askUserToAcceptUnsignedFile(const std::string &file, const KeyContext &keycontext=KeyContext())
Definition: KeyRing.cc:64
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.
Definition: KeyRing.cc:83
static constexpr const char * ACCEPT_PACKAGE_KEY_REQUEST
generic reports UserData::type
Definition: KeyRing.h:117
static constexpr const char * KEYS_NOT_IMPORTED_REPORT
generic reports UserData::type
Definition: KeyRing.h:130
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.
Definition: KeyRing.cc:102
virtual KeyTrust askUserToAcceptKey(const PublicKey &key, const KeyContext &keycontext=KeyContext())
Ask user to trust and/or import the key to trusted keyring.
Definition: KeyRing.cc:68
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...
Definition: KeyRing.cc:77
virtual bool askUserToAcceptVerificationFailed(const std::string &file, const PublicKey &key, const KeyContext &keycontext=KeyContext())
The file filedesc is signed but the verification failed.
Definition: KeyRing.cc:80
KeyRing implementation.
Definition: KeyRing.cc:231
void importKey(const PublicKey &key, bool trusted=false)
Definition: KeyRing.cc:366
PublicKeyData trustedPublicKeyExists(const std::string &id)
Definition: KeyRing.cc:284
void preloadCachedKeys()
Load key files cached on the system into the generalKeyRing.
Definition: KeyRing.cc:442
bool provideAndImportKeyFromRepositoryWorkflow(const std::string &id_r, const RepoInfo &info_r)
Definition: KeyRing.cc:687
std::list< PublicKey > trustedPublicKeys()
Definition: KeyRing.cc:251
CachedPublicKeyData::Manip keyRingManip(const Pathname &keyring)
Impl helper providing on demand a KeyManagerCtx to manip a cached keyring.
Definition: KeyRing.cc:294
PublicKeyData publicKeyExists(const std::string &id)
Definition: KeyRing.cc:282
PublicKey exportKey(const std::string &id, const Pathname &keyring)
Definition: KeyRing.cc:501
PublicKey exportPublicKey(const PublicKeyData &keyData)
Definition: KeyRing.cc:264
bool verifyFileSignatureWorkflow(keyring::VerifyFileContext &context_r)
Definition: KeyRing.cc:269
bool isKeyKnown(const std::string &id)
Definition: KeyRing.cc:248
const std::list< PublicKeyData > & publicKeyData()
Definition: KeyRing.cc:258
bool verifyFileTrustedSignature(const Pathname &file, const Pathname &signature)
Definition: KeyRing.cc:279
void allowPreload(bool yesno_r)
Definition: KeyRing.cc:289
PublicKey exportTrustedPublicKey(const PublicKeyData &keyData)
Definition: KeyRing.cc:266
Impl(const Pathname &baseTmpDir)
Definition: KeyRing.cc:232
bool verifyFile(const Pathname &file, const Pathname &signature, const Pathname &keyring)
Definition: KeyRing.cc:785
const Pathname generalKeyRing() const
Definition: KeyRing.cc:319
const std::list< PublicKeyData > & trustedPublicKeyData()
Definition: KeyRing.cc:256
filesystem::TmpDir _general_tmp_dir
Definition: KeyRing.cc:326
bool verifyFileSignature(const Pathname &file, const Pathname &signature)
Definition: KeyRing.cc:277
CachedPublicKeyData cachedPublicKeyData
Functor returning the keyrings data (cached).
Definition: KeyRing.cc:336
std::string readSignatureKeyId(const Pathname &signature)
Definition: KeyRing.cc:769
void multiKeyImport(const Pathname &keyfile_r, bool trusted_r=false)
Definition: KeyRing.cc:388
std::list< PublicKey > publicKeys()
Definition: KeyRing.cc:253
const std::list< PublicKeyData > & publicKeyData(const Pathname &keyring)
Definition: KeyRing.cc:311
void deleteKey(const std::string &id, bool trusted)
Definition: KeyRing.cc:393
const Pathname trustedKeyRing() const
Definition: KeyRing.cc:321
bool _verifyFileSignatureWorkflow(keyring::VerifyFileContext &context_r)
Definition: KeyRing.cc:529
filesystem::TmpFile dumpPublicKeyToTmp(const std::string &id, const Pathname &keyring)
Definition: KeyRing.cc:518
PublicKey exportKey(const PublicKey &key, const Pathname &keyring)
Definition: KeyRing.cc:302
Pathname _base_dir
Definition: KeyRing.cc:327
filesystem::TmpDir _trusted_tmp_dir
Definition: KeyRing.cc:325
bool isKeyTrusted(const std::string &id)
Definition: KeyRing.cc:246
void dumpPublicKey(const std::string &id, bool trusted, std::ostream &stream)
Definition: KeyRing.cc:261
virtual void report(const UserData &userData_r=UserData())
The most generic way of sending/receiving data.
Definition: Callback.h:155
Convenient building of std::string with boost::format.
Definition: String.h:253
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:28
#define NON_COPYABLE_BUT_MOVE(CLASS)
Delete copy ctor and copy assign but enable default move.
Definition: Easy.h:79
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:436
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:428
#define _(MSG)
Definition: Gettext.h:37
#define DBG
Definition: Logger.h:95
#define MIL
Definition: Logger.h:96
#define ERR
Definition: Logger.h:98
#define WAR
Definition: Logger.h:97
#define IMPL_PTR_TYPE(NAME)