libzypp 17.35.1
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
20#include <utility>
21#include <zypp-core/zyppng/pipelines/Expected>
23#include <zypp/ng/Context>
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
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
122 using ZyppContextRefType = MaybeAsyncContextRef<OpType>;
123 using KeyTrust = zypp::KeyRingReport::KeyTrust;
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:
319 ZyppContextRefType _zyppContext;
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}
Base class for Exception.
Definition Exception.h:147
Class representing one GPG Public Keys data.
Definition PublicKey.h:208
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
Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile).
Definition PublicKey.h:365
std::string name() const
Definition PublicKey.cc:666
bool isValid() const
Definition PublicKey.h:403
What is known about a repository.
Definition RepoInfo.h:72
Interim helper class to collect global options and settings.
Definition ZConfig.h:69
Pathname repoManagerRoot() const
The RepoManager root directory.
Definition ZConfig.cc:956
Pathname pubkeyCachePath() const
Path where the pubkey caches.
Definition ZConfig.cc:1048
Wrapper class for stat/lstat.
Definition PathInfo.h:222
bool isExist() const
Return whether valid stat info exists.
Definition PathInfo.h:282
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.
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...
bool trusted
Definition keyringwf.cc:135
zypp::keyring::VerifyFileContext _verifyContext
Definition keyringwf.cc:322
zypp::Pathname _whichKeyRing
Definition keyringwf.cc:134
zypp::PublicKeyData _foundKey
Definition keyringwf.cc:133
KeyRingReportHelper< ZyppContextRefType > _keyringReport
Definition keyringwf.cc:320
KeyRingRef _keyRing
Definition keyringwf.cc:321
#define ZYPP_ENABLE_LOGIC_BASE(Executor, OpType)
Definition Arch.h:364
bool empty() const
Whether neither idents nor provides are set.
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
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::Pathname provideKey(SyncContextRef ctx, zypp::RepoInfo info, std::string keyID_r, zypp::Pathname targetDirectory_r)
std::conditional_t< isAsync, AsyncOpRef< T >, T > makeReadyResult(T &&result)
Definition asyncop.h:297
std::shared_ptr< AsyncOp< T > > AsyncOpRef
Definition asyncop.h:255
typename remove_smart_ptr< T >::type remove_smart_ptr_t
zypp::KeyRing_Ptr KeyRingRef
Definition context.h:29
std::conditional_t< detail::is_async_op_v< OpType >, ContextRef, SyncContextRef > MaybeAsyncContextRef
ZyppContextRefType _zyppContext
void setRepoInfo(const RepoInfo &repoinfo)
Definition KeyContext.h:19
const RepoInfo repoInfo() const
Definition KeyContext.h:18
bool empty() const
Is the context unknown?
Definition KeyContext.h:15
KeyTrust
User reply options for the askUserToTrustKey callback.
Definition KeyRing.h:52
@ KEY_TRUST_AND_IMPORT
Import the key.
Definition KeyRing.h:70
@ KEY_TRUST_TEMPORARILY
This basically means, we knew the key, but it was not trusted.
Definition KeyRing.h:61
remove_smart_ptr_t< ZyppContextRefType > ZyppContextType
Definition keyringwf.cc:33
ImportKeyFromRepoLogic(ZyppContextRefType context, std::string &&keyId, zypp::RepoInfo &&info)
Definition keyringwf.cc:41
typename ProvideType::MediaHandle MediaHandle
Definition keyringwf.cc:35
MaybeAsyncContextRef< OpType > ZyppContextRefType
Definition keyringwf.cc:32
typename ZyppContextType::ProvideType ProvideType
Definition keyringwf.cc:34
std::conditional_t< isAsync, AsyncOpRef< Type >, Type > MaybeAsyncRef
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition Exception.h:440
#define MIL
Definition Logger.h:98
#define ERR
Definition Logger.h:100
#define WAR
Definition Logger.h:99