c3e11690fb3ef9b4fe0f6adf88ef982c417f10ae
[platform/upstream/libzypp.git] / zypp / KeyRing.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/KeyRing.cc
10  *
11 */
12 #include <iostream>
13 #include <fstream>
14 #include <sys/file.h>
15 #include <cstdio>
16 #include <unistd.h>
17
18 #include "zypp/TmpPath.h"
19 #include "zypp/ZYppFactory.h"
20 #include "zypp/ZYpp.h"
21
22 #include "zypp/base/LogTools.h"
23 #include "zypp/base/IOStream.h"
24 #include "zypp/base/String.h"
25 #include "zypp/base/Regex.h"
26 #include "zypp/base/Gettext.h"
27 #include "zypp/base/WatchFile.h"
28 #include "zypp/PathInfo.h"
29 #include "zypp/KeyRing.h"
30 #include "zypp/ExternalProgram.h"
31 #include "zypp/TmpPath.h"
32 #include "zypp/ZYppCallbacks.h"       // JobReport::instance
33
34 using std::endl;
35
36 #undef  ZYPP_BASE_LOGGER_LOGGROUP
37 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::KeyRing"
38
39 /** \todo Fix duplicate define in PublicKey/KeyRing */
40 #define GPG_BINARY "/usr/bin/gpg2"
41
42 ///////////////////////////////////////////////////////////////////
43 namespace zypp
44 { /////////////////////////////////////////////////////////////////
45
46   IMPL_PTR_TYPE(KeyRing);
47
48   namespace
49   {
50     KeyRing::DefaultAccept _keyRingDefaultAccept( KeyRing::ACCEPT_NOTHING );
51   }
52
53   KeyRing::DefaultAccept KeyRing::defaultAccept()
54   { return _keyRingDefaultAccept; }
55
56   void KeyRing::setDefaultAccept( DefaultAccept value_r )
57   {
58     MIL << "Set new KeyRing::DefaultAccept: " << value_r << endl;
59     _keyRingDefaultAccept = value_r;
60   }
61
62   void KeyRingReport::infoVerify( const std::string & file_r, const PublicKeyData & keyData_r, const KeyContext & keycontext )
63   {}
64
65   bool KeyRingReport::askUserToAcceptUnsignedFile( const std::string & file, const KeyContext & keycontext )
66   { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_UNSIGNED_FILE ); }
67
68   KeyRingReport::KeyTrust
69   KeyRingReport::askUserToAcceptKey( const PublicKey & key, const KeyContext & keycontext )
70   {
71     if ( _keyRingDefaultAccept.testFlag( KeyRing::TRUST_KEY_TEMPORARILY ) )
72       return KEY_TRUST_TEMPORARILY;
73     if ( _keyRingDefaultAccept.testFlag( KeyRing::TRUST_AND_IMPORT_KEY ) )
74       return KEY_TRUST_AND_IMPORT;
75     return KEY_DONT_TRUST;
76   }
77
78   bool KeyRingReport::askUserToAcceptUnknownKey( const std::string & file, const std::string & id, const KeyContext & keycontext )
79   { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_UNKNOWNKEY ); }
80
81   bool KeyRingReport::askUserToAcceptVerificationFailed( const std::string & file, const PublicKey & key, const KeyContext & keycontext )
82   { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_VERIFICATION_FAILED ); }
83
84   namespace
85   {
86     ///////////////////////////////////////////////////////////////////
87     /// \class CachedPublicKeyData
88     /// \brief Functor returning the keyrings data (cached).
89     /// \code
90     ///   const std::list<PublicKeyData> & cachedPublicKeyData( const Pathname & keyring );
91     /// \endcode
92     ///////////////////////////////////////////////////////////////////
93     struct CachedPublicKeyData : private base::NonCopyable
94     {
95       const std::list<PublicKeyData> & operator()( const Pathname & keyring_r ) const
96       { return getData( keyring_r ); }
97
98       void setDirty( const Pathname & keyring_r )
99       { _cacheMap[keyring_r].setDirty(); }
100
101     private:
102       struct Cache
103       {
104         Cache() {}
105
106         void setDirty()
107         {
108           _keyringK.reset();
109           _keyringP.reset();
110         }
111
112         void assertCache( const Pathname & keyring_r )
113         {
114           // .kbx since gpg2-2.1
115           if ( !_keyringK )
116             _keyringK.reset( new WatchFile( keyring_r/"pubring.kbx", WatchFile::NO_INIT ) );
117           if ( !_keyringP )
118             _keyringP.reset( new WatchFile( keyring_r/"pubring.gpg", WatchFile::NO_INIT ) );
119         }
120
121         bool hasChanged() const
122         {
123           bool k = _keyringK->hasChanged();     // be sure both files are checked
124           bool p = _keyringP->hasChanged();
125           return k || p;
126         }
127
128         std::list<PublicKeyData> _data;
129
130       private:
131         scoped_ptr<WatchFile> _keyringK;
132         scoped_ptr<WatchFile> _keyringP;
133       };
134
135       typedef std::map<Pathname,Cache> CacheMap;
136
137       const std::list<PublicKeyData> & getData( const Pathname & keyring_r ) const
138       {
139         Cache & cache( _cacheMap[keyring_r] );
140         // init new cache entry
141         cache.assertCache( keyring_r );
142         return getData( keyring_r, cache );
143       }
144
145       const std::list<PublicKeyData> & getData( const Pathname & keyring_r, Cache & cache_r ) const
146       {
147         if ( cache_r.hasChanged() )
148         {
149           const char* argv[] =
150           {
151             GPG_BINARY,
152             "--list-public-keys",
153             "--homedir", keyring_r.c_str(),
154             "--no-default-keyring",
155             "--quiet",
156             "--with-colons",
157             "--fixed-list-mode",
158             "--with-fingerprint",
159             "--with-sig-list",
160             "--no-tty",
161             "--no-greeting",
162             "--batch",
163             "--status-fd", "1",
164             NULL
165           };
166
167           PublicKeyScanner scanner;
168           ExternalProgram prog( argv ,ExternalProgram::Discard_Stderr, false, -1, true );
169           for( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
170           {
171             scanner.scan( line );
172           }
173           prog.close();
174
175           cache_r._data.swap( scanner._keys );
176           MIL << "Found keys: " << cache_r._data  << endl;
177         }
178         return cache_r._data;
179       }
180
181       mutable CacheMap _cacheMap;
182     };
183     ///////////////////////////////////////////////////////////////////
184   }
185
186   ///////////////////////////////////////////////////////////////////
187   //
188   //    CLASS NAME : KeyRing::Impl
189   //
190   /** KeyRing implementation. */
191   struct KeyRing::Impl
192   {
193     Impl( const Pathname & baseTmpDir )
194     : _trusted_tmp_dir( baseTmpDir, "zypp-trusted-kr" )
195     , _general_tmp_dir( baseTmpDir, "zypp-general-kr" )
196     , _base_dir( baseTmpDir )
197     {
198       MIL << "Current KeyRing::DefaultAccept: " << _keyRingDefaultAccept << endl;
199     }
200
201     void importKey( const PublicKey & key, bool trusted = false );
202     void multiKeyImport( const Pathname & keyfile_r, bool trusted_r = false );
203     void deleteKey( const std::string & id, bool trusted );
204
205     std::string readSignatureKeyId( const Pathname & signature );
206
207     bool isKeyTrusted( const std::string & id )
208     { return bool(publicKeyExists( id, trustedKeyRing() )); }
209     bool isKeyKnown( const std::string & id )
210     { return publicKeyExists( id, trustedKeyRing() ) || publicKeyExists( id, generalKeyRing() ); }
211
212     std::list<PublicKey> trustedPublicKeys()
213     { return publicKeys( trustedKeyRing() ); }
214     std::list<PublicKey> publicKeys()
215     { return publicKeys( generalKeyRing() ); }
216
217     const std::list<PublicKeyData> & trustedPublicKeyData()
218     { return publicKeyData( trustedKeyRing() ); }
219     const std::list<PublicKeyData> & publicKeyData()
220     { return publicKeyData( generalKeyRing() ); }
221
222     void dumpPublicKey( const std::string & id, bool trusted, std::ostream & stream )
223     { dumpPublicKey( id, ( trusted ? trustedKeyRing() : generalKeyRing() ), stream ); }
224
225     PublicKey exportPublicKey( const PublicKeyData & keyData )
226     { return exportKey( keyData, generalKeyRing() ); }
227     PublicKey exportTrustedPublicKey( const PublicKeyData & keyData )
228     { return exportKey( keyData, trustedKeyRing() ); }
229
230     bool verifyFileSignatureWorkflow( const Pathname & file, const std::string & filedesc, const Pathname & signature, bool & sigValid_r, const KeyContext & keycontext = KeyContext());
231
232     bool verifyFileSignature( const Pathname & file, const Pathname & signature )
233     { return verifyFile( file, signature, generalKeyRing() ); }
234     bool verifyFileTrustedSignature( const Pathname & file, const Pathname & signature )
235     { return verifyFile( file, signature, trustedKeyRing() ); }
236
237   private:
238     bool verifyFile( const Pathname & file, const Pathname & signature, const Pathname & keyring );
239     void importKey( const Pathname & keyfile, const Pathname & keyring );
240
241     PublicKey exportKey( const std::string & id, const Pathname & keyring );
242     PublicKey exportKey( const PublicKeyData & keyData, const Pathname & keyring );
243     PublicKey exportKey( const PublicKey & key, const Pathname & keyring )
244     { return exportKey( key.keyData(), keyring ); }
245
246     void dumpPublicKey( const std::string & id, const Pathname & keyring, std::ostream & stream );
247     filesystem::TmpFile dumpPublicKeyToTmp( const std::string & id, const Pathname & keyring );
248
249     void deleteKey( const std::string & id, const Pathname & keyring );
250
251     std::list<PublicKey> publicKeys( const Pathname & keyring);
252     const std::list<PublicKeyData> & publicKeyData( const Pathname & keyring )
253     { return cachedPublicKeyData( keyring ); }
254
255     /** Get \ref PublicKeyData for ID (\c false if ID is not found). */
256     PublicKeyData publicKeyExists( const std::string & id, const Pathname & keyring );
257
258     const Pathname generalKeyRing() const
259     { return _general_tmp_dir.path(); }
260     const Pathname trustedKeyRing() const
261     { return _trusted_tmp_dir.path(); }
262
263     // Used for trusted and untrusted keyrings
264     filesystem::TmpDir _trusted_tmp_dir;
265     filesystem::TmpDir _general_tmp_dir;
266     Pathname _base_dir;
267
268   private:
269     /** Functor returning the keyrings data (cached).
270      * \code
271      *  const std::list<PublicKeyData> & cachedPublicKeyData( const Pathname & keyring );
272      * \endcode
273      */
274     CachedPublicKeyData cachedPublicKeyData;
275   };
276   ///////////////////////////////////////////////////////////////////
277
278   namespace
279   {
280     /// Handle signal emission from within KeyRing::Impl::importKey
281     struct ImportKeyCBHelper
282     {
283       void operator()( const PublicKey & key_r )
284       {
285         try {
286           _rpmdbEmitSignal->trustedKeyAdded( key_r );
287           _emitSignal->trustedKeyAdded( key_r );
288         }
289         catch ( const Exception & excp )
290         {
291           ERR << "Could not import key into rpmdb: " << excp << endl;
292           // TODO: JobReport as hotfix for bsc#1057188; should bubble up and go through some callback
293           JobReport::error( excp.asUserHistory() );
294         }
295       }
296
297     private:
298       callback::SendReport<target::rpm::KeyRingSignals> _rpmdbEmitSignal;
299       callback::SendReport<KeyRingSignals>              _emitSignal;
300     };
301   } // namespace
302
303
304   void KeyRing::Impl::importKey( const PublicKey & key, bool trusted )
305   {
306     importKey( key.path(), trusted ? trustedKeyRing() : generalKeyRing() );
307     MIL << "Imported key " << key << " to " << (trusted ? "trustedKeyRing" : "generalKeyRing" ) << endl;
308
309     if ( trusted )
310     {
311       ImportKeyCBHelper emitSignal;
312       if ( key.hiddenKeys().empty() )
313       {
314         emitSignal( key );
315       }
316       else
317       {
318         // multiple keys: Export individual keys ascii armored to import in rpmdb
319         emitSignal( exportKey( key, trustedKeyRing() ) );
320         for ( const PublicKeyData & hkey : key.hiddenKeys() )
321           emitSignal( exportKey( hkey, trustedKeyRing() ) );
322       }
323     }
324   }
325
326   void KeyRing::Impl::multiKeyImport( const Pathname & keyfile_r, bool trusted_r )
327   {
328     importKey( keyfile_r, trusted_r ? trustedKeyRing() : generalKeyRing() );
329   }
330
331   void KeyRing::Impl::deleteKey( const std::string & id, bool trusted )
332   {
333     PublicKeyData keyDataToDel( publicKeyExists( id, trusted ? trustedKeyRing() : generalKeyRing() ) );
334     if ( ! keyDataToDel )
335     {
336       WAR << "Key to delete [" << id << "] is not in " << (trusted ? "trustedKeyRing" : "generalKeyRing" ) << endl;
337       return;
338     }
339     deleteKey( id, trusted ? trustedKeyRing() : generalKeyRing() );
340     MIL << "Deleted key [" << id << "] from " << (trusted ? "trustedKeyRing" : "generalKeyRing" ) << endl;
341
342     if ( trusted )
343     try {
344       PublicKey key( keyDataToDel );
345
346       callback::SendReport<target::rpm::KeyRingSignals> rpmdbEmitSignal;
347       rpmdbEmitSignal->trustedKeyRemoved( key );
348
349       callback::SendReport<KeyRingSignals> emitSignal;
350       emitSignal->trustedKeyRemoved( key );
351     }
352     catch ( const Exception & excp )
353     {
354       ERR << "Could not delete key from rpmmdb: " << excp << endl;
355       // TODO: JobReport as hotfix for bsc#1057188; should bubble up and go through some callback
356       JobReport::error( excp.asUserHistory() );
357     }
358   }
359
360   PublicKeyData KeyRing::Impl::publicKeyExists( const std::string & id, const Pathname & keyring )
361   {
362     PublicKeyData ret;
363     for ( const PublicKeyData & key : publicKeyData( keyring ) )
364     {
365       if ( key.providesKey( id ) )
366       {
367         ret = key;
368         break;
369       }
370     }
371     MIL << (ret ? "Found" : "No") << " key [" << id << "] in keyring " << keyring << endl;
372     return ret;
373   }
374
375   PublicKey KeyRing::Impl::exportKey( const PublicKeyData & keyData, const Pathname & keyring )
376   {
377     return PublicKey( dumpPublicKeyToTmp( keyData.id(), keyring ), keyData );
378   }
379
380   PublicKey KeyRing::Impl::exportKey( const std::string & id, const Pathname & keyring )
381   {
382     PublicKeyData keyData( publicKeyExists( id, keyring ) );
383     if ( keyData )
384       return PublicKey( dumpPublicKeyToTmp( keyData.id(), keyring ), keyData );
385
386     // Here: key not found
387     WAR << "No key [" << id << "] to export from " << keyring << endl;
388     return PublicKey();
389   }
390
391
392   void KeyRing::Impl::dumpPublicKey( const std::string & id, const Pathname & keyring, std::ostream & stream )
393   {
394     const char* argv[] =
395     {
396       GPG_BINARY,
397       "-a",
398       "--export",
399       "--homedir", keyring.asString().c_str(),
400       "--no-default-keyring",
401       "--quiet",
402       "--no-tty",
403       "--no-greeting",
404       "--no-permission-warning",
405       "--batch",
406       id.c_str(),
407       NULL
408     };
409     ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true );
410     for ( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
411     {
412       stream << line;
413     }
414     prog.close();
415   }
416
417   filesystem::TmpFile KeyRing::Impl::dumpPublicKeyToTmp( const std::string & id, const Pathname & keyring )
418   {
419     filesystem::TmpFile tmpFile( _base_dir, "pubkey-"+id+"-" );
420     MIL << "Going to export key [" << id << "] from " << keyring << " to " << tmpFile.path() << endl;
421
422     std::ofstream os( tmpFile.path().c_str() );
423     dumpPublicKey( id, keyring, os );
424     os.close();
425     return tmpFile;
426   }
427
428   bool KeyRing::Impl::verifyFileSignatureWorkflow( const Pathname & file, const std::string & filedesc, const Pathname & signature, bool & sigValid_r, const KeyContext & context )
429   {
430     sigValid_r = false; // set true if signature is actually successfully validated!
431
432     callback::SendReport<KeyRingReport> report;
433     MIL << "Going to verify signature for " << filedesc << " ( " << file << " ) with " << signature << endl;
434
435     // if signature does not exists, ask user if he wants to accept unsigned file.
436     if( signature.empty() || (!PathInfo( signature ).isExist()) )
437     {
438       bool res = report->askUserToAcceptUnsignedFile( filedesc, context );
439       MIL << "askUserToAcceptUnsignedFile: " << res << endl;
440       return res;
441     }
442
443     // get the id of the signature (it might be a subkey id!)
444     std::string id = readSignatureKeyId( signature );
445
446     // does key exists in trusted keyring
447     PublicKeyData trustedKeyData( publicKeyExists( id, trustedKeyRing() ) );
448     if ( trustedKeyData )
449     {
450       MIL << "Key is trusted: " << trustedKeyData << endl;
451
452       // lets look if there is an updated key in the
453       // general keyring
454       PublicKeyData generalKeyData( publicKeyExists( id, generalKeyRing() ) );
455       if ( generalKeyData )
456       {
457         // bnc #393160: Comment #30: Compare at least the fingerprint
458         // in case an attacker created a key the the same id.
459         //
460         // FIXME: bsc#1008325: For keys using subkeys, we'd actually need
461         // to compare the subkey sets, to tell whether a key was updated.
462         // because created() remains unchanged if the primary key is not touched.
463         // For now we wait until a new subkey signs the data and treat it as a
464         //  new key (else part below).
465         if ( trustedKeyData.fingerprint() == generalKeyData.fingerprint()
466            && trustedKeyData.created() < generalKeyData.created() )
467         {
468           MIL << "Key was updated. Saving new version into trusted keyring: " << generalKeyData << endl;
469           importKey( exportKey( generalKeyData, generalKeyRing() ), true );
470           trustedKeyData = publicKeyExists( id, trustedKeyRing() ); // re-read: invalidated by import?
471         }
472       }
473
474       // it exists, is trusted, does it validate?
475       report->infoVerify( filedesc, trustedKeyData, context );
476       if ( verifyFile( file, signature, trustedKeyRing() ) )
477       {
478         return (sigValid_r=true);       // signature is actually successfully validated!
479       }
480       else
481       {
482         bool res = report->askUserToAcceptVerificationFailed( filedesc, exportKey( trustedKeyData, trustedKeyRing() ), context );
483         MIL << "askUserToAcceptVerificationFailed: " << res << endl;
484         return res;
485       }
486     }
487     else
488     {
489       PublicKeyData generalKeyData( publicKeyExists( id, generalKeyRing() ) );
490       if ( generalKeyData )
491       {
492         PublicKey key( exportKey( generalKeyData, generalKeyRing() ) );
493         MIL << "Key [" << id << "] " << key.name() << " is not trusted" << endl;
494
495         // ok the key is not trusted, ask the user to trust it or not
496         KeyRingReport::KeyTrust reply = report->askUserToAcceptKey( key, context );
497         if ( reply == KeyRingReport::KEY_TRUST_TEMPORARILY ||
498             reply == KeyRingReport::KEY_TRUST_AND_IMPORT )
499         {
500           MIL << "User wants to trust key [" << id << "] " << key.name() << endl;
501
502           Pathname whichKeyring;
503           if ( reply == KeyRingReport::KEY_TRUST_AND_IMPORT )
504           {
505             MIL << "User wants to import key [" << id << "] " << key.name() << endl;
506             importKey( key, true );
507             whichKeyring = trustedKeyRing();
508           }
509           else
510             whichKeyring = generalKeyRing();
511
512           // does it validate?
513           report->infoVerify( filedesc, generalKeyData, context );
514           if ( verifyFile( file, signature, whichKeyring ) )
515           {
516             return (sigValid_r=true);   // signature is actually successfully validated!
517           }
518           else
519           {
520             bool res = report->askUserToAcceptVerificationFailed( filedesc, key, context );
521             MIL << "askUserToAcceptVerificationFailed: " << res << endl;
522             return res;
523           }
524         }
525         else
526         {
527           MIL << "User does not want to trust key [" << id << "] " << key.name() << endl;
528           return false;
529         }
530       }
531       else
532       {
533         // signed with an unknown key...
534         MIL << "File [" << file << "] ( " << filedesc << " ) signed with unknown key [" << id << "]" << endl;
535         bool res = report->askUserToAcceptUnknownKey( filedesc, id, context );
536         MIL << "askUserToAcceptUnknownKey: " << res << endl;
537         return res;
538       }
539     }
540     return false;
541   }
542
543   std::list<PublicKey> KeyRing::Impl::publicKeys( const Pathname & keyring )
544   {
545     const std::list<PublicKeyData> & keys( publicKeyData( keyring ) );
546     std::list<PublicKey> ret;
547
548     for_( it, keys.begin(), keys.end() )
549     {
550       PublicKey key( exportKey( *it, keyring ) );
551       ret.push_back( key );
552       MIL << "Found key " << key << endl;
553     }
554     return ret;
555   }
556
557   void KeyRing::Impl::importKey( const Pathname & keyfile, const Pathname & keyring )
558   {
559     if ( ! PathInfo( keyfile ).isExist() )
560       // TranslatorExplanation first %s is key name, second is keyring name
561       ZYPP_THROW(KeyRingException( str::Format(_("Tried to import not existent key %s into keyring %s"))
562                                    % keyfile.asString()
563                                    % keyring.asString() ));
564
565     const char* argv[] =
566     {
567       GPG_BINARY,
568       "--import",
569       "--homedir", keyring.asString().c_str(),
570       "--no-default-keyring",
571       "--quiet",
572       "--no-tty",
573       "--no-greeting",
574       "--no-permission-warning",
575       "--status-fd", "1",
576       keyfile.asString().c_str(),
577       NULL
578     };
579
580     cachedPublicKeyData.setDirty( keyring );
581     ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true );
582     if ( prog.close() )
583       ZYPP_THROW(KeyRingException(_("Failed to import key.")));
584   }
585
586   void KeyRing::Impl::deleteKey( const std::string & id, const Pathname & keyring )
587   {
588     const char* argv[] =
589     {
590       GPG_BINARY,
591       "--delete-keys",
592       "--homedir", keyring.asString().c_str(),
593       "--no-default-keyring",
594       "--yes",
595       "--quiet",
596       "--no-tty",
597       "--batch",
598       "--status-fd", "1",
599       id.c_str(),
600       NULL
601     };
602
603     cachedPublicKeyData.setDirty( keyring );
604     ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true );
605     if ( prog.close() )
606       ZYPP_THROW(KeyRingException(_("Failed to delete key.")));
607   }
608
609   std::string KeyRing::Impl::readSignatureKeyId( const Pathname & signature )
610   {
611     if ( ! PathInfo( signature ).isFile() )
612       ZYPP_THROW(KeyRingException( str::Format(_("Signature file %s not found")) % signature.asString() ));
613
614     MIL << "Determining key id of signature " << signature << endl;
615     const char* argv[] =
616     {
617       GPG_BINARY,
618       "--list-packets",
619       signature.asString().c_str(),
620       NULL
621     };
622     ExternalProgram prog( argv ,ExternalProgram::Discard_Stderr, false, -1, true );
623
624     // :signature packet: algo 1, keyid 1397BC53640DB551
625     //         version 4, created 1501094968, md5len 0, sigclass 0x00
626     //         digest algo 8, begin of digest 15 89
627     //         hashed subpkt 2 len 4 (sig created 2017-07-26)
628     //         subpkt 16 len 8 (issuer key ID 1397BC53640DB551)
629     //         data: [4095 bits]
630     std::string id;
631     for( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
632     {
633       if ( id.empty() && str::startsWith( line, ":signature packet:" ) )
634       {
635         static const str::regex rxKeyId( " keyid +([0-9A-Z]+)" );
636         str::smatch what;
637         if( str::regex_match( line, what, rxKeyId ) )
638           id = what[1];
639       }
640     }
641
642     MIL << "Determined key id [" << id << "] for signature " << signature << endl;
643     prog.close();
644     return id;
645   }
646
647   bool KeyRing::Impl::verifyFile( const Pathname & file, const Pathname & signature, const Pathname & keyring )
648   {
649     const char* argv[] =
650     {
651       GPG_BINARY,
652       "--verify",
653       "--homedir", keyring.asString().c_str(),
654       "--no-default-keyring",
655       "--quiet",
656       "--no-tty",
657       "--batch",
658       "--no-greeting",
659       "--status-fd", "1",
660       signature.asString().c_str(),
661       file.asString().c_str(),
662       NULL
663     };
664
665     // no need to parse output for now
666     //     [GNUPG:] SIG_ID yCc4u223XRJnLnVAIllvYbUd8mQ 2006-03-29 1143618744
667     //     [GNUPG:] GOODSIG A84EDAE89C800ACA SuSE Package Signing Key <build@suse.de>
668     //     gpg: Good signature from "SuSE Package Signing Key <build@suse.de>"
669     //     [GNUPG:] VALIDSIG 79C179B2E1C820C1890F9994A84EDAE89C800ACA 2006-03-29 1143618744 0 3 0 17 2 00 79C179B2E1C820C1890F9994A84EDAE89C800ACA
670     //     [GNUPG:] TRUST_UNDEFINED
671
672     //     [GNUPG:] ERRSIG A84EDAE89C800ACA 17 2 00 1143618744 9
673     //     [GNUPG:] NO_PUBKEY A84EDAE89C800ACA
674
675     ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true );
676
677     return ( prog.close() == 0 ) ? true : false;
678   }
679
680   ///////////////////////////////////////////////////////////////////
681
682   ///////////////////////////////////////////////////////////////////
683   //
684   //    CLASS NAME : KeyRing
685   //
686   ///////////////////////////////////////////////////////////////////
687
688   KeyRing::KeyRing( const Pathname & baseTmpDir )
689   : _pimpl( new Impl( baseTmpDir ) )
690   {}
691
692   KeyRing::~KeyRing()
693   {}
694
695
696   void KeyRing::importKey( const PublicKey & key, bool trusted )
697   { _pimpl->importKey( key, trusted ); }
698
699   void KeyRing::multiKeyImport( const Pathname & keyfile_r, bool trusted_r )
700   { _pimpl->multiKeyImport( keyfile_r, trusted_r ); }
701
702   std::string KeyRing::readSignatureKeyId( const Pathname & signature )
703   { return _pimpl->readSignatureKeyId( signature ); }
704
705   void KeyRing::deleteKey( const std::string & id, bool trusted )
706   { _pimpl->deleteKey( id, trusted ); }
707
708   std::list<PublicKey> KeyRing::publicKeys()
709   { return _pimpl->publicKeys(); }
710
711   std:: list<PublicKey> KeyRing::trustedPublicKeys()
712   { return _pimpl->trustedPublicKeys(); }
713
714   std::list<PublicKeyData> KeyRing::publicKeyData()
715   { return _pimpl->publicKeyData(); }
716
717   std::list<PublicKeyData> KeyRing::trustedPublicKeyData()
718   { return _pimpl->trustedPublicKeyData(); }
719
720   bool KeyRing::verifyFileSignatureWorkflow( const Pathname & file, const std::string & filedesc, const Pathname & signature, bool & sigValid_r, const KeyContext & keycontext )
721   { return _pimpl->verifyFileSignatureWorkflow( file, filedesc, signature, sigValid_r, keycontext ); }
722
723   bool KeyRing::verifyFileSignatureWorkflow( const Pathname & file, const std::string filedesc, const Pathname & signature, const KeyContext & keycontext )
724   { bool unused; return _pimpl->verifyFileSignatureWorkflow( file, filedesc, signature, unused, keycontext ); }
725
726   bool KeyRing::verifyFileSignature( const Pathname & file, const Pathname & signature )
727   { return _pimpl->verifyFileSignature( file, signature ); }
728
729   bool KeyRing::verifyFileTrustedSignature( const Pathname & file, const Pathname & signature )
730   { return _pimpl->verifyFileTrustedSignature( file, signature ); }
731
732   void KeyRing::dumpPublicKey( const std::string & id, bool trusted, std::ostream & stream )
733   { _pimpl->dumpPublicKey( id, trusted, stream ); }
734
735   PublicKey KeyRing::exportPublicKey( const PublicKeyData & keyData )
736   { return _pimpl->exportPublicKey( keyData ); }
737
738   PublicKey KeyRing::exportTrustedPublicKey( const PublicKeyData & keyData )
739   { return _pimpl->exportTrustedPublicKey( keyData ); }
740
741   bool KeyRing::isKeyTrusted( const std::string & id )
742   { return _pimpl->isKeyTrusted( id ); }
743
744   bool KeyRing::isKeyKnown( const std::string & id )
745   { return _pimpl->isKeyKnown( id ); }
746
747   /////////////////////////////////////////////////////////////////
748 } // namespace zypp
749 ///////////////////////////////////////////////////////////////////