implement signature file to id, keyexists, and others
[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 "zypp/base/Logger.h"
15 #include <sys/file.h>
16 #include <cstdio>
17 #include <unistd.h>
18
19 #include "zypp/ZYppFactory.h"
20 #include "zypp/ZYpp.h"
21
22 #include <boost/regex.hpp>
23
24 #include "zypp/base/String.h"
25 #include "zypp/KeyRing.h"
26 #include "zypp/ExternalProgram.h"
27 #include "zypp/TmpPath.h"
28
29 using std::endl;
30 using namespace boost;
31 using namespace zypp::filesystem;
32 using namespace std;
33
34 ///////////////////////////////////////////////////////////////////
35 namespace zypp
36 { /////////////////////////////////////////////////////////////////
37
38   IMPL_PTR_TYPE(KeyRing);
39   
40   static void dumpRegexpResults( const boost::smatch &what )
41   {
42     for ( unsigned int k=0; k < what.size(); k++)
43     {
44       XXX << "[match "<< k << "] [" << what[k] << "]" << std::endl;
45     }
46   }
47   
48   ///////////////////////////////////////////////////////////////////
49   //
50   //    CLASS NAME : KeyRing::Impl
51   //
52   /** KeyRing implementation. */
53   struct KeyRing::Impl
54   {
55     Impl()
56     {}
57
58     Impl( const Pathname &general_kr, const Pathname &trusted_kr )
59     {
60       filesystem::assert_dir(general_kr);
61       filesystem::assert_dir(trusted_kr);
62       
63       _general_kr = general_kr;
64       _trusted_kr = trusted_kr;
65     }
66
67     void importKey( const Pathname &keyfile, bool trusted = false);
68     PublicKey readPublicKey( const Pathname &keyfile );
69     std::string readSignatureKeyId( const Pathname &keyfile );
70     
71     void deleteKey( const std::string &id, bool trusted );
72     std::list<PublicKey> trustedPublicKeys();
73     std::list<PublicKey> publicKeys();
74     
75     bool verifyFileSignatureWorkflow( const Pathname &file, const Pathname &signature);
76     
77     bool verifyFileSignature( const Pathname &file, const Pathname &signature);
78     bool verifyFileTrustedSignature( const Pathname &file, const Pathname &signature);
79   private:
80     //mutable std::map<Locale, std::string> translations;
81     bool verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring);
82     void importKey( const Pathname &keyfile, const Pathname &keyring);
83     void deleteKey( const std::string &id, const Pathname &keyring );
84     std::list<PublicKey> publicKeys(const Pathname &keyring);
85     
86     bool publicKeyExists( std::string id, const Pathname &keyring);
87     
88     Pathname _general_kr;
89     Pathname _trusted_kr;
90   public:
91     /** Offer default Impl. */
92     static shared_ptr<Impl> nullimpl()
93     {
94       static shared_ptr<Impl> _nullimpl( new Impl );
95       return _nullimpl;
96     }
97
98   private:
99     friend Impl * rwcowClone<Impl>( const Impl * rhs );
100     /** clone for RWCOW_pointer */
101     Impl * clone() const
102     { return new Impl( *this ); }
103   };
104   
105   void KeyRing::Impl::importKey( const Pathname &keyfile, bool trusted)
106   {
107     importKey( keyfile, trusted ? _trusted_kr : _general_kr );
108   }
109   
110   void KeyRing::Impl::deleteKey( const std::string &id, bool trusted)
111   {
112     deleteKey( id, trusted ? _trusted_kr : _general_kr );
113   }
114   
115   std::list<PublicKey> KeyRing::Impl::publicKeys()
116   {
117     return publicKeys( _general_kr );
118   }
119   
120   std::list<PublicKey> KeyRing::Impl::trustedPublicKeys()
121   {
122     return publicKeys( _trusted_kr );
123   }
124   
125   bool KeyRing::Impl::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
126   {
127     return verifyFile( file, signature, _trusted_kr );
128   }
129   
130   bool KeyRing::Impl::verifyFileSignature( const Pathname &file, const Pathname &signature)
131   {
132     return verifyFile( file, signature, _general_kr );
133   }
134   
135   bool KeyRing::Impl::publicKeyExists( std::string id, const Pathname &keyring)
136   {
137     std::list<PublicKey> keys = publicKeys(keyring);
138     for (std::list<PublicKey>::const_iterator it = keys.begin(); it != keys.end(); it++)
139     {
140       if ( id == (*it).id )
141         return true;
142     }
143     return false;
144   }
145   
146   bool KeyRing::Impl::verifyFileSignatureWorkflow( const Pathname &file, const Pathname &signature)
147   {
148     
149     return true;
150   }
151   
152   
153   PublicKey KeyRing::Impl::readPublicKey( const Pathname &keyfile )
154   {  
155     const char* argv[] =
156     {
157       "gpg",
158       "--with-fingerprint",
159       "--with-colons",
160       "--quiet",
161       "--no-tty",
162       "--no-greeting",
163       "--batch",
164       "--status-fd",
165       "1",  
166       keyfile.asString().c_str(),
167       NULL
168     };
169     
170     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
171     
172     std::string line;
173     int count = 0;
174     
175     boost::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
176     
177     // pub:-:1024:17:A84EDAE89C800ACA:2000-10-19:2008-06-21::-:SuSE Package Signing Key <build@suse.de>:
178     
179     PublicKey key;
180     for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
181     {
182       //MIL << "[" << line << "]" << std::endl;
183       boost::smatch what;
184       if(boost::regex_match(line, what, rxColons, boost::match_extra))
185       {
186         if ( what[1] == "pub" )
187         {
188           key.id = what[5];
189           key.name = what[10];
190           return key;
191         }
192         //dumpRegexpResults(what);
193       }
194     }
195     prog.close();
196     return key;
197   }
198   
199   std::list<PublicKey> KeyRing::Impl::publicKeys(const Pathname &keyring)
200   {
201     const char* argv[] =
202     {
203       "gpg",
204       "--quiet",
205       "--list-public-keys",
206       "--with-colons",
207       "--with-fingerprint",
208       "--homedir",
209       keyring.asString().c_str(),
210       NULL
211     };
212     std::list<PublicKey> keys;
213     
214     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
215     std::string line;
216     int count = 0;
217     
218     boost::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
219     for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
220     {
221       //MIL << line << std::endl;
222       boost::smatch what;
223       if(boost::regex_match(line, what, rxColons, boost::match_extra))
224       {
225         if ( what[1] == "pub" )
226         {
227           PublicKey key;
228           key.id = what[5];
229           key.name = what[10];
230           MIL << "Found key " << key.id << " [" << key.name << "]" << std::endl;
231           keys.push_back(key);
232         }
233         dumpRegexpResults(what);
234       }
235     }
236     prog.close();
237     return keys;
238   }
239   
240   void KeyRing::Impl::importKey( const Pathname &keyfile, const Pathname &keyring)
241   {
242     const char* argv[] =
243     {
244       "gpg",
245       "--quiet",
246       "--no-tty",
247       "--no-greeting",
248       "--status-fd",
249       "1",  
250       "--homedir",
251       keyring.asString().c_str(),
252       "--import",
253       keyfile.asString().c_str(),
254       NULL
255     };
256     
257     int code;
258     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
259     code = prog.close();
260     
261     if ( code != 0 )
262       ZYPP_THROW(Exception("failed to import key"));
263   }
264   
265   void KeyRing::Impl::deleteKey( const std::string &id, const Pathname &keyring )
266   {
267     const char* argv[] =
268     {
269       "gpg",
270       "--yes",
271       "--quiet",
272       "--no-tty",
273       "--batch",
274       "--status-fd",
275       "1",
276       "--homedir",
277       keyring.asString().c_str(),
278       "--delete-keys",
279       id.c_str(),
280       NULL
281     };
282     
283     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
284     
285     int code = prog.close();
286     if ( code )
287       ZYPP_THROW(Exception("Failed to delete key."));
288     else    
289       MIL << "Deleted key " << id << " from keyring " << keyring << std::endl;
290   }    
291   
292   
293   std::string KeyRing::Impl::readSignatureKeyId( const Pathname &keyfile )
294   {  
295     // HACK create a tmp keyring with no keys
296     TmpDir dir;
297     
298     const char* argv[] =
299     {
300       "gpg",
301       "--quiet",
302       "--no-tty",
303       "--no-greeting",
304       "--batch",
305       "--status-fd",
306       "1",
307       "--homedir",
308       dir.path().asString().c_str(),
309       keyfile.asString().c_str(),
310       NULL
311     };
312     
313     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
314     
315     std::string line;
316     int count = 0;
317     
318     boost::regex rxNoKey("^\\[GNUPG:\\] NO_PUBKEY (.+)\n$");
319     std::string id;
320     for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
321     {
322       //MIL << "[" << line << "]" << std::endl;
323       boost::smatch what;
324       if(boost::regex_match(line, what, rxNoKey, boost::match_extra))
325       {
326         if ( what.size() > 1 )
327           id = what[1];
328         //dumpRegexpResults(what);
329       }
330     }
331     prog.close();
332     return id;
333   }    
334       
335   bool KeyRing::Impl::verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring)
336   {
337     const char* argv[] =
338     {
339       "gpg",
340       "--quiet",
341       "--no-tty",
342       "--batch",
343       "--no-greeting",
344       "--status-fd",
345       "1",
346       "--homedir",
347       keyring.asString().c_str(),
348       "--verify",
349       signature.asString().c_str(),
350       file.asString().c_str(),
351       NULL
352     };
353     
354     // no need to parse output for now
355     //     [GNUPG:] SIG_ID yCc4u223XRJnLnVAIllvYbUd8mQ 2006-03-29 1143618744
356     //     [GNUPG:] GOODSIG A84EDAE89C800ACA SuSE Package Signing Key <build@suse.de>
357     //     gpg: Good signature from "SuSE Package Signing Key <build@suse.de>"
358     //     [GNUPG:] VALIDSIG 79C179B2E1C820C1890F9994A84EDAE89C800ACA 2006-03-29 1143618744 0 3 0 17 2 00 79C179B2E1C820C1890F9994A84EDAE89C800ACA
359     //     [GNUPG:] TRUST_UNDEFINED
360     
361     //     [GNUPG:] ERRSIG A84EDAE89C800ACA 17 2 00 1143618744 9
362     //     [GNUPG:] NO_PUBKEY A84EDAE89C800ACA
363
364     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
365      
366     return (prog.close() == 0) ? true : false;
367   }
368   
369   ///////////////////////////////////////////////////////////////////
370
371   ///////////////////////////////////////////////////////////////////
372   //
373   //    CLASS NAME : KeyRing
374   //
375   ///////////////////////////////////////////////////////////////////
376
377   ///////////////////////////////////////////////////////////////////
378   //
379   //    METHOD NAME : KeyRing::KeyRing
380   //    METHOD TYPE : Ctor
381   //
382   KeyRing::KeyRing()
383   : _pimpl( Impl::nullimpl() )
384   {}
385
386   ///////////////////////////////////////////////////////////////////
387   //
388   //    METHOD NAME : KeyRing::KeyRing
389   //    METHOD TYPE : Ctor
390   //
391   KeyRing::KeyRing( const Pathname &general_kr, const Pathname &trusted_kr )
392   : _pimpl( new Impl(general_kr, trusted_kr) )
393   {}
394
395   ///////////////////////////////////////////////////////////////////
396   //
397   //    METHOD NAME : KeyRing::~KeyRing
398   //    METHOD TYPE : Dtor
399   //
400   KeyRing::~KeyRing()
401   {}
402
403   ///////////////////////////////////////////////////////////////////
404   //
405   // Forward to implementation:
406   //
407   ///////////////////////////////////////////////////////////////////
408
409   void KeyRing::importKey( const Pathname &keyfile, bool trusted)
410   {
411     _pimpl->importKey(keyfile, trusted);
412   }
413   
414   PublicKey KeyRing::readPublicKey( const Pathname &keyfile )
415   {
416     return _pimpl->readPublicKey(keyfile);
417   }
418   
419   std::string KeyRing::readSignatureKeyId( const Pathname &keyfile )
420   {
421     return _pimpl->readSignatureKeyId(keyfile);
422   }
423   
424   void KeyRing::deleteKey( const std::string &id, bool trusted )
425   {
426     _pimpl->deleteKey(id, trusted);
427   }
428   
429   std::list<PublicKey> KeyRing::publicKeys()
430   {
431     return _pimpl->publicKeys();
432   }
433   
434   std::list<PublicKey> KeyRing::trustedPublicKeys()
435   {
436     return _pimpl->trustedPublicKeys();
437   }
438   
439   bool KeyRing::verifyFileSignatureWorkflow( const Pathname &file, const Pathname &signature)
440   {
441     return _pimpl->verifyFileSignatureWorkflow(file, signature);
442   }
443   
444   bool KeyRing::verifyFileSignature( const Pathname &file, const Pathname &signature)
445   {
446     return _pimpl->verifyFileSignature(file, signature);
447   }
448   
449   bool KeyRing::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
450   {
451     return _pimpl->verifyFileTrustedSignature(file, signature);
452   }
453   
454   /////////////////////////////////////////////////////////////////
455 } // namespace zypp
456 ///////////////////////////////////////////////////////////////////