KeyRing.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <fstream>
00014 #include <sys/file.h>
00015 #include <cstdio>
00016 #include <unistd.h>
00017 
00018 #include "zypp/ZYppFactory.h"
00019 #include "zypp/ZYpp.h"
00020 
00021 #include "zypp/base/Logger.h"
00022 #include "zypp/base/IOStream.h"
00023 #include "zypp/base/String.h"
00024 #include "zypp/Pathname.h"
00025 #include "zypp/KeyRing.h"
00026 #include "zypp/ExternalProgram.h"
00027 #include "zypp/TmpPath.h"
00028 
00029 using std::endl;
00030 using namespace zypp::filesystem;
00031 using namespace std;
00032 
00033 #undef  ZYPP_BASE_LOGGER_LOGGROUP
00034 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::KeyRing"
00035 
00037 namespace zypp
00038 { 
00039 
00040   IMPL_PTR_TYPE(KeyRing);
00041 
00042   static void dumpRegexpResults( const str::smatch &what )
00043   {
00044     for ( unsigned int k=0; k < what.size(); k++)
00045     {
00046       XXX << "[match "<< k << "] [" << what[k] << "]" << std::endl;
00047     }
00048   }
00049 
00050   static bool printLine( const std::string &line )
00051   {
00052     MIL <<  line << std::endl;
00053   }
00054 
00055   static void dumpFile(const Pathname &file)
00056   {
00057     std::ifstream is(file.asString().c_str());
00058     iostr::forEachLine( is, printLine);
00059   }
00060 
00061   namespace
00062   {
00063     bool _keyRingDefaultAccept( getenv("ZYPP_KEYRING_DEFAULT_ACCEPT_ALL") );
00064   }
00065 
00066   bool KeyRingReport::askUserToAcceptUnsignedFile( const std::string &file )
00067   { return _keyRingDefaultAccept; }
00068 
00069   bool KeyRingReport::askUserToAcceptUnknownKey( const std::string &file, const std::string &keyid, const std::string &keyname, const std::string &fingerprint )
00070   { return _keyRingDefaultAccept; }
00071 
00072   bool KeyRingReport::askUserToTrustKey( const std::string &keyid, const std::string &keyname, const std::string &fingerprint )
00073   { return _keyRingDefaultAccept; }
00074 
00075   bool KeyRingReport::askUserToAcceptVerificationFailed( const std::string &file, const std::string &keyid, const std::string &keyname, const std::string &fingerprint )
00076   { return _keyRingDefaultAccept; }
00077 
00079   //
00080   //    CLASS NAME : KeyRing::Impl
00081   //
00083   struct KeyRing::Impl
00084   {
00085     Impl()
00086     {
00087       _general_kr = _general_tmp_dir.path();
00088       _trusted_kr = _trusted_tmp_dir.path();
00089     }
00090 
00091     /*
00092     Impl( const Pathname &general_kr, const Pathname &trusted_kr )
00093     {
00094       filesystem::assert_dir(general_kr);
00095       filesystem::assert_dir(trusted_kr);
00096 
00097       _general_kr = general_kr;
00098       _trusted_kr = trusted_kr;
00099     }
00100     */
00101 
00102     void importKey( const Pathname &keyfile, bool trusted = false);
00103     PublicKey readPublicKey( const Pathname &keyfile );
00104     std::string readSignatureKeyId( const Pathname &signature );
00105 
00106     void deleteKey( const std::string &id, bool trusted );
00107     std::list<PublicKey> trustedPublicKeys();
00108     std::list<PublicKey> publicKeys();
00109 
00110     void dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream );
00111 
00112     bool verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature);
00113 
00114     bool verifyFileSignature( const Pathname &file, const Pathname &signature);
00115     bool verifyFileTrustedSignature( const Pathname &file, const Pathname &signature);
00116   private:
00117     //mutable std::map<Locale, std::string> translations;
00118     bool verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring);
00119     void importKey( const Pathname &keyfile, const Pathname &keyring);
00120 
00121     void exportKey( std::string id, const Pathname &keyfile, bool trusted);
00122 
00123     void deleteKey( const std::string &id, const Pathname &keyring );
00124     std::list<PublicKey> publicKeys(const Pathname &keyring);
00125 
00126     bool publicKeyExists( std::string id, const Pathname &keyring);
00127 
00128     Pathname _general_kr;
00129     Pathname _trusted_kr;
00130 
00131     // Used for trusted and untrusted keyrings
00132     TmpDir _trusted_tmp_dir;
00133     TmpDir _general_tmp_dir;
00134   public:
00136     static shared_ptr<Impl> nullimpl()
00137     {
00138       static shared_ptr<Impl> _nullimpl( new Impl );
00139       return _nullimpl;
00140     }
00141 
00142   private:
00143     friend Impl * rwcowClone<Impl>( const Impl * rhs );
00145     Impl * clone() const
00146     { return new Impl( *this ); }
00147   };
00148 
00149   void KeyRing::Impl::importKey( const Pathname &keyfile, bool trusted)
00150   {
00151     importKey( keyfile, trusted ? _trusted_kr : _general_kr );
00152   }
00153 
00154   void KeyRing::Impl::deleteKey( const std::string &id, bool trusted)
00155   {
00156     deleteKey( id, trusted ? _trusted_kr : _general_kr );
00157   }
00158 
00159   std::list<PublicKey> KeyRing::Impl::publicKeys()
00160   {
00161     return publicKeys( _general_kr );
00162   }
00163 
00164   std::list<PublicKey> KeyRing::Impl::trustedPublicKeys()
00165   {
00166     return publicKeys( _trusted_kr );
00167   }
00168 
00169   bool KeyRing::Impl::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
00170   {
00171     return verifyFile( file, signature, _trusted_kr );
00172   }
00173 
00174   bool KeyRing::Impl::verifyFileSignature( const Pathname &file, const Pathname &signature)
00175   {
00176     return verifyFile( file, signature, _general_kr );
00177   }
00178 
00179   bool KeyRing::Impl::publicKeyExists( std::string id, const Pathname &keyring)
00180   {
00181     MIL << "Searching key [" << id << "] in keyring " << keyring << std::endl;
00182     std::list<PublicKey> keys = publicKeys(keyring);
00183     for (std::list<PublicKey>::const_iterator it = keys.begin(); it != keys.end(); it++)
00184     {
00185       if ( id == (*it).id )
00186         return true;
00187     }
00188     return false;
00189   }
00190 
00191   void KeyRing::Impl::exportKey( std::string id, const Pathname &keyfile, bool trusted)
00192   {
00193     try {
00194       std::ofstream os(keyfile.asString().c_str());
00195       dumpPublicKey( id, trusted, os );
00196       os.close();
00197     }
00198     catch (std::exception &e)
00199     {
00200       ERR << "Cannot export key " << id << " from " << (trusted ? "trusted" : "untrusted ") << " keyring  to file " << keyfile << std::endl;
00201     }
00202   }
00203 
00204   void KeyRing::Impl::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
00205   {
00206     Pathname keyring = trusted ? _trusted_kr : _general_kr;
00207     const char* argv[] =
00208     {
00209       "gpg",
00210       "--no-default-keyring",
00211       "--quiet",
00212       "--no-tty",
00213       "--no-greeting",
00214       "--no-permission-warning",
00215       "--batch",
00216       "--homedir",
00217       keyring.asString().c_str(),
00218       "-a",
00219       "--export",
00220       id.c_str(),
00221       NULL
00222     };
00223     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00224     std::string line;
00225     int count;
00226     for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
00227     {
00228       stream << line;
00229     }
00230     prog.close();
00231   }
00232 
00233 
00234   bool KeyRing::Impl::verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature)
00235   {
00236     callback::SendReport<KeyRingReport> report;
00237     callback::SendReport<KeyRingSignals> emitSignal;
00238     MIL << "Going to verify signature for " << file << " with " << signature << std::endl;
00239 
00240     // if signature does not exists, ask user if he wants to accept unsigned file.
00241     if( signature.empty() || (!PathInfo(signature).isExist()) )
00242     {
00243         bool res = report->askUserToAcceptUnsignedFile( filedesc );
00244         MIL << "User decision on unsigned file: " << res << endl;
00245         return res;
00246     }
00247 
00248     // get the id of the signature
00249     std::string id = readSignatureKeyId(signature);
00250 
00251     // doeskey exists in trusted keyring
00252     if ( publicKeyExists( id, _trusted_kr ) )
00253     {
00254       TmpFile trustedKey;
00255       exportKey( id, trustedKey.path(), true);
00256       PublicKey key = readPublicKey(trustedKey.path());
00257       MIL << "Key " << id << " " << key.name << " is trusted" << std::endl;
00258       // it exists, is trusted, does it validates?
00259       if ( verifyFile( file, signature, _trusted_kr ) )
00260         return true;
00261       else
00262         return report->askUserToAcceptVerificationFailed( filedesc, key.id, key.name, key.fingerprint );
00263     }
00264     else
00265     {
00266       if ( publicKeyExists( id, _general_kr ) )
00267       {
00268         TmpFile unKey;
00269         exportKey( id, unKey.path(), false);
00270         MIL << "Exported key " << id << " to " << unKey << std::endl;
00271 
00272         PublicKey key = readPublicKey(unKey.path());
00273         MIL << "Key " << id << " " << key.name << " is not trusted" << std::endl;
00274         // ok the key is not trusted, ask the user to trust it or not
00275 #warning We need the key details passed to the callback
00276         if ( report->askUserToTrustKey(key.id, key.name, key.fingerprint) )
00277         {
00278           MIL << "User wants to trust key " << id << " " << key.name << std::endl;
00279           //dumpFile(unKey.path());
00280 
00281           importKey( unKey.path(), _trusted_kr );
00282           emitSignal->trustedKeyAdded( (const KeyRing &)(*this), id, key.name, key.fingerprint );
00283 
00284           // emit key added
00285           if ( verifyFile( file, signature, _trusted_kr ) )
00286           {
00287             MIL << "File signature is verified" << std::endl;
00288             return true;
00289           }
00290           else
00291           {
00292             MIL << "File signature check fails" << std::endl;
00293             if ( report->askUserToAcceptVerificationFailed( filedesc, key.id, key.name, key.fingerprint ) )
00294             {
00295               MIL << "User continues anyway." << std::endl;
00296               return true;
00297             }
00298             else
00299             {
00300               MIL << "User does not want to continue" << std::endl;
00301               return false;
00302             }
00303           }
00304         }
00305         else
00306         {
00307           MIL << "User does not want to trust key " << id << " " << key.name << std::endl;
00308           return false;
00309         }
00310       }
00311       else
00312       {
00313         // unknown key...
00314         MIL << "File [" << file << "] ( " << filedesc << " ) signed with unknown key [" << id << "]" << std::endl;
00315         if ( report->askUserToAcceptUnknownKey( filedesc, id, "", "" ) )
00316         {
00317           MIL << "User wants to accept unknown key " << id << std::endl;
00318           return true;
00319         }
00320         else
00321         {
00322           MIL << "User does not want to accept unknown key " << id << std::endl;
00323           return false;
00324         }
00325       }
00326     }
00327     return false;
00328   }
00329 
00330 
00331   PublicKey KeyRing::Impl::readPublicKey( const Pathname &keyfile )
00332   {
00333     const char* argv[] =
00334     {
00335       "gpg",
00336       "--no-default-keyring",
00337       "--with-fingerprint",
00338       "--with-colons",
00339       "--quiet",
00340       "--no-tty",
00341       "--no-greeting",
00342       "--batch",
00343       "--status-fd",
00344       "1",
00345       keyfile.asString().c_str(),
00346       NULL
00347     };
00348 
00349     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00350 
00351     std::string line;
00352     int count = 0;
00353 
00354     str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
00355 
00356     // pub:-:1024:17:A84EDAE89C800ACA:2000-10-19:2008-06-21::-:SuSE Package Signing Key <build@suse.de>:
00357 
00358     PublicKey key;
00359     for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
00360     {
00361       //MIL << "[" << line << "]" << std::endl;
00362       str::smatch what;
00363       if(str::regex_match(line, what, rxColons, str::match_extra))
00364       {
00365         if ( what[1] == "pub" )
00366         {
00367           key.id = what[5];
00368           key.name = what[10];
00369           //return key;
00370         }
00371         else if ( what[1] == "fpr" )
00372         {
00373           key.fingerprint = what[10];
00374         }
00375         //dumpRegexpResults(what);
00376       }
00377     }
00378     prog.close();
00379     return key;
00380   }
00381 
00382   std::list<PublicKey> KeyRing::Impl::publicKeys(const Pathname &keyring)
00383   {
00384     const char* argv[] =
00385     {
00386       "gpg",
00387       "--no-default-keyring",
00388       "--quiet",
00389       "--list-public-keys",
00390       "--with-colons",
00391       "--with-fingerprint",
00392       "--no-tty",
00393       "--no-greeting",
00394       "--batch",
00395       "--status-fd",
00396       "1",
00397       "--homedir",
00398       keyring.asString().c_str(),
00399       NULL
00400     };
00401     std::list<PublicKey> keys;
00402 
00403     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00404     std::string line;
00405     int count = 0;
00406 
00407     str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
00408     str::regex rxColonsFpr("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
00409 
00410     for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
00411     {
00412       //MIL << line << std::endl;
00413       str::smatch what;
00414       if(str::regex_match(line, what, rxColons, str::match_extra))
00415       {
00416         PublicKey key;
00417         if ( what[1] == "pub" )
00418         {
00419           key.id = what[5];
00420           key.name = what[10];
00421 
00422           std::string line2;
00423           for(line2 = prog.receiveLine(); !line2.empty(); line2 = prog.receiveLine(), count++ )
00424           {
00425             str::smatch what2;
00426             if (str::regex_match(line2, what2, rxColonsFpr, str::match_extra))
00427             {
00428               if ( (what2[1] == "fpr") && (what2[1] != "pub") && (what2[1] !="sub"))
00429               {
00430                 key.fingerprint = what2[10];
00431                 break;
00432               }
00433             }
00434           }
00435           keys.push_back(key);
00436           MIL << "Found key " << "[" << key.id << "]" << " [" << key.name << "]" << " [" << key.fingerprint << "]" << std::endl;
00437         }
00438         //dumpRegexpResults(what);
00439       }
00440     }
00441     prog.close();
00442     return keys;
00443   }
00444 
00445   void KeyRing::Impl::importKey( const Pathname &keyfile, const Pathname &keyring)
00446   {
00447     const char* argv[] =
00448     {
00449       "gpg",
00450       "--no-default-keyring",
00451       "--quiet",
00452       "--no-tty",
00453       "--no-greeting",
00454       "--no-permission-warning",
00455       "--status-fd",
00456       "1",
00457       "--homedir",
00458       keyring.asString().c_str(),
00459       "--import",
00460       keyfile.asString().c_str(),
00461       NULL
00462     };
00463 
00464     int code;
00465     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00466     code = prog.close();
00467 
00468     //if ( code != 0 )
00469     //  ZYPP_THROW(Exception("failed to import key"));
00470   }
00471 
00472   void KeyRing::Impl::deleteKey( const std::string &id, const Pathname &keyring )
00473   {
00474     const char* argv[] =
00475     {
00476       "gpg",
00477       "--no-default-keyring",
00478       "--yes",
00479       "--quiet",
00480       "--no-tty",
00481       "--batch",
00482       "--status-fd",
00483       "1",
00484       "--homedir",
00485       keyring.asString().c_str(),
00486       "--delete-keys",
00487       id.c_str(),
00488       NULL
00489     };
00490 
00491     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00492 
00493     int code = prog.close();
00494     if ( code )
00495       ZYPP_THROW(Exception("Failed to delete key."));
00496     else
00497       MIL << "Deleted key " << id << " from keyring " << keyring << std::endl;
00498   }
00499 
00500 
00501   std::string KeyRing::Impl::readSignatureKeyId(const Pathname &signature )
00502   {
00503     MIL << "Deetermining key id if signature " << signature << std::endl;
00504     // HACK create a tmp keyring with no keys
00505     TmpDir dir;
00506     TmpFile fakeData;
00507     
00508     const char* argv[] =
00509     {
00510       "gpg",
00511       "--no-default-keyring",
00512       "--quiet",
00513       "--no-tty",
00514       "--no-greeting",
00515       "--batch",
00516       "--status-fd",
00517       "1",
00518       "--homedir",
00519       dir.path().asString().c_str(),
00520       "--verify",
00521       signature.asString().c_str(),
00522       fakeData.path().asString().c_str(),
00523       NULL
00524     };
00525 
00526     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00527 
00528     std::string line;
00529     int count = 0;
00530 
00531     str::regex rxNoKey("^\\[GNUPG:\\] NO_PUBKEY (.+)\n$");
00532     std::string id;
00533     for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
00534     {
00535       //MIL << "[" << line << "]" << std::endl;
00536       str::smatch what;
00537       if(str::regex_match(line, what, rxNoKey, str::match_extra))
00538       {
00539         if ( what.size() > 1 )
00540           id = what[1];
00541         //dumpRegexpResults(what);
00542       }
00543     }
00544     MIL << "Determined key id [" << id << "] for signature " << signature << std::endl;
00545     prog.close();
00546     return id;
00547   }
00548 
00549   bool KeyRing::Impl::verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring)
00550   {
00551     const char* argv[] =
00552     {
00553       "gpg",
00554       "--no-default-keyring",
00555       "--quiet",
00556       "--no-tty",
00557       "--batch",
00558       "--no-greeting",
00559       "--status-fd",
00560       "1",
00561       "--homedir",
00562       keyring.asString().c_str(),
00563       "--verify",
00564       signature.asString().c_str(),
00565       file.asString().c_str(),
00566       NULL
00567     };
00568 
00569     // no need to parse output for now
00570     //     [GNUPG:] SIG_ID yCc4u223XRJnLnVAIllvYbUd8mQ 2006-03-29 1143618744
00571     //     [GNUPG:] GOODSIG A84EDAE89C800ACA SuSE Package Signing Key <build@suse.de>
00572     //     gpg: Good signature from "SuSE Package Signing Key <build@suse.de>"
00573     //     [GNUPG:] VALIDSIG 79C179B2E1C820C1890F9994A84EDAE89C800ACA 2006-03-29 1143618744 0 3 0 17 2 00 79C179B2E1C820C1890F9994A84EDAE89C800ACA
00574     //     [GNUPG:] TRUST_UNDEFINED
00575 
00576     //     [GNUPG:] ERRSIG A84EDAE89C800ACA 17 2 00 1143618744 9
00577     //     [GNUPG:] NO_PUBKEY A84EDAE89C800ACA
00578 
00579     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00580 
00581     return (prog.close() == 0) ? true : false;
00582   }
00583 
00585 
00587   //
00588   //    CLASS NAME : KeyRing
00589   //
00591 
00593   //
00594   //    METHOD NAME : KeyRing::KeyRing
00595   //    METHOD TYPE : Ctor
00596   //
00597   KeyRing::KeyRing()
00598   : _pimpl( new Impl() )
00599   {}
00600 
00602   //
00603   //    METHOD NAME : KeyRing::KeyRing
00604   //    METHOD TYPE : Ctor
00605   //
00606   //KeyRing::KeyRing( const Pathname &general_kr, const Pathname &trusted_kr )
00607   //: _pimpl( new Impl(general_kr, trusted_kr) )
00608   //{}
00609 
00611   //
00612   //    METHOD NAME : KeyRing::~KeyRing
00613   //    METHOD TYPE : Dtor
00614   //
00615   KeyRing::~KeyRing()
00616   {}
00617 
00619   //
00620   // Forward to implementation:
00621   //
00623 
00624   void KeyRing::importKey( const Pathname &keyfile, bool trusted)
00625   {
00626     _pimpl->importKey(keyfile, trusted);
00627   }
00628 
00629   PublicKey KeyRing::readPublicKey( const Pathname &keyfile )
00630   {
00631     return _pimpl->readPublicKey(keyfile);
00632   }
00633 
00634   std::string KeyRing::readSignatureKeyId( const Pathname &signature )
00635   {
00636     return _pimpl->readSignatureKeyId(signature);
00637   }
00638 
00639   void KeyRing::deleteKey( const std::string &id, bool trusted )
00640   {
00641     _pimpl->deleteKey(id, trusted);
00642   }
00643 
00644   std::list<PublicKey> KeyRing::publicKeys()
00645   {
00646     return _pimpl->publicKeys();
00647   }
00648 
00649   std::list<PublicKey> KeyRing::trustedPublicKeys()
00650   {
00651     return _pimpl->trustedPublicKeys();
00652   }
00653 
00654   bool KeyRing::verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature)
00655   {
00656     return _pimpl->verifyFileSignatureWorkflow(file, filedesc, signature);
00657   }
00658 
00659   bool KeyRing::verifyFileSignature( const Pathname &file, const Pathname &signature)
00660   {
00661     return _pimpl->verifyFileSignature(file, signature);
00662   }
00663 
00664   bool KeyRing::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
00665   {
00666     return _pimpl->verifyFileTrustedSignature(file, signature);
00667   }
00668 
00669   void KeyRing::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
00670   {
00671     _pimpl->dumpPublicKey( id, trusted, stream);
00672   }
00673 
00675 } // namespace zypp

Generated on Thu May 4 16:03:22 2006 for zypp by  doxygen 1.4.6