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