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     TmpDir dir;
00334     
00335     const char* argv[] =
00336     {
00337       "gpg",
00338       "--no-default-keyring",
00339       "--homedir",
00340       dir.path().asString().c_str(),
00341       "--with-fingerprint",
00342       "--with-colons",
00343       "--quiet",
00344       "--no-tty",
00345       "--no-greeting",
00346       "--batch",
00347       "--status-fd",
00348       "1",
00349       keyfile.asString().c_str(),
00350       NULL
00351     };
00352 
00353     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00354 
00355     std::string line;
00356     int count = 0;
00357 
00358     str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
00359 
00360     // pub:-:1024:17:A84EDAE89C800ACA:2000-10-19:2008-06-21::-:SuSE Package Signing Key <build@suse.de>:
00361 
00362     PublicKey key;
00363     for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
00364     {
00365       //MIL << "[" << line << "]" << std::endl;
00366       str::smatch what;
00367       if(str::regex_match(line, what, rxColons, str::match_extra))
00368       {
00369         if ( what[1] == "pub" )
00370         {
00371           key.id = what[5];
00372           key.name = what[10];
00373           //return key;
00374         }
00375         else if ( what[1] == "fpr" )
00376         {
00377           key.fingerprint = what[10];
00378         }
00379         //dumpRegexpResults(what);
00380       }
00381     }
00382     prog.close();
00383     return key;
00384   }
00385 
00386   std::list<PublicKey> KeyRing::Impl::publicKeys(const Pathname &keyring)
00387   {
00388     const char* argv[] =
00389     {
00390       "gpg",
00391       "--no-default-keyring",
00392       "--quiet",
00393       "--list-public-keys",
00394       "--with-colons",
00395       "--with-fingerprint",
00396       "--no-tty",
00397       "--no-greeting",
00398       "--batch",
00399       "--status-fd",
00400       "1",
00401       "--homedir",
00402       keyring.asString().c_str(),
00403       NULL
00404     };
00405     std::list<PublicKey> keys;
00406 
00407     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00408     std::string line;
00409     int count = 0;
00410 
00411     str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
00412     str::regex rxColonsFpr("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
00413 
00414     for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
00415     {
00416       //MIL << line << std::endl;
00417       str::smatch what;
00418       if(str::regex_match(line, what, rxColons, str::match_extra))
00419       {
00420         PublicKey key;
00421         if ( what[1] == "pub" )
00422         {
00423           key.id = what[5];
00424           key.name = what[10];
00425 
00426           std::string line2;
00427           for(line2 = prog.receiveLine(); !line2.empty(); line2 = prog.receiveLine(), count++ )
00428           {
00429             str::smatch what2;
00430             if (str::regex_match(line2, what2, rxColonsFpr, str::match_extra))
00431             {
00432               if ( (what2[1] == "fpr") && (what2[1] != "pub") && (what2[1] !="sub"))
00433               {
00434                 key.fingerprint = what2[10];
00435                 break;
00436               }
00437             }
00438           }
00439           keys.push_back(key);
00440           MIL << "Found key " << "[" << key.id << "]" << " [" << key.name << "]" << " [" << key.fingerprint << "]" << std::endl;
00441         }
00442         //dumpRegexpResults(what);
00443       }
00444     }
00445     prog.close();
00446     return keys;
00447   }
00448 
00449   void KeyRing::Impl::importKey( const Pathname &keyfile, const Pathname &keyring)
00450   {
00451     const char* argv[] =
00452     {
00453       "gpg",
00454       "--no-default-keyring",
00455       "--quiet",
00456       "--no-tty",
00457       "--no-greeting",
00458       "--no-permission-warning",
00459       "--status-fd",
00460       "1",
00461       "--homedir",
00462       keyring.asString().c_str(),
00463       "--import",
00464       keyfile.asString().c_str(),
00465       NULL
00466     };
00467 
00468     int code;
00469     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00470     code = prog.close();
00471 
00472     //if ( code != 0 )
00473     //  ZYPP_THROW(Exception("failed to import key"));
00474   }
00475 
00476   void KeyRing::Impl::deleteKey( const std::string &id, const Pathname &keyring )
00477   {
00478     const char* argv[] =
00479     {
00480       "gpg",
00481       "--no-default-keyring",
00482       "--yes",
00483       "--quiet",
00484       "--no-tty",
00485       "--batch",
00486       "--status-fd",
00487       "1",
00488       "--homedir",
00489       keyring.asString().c_str(),
00490       "--delete-keys",
00491       id.c_str(),
00492       NULL
00493     };
00494 
00495     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00496 
00497     int code = prog.close();
00498     if ( code )
00499       ZYPP_THROW(Exception("Failed to delete key."));
00500     else
00501       MIL << "Deleted key " << id << " from keyring " << keyring << std::endl;
00502   }
00503 
00504 
00505   std::string KeyRing::Impl::readSignatureKeyId(const Pathname &signature )
00506   {
00507     MIL << "Deetermining key id if signature " << signature << std::endl;
00508     // HACK create a tmp keyring with no keys
00509     TmpDir dir;
00510     TmpFile fakeData;
00511     
00512     const char* argv[] =
00513     {
00514       "gpg",
00515       "--no-default-keyring",
00516       "--quiet",
00517       "--no-tty",
00518       "--no-greeting",
00519       "--batch",
00520       "--status-fd",
00521       "1",
00522       "--homedir",
00523       dir.path().asString().c_str(),
00524       "--verify",
00525       signature.asString().c_str(),
00526       fakeData.path().asString().c_str(),
00527       NULL
00528     };
00529 
00530     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00531 
00532     std::string line;
00533     int count = 0;
00534 
00535     str::regex rxNoKey("^\\[GNUPG:\\] NO_PUBKEY (.+)\n$");
00536     std::string id;
00537     for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
00538     {
00539       //MIL << "[" << line << "]" << std::endl;
00540       str::smatch what;
00541       if(str::regex_match(line, what, rxNoKey, str::match_extra))
00542       {
00543         if ( what.size() > 1 )
00544           id = what[1];
00545         //dumpRegexpResults(what);
00546       }
00547     }
00548     MIL << "Determined key id [" << id << "] for signature " << signature << std::endl;
00549     prog.close();
00550     return id;
00551   }
00552 
00553   bool KeyRing::Impl::verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring)
00554   {
00555     const char* argv[] =
00556     {
00557       "gpg",
00558       "--no-default-keyring",
00559       "--quiet",
00560       "--no-tty",
00561       "--batch",
00562       "--no-greeting",
00563       "--status-fd",
00564       "1",
00565       "--homedir",
00566       keyring.asString().c_str(),
00567       "--verify",
00568       signature.asString().c_str(),
00569       file.asString().c_str(),
00570       NULL
00571     };
00572 
00573     // no need to parse output for now
00574     //     [GNUPG:] SIG_ID yCc4u223XRJnLnVAIllvYbUd8mQ 2006-03-29 1143618744
00575     //     [GNUPG:] GOODSIG A84EDAE89C800ACA SuSE Package Signing Key <build@suse.de>
00576     //     gpg: Good signature from "SuSE Package Signing Key <build@suse.de>"
00577     //     [GNUPG:] VALIDSIG 79C179B2E1C820C1890F9994A84EDAE89C800ACA 2006-03-29 1143618744 0 3 0 17 2 00 79C179B2E1C820C1890F9994A84EDAE89C800ACA
00578     //     [GNUPG:] TRUST_UNDEFINED
00579 
00580     //     [GNUPG:] ERRSIG A84EDAE89C800ACA 17 2 00 1143618744 9
00581     //     [GNUPG:] NO_PUBKEY A84EDAE89C800ACA
00582 
00583     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00584 
00585     return (prog.close() == 0) ? true : false;
00586   }
00587 
00589 
00591   //
00592   //    CLASS NAME : KeyRing
00593   //
00595 
00597   //
00598   //    METHOD NAME : KeyRing::KeyRing
00599   //    METHOD TYPE : Ctor
00600   //
00601   KeyRing::KeyRing()
00602   : _pimpl( new Impl() )
00603   {}
00604 
00606   //
00607   //    METHOD NAME : KeyRing::KeyRing
00608   //    METHOD TYPE : Ctor
00609   //
00610   //KeyRing::KeyRing( const Pathname &general_kr, const Pathname &trusted_kr )
00611   //: _pimpl( new Impl(general_kr, trusted_kr) )
00612   //{}
00613 
00615   //
00616   //    METHOD NAME : KeyRing::~KeyRing
00617   //    METHOD TYPE : Dtor
00618   //
00619   KeyRing::~KeyRing()
00620   {}
00621 
00623   //
00624   // Forward to implementation:
00625   //
00627 
00628   void KeyRing::importKey( const Pathname &keyfile, bool trusted)
00629   {
00630     _pimpl->importKey(keyfile, trusted);
00631   }
00632 
00633   PublicKey KeyRing::readPublicKey( const Pathname &keyfile )
00634   {
00635     return _pimpl->readPublicKey(keyfile);
00636   }
00637 
00638   std::string KeyRing::readSignatureKeyId( const Pathname &signature )
00639   {
00640     return _pimpl->readSignatureKeyId(signature);
00641   }
00642 
00643   void KeyRing::deleteKey( const std::string &id, bool trusted )
00644   {
00645     _pimpl->deleteKey(id, trusted);
00646   }
00647 
00648   std::list<PublicKey> KeyRing::publicKeys()
00649   {
00650     return _pimpl->publicKeys();
00651   }
00652 
00653   std::list<PublicKey> KeyRing::trustedPublicKeys()
00654   {
00655     return _pimpl->trustedPublicKeys();
00656   }
00657 
00658   bool KeyRing::verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature)
00659   {
00660     return _pimpl->verifyFileSignatureWorkflow(file, filedesc, signature);
00661   }
00662 
00663   bool KeyRing::verifyFileSignature( const Pathname &file, const Pathname &signature)
00664   {
00665     return _pimpl->verifyFileSignature(file, signature);
00666   }
00667 
00668   bool KeyRing::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
00669   {
00670     return _pimpl->verifyFileTrustedSignature(file, signature);
00671   }
00672 
00673   void KeyRing::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
00674   {
00675     _pimpl->dumpPublicKey( id, trusted, stream);
00676   }
00677 
00679 } // namespace zypp

Generated on Mon Jun 5 19:10:32 2006 for zypp by  doxygen 1.4.6