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

Generated on Tue Nov 28 16:49:29 2006 for zypp by  doxygen 1.5.0