PublicKey.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <climits>
00013 
00014 #include <iostream>
00015 #include <vector>
00016 
00017 #include "zypp/base/Gettext.h"
00018 #include "zypp/base/String.h"
00019 #include "zypp/base/Regex.h"
00020 #include "zypp/PublicKey.h"
00021 #include "zypp/ExternalProgram.h"
00022 #include "zypp/TmpPath.h"
00023 #include "zypp/PathInfo.h"
00024 #include "zypp/base/Exception.h"
00025 #include "zypp/base/LogTools.h"
00026 #include "zypp/Date.h"
00027 #include "zypp/TmpPath.h"
00028 
00029 #include <ctime>
00030 
00031 using std::endl;
00032 
00034 namespace zypp
00035 { 
00036 
00041   struct PublicKeyData::Impl
00042   {
00043     std::string _id;
00044     std::string _name;
00045     std::string _fingerprint;
00046     Date        _created;
00047     Date        _expires;
00048 
00049   public:
00051     static shared_ptr<Impl> nullimpl()
00052     {
00053       static shared_ptr<Impl> _nullimpl( new Impl );
00054       return _nullimpl;
00055     }
00056 
00057   private:
00058     friend Impl * rwcowClone<Impl>( const Impl * rhs );
00060     Impl * clone() const
00061     { return new Impl( *this ); }
00062   };
00064 
00068 
00069   PublicKeyData::PublicKeyData()
00070     : _pimpl( Impl::nullimpl() )
00071   {}
00072 
00073   PublicKeyData::~PublicKeyData()
00074   {}
00075 
00076   bool PublicKeyData::boolTest() const
00077   { return !_pimpl->_fingerprint.empty(); }
00078 
00079   std::string PublicKeyData::id() const
00080   { return _pimpl->_id; }
00081 
00082   std::string PublicKeyData::name() const
00083   { return _pimpl->_name; }
00084 
00085   std::string PublicKeyData::fingerprint() const
00086   { return _pimpl->_fingerprint; }
00087 
00088   Date PublicKeyData::created() const
00089   { return _pimpl->_created; }
00090 
00091   Date PublicKeyData::expires() const
00092   { return _pimpl->_expires; }
00093 
00094   bool PublicKeyData::expired() const
00095   { return( _pimpl->_expires && _pimpl->_expires < Date::now() ); }
00096 
00097   int PublicKeyData::daysToLive() const
00098   {
00099     if ( _pimpl->_expires )
00100     {
00101       Date exp( _pimpl->_expires - Date::now() );
00102       return exp < 0 ? exp / Date::day - 1 : exp / Date::day;
00103     }
00104     return INT_MAX;
00105   }
00106 
00107   std::string PublicKeyData::expiresAsString() const
00108   {
00109     if ( !_pimpl->_expires )
00110     { // translators: an annotation to a gpg keys expiry date
00111       return _("(does not expire)");
00112     }
00113     std::string ret( _pimpl->_expires.asString() );
00114     int ttl( daysToLive() );
00115     if ( ttl <= 90 )
00116     {
00117       ret += " ";
00118       if ( ttl < 0 )
00119       { // translators: an annotation to a gpg keys expiry date
00120         ret += _("(EXPIRED)");
00121       }
00122       else if ( ttl == 0 )
00123       { // translators: an annotation to a gpg keys expiry date
00124         ret += _("(expires within 24h)");
00125       }
00126       else
00127       { // translators: an annotation to a gpg keys expiry date
00128         ret += str::form( _PL("(expires in %d day)", "(expires in %d days)", ttl ), ttl );
00129       }
00130     }
00131     return ret;
00132   }
00133 
00134   std::string PublicKeyData::gpgPubkeyVersion() const
00135   { return _pimpl->_id.empty() ? _pimpl->_id : str::toLower( _pimpl->_id.substr(8,8) ); }
00136 
00137   std::string PublicKeyData::gpgPubkeyRelease() const
00138   { return _pimpl->_created ? str::hexstring( _pimpl->_created ).substr(2) : std::string(); }
00139 
00140   std::string PublicKeyData::asString() const
00141   {
00142     return str::form( "[%s-%s] [%s] [%s] [TTL %d]",
00143                       _pimpl->_id.c_str(),
00144                       gpgPubkeyRelease().c_str(),
00145                       _pimpl->_name.c_str(),
00146                       _pimpl->_fingerprint.c_str(),
00147                       daysToLive() );
00148   }
00149 
00150   std::ostream & dumpOn( std::ostream & str, const PublicKeyData & obj )
00151   {
00152     str << "[" << obj.name() << "]" << endl;
00153     str << "  fpr " << obj.fingerprint() << endl;
00154     str << "   id " << obj.id() << endl;
00155     str << "  cre " << Date::ValueType(obj.created()) << ' ' << obj.created() << endl;
00156     str << "  exp " << Date::ValueType(obj.expires()) << ' ' << obj.expiresAsString() << endl;
00157     str << "  ttl " << obj.daysToLive() << endl;
00158     str << "  rpm " << obj.gpgPubkeyVersion() << "-" << obj.gpgPubkeyRelease() << endl;
00159     str << "]";
00160     return str;
00161   }
00162 
00163   bool operator==( const PublicKeyData & lhs, const PublicKeyData & rhs )
00164   { return ( lhs.fingerprint() == rhs.fingerprint() && lhs.created() == rhs.created() ); }
00165 
00166 
00171   struct PublicKeyScanner::Impl
00172   {
00173     std::vector<std::string>                    _words;
00174     enum { pNONE, pPUB, pSIG, pFPR, pUID }      _parseEntry;
00175 
00176    Impl()
00177       : _parseEntry( pNONE )
00178     {}
00179 
00180     void scan( std::string & line_r, std::list<PublicKeyData> & keys_r )
00181     {
00182       // pub:-:1024:17:A84EDAE89C800ACA:971961473:1214043198::-:SuSE Package Signing Key <build@suse.de>:
00183       // fpr:::::::::79C179B2E1C820C1890F9994A84EDAE89C800ACA:
00184       // sig:::17:A84EDAE89C800ACA:1087899198:::::[selfsig]::13x:
00185       // sig:::17:9E40E310000AABA4:980442706::::[User ID not found]:10x:
00186       // sig:::1:77B2E6003D25D3D9:980443247::::[User ID not found]:10x:
00187       // sig:::17:A84EDAE89C800ACA:1318348291:::::[selfsig]::13x:
00188       // sub:-:2048:16:197448E88495160C:971961490:1214043258::: [expires: 2008-06-21]
00189       // sig:::17:A84EDAE89C800ACA:1087899258:::::[keybind]::18x:
00190       if ( line_r.empty() )
00191         return;
00192 
00193       // quick check for interesting entries
00194       _parseEntry = pNONE;
00195       switch ( line_r[0] )
00196       {
00197         #define DOTEST( C1, C2, C3, E ) case C1: if ( line_r[1] == C2 && line_r[2] == C3 && line_r[3] == ':' ) _parseEntry = E; break
00198         DOTEST( 'p', 'u', 'b', pPUB );
00199         DOTEST( 's', 'i', 'g', pSIG );
00200         DOTEST( 'f', 'p', 'r', pFPR );
00201         DOTEST( 'u', 'i', 'd', pUID );
00202         #undef DOTEST
00203       }
00204       if ( _parseEntry == pNONE )
00205         return;
00206 
00207       if ( line_r[line_r.size()-1] == '\n' )
00208         line_r.erase( line_r.size()-1 );
00209       // DBG << line_r << endl;
00210 
00211       _words.clear();
00212       str::splitFields( line_r, std::back_inserter(_words), ":" );
00213 
00214       PublicKeyData * key( &keys_r.back() );
00215 
00216       switch ( _parseEntry )
00217       {
00218         case pPUB:
00219           keys_r.push_back( PublicKeyData() );  // reset upon new key
00220           key = &keys_r.back();
00221           key->_pimpl->_id      = _words[4];
00222           key->_pimpl->_name    = str::replaceAll( _words[9], "\\x3a", ":" );
00223           key->_pimpl->_created = Date(str::strtonum<Date::ValueType>(_words[5]));
00224           key->_pimpl->_expires = Date(str::strtonum<Date::ValueType>(_words[6]));
00225           break;
00226 
00227         case pSIG:
00228           // Update creation/modification date from signatures type "13x".
00229           if ( _words[_words.size()-2] == "13x" )
00230           {
00231             Date cdate(str::strtonum<Date::ValueType>(_words[5]));
00232             if ( key->_pimpl->_created < cdate )
00233               key->_pimpl->_created = cdate;
00234           }
00235           break;
00236 
00237         case pFPR:
00238           if ( key->_pimpl->_fingerprint.empty() )
00239             key->_pimpl->_fingerprint = _words[9];
00240           break;
00241 
00242         case pUID:
00243           if ( ! _words[9].empty() )
00244             key->_pimpl->_name = str::replaceAll( _words[9], "\\x3a", ":" );
00245           break;
00246 
00247         case pNONE:
00248           break;
00249       }
00250     }
00251   };
00253 
00255   // class PublicKeyScanner
00257 
00258   PublicKeyScanner::PublicKeyScanner()
00259     : _pimpl( new Impl )
00260   {}
00261 
00262   PublicKeyScanner::~PublicKeyScanner()
00263   {}
00264 
00265   void PublicKeyScanner::scan( std::string line_r )
00266   { _pimpl->scan( line_r, _keys ); }
00267 
00268 
00273   struct PublicKey::Impl
00274   {
00275     Impl()
00276     {}
00277 
00278     Impl( const Pathname & keyFile_r )
00279     {
00280       PathInfo info( keyFile_r );
00281       MIL << "Taking pubkey from " << keyFile_r << " of size " << info.size() << " and sha1 " << filesystem::checksum(keyFile_r, "sha1") << endl;
00282 
00283       if ( !info.isExist() )
00284         ZYPP_THROW(Exception("Can't read public key from " + keyFile_r.asString() + ", file not found"));
00285 
00286       if ( filesystem::hardlinkCopy( keyFile_r, _dataFile.path() ) != 0 )
00287         ZYPP_THROW(Exception("Can't copy public key data from " + keyFile_r.asString() + " to " +  _dataFile.path().asString() ));
00288 
00289       readFromFile();
00290     }
00291 
00292     Impl( const filesystem::TmpFile & sharedFile_r )
00293       : _dataFile( sharedFile_r )
00294     { readFromFile(); }
00295 
00296     Impl( const filesystem::TmpFile & sharedFile_r, const PublicKeyData & keyData_r )
00297       : _dataFile( sharedFile_r )
00298       , _keyData( keyData_r )
00299     {
00300       if ( ! keyData_r )
00301       {
00302         WAR << "Invalid PublicKeyData supplied: scanning from file" << endl;
00303         readFromFile();
00304       }
00305     }
00306 
00307     public:
00308       const PublicKeyData & keyData() const
00309       { return _keyData; }
00310 
00311       Pathname path() const
00312       { return _dataFile.path(); }
00313 
00314       const std::list<PublicKeyData> & hiddenKeys() const
00315       { return _hiddenKeys; }
00316 
00317     protected:
00318       void readFromFile()
00319       {
00320         PathInfo info( _dataFile.path() );
00321         MIL << "Reading pubkey from " << info.path() << " of size " << info.size() << " and sha1 " << filesystem::checksum(info.path(), "sha1") << endl;
00322 
00323         static filesystem::TmpDir dir;
00324         const char* argv[] =
00325         {
00326           "gpg",
00327           "-v",
00328           "--no-default-keyring",
00329           "--fixed-list-mode",
00330           "--with-fingerprint",
00331           "--with-colons",
00332           "--homedir",
00333           dir.path().asString().c_str(),
00334           "--quiet",
00335           "--no-tty",
00336           "--no-greeting",
00337           "--batch",
00338           "--status-fd",
00339           "1",
00340           _dataFile.path().asString().c_str(),
00341           NULL
00342         };
00343         ExternalProgram prog( argv, ExternalProgram::Discard_Stderr, false, -1, true );
00344 
00345         PublicKeyScanner scanner;
00346         for ( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
00347         {
00348           scanner.scan( line );
00349         }
00350         prog.close();
00351 
00352         switch ( scanner._keys.size() )
00353         {
00354           case 0:
00355             ZYPP_THROW( BadKeyException( "File " + _dataFile.path().asString() + " doesn't contain public key data" , _dataFile.path() ) );
00356             break;
00357 
00358           case 1:
00359             // ok.
00360             _keyData = scanner._keys.back();
00361             _hiddenKeys.clear();
00362             break;
00363 
00364           default:
00365             WAR << "File " << _dataFile.path().asString() << " contains multiple keys: " <<  scanner._keys << endl;
00366             _keyData = scanner._keys.back();
00367             scanner._keys.pop_back();
00368             _hiddenKeys.swap( scanner._keys );
00369             break;
00370         }
00371 
00372         MIL << "Read pubkey from " << info.path() << ": " << _keyData << endl;
00373       }
00374 
00375     private:
00376       filesystem::TmpFile       _dataFile;
00377       PublicKeyData             _keyData;
00378       std::list<PublicKeyData>  _hiddenKeys;
00379 
00380     public:
00382       static shared_ptr<Impl> nullimpl()
00383       {
00384         static shared_ptr<Impl> _nullimpl( new Impl );
00385         return _nullimpl;
00386       }
00387 
00388     private:
00389       friend Impl * rwcowClone<Impl>( const Impl * rhs );
00391       Impl * clone() const
00392       { return new Impl( *this ); }
00393   };
00395 
00397   // class PublicKey
00399   PublicKey::PublicKey()
00400   : _pimpl( Impl::nullimpl() )
00401   {}
00402 
00403   PublicKey::PublicKey( const Pathname & file )
00404   : _pimpl( new Impl( file ) )
00405   {}
00406 
00407   PublicKey::PublicKey( const filesystem::TmpFile & sharedfile )
00408   : _pimpl( new Impl( sharedfile ) )
00409   {}
00410 
00411   PublicKey::PublicKey( const filesystem::TmpFile & sharedfile, const PublicKeyData & keydata )
00412   : _pimpl( new Impl( sharedfile, keydata ) )
00413   {}
00414 
00415   PublicKey::~PublicKey()
00416   {}
00417 
00418   const PublicKeyData & PublicKey::keyData() const
00419   { return _pimpl->keyData(); }
00420 
00421   Pathname PublicKey::path() const
00422   { return _pimpl->path(); }
00423 
00424   const std::list<PublicKeyData> & PublicKey::hiddenKeys() const
00425   { return _pimpl->hiddenKeys(); }
00426 
00427   std::string PublicKey::id() const
00428   { return keyData().id(); }
00429 
00430   std::string PublicKey::name() const
00431   { return keyData().name(); }
00432 
00433   std::string PublicKey::fingerprint() const
00434   { return keyData().fingerprint(); }
00435 
00436   Date PublicKey::created() const
00437   { return keyData().created(); }
00438 
00439   Date PublicKey::expires() const
00440   { return keyData().expires(); }
00441 
00442   bool PublicKey::expired() const
00443   { return keyData().expired(); }
00444 
00445   int PublicKey::daysToLive() const
00446   { return keyData().daysToLive(); }
00447 
00448   std::string PublicKey::expiresAsString() const
00449   { return keyData().expiresAsString(); }
00450 
00451   std::string PublicKey::gpgPubkeyVersion() const
00452   { return keyData().gpgPubkeyVersion(); }
00453 
00454   std::string PublicKey::gpgPubkeyRelease() const
00455   { return keyData().gpgPubkeyRelease(); }
00456 
00457   std::string PublicKey::asString() const
00458   { return keyData().asString(); }
00459 
00460   bool PublicKey::operator==( PublicKey rhs ) const
00461   { return rhs.keyData() == keyData(); }
00462 
00463   bool PublicKey::operator==( std::string sid ) const
00464   { return sid == id(); }
00465 
00466   std::ostream & dumpOn( std::ostream & str, const PublicKey & obj )
00467   { return dumpOn( str, obj.keyData() ); }
00468 
00470 } // namespace zypp

Generated on Tue May 5 14:43:18 2015 for libzypp by  doxygen 1.5.6