libzypp  17.35.16
keyringwf.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
9 
10 #include "keyringwf.h"
11 #include "logichelpers.h"
14 #include <zypp/RepoInfo.h>
15 #include <zypp/ZConfig.h>
16 #include <zypp/Pathname.h>
17 #include <zypp/PublicKey.h>
18 
19 #include <zypp-core/base/Gettext.h>
20 #include <utility>
21 #include <zypp-core/zyppng/pipelines/Expected>
23 #include <zypp/ng/Context>
24 #include <zypp/ng/reporthelper.h>
25 #include <zypp/ng/UserRequest>
26 
28 
29  template <class Executor, class OpType>
30  struct ImportKeyFromRepoLogic : public LogicBase<Executor, OpType> {
31 
34  using ProvideType = typename ZyppContextType::ProvideType;
35  using MediaHandle = typename ProvideType::MediaHandle;
36  using ProvideRes = typename ProvideType::Res;
37 
38  ZYPP_ENABLE_LOGIC_BASE(Executor, OpType);
39 
40  public:
41  ImportKeyFromRepoLogic( ZyppContextRefType context, std::string &&keyId, zypp::RepoInfo &&info )
42  : _context( std::move(context) ), _keyId(std::move(keyId)), _repo( std::move(info) )
43  { }
44 
46 
47  using namespace zyppng::operators;
48  using zyppng::operators::operator|;
49  using zyppng::expected;
50 
51  if ( _keyId.empty() || !_context )
52  return makeReadyResult(false);
53 
54  const zypp::ZConfig &conf = _context->config();
55  zypp::Pathname cacheDir = conf.repoManagerRoot() / conf.pubkeyCachePath();
56 
58  | [this, cacheDir]( zypp::Pathname myKey ) {
59  if ( myKey.empty() )
60  // if we did not find any keys, there is no point in checking again, break
61  return false;
62 
63  zypp::PublicKey key;
64  try {
65  key = zypp::PublicKey( myKey );
66  } catch ( const zypp::Exception &e ) {
67  ZYPP_CAUGHT(e);
68  return false;
69  }
70 
71  if ( !key.isValid() ) {
72  ERR << "Key [" << _keyId << "] from cache: " << cacheDir << " is not valid" << std::endl;
73  return false;
74  }
75 
76  MIL << "Key [" << _keyId << "] " << key.name() << " loaded from cache" << std::endl;
77 
78  zypp::KeyContext context;
79  context.setRepoInfo( _repo );
80  if ( !KeyRingReportHelper(_context).askUserToAcceptPackageKey( key, context ) ) {
81  return false;
82  }
83 
84  MIL << "User wants to import key [" << _keyId << "] " << key.name() << " from cache" << std::endl;
85  try {
86  _context->keyRing()->importKey( key, true );
87  } catch ( const zypp::KeyRingException &e ) {
88  ZYPP_CAUGHT(e);
89  ERR << "Failed to import key: "<<_keyId;
90  return false;
91  }
92  return true;
93  };
94  }
95 
97  std::string _keyId;
99  };
100 
101  bool provideAndImportKeyFromRepository( SyncContextRef ctx, std::string id_r, zypp::RepoInfo info_r )
102  {
103  return SimpleExecutor<ImportKeyFromRepoLogic, SyncOp<bool>>::run( ctx, std::move(id_r), std::move(info_r) );
104  }
105 
106  AsyncOpRef<bool> provideAndImportKeyFromRepository( ContextRef ctx, std::string id_r, zypp::RepoInfo info_r)
107  {
108  return SimpleExecutor<ImportKeyFromRepoLogic, AsyncOp<bool>>::run( ctx, std::move(id_r), std::move(info_r) );
109  }
110 
111  namespace {
112 
117  template <class Executor, class OpType>
118  struct VerifyFileSignatureLogic : public LogicBase<Executor, OpType>
119  {
120  ZYPP_ENABLE_LOGIC_BASE(Executor, OpType);
121 
124 
125  VerifyFileSignatureLogic( ZyppContextRefType zyppContext, KeyRingRef &&keyRing, zypp::keyring::VerifyFileContext &&ctx )
126  : _zyppContext( std::move(zyppContext) )
128  , _keyRing( std::move(keyRing) )
129  , _verifyContext( std::move(ctx) )
130  { }
131 
132  struct FoundKeyData {
135  bool trusted = false;
136  };
137 
138  MaybeAsyncRef<FoundKeyData> findKey ( const std::string &id ) {
139 
140  using zyppng::operators::operator|;
141 
142  if ( id.empty() )
143  return makeReadyResult(FoundKeyData{zypp::PublicKeyData(), zypp::Pathname()});
144 
145  // does key exists in trusted keyring
146  zypp::PublicKeyData trustedKeyData( _keyRing->pimpl().publicKeyExists( id, _keyRing->pimpl().trustedKeyRing() ) );
147  if ( trustedKeyData )
148  {
149  MIL << "Key is trusted: " << trustedKeyData << std::endl;
150 
151  // lets look if there is an updated key in the
152  // general keyring
153  zypp::PublicKeyData generalKeyData( _keyRing->pimpl().publicKeyExists( id, _keyRing->pimpl().generalKeyRing() ) );
154  if ( generalKeyData )
155  {
156  // bnc #393160: Comment #30: Compare at least the fingerprint
157  // in case an attacker created a key the the same id.
158  //
159  // FIXME: bsc#1008325: For keys using subkeys, we'd actually need
160  // to compare the subkey sets, to tell whether a key was updated.
161  // because created() remains unchanged if the primary key is not touched.
162  // For now we wait until a new subkey signs the data and treat it as a
163  // new key (else part below).
164  if ( trustedKeyData.fingerprint() == generalKeyData.fingerprint()
165  && trustedKeyData.created() < generalKeyData.created() )
166  {
167  MIL << "Key was updated. Saving new version into trusted keyring: " << generalKeyData << std::endl;
168  _keyRing->importKey( _keyRing->pimpl().exportKey( generalKeyData, _keyRing->pimpl().generalKeyRing() ), true );
169  trustedKeyData = _keyRing->pimpl().publicKeyExists( id, _keyRing->pimpl().trustedKeyRing() ); // re-read: invalidated by import?
170  }
171  }
172 
173  return makeReadyResult( FoundKeyData{ trustedKeyData, _keyRing->pimpl().trustedKeyRing(), true } );
174  }
175  else
176  {
177  zypp::PublicKeyData generalKeyData( _keyRing->pimpl().publicKeyExists( id, _keyRing->pimpl().generalKeyRing() ) );
178  if ( generalKeyData )
179  {
180  zypp::PublicKey key( _keyRing->pimpl().exportKey( generalKeyData, _keyRing->pimpl().generalKeyRing() ) );
181  MIL << "Key [" << id << "] " << key.name() << " is not trusted" << std::endl;
182 
183  // ok the key is not trusted, ask the user to trust it or not
184  zypp::KeyRingReport::KeyTrust reply = _keyringReport.askUserToAcceptKey( key, _verifyContext.keyContext() );
187  {
188  zypp::Pathname whichKeyring;
189 
190  MIL << "User wants to trust key [" << id << "] " << key.name() << std::endl;
191 
193  {
194  MIL << "User wants to import key [" << id << "] " << key.name() << std::endl;
195  _keyRing->importKey( key, true );
196  whichKeyring = _keyRing->pimpl().trustedKeyRing();
197  }
198  else
199  whichKeyring = _keyRing->pimpl().generalKeyRing();
200 
201  return makeReadyResult(FoundKeyData { std::move(generalKeyData), std::move(whichKeyring), true });
202  }
203  else
204  {
205  MIL << "User does not want to trust key [" << id << "] " << key.name() << std::endl;
206  return makeReadyResult(FoundKeyData { std::move(generalKeyData), _keyRing->pimpl().generalKeyRing(), false });
207  }
208  }
209  else if ( ! _verifyContext.keyContext().empty() )
210  {
211  // try to find the key in the repository info
213  | [this, id]( bool success ) {
214  if ( !success ) {
215  return FoundKeyData{ zypp::PublicKeyData(), zypp::Pathname() };
216  }
217  return FoundKeyData{ _keyRing->pimpl().publicKeyExists( id, _keyRing->pimpl().trustedKeyRing() ), _keyRing->pimpl().trustedKeyRing(), true };
218  };
219  }
220  }
221  return makeReadyResult(FoundKeyData{ zypp::PublicKeyData(), zypp::Pathname() });
222  }
223 
224  // returns std::pair<bool, zypp::keyring::VerifyFileContext>
225  auto execute () {
226 
228  const zypp::Pathname & file { _verifyContext.file() };
229  const zypp::Pathname & signature { _verifyContext.signature() };
230  const std::string & filedesc { _verifyContext.shortFile() };
231 
232  MIL << "Going to verify signature for " << filedesc << " ( " << file << " ) with " << signature << std::endl;
233 
234  // if signature does not exists, ask user if they want to accept unsigned file.
235  if( signature.empty() || (!zypp::PathInfo( signature ).isExist()) )
236  {
237  bool res = _keyringReport.askUserToAcceptUnsignedFile( filedesc, _verifyContext.keyContext() );
238  MIL << "askUserToAcceptUnsignedFile: " << res << std::endl;
239  return makeReadyResult( makeReturn(res) );
240  }
241 
242  // get the id of the signature (it might be a subkey id!)
243  _verifyContext.signatureId( _keyRing->readSignatureKeyId( signature ) ); //throws !
244  const std::string & id = _verifyContext.signatureId();
245 
246  // collect the buddies
247  std::list<zypp::PublicKeyData> buddies; // Could be imported IFF the file is validated by a trusted key
248  for ( const auto & sid : _verifyContext.buddyKeys() ) {
249  if ( not zypp::PublicKeyData::isSafeKeyId( sid ) ) {
250  WAR << "buddy " << sid << ": key id is too short to safely identify a gpg key. Skipping it." << std::endl;
251  continue;
252  }
253  if ( _keyRing->pimpl().trustedPublicKeyExists( sid ) ) {
254  MIL << "buddy " << sid << ": already in trusted key ring. Not needed." << std::endl;
255  continue;
256  }
257  auto pk = _keyRing->pimpl().publicKeyExists( sid );
258  if ( not pk ) {
259  WAR << "buddy " << sid << ": not available in the public key ring. Skipping it." << std::endl;
260  continue;
261  }
262  if ( pk.providesKey(id) ) {
263  MIL << "buddy " << sid << ": is the signing key. Handled separately." << std::endl;
264  continue;
265  }
266  MIL << "buddy " << sid << ": candidate for auto import. Remeber it." << std::endl;
267  buddies.push_back( pk );
268  }
269 
270  using zyppng::operators::operator|;
271  return findKey( id ) | [this, id, buddies=std::move(buddies)]( FoundKeyData res ) {
272 
273  const zypp::Pathname & file { _verifyContext.file() };
274  const zypp::KeyContext & keyContext { _verifyContext.keyContext() };
275  const zypp::Pathname & signature { _verifyContext.signature() };
276  const std::string & filedesc { _verifyContext.shortFile() };
277 
278  if ( res._foundKey ) {
279 
280  // we found a key but it is not trusted ( e.g. user did not want to trust it )
281  if ( !res.trusted )
282  return makeReturn(false);
283 
284  // it exists, is trusted, does it validate?
285  _verifyContext.signatureIdTrusted( res._whichKeyRing == _keyRing->pimpl().trustedKeyRing() );
286  _keyringReport.infoVerify( filedesc, res._foundKey, keyContext );
287  if ( _keyRing->pimpl().verifyFile( file, signature, res._whichKeyRing ) )
288  {
290  if ( _verifyContext.signatureIdTrusted() && not buddies.empty() ) {
291  // Check for buddy keys to be imported...
292  MIL << "Validated with trusted key: importing buddy list..." << std::endl;
293  _keyringReport.reportAutoImportKey( buddies, res._foundKey, keyContext );
294  for ( const auto & kd : buddies ) {
295  _keyRing->importKey( _keyRing->pimpl().exportKey( kd, _keyRing->pimpl().generalKeyRing() ), true );
296  }
297  }
298  return makeReturn(_verifyContext.fileValidated()); // signature is actually successfully validated!
299  }
300  else
301  {
302  bool userAnswer = _keyringReport.askUserToAcceptVerificationFailed( filedesc, _keyRing->pimpl().exportKey( res._foundKey, res._whichKeyRing ), keyContext );
303  MIL << "askUserToAcceptVerificationFailed: " << userAnswer << std::endl;
304  return makeReturn(userAnswer);
305  }
306  } else {
307  // signed with an unknown key...
308  MIL << "File [" << file << "] ( " << filedesc << " ) signed with unknown key [" << id << "]" << std::endl;
309  bool res = _keyringReport.askUserToAcceptUnknownKey( filedesc, id, _verifyContext.keyContext() );
310  MIL << "askUserToAcceptUnknownKey: " << res << std::endl;
311  return makeReturn(res);
312  }
313 
314  return makeReturn(false);
315  };
316  }
317 
318  protected:
320  KeyRingReportHelper<ZyppContextRefType> _keyringReport;
323 
324  private:
325  inline std::pair<bool, zypp::keyring::VerifyFileContext> makeReturn( bool res ){
327  return std::make_pair( res, std::move(_verifyContext) ) ;
328  }
329  };
330  }
331 
332  std::pair<bool,zypp::keyring::VerifyFileContext> verifyFileSignature( SyncContextRef zyppContext, zypp::keyring::VerifyFileContext &&context_r )
333  {
334  auto kr = zyppContext->keyRing();
335  return SimpleExecutor<VerifyFileSignatureLogic, SyncOp<std::pair<bool,zypp::keyring::VerifyFileContext> >>::run( std::move(zyppContext), std::move(kr), std::move(context_r) );
336  }
337 
339  {
340  auto kr = zyppContext->keyRing();
341  return SimpleExecutor<VerifyFileSignatureLogic, AsyncOp<std::pair<bool,zypp::keyring::VerifyFileContext> >>::run( std::move(zyppContext), std::move(kr), std::move(context_r) );
342  }
343 
344  std::pair<bool,zypp::keyring::VerifyFileContext> verifyFileSignature( SyncContextRef zyppContext, zypp::KeyRing_Ptr keyRing, zypp::keyring::VerifyFileContext &&context_r )
345  {
346  return SimpleExecutor<VerifyFileSignatureLogic, SyncOp<std::pair<bool,zypp::keyring::VerifyFileContext> >>::run( std::move(zyppContext), std::move(keyRing), std::move(context_r) );
347  }
348 
350  {
351  return SimpleExecutor<VerifyFileSignatureLogic, AsyncOp<std::pair<bool,zypp::keyring::VerifyFileContext> >>::run( std::move(zyppContext), std::move(keyRing), std::move(context_r) );
352  }
353 
354 }
bool fileValidated() const
Whether the signature was actually successfully verified.
#define MIL
Definition: Logger.h:100
static bool isSafeKeyId(const std::string &id_r)
Whether this is a long id (64bit/16byte) or even better a fingerprint.
Definition: PublicKey.h:308
zypp::PublicKeyData _foundKey
Definition: keyringwf.cc:133
std::string name() const
Definition: PublicKey.cc:666
const std::string & signatureId() const
The id of the gpg key which signed the file.
zypp::keyring::VerifyFileContext _verifyContext
Definition: keyringwf.cc:322
This basically means, we knew the key, but it was not trusted.
Definition: KeyRing.h:61
Class representing one GPG Public Keys data.
Definition: PublicKey.h:207
Pathname pubkeyCachePath() const
Path where the pubkey caches.
Definition: ZConfig.cc:1048
zypp::Pathname _whichKeyRing
Definition: keyringwf.cc:134
bool provideAndImportKeyFromRepository(SyncContextRef ctx, std::string id_r, zypp::RepoInfo info_r)
Try to find the id in key cache or repository specified in info.
Definition: keyringwf.cc:101
Definition: Arch.h:363
What is known about a repository.
Definition: RepoInfo.h:71
I/O context for KeyRing::verifyFileSignatureWorkflow.
std::pair< bool, zypp::keyring::VerifyFileContext > verifyFileSignature(SyncContextRef zyppContext, zypp::keyring::VerifyFileContext &&context_r)
Follows a signature verification interacting with the user.
Definition: keyringwf.cc:332
zypp::KeyRing_Ptr KeyRingRef
Definition: context.h:29
#define ERR
Definition: Logger.h:102
const KeyContext & keyContext() const
KeyContext passed to callbacks
bool signatureIdTrusted() const
Whether the SignatureId is in the trusted keyring (not temp.
void resetResults()
Reset all result values to safe defaults.
Pathname repoManagerRoot() const
The RepoManager root directory.
Definition: ZConfig.cc:956
KeyTrust
User reply options for the askUserToTrustKey callback.
Definition: KeyRing.h:51
bool trusted
Definition: keyringwf.cc:135
static std::enable_if_t< detail::is_async_op_v< FOpType >, AsyncOpRef< Result > > run(Args &&...args)
Definition: logichelpers.h:170
const Pathname & signature() const
Detached signature or empty.
KeyRingRef _keyRing
Definition: keyringwf.cc:321
bool isExist() const
Return whether valid stat info exists.
Definition: PathInfo.h:282
Interim helper class to collect global options and settings.
Definition: ZConfig.h:68
#define WAR
Definition: Logger.h:101
ImportKeyFromRepoLogic(ZyppContextRefType context, std::string &&keyId, zypp::RepoInfo &&info)
Definition: keyringwf.cc:41
typename ProvideType::MediaHandle MediaHandle
Definition: keyringwf.cc:35
const Pathname & file() const
File to verify.
KeyRingReportHelper< ZyppContextRefType > _keyringReport
Definition: keyringwf.cc:320
const BuddyKeys & buddyKeys() const
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:440
const RepoInfo repoInfo() const
Definition: KeyContext.h:18
std::shared_ptr< AsyncOp< T > > AsyncOpRef
Definition: asyncop.h:255
Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile).
Definition: PublicKey.h:364
typename ZyppContextType::ProvideType ProvideType
Definition: keyringwf.cc:34
Base class for Exception.
Definition: Exception.h:146
bool empty() const
Is the context unknown?
Definition: KeyContext.h:15
zypp::Pathname provideKey(SyncContextRef ctx, zypp::RepoInfo info, std::string keyID_r, zypp::Pathname targetDirectory_r)
Definition: repoinfowf.cc:212
remove_smart_ptr_t< ZyppContextRefType > ZyppContextType
Definition: keyringwf.cc:33
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
MaybeAsyncContextRef< OpType > ZyppContextRefType
Definition: keyringwf.cc:32
std::conditional_t< isAsync, AsyncOpRef< Type >, Type > MaybeAsyncRef
Definition: logichelpers.h:44
bool fileAccepted() const
May return true due to user interaction or global defaults even if the signature was not actually ver...
bool isValid() const
Definition: PublicKey.h:403
std::conditional_t< detail::is_async_op_v< OpType >, ContextRef, SyncContextRef > MaybeAsyncContextRef
Definition: contextfacade.h:51
void setRepoInfo(const RepoInfo &repoinfo)
Definition: KeyContext.h:19
ZyppContextRefType _zyppContext
Definition: keyringwf.cc:319
typename remove_smart_ptr< T >::type remove_smart_ptr_t
Definition: type_traits.h:128
std::string shortFile() const
Short name for file (default: basename).