1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/PublicKey.cc
17 #include "zypp/base/Gettext.h"
18 #include "zypp/base/String.h"
19 #include "zypp/base/Regex.h"
20 #include "zypp/PublicKey.h"
21 #include "zypp/ExternalProgram.h"
22 #include "zypp/TmpPath.h"
23 #include "zypp/PathInfo.h"
24 #include "zypp/base/Exception.h"
25 #include "zypp/base/LogTools.h"
26 #include "zypp/Date.h"
27 #include "zypp/TmpPath.h"
33 ///////////////////////////////////////////////////////////////////
35 { /////////////////////////////////////////////////////////////////
37 ///////////////////////////////////////////////////////////////////
38 /// \class PublicKeyData::Impl
39 /// \brief PublicKeyData implementation.
40 ///////////////////////////////////////////////////////////////////
41 struct PublicKeyData::Impl
45 std::string _fingerprint;
50 /** Offer default Impl. */
51 static shared_ptr<Impl> nullimpl()
53 static shared_ptr<Impl> _nullimpl( new Impl );
58 friend Impl * rwcowClone<Impl>( const Impl * rhs );
59 /** clone for RWCOW_pointer */
61 { return new Impl( *this ); }
63 ///////////////////////////////////////////////////////////////////
65 ///////////////////////////////////////////////////////////////////
66 /// class PublicKeyData
67 ///////////////////////////////////////////////////////////////////
69 PublicKeyData::PublicKeyData()
70 : _pimpl( Impl::nullimpl() )
73 PublicKeyData::~PublicKeyData()
76 PublicKeyData::operator bool() const
77 { return !_pimpl->_fingerprint.empty(); }
79 std::string PublicKeyData::id() const
80 { return _pimpl->_id; }
82 std::string PublicKeyData::name() const
83 { return _pimpl->_name; }
85 std::string PublicKeyData::fingerprint() const
86 { return _pimpl->_fingerprint; }
88 Date PublicKeyData::created() const
89 { return _pimpl->_created; }
91 Date PublicKeyData::expires() const
92 { return _pimpl->_expires; }
94 bool PublicKeyData::expired() const
95 { return( _pimpl->_expires && _pimpl->_expires < Date::now() ); }
97 int PublicKeyData::daysToLive() const
99 if ( _pimpl->_expires )
101 Date exp( _pimpl->_expires - Date::now() );
102 return exp < 0 ? exp / Date::day - 1 : exp / Date::day;
107 std::string PublicKeyData::expiresAsString() const
109 if ( !_pimpl->_expires )
110 { // translators: an annotation to a gpg keys expiry date
111 return _("(does not expire)");
113 std::string ret( _pimpl->_expires.asString() );
114 int ttl( daysToLive() );
119 { // translators: an annotation to a gpg keys expiry date
120 ret += _("(EXPIRED)");
123 { // translators: an annotation to a gpg keys expiry date
124 ret += _("(expires within 24h)");
127 { // translators: an annotation to a gpg keys expiry date
128 ret += str::form( _PL("(expires in %d day)", "(expires in %d days)", ttl ), ttl );
134 std::string PublicKeyData::gpgPubkeyVersion() const
135 { return _pimpl->_id.empty() ? _pimpl->_id : str::toLower( _pimpl->_id.substr(8,8) ); }
137 std::string PublicKeyData::gpgPubkeyRelease() const
138 { return _pimpl->_created ? str::hexstring( _pimpl->_created ).substr(2) : std::string(); }
140 std::string PublicKeyData::asString() const
142 return str::form( "[%s-%s] [%s] [%s] [TTL %d]",
144 gpgPubkeyRelease().c_str(),
145 _pimpl->_name.c_str(),
146 _pimpl->_fingerprint.c_str(),
150 std::ostream & dumpOn( std::ostream & str, const PublicKeyData & obj )
152 str << "[" << obj.name() << "]" << endl;
153 str << " fpr " << obj.fingerprint() << endl;
154 str << " id " << obj.id() << endl;
155 str << " cre " << Date::ValueType(obj.created()) << ' ' << obj.created() << endl;
156 str << " exp " << Date::ValueType(obj.expires()) << ' ' << obj.expiresAsString() << endl;
157 str << " ttl " << obj.daysToLive() << endl;
158 str << " rpm " << obj.gpgPubkeyVersion() << "-" << obj.gpgPubkeyRelease() << endl;
163 bool operator==( const PublicKeyData & lhs, const PublicKeyData & rhs )
164 { return ( lhs.fingerprint() == rhs.fingerprint() && lhs.created() == rhs.created() ); }
167 ///////////////////////////////////////////////////////////////////
168 /// \class PublicKeyScanner::Impl
169 /// \brief PublicKeyScanner implementation.
170 ///////////////////////////////////////////////////////////////////
171 struct PublicKeyScanner::Impl
173 std::vector<std::string> _words;
174 enum { pNONE, pPUB, pSIG, pFPR, pUID } _parseEntry;
177 : _parseEntry( pNONE )
180 void scan( std::string & line_r, std::list<PublicKeyData> & keys_r )
182 // pub:-:1024:17:A84EDAE89C800ACA:971961473:1214043198::-:SuSE Package Signing Key <build@suse.de>:
183 // fpr:::::::::79C179B2E1C820C1890F9994A84EDAE89C800ACA:
184 // sig:::17:A84EDAE89C800ACA:1087899198:::::[selfsig]::13x:
185 // sig:::17:9E40E310000AABA4:980442706::::[User ID not found]:10x:
186 // sig:::1:77B2E6003D25D3D9:980443247::::[User ID not found]:10x:
187 // sig:::17:A84EDAE89C800ACA:1318348291:::::[selfsig]::13x:
188 // sub:-:2048:16:197448E88495160C:971961490:1214043258::: [expires: 2008-06-21]
189 // sig:::17:A84EDAE89C800ACA:1087899258:::::[keybind]::18x:
190 if ( line_r.empty() )
193 // quick check for interesting entries
197 #define DOTEST( C1, C2, C3, E ) case C1: if ( line_r[1] == C2 && line_r[2] == C3 && line_r[3] == ':' ) _parseEntry = E; break
198 DOTEST( 'p', 'u', 'b', pPUB );
199 DOTEST( 's', 'i', 'g', pSIG );
200 DOTEST( 'f', 'p', 'r', pFPR );
201 DOTEST( 'u', 'i', 'd', pUID );
204 if ( _parseEntry == pNONE )
207 if ( line_r[line_r.size()-1] == '\n' )
208 line_r.erase( line_r.size()-1 );
209 // DBG << line_r << endl;
212 str::splitFields( line_r, std::back_inserter(_words), ":" );
214 PublicKeyData * key( &keys_r.back() );
216 switch ( _parseEntry )
219 keys_r.push_back( PublicKeyData() ); // reset upon new key
220 key = &keys_r.back();
221 key->_pimpl->_id = _words[4];
222 key->_pimpl->_name = str::replaceAll( _words[9], "\\x3a", ":" );
223 key->_pimpl->_created = Date(str::strtonum<Date::ValueType>(_words[5]));
224 key->_pimpl->_expires = Date(str::strtonum<Date::ValueType>(_words[6]));
228 // Update creation/modification date from signatures type "13x".
229 if ( _words[_words.size()-2] == "13x" )
231 Date cdate(str::strtonum<Date::ValueType>(_words[5]));
232 if ( key->_pimpl->_created < cdate )
233 key->_pimpl->_created = cdate;
238 if ( key->_pimpl->_fingerprint.empty() )
239 key->_pimpl->_fingerprint = _words[9];
243 if ( ! _words[9].empty() )
244 key->_pimpl->_name = str::replaceAll( _words[9], "\\x3a", ":" );
252 ///////////////////////////////////////////////////////////////////
254 ///////////////////////////////////////////////////////////////////
255 // class PublicKeyScanner
256 ///////////////////////////////////////////////////////////////////
258 PublicKeyScanner::PublicKeyScanner()
262 PublicKeyScanner::~PublicKeyScanner()
265 void PublicKeyScanner::scan( std::string line_r )
266 { _pimpl->scan( line_r, _keys ); }
269 ///////////////////////////////////////////////////////////////////
270 /// \class PublicKey::Impl
271 /// \brief PublicKey implementation.
272 ///////////////////////////////////////////////////////////////////
273 struct PublicKey::Impl
278 Impl( const Pathname & keyFile_r )
280 PathInfo info( keyFile_r );
281 MIL << "Taking pubkey from " << keyFile_r << " of size " << info.size() << " and sha1 " << filesystem::checksum(keyFile_r, "sha1") << endl;
283 if ( !info.isExist() )
284 ZYPP_THROW(Exception("Can't read public key from " + keyFile_r.asString() + ", file not found"));
286 if ( filesystem::hardlinkCopy( keyFile_r, _dataFile.path() ) != 0 )
287 ZYPP_THROW(Exception("Can't copy public key data from " + keyFile_r.asString() + " to " + _dataFile.path().asString() ));
292 Impl( const filesystem::TmpFile & sharedFile_r )
293 : _dataFile( sharedFile_r )
296 Impl( const filesystem::TmpFile & sharedFile_r, const PublicKeyData & keyData_r )
297 : _dataFile( sharedFile_r )
298 , _keyData( keyData_r )
302 WAR << "Invalid PublicKeyData supplied: scanning from file" << endl;
308 const PublicKeyData & keyData() const
311 Pathname path() const
312 { return _dataFile.path(); }
317 PathInfo info( _dataFile.path() );
318 MIL << "Reading pubkey from " << info.path() << " of size " << info.size() << " and sha1 " << filesystem::checksum(info.path(), "sha1") << endl;
320 static filesystem::TmpDir dir;
325 "--no-default-keyring",
327 "--with-fingerprint",
330 dir.path().asString().c_str(),
337 _dataFile.path().asString().c_str(),
340 ExternalProgram prog( argv, ExternalProgram::Discard_Stderr, false, -1, true );
342 PublicKeyScanner scanner;
343 for ( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
345 scanner.scan( line );
349 switch ( scanner._keys.size() )
352 ZYPP_THROW( BadKeyException( "File " + _dataFile.path().asString() + " doesn't contain public key data" , _dataFile.path() ) );
360 WAR << "File " << _dataFile.path().asString() << " contains multiple keys: " << scanner._keys << endl;
364 _keyData = scanner._keys.back();
365 MIL << "Read pubkey from " << info.path() << ": " << _keyData << endl;
369 filesystem::TmpFile _dataFile;
370 PublicKeyData _keyData;
373 /** Offer default Impl. */
374 static shared_ptr<Impl> nullimpl()
376 static shared_ptr<Impl> _nullimpl( new Impl );
381 friend Impl * rwcowClone<Impl>( const Impl * rhs );
382 /** clone for RWCOW_pointer */
384 { return new Impl( *this ); }
386 ///////////////////////////////////////////////////////////////////
388 ///////////////////////////////////////////////////////////////////
390 ///////////////////////////////////////////////////////////////////
391 PublicKey::PublicKey()
392 : _pimpl( Impl::nullimpl() )
395 PublicKey::PublicKey( const Pathname & file )
396 : _pimpl( new Impl( file ) )
399 PublicKey::PublicKey( const filesystem::TmpFile & sharedfile )
400 : _pimpl( new Impl( sharedfile ) )
403 PublicKey::PublicKey( const filesystem::TmpFile & sharedfile, const PublicKeyData & keydata )
404 : _pimpl( new Impl( sharedfile, keydata ) )
407 PublicKey::~PublicKey()
410 const PublicKeyData & PublicKey::keyData() const
411 { return _pimpl->keyData(); }
413 Pathname PublicKey::path() const
414 { return _pimpl->path(); }
416 std::string PublicKey::id() const
417 { return keyData().id(); }
419 std::string PublicKey::name() const
420 { return keyData().name(); }
422 std::string PublicKey::fingerprint() const
423 { return keyData().fingerprint(); }
425 Date PublicKey::created() const
426 { return keyData().created(); }
428 Date PublicKey::expires() const
429 { return keyData().expires(); }
431 bool PublicKey::expired() const
432 { return keyData().expired(); }
434 int PublicKey::daysToLive() const
435 { return keyData().daysToLive(); }
437 std::string PublicKey::expiresAsString() const
438 { return keyData().expiresAsString(); }
440 std::string PublicKey::gpgPubkeyVersion() const
441 { return keyData().gpgPubkeyVersion(); }
443 std::string PublicKey::gpgPubkeyRelease() const
444 { return keyData().gpgPubkeyRelease(); }
446 std::string PublicKey::asString() const
447 { return keyData().asString(); }
449 bool PublicKey::operator==( PublicKey rhs ) const
450 { return rhs.keyData() == keyData(); }
452 bool PublicKey::operator==( std::string sid ) const
453 { return sid == id(); }
455 std::ostream & dumpOn( std::ostream & str, const PublicKey & obj )
456 { return dumpOn( str, obj.keyData() ); }
458 /////////////////////////////////////////////////////////////////
460 ///////////////////////////////////////////////////////////////////