libzypp  16.1.1
PublicKey.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include <climits>
13 
14 #include <iostream>
15 #include <vector>
16 
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"
28 
29 #include <ctime>
30 
32 #define GPG_BINARY "/usr/bin/gpg2"
33 
34 using std::endl;
35 
37 namespace zypp
38 {
39 
45  {
46  std::string _id;
47  std::string _name;
48  std::string _fingerprint;
51 
52  public:
54  static shared_ptr<Impl> nullimpl()
55  {
56  static shared_ptr<Impl> _nullimpl( new Impl );
57  return _nullimpl;
58  }
59 
60  private:
61  friend Impl * rwcowClone<Impl>( const Impl * rhs );
63  Impl * clone() const
64  { return new Impl( *this ); }
65  };
67 
71 
73  : _pimpl( Impl::nullimpl() )
74  {}
75 
77  {}
78 
79  PublicKeyData::operator bool() const
80  { return !_pimpl->_fingerprint.empty(); }
81 
82  std::string PublicKeyData::id() const
83  { return _pimpl->_id; }
84 
85  std::string PublicKeyData::name() const
86  { return _pimpl->_name; }
87 
88  std::string PublicKeyData::fingerprint() const
89  { return _pimpl->_fingerprint; }
90 
92  { return _pimpl->_created; }
93 
95  { return _pimpl->_expires; }
96 
98  { return( _pimpl->_expires && _pimpl->_expires < Date::now() ); }
99 
101  {
102  if ( _pimpl->_expires )
103  {
104  Date exp( _pimpl->_expires - Date::now() );
105  int ret = exp / Date::day;
106  if ( exp < 0 ) ret -= 1;
107  return ret;
108  }
109  return INT_MAX;
110  }
111 
112  std::string PublicKeyData::expiresAsString() const
113  {
114  if ( !_pimpl->_expires )
115  { // translators: an annotation to a gpg keys expiry date
116  return _("(does not expire)");
117  }
118  std::string ret( _pimpl->_expires.asString() );
119  int ttl( daysToLive() );
120  if ( ttl <= 90 )
121  {
122  ret += " ";
123  if ( ttl < 0 )
124  { // translators: an annotation to a gpg keys expiry date
125  ret += _("(EXPIRED)");
126  }
127  else if ( ttl == 0 )
128  { // translators: an annotation to a gpg keys expiry date
129  ret += _("(expires within 24h)");
130  }
131  else
132  { // translators: an annotation to a gpg keys expiry date
133  ret += str::form( PL_("(expires in %d day)", "(expires in %d days)", ttl ), ttl );
134  }
135  }
136  return ret;
137  }
138 
140  { return _pimpl->_id.empty() ? _pimpl->_id : str::toLower( _pimpl->_id.substr(8,8) ); }
141 
143  { return _pimpl->_created ? str::hexstring( _pimpl->_created ).substr(2) : std::string(); }
144 
145  std::string PublicKeyData::asString() const
146  {
147  return str::form( "[%s-%s] [%s] [%s] [TTL %d]",
148  _pimpl->_id.c_str(),
149  gpgPubkeyRelease().c_str(),
150  _pimpl->_name.c_str(),
151  _pimpl->_fingerprint.c_str(),
152  daysToLive() );
153  }
154 
155  std::ostream & dumpOn( std::ostream & str, const PublicKeyData & obj )
156  {
157  str << "[" << obj.name() << "]" << endl;
158  str << " fpr " << obj.fingerprint() << endl;
159  str << " id " << obj.id() << endl;
160  str << " cre " << Date::ValueType(obj.created()) << ' ' << obj.created() << endl;
161  str << " exp " << Date::ValueType(obj.expires()) << ' ' << obj.expiresAsString() << endl;
162  str << " ttl " << obj.daysToLive() << endl;
163  str << " rpm " << obj.gpgPubkeyVersion() << "-" << obj.gpgPubkeyRelease() << endl;
164  str << "]";
165  return str;
166  }
167 
168  bool operator==( const PublicKeyData & lhs, const PublicKeyData & rhs )
169  { return ( lhs.fingerprint() == rhs.fingerprint() && lhs.created() == rhs.created() ); }
170 
171 
177  {
178  std::vector<std::string> _words;
179  enum { pNONE, pPUB, pSIG, pFPR, pUID } _parseEntry;
180  bool _parseOff; // no 'sub:' key parsing
181 
183  : _parseEntry( pNONE )
184  , _parseOff( false )
185  {}
186 
187  void scan( std::string & line_r, std::list<PublicKeyData> & keys_r )
188  {
189  // pub:-:1024:17:A84EDAE89C800ACA:971961473:1214043198::-:SuSE Package Signing Key <build@suse.de>:
190  // fpr:::::::::79C179B2E1C820C1890F9994A84EDAE89C800ACA:
191  // sig:::17:A84EDAE89C800ACA:1087899198:::::[selfsig]::13x:
192  // sig:::17:9E40E310000AABA4:980442706::::[User ID not found]:10x:
193  // sig:::1:77B2E6003D25D3D9:980443247::::[User ID not found]:10x:
194  // sig:::17:A84EDAE89C800ACA:1318348291:::::[selfsig]::13x:
195  // sub:-:2048:16:197448E88495160C:971961490:1214043258::: [expires: 2008-06-21]
196  // sig:::17:A84EDAE89C800ACA:1087899258:::::[keybind]::18x:
197  if ( line_r.empty() )
198  return;
199 
200  // quick check for interesting entries, no parsing in subkeys
201  _parseEntry = pNONE;
202  switch ( line_r[0] )
203  {
204  case 'p':
205  if ( line_r[1] == 'u' && line_r[2] == 'b' && line_r[3] == ':' )
206  {
207  _parseEntry = pPUB;
208  _parseOff = false;
209  }
210  break;
211 
212  case 'f':
213  if ( line_r[1] == 'p' && line_r[2] == 'r' && line_r[3] == ':' )
214  _parseEntry = pFPR;
215  break;
216 
217  case 'u':
218  if ( line_r[1] == 'i' && line_r[2] == 'd' && line_r[3] == ':' )
219  _parseEntry = pUID;
220  break;
221 
222  case 's':
223  if ( line_r[1] == 'i' && line_r[2] == 'g' && line_r[3] == ':' )
224  _parseEntry = pSIG;
225  else if ( line_r[1] == 'u' && line_r[2] == 'b' && line_r[3] == ':' )
226  _parseOff = true;
227  break;
228 
229  default:
230  return;
231  }
232  if ( _parseOff || _parseEntry == pNONE )
233  return;
234 
235  if ( line_r[line_r.size()-1] == '\n' )
236  line_r.erase( line_r.size()-1 );
237  // DBG << line_r << endl;
238 
239  _words.clear();
240  str::splitFields( line_r, std::back_inserter(_words), ":" );
241 
242  PublicKeyData * key( &keys_r.back() );
243 
244  switch ( _parseEntry )
245  {
246  case pPUB:
247  keys_r.push_back( PublicKeyData() ); // reset upon new key
248  key = &keys_r.back();
249  key->_pimpl->_id = _words[4];
250  key->_pimpl->_name = str::replaceAll( _words[9], "\\x3a", ":" );
251  key->_pimpl->_created = Date(str::strtonum<Date::ValueType>(_words[5]));
252  key->_pimpl->_expires = Date(str::strtonum<Date::ValueType>(_words[6]));
253  break;
254 
255  case pSIG:
256  // Update creation/modification date from signatures type "13x".
257  if ( ( _words.size() > 10 && _words[10] == "13x" )
258  || ( _words.size() > 12 && _words[12] == "13x" ) )
259  {
260  Date cdate(str::strtonum<Date::ValueType>(_words[5]));
261  if ( key->_pimpl->_created < cdate )
262  key->_pimpl->_created = cdate;
263  }
264  break;
265 
266  case pFPR:
267  if ( key->_pimpl->_fingerprint.empty() )
268  key->_pimpl->_fingerprint = _words[9];
269  break;
270 
271  case pUID:
272  if ( ! _words[9].empty() )
273  key->_pimpl->_name = str::replaceAll( _words[9], "\\x3a", ":" );
274  break;
275 
276  case pNONE:
277  break; // intentionally no default:
278  }
279  }
280  };
282 
284  // class PublicKeyScanner
286 
288  : _pimpl( new Impl )
289  {}
290 
292  {}
293 
294  void PublicKeyScanner::scan( std::string line_r )
295  { _pimpl->scan( line_r, _keys ); }
296 
297 
303  {
305  {}
306 
307  Impl( const Pathname & keyFile_r )
308  {
309  PathInfo info( keyFile_r );
310  MIL << "Taking pubkey from " << keyFile_r << " of size " << info.size() << " and sha1 " << filesystem::checksum(keyFile_r, "sha1") << endl;
311 
312  if ( !info.isExist() )
313  ZYPP_THROW(Exception("Can't read public key from " + keyFile_r.asString() + ", file not found"));
314 
315  if ( filesystem::hardlinkCopy( keyFile_r, _dataFile.path() ) != 0 )
316  ZYPP_THROW(Exception("Can't copy public key data from " + keyFile_r.asString() + " to " + _dataFile.path().asString() ));
317 
318  readFromFile();
319  }
320 
321  Impl( const filesystem::TmpFile & sharedFile_r )
322  : _dataFile( sharedFile_r )
323  { readFromFile(); }
324 
325  Impl( const filesystem::TmpFile & sharedFile_r, const PublicKeyData & keyData_r )
326  : _dataFile( sharedFile_r )
327  , _keyData( keyData_r )
328  {
329  if ( ! keyData_r )
330  {
331  WAR << "Invalid PublicKeyData supplied: scanning from file" << endl;
332  readFromFile();
333  }
334  }
335 
336  public:
337  const PublicKeyData & keyData() const
338  { return _keyData; }
339 
340  Pathname path() const
341  { return _dataFile.path(); }
342 
343  const std::list<PublicKeyData> & hiddenKeys() const
344  { return _hiddenKeys; }
345 
346  protected:
348  {
349  PathInfo info( _dataFile.path() );
350  MIL << "Reading pubkey from " << info.path() << " of size " << info.size() << " and sha1 " << filesystem::checksum(info.path(), "sha1") << endl;
351 
352  static filesystem::TmpDir dir;
353  std::string tmppath( dir.path().asString() );
354  std::string datapath( _dataFile.path().asString() );
355 
356  const char* argv[] =
357  {
358  GPG_BINARY,
359  "-v",
360  "--no-default-keyring",
361  "--fixed-list-mode",
362  "--with-fingerprint",
363  "--with-colons",
364  "--homedir",
365  tmppath.c_str(),
366  "--quiet",
367  "--no-tty",
368  "--no-greeting",
369  "--batch",
370  "--status-fd", "1",
371  datapath.c_str(),
372  NULL
373  };
374  ExternalProgram prog( argv, ExternalProgram::Discard_Stderr, false, -1, true );
375 
376  PublicKeyScanner scanner;
377  for ( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
378  {
379  scanner.scan( line );
380  }
381  int ret = prog.close();
382 
383  switch ( scanner._keys.size() )
384  {
385  case 0:
386  if ( ret == 129 )
387  ZYPP_THROW( Exception( std::string("Can't read public key data: ") + GPG_BINARY + " is not installed!" ) );
388  else
389  ZYPP_THROW( BadKeyException( "File " + _dataFile.path().asString() + " doesn't contain public key data" , _dataFile.path() ) );
390  break;
391 
392  case 1:
393  // ok.
394  _keyData = scanner._keys.back();
395  _hiddenKeys.clear();
396  break;
397 
398  default:
399  WAR << "File " << _dataFile.path().asString() << " contains multiple keys: " << scanner._keys << endl;
400  _keyData = scanner._keys.back();
401  scanner._keys.pop_back();
402  _hiddenKeys.swap( scanner._keys );
403  break;
404  }
405 
406  MIL << "Read pubkey from " << info.path() << ": " << _keyData << endl;
407  }
408 
409  private:
412  std::list<PublicKeyData> _hiddenKeys;
413 
414  public:
416  static shared_ptr<Impl> nullimpl()
417  {
418  static shared_ptr<Impl> _nullimpl( new Impl );
419  return _nullimpl;
420  }
421 
422  private:
423  friend Impl * rwcowClone<Impl>( const Impl * rhs );
425  Impl * clone() const
426  { return new Impl( *this ); }
427  };
429 
431  // class PublicKey
434  : _pimpl( Impl::nullimpl() )
435  {}
436 
437  PublicKey::PublicKey( const Pathname & file )
438  : _pimpl( new Impl( file ) )
439  {}
440 
442  : _pimpl( new Impl( sharedfile ) )
443  {}
444 
445  PublicKey::PublicKey( const filesystem::TmpFile & sharedfile, const PublicKeyData & keydata )
446  : _pimpl( new Impl( sharedfile, keydata ) )
447  {}
448 
450  {}
451 
453  { return _pimpl->keyData(); }
454 
455  Pathname PublicKey::path() const
456  { return _pimpl->path(); }
457 
458  const std::list<PublicKeyData> & PublicKey::hiddenKeys() const
459  { return _pimpl->hiddenKeys(); }
460 
461  std::string PublicKey::id() const
462  { return keyData().id(); }
463 
464  std::string PublicKey::name() const
465  { return keyData().name(); }
466 
467  std::string PublicKey::fingerprint() const
468  { return keyData().fingerprint(); }
469 
471  { return keyData().created(); }
472 
474  { return keyData().expires(); }
475 
476  bool PublicKey::expired() const
477  { return keyData().expired(); }
478 
480  { return keyData().daysToLive(); }
481 
482  std::string PublicKey::expiresAsString() const
483  { return keyData().expiresAsString(); }
484 
485  std::string PublicKey::gpgPubkeyVersion() const
486  { return keyData().gpgPubkeyVersion(); }
487 
488  std::string PublicKey::gpgPubkeyRelease() const
489  { return keyData().gpgPubkeyRelease(); }
490 
491  std::string PublicKey::asString() const
492  { return keyData().asString(); }
493 
494  bool PublicKey::operator==( const PublicKey & rhs ) const
495  { return rhs.keyData() == keyData(); }
496 
497  bool PublicKey::operator==( const std::string & sid ) const
498  { return sid == id(); }
499 
500  std::ostream & dumpOn( std::ostream & str, const PublicKey & obj )
501  { return dumpOn( str, obj.keyData() ); }
502 
504 } // namespace zypp
std::string name() const
Key name.
Definition: PublicKey.cc:85
static const ValueType day
Definition: Date.h:44
Date expires() const
Expiry date, or Date() if the key never expires.
Definition: PublicKey.cc:94
Interface to gettext.
#define MIL
Definition: Logger.h:64
Impl(const filesystem::TmpFile &sharedFile_r, const PublicKeyData &keyData_r)
Definition: PublicKey.cc:325
std::string gpgPubkeyRelease() const
Gpg-pubkey release as computed by rpm (hexencoded created)
Definition: PublicKey.cc:142
int daysToLive() const
Number of days (24h) until the key expires (or since it exired).
Definition: PublicKey.cc:100
#define GPG_BINARY
Definition: PublicKey.cc:32
std::list< PublicKeyData > _hiddenKeys
Definition: PublicKey.cc:412
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:321
int daysToLive() const
Definition: PublicKey.cc:479
std::list< PublicKeyData > _keys
Extracted keys.
Definition: PublicKey.h:188
Impl * clone() const
clone for RWCOW_pointer
Definition: PublicKey.cc:63
std::string _fingerprint
Definition: PublicKey.cc:48
Class representing one GPG Public Keys data.
Definition: PublicKey.h:74
Exception thrown when the supplied key is not a valid gpg key.
Definition: PublicKey.h:39
const std::list< PublicKeyData > & hiddenKeys() const
Additional keys data in case the ASCII armored blob containes multiple keys.
Definition: PublicKey.cc:458
Date expires() const
Definition: PublicKey.cc:473
std::string asString() const
Definition: PublicKey.cc:491
String related utilities and Regular expression matching.
void scan(std::string line_r)
Feed gpg output line by line into scan.
Definition: PublicKey.cc:294
RW_pointer< Impl, rw_pointer::Scoped< Impl > > _pimpl
Definition: PublicKey.h:191
Date created() const
Definition: PublicKey.cc:470
std::string gpgPubkeyVersion() const
Gpg-pubkey version as computed by rpm (trailing 8 byte id)
Definition: PublicKey.cc:139
PublicKeyScanner implementation.
Definition: PublicKey.cc:176
std::string expiresAsString() const
Definition: PublicKey.cc:112
Provide a new empty temporary file and delete it when no longer needed.
Definition: TmpPath.h:126
const std::list< PublicKeyData > & hiddenKeys() const
Definition: PublicKey.cc:343
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:36
PublicKeyData()
Default constructed: empty data.
Definition: PublicKey.cc:72
#define PL_(MSG1, MSG2, N)
Definition: Gettext.h:30
std::string gpgPubkeyVersion() const
Definition: PublicKey.cc:485
std::string & replaceAll(std::string &str_r, const std::string &from_r, const std::string &to_r)
Replace all occurrences of from_r with to_r in str_r (inplace).
Definition: String.cc:328
std::string id() const
Definition: PublicKey.cc:461
bool expired() const
Definition: PublicKey.cc:476
Pathname path() const
File containig the ASCII armored key.
Definition: PublicKey.cc:455
RWCOW_pointer< Impl > _pimpl
Pointer to implementation.
Definition: PublicKey.h:275
Store and operate on date (time_t).
Definition: Date.h:32
PublicKeyData _keyData
Definition: PublicKey.cc:411
Provide a new empty temporary directory and recursively delete it when no longer needed.
Definition: TmpPath.h:170
Pathname path() const
Definition: PublicKey.cc:340
Impl(const Pathname &keyFile_r)
Definition: PublicKey.cc:307
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
std::string fingerprint() const
Key fingerprint.
Definition: PublicKey.cc:88
#define WAR
Definition: Logger.h:65
std::ostream & dumpOn(std::ostream &str, const PublicKey &obj)
Definition: PublicKey.cc:500
std::string expiresAsString() const
Definition: PublicKey.cc:482
bool expired() const
Whether the key has expired.
Definition: PublicKey.cc:97
int hardlinkCopy(const Pathname &oldpath, const Pathname &newpath)
Create newpath as hardlink or copy of oldpath.
Definition: PathInfo.cc:808
static shared_ptr< Impl > nullimpl()
Offer default Impl.
Definition: PublicKey.cc:416
#define _(MSG)
Definition: Gettext.h:29
std::string receiveLine()
Read one line from the input stream.
Scan abstract from &#39;gpg –with-colons&#39; key listings.
Definition: PublicKey.h:179
std::string toLower(const std::string &s)
Return lowercase version of s.
Definition: String.cc:175
PublicKey()
Default ctor.
Definition: PublicKey.cc:433
std::vector< std::string > _words
Definition: PublicKey.cc:178
PublicKey implementation.
Definition: PublicKey.cc:302
int close()
Wait for the progamm to complete.
unsigned splitFields(const C_Str &line_r, TOutputIterator result_r, const C_Str &sepchars_r=":")
Split line_r into fields.
Definition: String.h:708
Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile).
Definition: PublicKey.h:208
std::ostream & dumpOn(std::ostream &str, const PublicKeyData &obj)
Definition: PublicKey.cc:155
Base class for Exception.
Definition: Exception.h:143
Impl(const filesystem::TmpFile &sharedFile_r)
Definition: PublicKey.cc:321
const PublicKeyData & keyData() const
The public keys data (.
Definition: PublicKey.cc:452
static Date now()
Return the current time.
Definition: Date.h:78
std::string asString() const
Default string representation of Date.
Definition: Date.h:120
std::string checksum(const Pathname &file, const std::string &algorithm)
Compute a files checksum.
Definition: PathInfo.cc:974
RWCOW_pointer< Impl > _pimpl
Definition: PublicKey.h:143
Impl * clone() const
clone for RWCOW_pointer
Definition: PublicKey.cc:425
std::string id() const
Key ID.
Definition: PublicKey.cc:82
static shared_ptr< Impl > nullimpl()
Offer default Impl.
Definition: PublicKey.cc:54
void scan(std::string &line_r, std::list< PublicKeyData > &keys_r)
Definition: PublicKey.cc:187
time_t ValueType
Definition: Date.h:38
PublicKeyData implementation.
Definition: PublicKey.cc:44
std::string fingerprint() const
Definition: PublicKey.cc:467
filesystem::TmpFile _dataFile
Definition: PublicKey.cc:410
Date created() const
Creation / last modification date (latest selfsig).
Definition: PublicKey.cc:91
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
std::string gpgPubkeyRelease() const
Definition: PublicKey.cc:488
std::string hexstring(char n, int w=4)
Definition: String.h:340
bool operator==(const PublicKey &rhs) const
Definition: PublicKey.cc:494
std::string asString() const
Simple string representation.
Definition: PublicKey.cc:145
std::string name() const
Definition: PublicKey.cc:464
const PublicKeyData & keyData() const
Definition: PublicKey.cc:337
bool operator==(const PublicKeyData &lhs, const PublicKeyData &rhs)
Definition: PublicKey.cc:168