- fixed missplaced Logger.h includes
[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/ZYppFactory.h"
19 #include "zypp/ZYpp.h"
20
21 #include "zypp/base/Logger.h"
22 #include "zypp/base/IOStream.h"
23 #include "zypp/base/String.h"
24 #include "zypp/KeyRing.h"
25 #include "zypp/ExternalProgram.h"
26 #include "zypp/TmpPath.h"
27
28 using std::endl;
29 using namespace zypp::filesystem;
30 using namespace std;
31
32 #undef  ZYPP_BASE_LOGGER_LOGGROUP
33 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::KeyRing"
34
35 ///////////////////////////////////////////////////////////////////
36 namespace zypp
37 { /////////////////////////////////////////////////////////////////
38
39   IMPL_PTR_TYPE(KeyRing);
40
41   static void dumpRegexpResults( const str::smatch &what )
42   {
43     for ( unsigned int k=0; k < what.size(); k++)
44     {
45       XXX << "[match "<< k << "] [" << what[k] << "]" << std::endl;
46     }
47   }
48
49   static bool printLine( const std::string &line )
50   {
51     MIL <<  line << std::endl;
52   }
53
54   static void dumpFile(const Pathname &file)
55   {
56     std::ifstream is(file.asString().c_str());
57     iostr::forEachLine( is, printLine);
58   }
59
60   namespace
61   {
62     bool _keyRingDefaultAccept( getenv("ZYPP_KEYRING_DEFAULT_ACCEPT_ALL") );
63   }
64
65   bool KeyRingReport::askUserToAcceptUnsignedFile( const Pathname &file )
66   { return _keyRingDefaultAccept; }
67
68   bool KeyRingReport::askUserToAcceptUnknownKey( const Pathname &file, const std::string &keyid, const std::string &keyname )
69   { return _keyRingDefaultAccept; }
70
71   bool KeyRingReport::askUserToTrustKey( const std::string &keyid, const std::string &keyname, const std::string &keydetails )
72   { return _keyRingDefaultAccept; }
73
74   bool KeyRingReport::askUserToAcceptVerificationFailed( const Pathname &file, const std::string &keyid, const std::string &keyname )
75   { return _keyRingDefaultAccept; }
76
77   ///////////////////////////////////////////////////////////////////
78   //
79   //    CLASS NAME : KeyRing::Impl
80   //
81   /** KeyRing implementation. */
82   struct KeyRing::Impl
83   {
84     Impl()
85     {
86       _general_kr = _general_tmp_dir.path();
87       _trusted_kr = _trusted_tmp_dir.path();
88     }
89
90     /*
91     Impl( const Pathname &general_kr, const Pathname &trusted_kr )
92     {
93       filesystem::assert_dir(general_kr);
94       filesystem::assert_dir(trusted_kr);
95
96       _general_kr = general_kr;
97       _trusted_kr = trusted_kr;
98     }
99     */
100
101     void importKey( const Pathname &keyfile, bool trusted = false);
102     PublicKey readPublicKey( const Pathname &keyfile );
103     std::string readSignatureKeyId(  const Pathname &data, const Pathname &keyfile );
104
105     void deleteKey( const std::string &id, bool trusted );
106     std::list<PublicKey> trustedPublicKeys();
107     std::list<PublicKey> publicKeys();
108
109     void dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream );
110
111     bool verifyFileSignatureWorkflow( const Pathname &file, const Pathname &signature);
112
113     bool verifyFileSignature( const Pathname &file, const Pathname &signature);
114     bool verifyFileTrustedSignature( const Pathname &file, const Pathname &signature);
115   private:
116     //mutable std::map<Locale, std::string> translations;
117     bool verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring);
118     void importKey( const Pathname &keyfile, const Pathname &keyring);
119
120     void exportKey( std::string id, const Pathname &keyfile, bool trusted);
121
122     void deleteKey( const std::string &id, const Pathname &keyring );
123     std::list<PublicKey> publicKeys(const Pathname &keyring);
124
125     bool publicKeyExists( std::string id, const Pathname &keyring);
126
127     Pathname _general_kr;
128     Pathname _trusted_kr;
129
130     // Used for trusted and untrusted keyrings
131     TmpDir _trusted_tmp_dir;
132     TmpDir _general_tmp_dir;
133   public:
134     /** Offer default Impl. */
135     static shared_ptr<Impl> nullimpl()
136     {
137       static shared_ptr<Impl> _nullimpl( new Impl );
138       return _nullimpl;
139     }
140
141   private:
142     friend Impl * rwcowClone<Impl>( const Impl * rhs );
143     /** clone for RWCOW_pointer */
144     Impl * clone() const
145     { return new Impl( *this ); }
146   };
147
148   void KeyRing::Impl::importKey( const Pathname &keyfile, bool trusted)
149   {
150     importKey( keyfile, trusted ? _trusted_kr : _general_kr );
151   }
152
153   void KeyRing::Impl::deleteKey( const std::string &id, bool trusted)
154   {
155     deleteKey( id, trusted ? _trusted_kr : _general_kr );
156   }
157
158   std::list<PublicKey> KeyRing::Impl::publicKeys()
159   {
160     return publicKeys( _general_kr );
161   }
162
163   std::list<PublicKey> KeyRing::Impl::trustedPublicKeys()
164   {
165     return publicKeys( _trusted_kr );
166   }
167
168   bool KeyRing::Impl::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
169   {
170     return verifyFile( file, signature, _trusted_kr );
171   }
172
173   bool KeyRing::Impl::verifyFileSignature( const Pathname &file, const Pathname &signature)
174   {
175     return verifyFile( file, signature, _general_kr );
176   }
177
178   bool KeyRing::Impl::publicKeyExists( std::string id, const Pathname &keyring)
179   {
180     std::list<PublicKey> keys = publicKeys(keyring);
181     for (std::list<PublicKey>::const_iterator it = keys.begin(); it != keys.end(); it++)
182     {
183       if ( id == (*it).id )
184         return true;
185     }
186     return false;
187   }
188
189   void KeyRing::Impl::exportKey( std::string id, const Pathname &keyfile, bool trusted)
190   {
191     try {
192       std::ofstream os(keyfile.asString().c_str());
193       dumpPublicKey( id, trusted, os );
194       os.close();
195     }
196     catch (std::exception &e)
197     {
198       ERR << "Cannot export key " << id << " from " << (trusted ? "trusted" : "untrusted ") << " keyring  to file " << keyfile << std::endl;
199     }
200   }
201
202   void KeyRing::Impl::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
203   {
204     Pathname keyring = trusted ? _trusted_kr : _general_kr;
205     const char* argv[] =
206     {
207       "gpg",
208       "--quiet",
209       "--no-tty",
210       "--no-greeting",
211       "--no-permission-warning",
212       "--batch",
213       "--homedir",
214       keyring.asString().c_str(),
215       "-a",
216       "--export",
217       id.c_str(),
218       NULL
219     };
220     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
221     std::string line;
222     int count;
223     for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
224     {
225       stream << line;
226     }
227     prog.close();
228   }
229
230
231   bool KeyRing::Impl::verifyFileSignatureWorkflow( const Pathname &file, const Pathname &signature)
232   {
233     if ( ! getenv("ZYPP_CHECKSIG") )
234     {
235       MIL << "Digital signature check disabled. Accepting source." << std::endl;
236       return true;
237     }
238
239     callback::SendReport<KeyRingReport> report;
240     callback::SendReport<KeyRingSignals> emitSignal;
241     MIL << "Going to verify signature for " << file << " with " << signature << std::endl;
242
243     // if signature does not exists, ask user if he wants to accept unsigned file.
244     if( signature.empty() || (!PathInfo(signature).isExist()) )
245     {
246         bool res = report->askUserToAcceptUnsignedFile( file );
247         MIL << "User decision on unsigned file: " << res << endl;
248         return res;
249     }
250
251     // get the id of the signature
252     std::string id = readSignatureKeyId(file, signature);
253
254     // doeskey exists in trusted keyring
255     if ( publicKeyExists( id, _trusted_kr ) )
256     {
257       TmpFile trustedKey;
258       exportKey( id, trustedKey.path(), true);
259       PublicKey key = readPublicKey(trustedKey.path());
260       MIL << "Key " << id << " " << key.name << " is trusted" << std::endl;
261       // it exists, is trusted, does it validates?
262       if ( verifyFile( file, signature, _trusted_kr ) )
263         return true;
264       else
265         return report->askUserToAcceptVerificationFailed( file, key.id, key.name );
266     }
267     else
268     {
269       if ( publicKeyExists( id, _general_kr ) )
270       {
271         TmpFile unKey;
272         exportKey( id, unKey.path(), false);
273         MIL << "Exported key " << id << " to " << unKey << std::endl;
274
275         PublicKey key = readPublicKey(unKey.path());
276         MIL << "Key " << id << " " << key.name << " is not trusted" << std::endl;
277         // ok the key is not trusted, ask the user to trust it or not
278 #warning We need the key details passed to the callback
279         if ( report->askUserToTrustKey(key.id, key.name, "") )
280         {
281           MIL << "User wants to trust key " << id << " " << key.name << std::endl;
282           //dumpFile(unKey.path());
283
284           importKey( unKey.path(), _trusted_kr );
285           emitSignal->trustedKeyAdded( (const KeyRing &)(*this), id, key.name );
286
287           // emit key added
288           if ( verifyFile( file, signature, _trusted_kr ) )
289           {
290             MIL << "File signature is verified" << std::endl;
291             return true;
292           }
293           else
294           {
295             MIL << "File signature check fails" << std::endl;
296             if ( report->askUserToAcceptVerificationFailed( file, key.id, key.name ) )
297             {
298               MIL << "User continues anyway." << std::endl;
299               return true;
300             }
301             else
302             {
303               MIL << "User does not want to continue" << std::endl;
304               return false;
305             }
306           }
307         }
308         else
309         {
310           MIL << "User does not want to trust key " << id << " " << key.name << std::endl;
311           return false;
312         }
313       }
314       else
315       {
316         // unknown key...
317         if ( report->askUserToAcceptUnknownKey( file, id, "Unknown Key" ) )
318         {
319           MIL << "User wants to accept unknown key " << id << std::endl;
320           return true;
321         }
322         else
323         {
324           MIL << "User does not want to accept unknown key " << id << std::endl;
325           return false;
326         }
327       }
328     }
329     return false;
330   }
331
332
333   PublicKey KeyRing::Impl::readPublicKey( const Pathname &keyfile )
334   {
335     const char* argv[] =
336     {
337       "gpg",
338       "--with-fingerprint",
339       "--with-colons",
340       "--quiet",
341       "--no-tty",
342       "--no-greeting",
343       "--batch",
344       "--status-fd",
345       "1",
346       keyfile.asString().c_str(),
347       NULL
348     };
349
350     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
351
352     std::string line;
353     int count = 0;
354
355     str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
356
357     // pub:-:1024:17:A84EDAE89C800ACA:2000-10-19:2008-06-21::-:SuSE Package Signing Key <build@suse.de>:
358
359     PublicKey key;
360     for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
361     {
362       //MIL << "[" << line << "]" << std::endl;
363       str::smatch what;
364       if(str::regex_match(line, what, rxColons, str::match_extra))
365       {
366         if ( what[1] == "pub" )
367         {
368           key.id = what[5];
369           key.name = what[10];
370           return key;
371         }
372         //dumpRegexpResults(what);
373       }
374     }
375     prog.close();
376     return key;
377   }
378
379   std::list<PublicKey> KeyRing::Impl::publicKeys(const Pathname &keyring)
380   {
381     const char* argv[] =
382     {
383       "gpg",
384       "--quiet",
385       "--list-public-keys",
386       "--with-colons",
387       "--with-fingerprint",
388       "--homedir",
389       keyring.asString().c_str(),
390       NULL
391     };
392     std::list<PublicKey> keys;
393
394     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
395     std::string line;
396     int count = 0;
397
398     str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
399     for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
400     {
401       //MIL << line << std::endl;
402       str::smatch what;
403       if(str::regex_match(line, what, rxColons, str::match_extra))
404       {
405         if ( what[1] == "pub" )
406         {
407           PublicKey key;
408           key.id = what[5];
409           key.name = what[10];
410           MIL << "Found key " << key.id << " [" << key.name << "]" << std::endl;
411           keys.push_back(key);
412         }
413         //dumpRegexpResults(what);
414       }
415     }
416     prog.close();
417     return keys;
418   }
419
420   void KeyRing::Impl::importKey( const Pathname &keyfile, const Pathname &keyring)
421   {
422     const char* argv[] =
423     {
424       "gpg",
425       "--quiet",
426       "--no-tty",
427       "--no-greeting",
428       "--no-permission-warning",
429       "--status-fd",
430       "1",
431       "--homedir",
432       keyring.asString().c_str(),
433       "--import",
434       keyfile.asString().c_str(),
435       NULL
436     };
437
438     int code;
439     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
440     code = prog.close();
441
442     //if ( code != 0 )
443     //  ZYPP_THROW(Exception("failed to import key"));
444   }
445
446   void KeyRing::Impl::deleteKey( const std::string &id, const Pathname &keyring )
447   {
448     const char* argv[] =
449     {
450       "gpg",
451       "--yes",
452       "--quiet",
453       "--no-tty",
454       "--batch",
455       "--status-fd",
456       "1",
457       "--homedir",
458       keyring.asString().c_str(),
459       "--delete-keys",
460       id.c_str(),
461       NULL
462     };
463
464     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
465
466     int code = prog.close();
467     if ( code )
468       ZYPP_THROW(Exception("Failed to delete key."));
469     else
470       MIL << "Deleted key " << id << " from keyring " << keyring << std::endl;
471   }
472
473
474   std::string KeyRing::Impl::readSignatureKeyId( const Pathname &data, const Pathname &keyfile )
475   {
476     // HACK create a tmp keyring with no keys
477     TmpDir dir;
478
479     const char* argv[] =
480     {
481       "gpg",
482       "--quiet",
483       "--no-tty",
484       "--no-greeting",
485       "--batch",
486       "--status-fd",
487       "1",
488       "--homedir",
489       dir.path().asString().c_str(),
490       "--verify",
491       keyfile.asString().c_str(),
492       data.asString().c_str(),
493       NULL
494     };
495
496     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
497
498     std::string line;
499     int count = 0;
500
501     str::regex rxNoKey("^\\[GNUPG:\\] NO_PUBKEY (.+)\n$");
502     std::string id;
503     for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
504     {
505       //MIL << "[" << line << "]" << std::endl;
506       str::smatch what;
507       if(str::regex_match(line, what, rxNoKey, str::match_extra))
508       {
509         if ( what.size() > 1 )
510           id = what[1];
511         //dumpRegexpResults(what);
512       }
513     }
514     prog.close();
515     return id;
516   }
517
518   bool KeyRing::Impl::verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring)
519   {
520     const char* argv[] =
521     {
522       "gpg",
523       "--quiet",
524       "--no-tty",
525       "--batch",
526       "--no-greeting",
527       "--status-fd",
528       "1",
529       "--homedir",
530       keyring.asString().c_str(),
531       "--verify",
532       signature.asString().c_str(),
533       file.asString().c_str(),
534       NULL
535     };
536
537     // no need to parse output for now
538     //     [GNUPG:] SIG_ID yCc4u223XRJnLnVAIllvYbUd8mQ 2006-03-29 1143618744
539     //     [GNUPG:] GOODSIG A84EDAE89C800ACA SuSE Package Signing Key <build@suse.de>
540     //     gpg: Good signature from "SuSE Package Signing Key <build@suse.de>"
541     //     [GNUPG:] VALIDSIG 79C179B2E1C820C1890F9994A84EDAE89C800ACA 2006-03-29 1143618744 0 3 0 17 2 00 79C179B2E1C820C1890F9994A84EDAE89C800ACA
542     //     [GNUPG:] TRUST_UNDEFINED
543
544     //     [GNUPG:] ERRSIG A84EDAE89C800ACA 17 2 00 1143618744 9
545     //     [GNUPG:] NO_PUBKEY A84EDAE89C800ACA
546
547     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
548
549     return (prog.close() == 0) ? true : false;
550   }
551
552   ///////////////////////////////////////////////////////////////////
553
554   ///////////////////////////////////////////////////////////////////
555   //
556   //    CLASS NAME : KeyRing
557   //
558   ///////////////////////////////////////////////////////////////////
559
560   ///////////////////////////////////////////////////////////////////
561   //
562   //    METHOD NAME : KeyRing::KeyRing
563   //    METHOD TYPE : Ctor
564   //
565   KeyRing::KeyRing()
566   : _pimpl( new Impl() )
567   {}
568
569   ///////////////////////////////////////////////////////////////////
570   //
571   //    METHOD NAME : KeyRing::KeyRing
572   //    METHOD TYPE : Ctor
573   //
574   //KeyRing::KeyRing( const Pathname &general_kr, const Pathname &trusted_kr )
575   //: _pimpl( new Impl(general_kr, trusted_kr) )
576   //{}
577
578   ///////////////////////////////////////////////////////////////////
579   //
580   //    METHOD NAME : KeyRing::~KeyRing
581   //    METHOD TYPE : Dtor
582   //
583   KeyRing::~KeyRing()
584   {}
585
586   ///////////////////////////////////////////////////////////////////
587   //
588   // Forward to implementation:
589   //
590   ///////////////////////////////////////////////////////////////////
591
592   void KeyRing::importKey( const Pathname &keyfile, bool trusted)
593   {
594     _pimpl->importKey(keyfile, trusted);
595   }
596
597   PublicKey KeyRing::readPublicKey( const Pathname &keyfile )
598   {
599     return _pimpl->readPublicKey(keyfile);
600   }
601
602   std::string KeyRing::readSignatureKeyId(  const Pathname &data, const Pathname &keyfile )
603   {
604     return _pimpl->readSignatureKeyId(data, keyfile);
605   }
606
607   void KeyRing::deleteKey( const std::string &id, bool trusted )
608   {
609     _pimpl->deleteKey(id, trusted);
610   }
611
612   std::list<PublicKey> KeyRing::publicKeys()
613   {
614     return _pimpl->publicKeys();
615   }
616
617   std::list<PublicKey> KeyRing::trustedPublicKeys()
618   {
619     return _pimpl->trustedPublicKeys();
620   }
621
622   bool KeyRing::verifyFileSignatureWorkflow( const Pathname &file, const Pathname &signature)
623   {
624     return _pimpl->verifyFileSignatureWorkflow(file, signature);
625   }
626
627   bool KeyRing::verifyFileSignature( const Pathname &file, const Pathname &signature)
628   {
629     return _pimpl->verifyFileSignature(file, signature);
630   }
631
632   bool KeyRing::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
633   {
634     return _pimpl->verifyFileTrustedSignature(file, signature);
635   }
636
637   void KeyRing::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
638   {
639     _pimpl->dumpPublicKey( id, trusted, stream);
640   }
641
642   /////////////////////////////////////////////////////////////////
643 } // namespace zypp
644 ///////////////////////////////////////////////////////////////////