libzypp  14.29.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 
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;
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:
345  {
346  PathInfo info( _dataFile.path() );
347  MIL << "Reading pubkey from " << info.path() << " of size " << info.size() << " and sha1 " << filesystem::checksum(info.path(), "sha1") << endl;
348 
349  static filesystem::TmpDir dir;
350  const char* argv[] =
351  {
352  "gpg",
353  "-v",
354  "--no-default-keyring",
355  "--fixed-list-mode",
356  "--with-fingerprint",
357  "--with-colons",
358  "--homedir",
359  dir.path().asString().c_str(),
360  "--quiet",
361  "--no-tty",
362  "--no-greeting",
363  "--batch",
364  "--status-fd", "1",
365  _dataFile.path().asString().c_str(),
366  NULL
367  };
368  ExternalProgram prog( argv, ExternalProgram::Discard_Stderr, false, -1, true );
369 
370  PublicKeyScanner scanner;
371  for ( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
372  {
373  scanner.scan( line );
374  }
375  prog.close();
376 
377  switch ( scanner._keys.size() )
378  {
379  case 0:
380  ZYPP_THROW( BadKeyException( "File " + _dataFile.path().asString() + " doesn't contain public key data" , _dataFile.path() ) );
381  break;
382 
383  case 1:
384  // ok.
385  _keyData = scanner._keys.back();
386  _hiddenKeys.clear();
387  break;
388 
389  default:
390  WAR << "File " << _dataFile.path().asString() << " contains multiple keys: " << scanner._keys << endl;
391  _keyData = scanner._keys.back();
392  scanner._keys.pop_back();
393  _hiddenKeys.swap( scanner._keys );
394  break;
395  }
396 
397  MIL << "Read pubkey from " << info.path() << ": " << _keyData << endl;
398  }
399 
400  private:
403  std::list<PublicKeyData> _hiddenKeys;
404 
405  public:
407  static shared_ptr<Impl> nullimpl()
408  {
409  static shared_ptr<Impl> _nullimpl( new Impl );
410  return _nullimpl;
411  }
412 
413  private:
414  friend Impl * rwcowClone<Impl>( const Impl * rhs );
416  Impl * clone() const
417  { return new Impl( *this ); }
418  };
420 
422  // class PublicKey
425  : _pimpl( Impl::nullimpl() )
426  {}
427 
428  PublicKey::PublicKey( const Pathname & file )
429  : _pimpl( new Impl( file ) )
430  {}
431 
433  : _pimpl( new Impl( sharedfile ) )
434  {}
435 
436  PublicKey::PublicKey( const filesystem::TmpFile & sharedfile, const PublicKeyData & keydata )
437  : _pimpl( new Impl( sharedfile, keydata ) )
438  {}
439 
441  {}
442 
444  { return _pimpl->keyData(); }
445 
446  Pathname PublicKey::path() const
447  { return _pimpl->path(); }
448 
449  const std::list<PublicKeyData> & PublicKey::hiddenKeys() const
450  { return _pimpl->hiddenKeys(); }
451 
452  std::string PublicKey::id() const
453  { return keyData().id(); }
454 
455  std::string PublicKey::name() const
456  { return keyData().name(); }
457 
458  std::string PublicKey::fingerprint() const
459  { return keyData().fingerprint(); }
460 
462  { return keyData().created(); }
463 
465  { return keyData().expires(); }
466 
467  bool PublicKey::expired() const
468  { return keyData().expired(); }
469 
471  { return keyData().daysToLive(); }
472 
473  std::string PublicKey::expiresAsString() const
474  { return keyData().expiresAsString(); }
475 
476  std::string PublicKey::gpgPubkeyVersion() const
477  { return keyData().gpgPubkeyVersion(); }
478 
479  std::string PublicKey::gpgPubkeyRelease() const
480  { return keyData().gpgPubkeyRelease(); }
481 
482  std::string PublicKey::asString() const
483  { return keyData().asString(); }
484 
485  bool PublicKey::operator==( const PublicKey & rhs ) const
486  { return rhs.keyData() == keyData(); }
487 
488  bool PublicKey::operator==( const std::string & sid ) const
489  { return sid == id(); }
490 
491  std::ostream & dumpOn( std::ostream & str, const PublicKey & obj )
492  { return dumpOn( str, obj.keyData() ); }
493 
495 } // namespace zypp
std::string name() const
Key name.
Definition: PublicKey.cc:82
static const ValueType day
Definition: Date.h:43
Date expires() const
Expiry date, or Date() if the key never expires.
Definition: PublicKey.cc:91
Interface to gettext.
#define MIL
Definition: Logger.h:47
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
enum zypp::PublicKeyScanner::Impl::@1 _parseEntry
std::list< PublicKeyData > _hiddenKeys
Definition: PublicKey.cc:403
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:320
int daysToLive() const
Definition: PublicKey.cc:470
Pathname path() const
Definition: TmpPath.cc:146
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
#define _PL(MSG1, MSG2, N)
Return translated text (plural form).
Definition: Gettext.h:24
Class representing one GPG Public Keys data.
Definition: PublicKey.h:74
const std::string & asString() const
String representation.
Definition: Pathname.h:90
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:449
Date expires() const
Definition: PublicKey.cc:464
std::string asString() const
Definition: PublicKey.cc:482
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:461
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
bool operator==(const SetRelation::Enum &lhs, const SetCompare &rhs)
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:34
PublicKeyData()
Default constructed: empty data.
Definition: PublicKey.cc:69
std::string gpgPubkeyVersion() const
Definition: PublicKey.cc:476
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:304
std::string id() const
Definition: PublicKey.cc:452
bool expired() const
Definition: PublicKey.cc:467
Pathname path() const
File containig the ASCII armored key.
Definition: PublicKey.cc:446
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:402
Provide a new empty temporary directory and recursively delete it when no longer needed.
Definition: TmpPath.h:170
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:48
std::string expiresAsString() const
Definition: PublicKey.cc:473
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:815
static shared_ptr< Impl > nullimpl()
Offer default Impl.
Definition: PublicKey.cc:407
std::ostream & dumpOn(std::ostream &str, const Capability &obj)
Definition: Capability.cc:435
#define _(MSG)
Return translated text.
Definition: Gettext.h:21
std::string receiveLine()
Read one line from the input stream.
Scan abstract from 'gpg –with-colons' key listings.
Definition: PublicKey.h:179
std::string toLower(const std::string &s)
Return lowercase version of s.
Definition: String.cc:166
PublicKey()
Default ctor.
Definition: PublicKey.cc:424
std::vector< std::string > _words
Definition: PublicKey.cc:175
PublicKey implementation.
Definition: PublicKey.cc:299
int close()
Wait for the progamm to complete.
Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile).
Definition: PublicKey.h:208
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:443
static Date now()
Return the current time.
Definition: Date.h:77
std::string asString() const
Default string representation of Date.
Definition: Date.h:119
std::string checksum(const Pathname &file, const std::string &algorithm)
Compute a files checksum.
Definition: PathInfo.cc:981
RWCOW_pointer< Impl > _pimpl
Definition: PublicKey.h:143
Impl * clone() const
clone for RWCOW_pointer
Definition: PublicKey.cc:416
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:458
filesystem::TmpFile _dataFile
Definition: PublicKey.cc:401
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:479
std::string hexstring(char n, int w=4)
Definition: String.h:301
bool operator==(const PublicKey &rhs) const
Definition: PublicKey.cc:485
std::string asString() const
Simple string representation.
Definition: PublicKey.cc:142
std::string name() const
Definition: PublicKey.cc:455
const PublicKeyData & keyData() const
Definition: PublicKey.cc:334
unsigned splitFields(const C_Str &line_r, _OutputIterator result_r, const C_Str &sepchars_r=":")
Split line_r into fields.
Definition: String.h:653