libzypp  13.10.6
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  return exp < 0 ? exp / Date::day - 1 : exp / Date::day;
103  }
104  return INT_MAX;
105  }
106 
107  std::string PublicKeyData::expiresAsString() const
108  {
109  if ( !_pimpl->_expires )
110  { // translators: an annotation to a gpg keys expiry date
111  return _("(does not expire)");
112  }
113  std::string ret( _pimpl->_expires.asString() );
114  int ttl( daysToLive() );
115  if ( ttl <= 90 )
116  {
117  ret += " ";
118  if ( ttl < 0 )
119  { // translators: an annotation to a gpg keys expiry date
120  ret += _("(EXPIRED)");
121  }
122  else if ( ttl == 0 )
123  { // translators: an annotation to a gpg keys expiry date
124  ret += _("(expires within 24h)");
125  }
126  else
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 );
129  }
130  }
131  return ret;
132  }
133 
135  { return _pimpl->_id.empty() ? _pimpl->_id : str::toLower( _pimpl->_id.substr(8,8) ); }
136 
138  { return _pimpl->_created ? str::hexstring( _pimpl->_created ).substr(2) : std::string(); }
139 
140  std::string PublicKeyData::asString() const
141  {
142  return str::form( "[%s-%s] [%s] [%s] [TTL %d]",
143  _pimpl->_id.c_str(),
144  gpgPubkeyRelease().c_str(),
145  _pimpl->_name.c_str(),
146  _pimpl->_fingerprint.c_str(),
147  daysToLive() );
148  }
149 
150  std::ostream & dumpOn( std::ostream & str, const PublicKeyData & obj )
151  {
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;
159  str << "]";
160  return str;
161  }
162 
163  bool operator==( const PublicKeyData & lhs, const PublicKeyData & rhs )
164  { return ( lhs.fingerprint() == rhs.fingerprint() && lhs.created() == rhs.created() ); }
165 
166 
172  {
173  std::vector<std::string> _words;
175  bool _parseOff; // no 'sub:' key parsing
176 
178  : _parseEntry( pNONE )
179  , _parseOff( false )
180  {}
181 
182  void scan( std::string & line_r, std::list<PublicKeyData> & keys_r )
183  {
184  // pub:-:1024:17:A84EDAE89C800ACA:971961473:1214043198::-:SuSE Package Signing Key <build@suse.de>:
185  // fpr:::::::::79C179B2E1C820C1890F9994A84EDAE89C800ACA:
186  // sig:::17:A84EDAE89C800ACA:1087899198:::::[selfsig]::13x:
187  // sig:::17:9E40E310000AABA4:980442706::::[User ID not found]:10x:
188  // sig:::1:77B2E6003D25D3D9:980443247::::[User ID not found]:10x:
189  // sig:::17:A84EDAE89C800ACA:1318348291:::::[selfsig]::13x:
190  // sub:-:2048:16:197448E88495160C:971961490:1214043258::: [expires: 2008-06-21]
191  // sig:::17:A84EDAE89C800ACA:1087899258:::::[keybind]::18x:
192  if ( line_r.empty() )
193  return;
194 
195  // quick check for interesting entries, no parsing in subkeys
196  _parseEntry = pNONE;
197  switch ( line_r[0] )
198  {
199  case 'p':
200  if ( line_r[1] == 'u' && line_r[2] == 'b' && line_r[3] == ':' )
201  {
202  _parseEntry = pPUB;
203  _parseOff = false;
204  }
205  break;
206 
207  case 'f':
208  if ( line_r[1] == 'p' && line_r[2] == 'r' && line_r[3] == ':' )
209  _parseEntry = pFPR;
210  break;
211 
212  case 'u':
213  if ( line_r[1] == 'i' && line_r[2] == 'd' && line_r[3] == ':' )
214  _parseEntry = pUID;
215  break;
216 
217  case 's':
218  if ( line_r[1] == 'i' && line_r[2] == 'g' && line_r[3] == ':' )
219  _parseEntry = pSIG;
220  else if ( line_r[1] == 'u' && line_r[2] == 'b' && line_r[3] == ':' )
221  _parseOff = true;
222  break;
223 
224  default:
225  return;
226  }
227  if ( _parseOff || _parseEntry == pNONE )
228  return;
229 
230  if ( line_r[line_r.size()-1] == '\n' )
231  line_r.erase( line_r.size()-1 );
232  // DBG << line_r << endl;
233 
234  _words.clear();
235  str::splitFields( line_r, std::back_inserter(_words), ":" );
236 
237  PublicKeyData * key( &keys_r.back() );
238 
239  switch ( _parseEntry )
240  {
241  case pPUB:
242  keys_r.push_back( PublicKeyData() ); // reset upon new key
243  key = &keys_r.back();
244  key->_pimpl->_id = _words[4];
245  key->_pimpl->_name = str::replaceAll( _words[9], "\\x3a", ":" );
246  key->_pimpl->_created = Date(str::strtonum<Date::ValueType>(_words[5]));
247  key->_pimpl->_expires = Date(str::strtonum<Date::ValueType>(_words[6]));
248  break;
249 
250  case pSIG:
251  // Update creation/modification date from signatures type "13x".
252  if ( ( _words.size() > 10 && _words[10] == "13x" )
253  || ( _words.size() > 12 && _words[12] == "13x" ) )
254  {
255  Date cdate(str::strtonum<Date::ValueType>(_words[5]));
256  if ( key->_pimpl->_created < cdate )
257  key->_pimpl->_created = cdate;
258  }
259  break;
260 
261  case pFPR:
262  if ( key->_pimpl->_fingerprint.empty() )
263  key->_pimpl->_fingerprint = _words[9];
264  break;
265 
266  case pUID:
267  if ( ! _words[9].empty() )
268  key->_pimpl->_name = str::replaceAll( _words[9], "\\x3a", ":" );
269  break;
270 
271  case pNONE:
272  break; // intentionally no default:
273  }
274  }
275  };
277 
279  // class PublicKeyScanner
281 
283  : _pimpl( new Impl )
284  {}
285 
287  {}
288 
289  void PublicKeyScanner::scan( std::string line_r )
290  { _pimpl->scan( line_r, _keys ); }
291 
292 
298  {
300  {}
301 
302  Impl( const Pathname & keyFile_r )
303  {
304  PathInfo info( keyFile_r );
305  MIL << "Taking pubkey from " << keyFile_r << " of size " << info.size() << " and sha1 " << filesystem::checksum(keyFile_r, "sha1") << endl;
306 
307  if ( !info.isExist() )
308  ZYPP_THROW(Exception("Can't read public key from " + keyFile_r.asString() + ", file not found"));
309 
310  if ( filesystem::hardlinkCopy( keyFile_r, _dataFile.path() ) != 0 )
311  ZYPP_THROW(Exception("Can't copy public key data from " + keyFile_r.asString() + " to " + _dataFile.path().asString() ));
312 
313  readFromFile();
314  }
315 
316  Impl( const filesystem::TmpFile & sharedFile_r )
317  : _dataFile( sharedFile_r )
318  { readFromFile(); }
319 
320  Impl( const filesystem::TmpFile & sharedFile_r, const PublicKeyData & keyData_r )
321  : _dataFile( sharedFile_r )
322  , _keyData( keyData_r )
323  {
324  if ( ! keyData_r )
325  {
326  WAR << "Invalid PublicKeyData supplied: scanning from file" << endl;
327  readFromFile();
328  }
329  }
330 
331  public:
332  const PublicKeyData & keyData() const
333  { return _keyData; }
334 
335  Pathname path() const
336  { return _dataFile.path(); }
337 
338  const std::list<PublicKeyData> & hiddenKeys() const
339  { return _hiddenKeys; }
340 
341  protected:
343  {
344  PathInfo info( _dataFile.path() );
345  MIL << "Reading pubkey from " << info.path() << " of size " << info.size() << " and sha1 " << filesystem::checksum(info.path(), "sha1") << endl;
346 
347  static filesystem::TmpDir dir;
348  const char* argv[] =
349  {
350  "gpg",
351  "-v",
352  "--no-default-keyring",
353  "--fixed-list-mode",
354  "--with-fingerprint",
355  "--with-colons",
356  "--homedir",
357  dir.path().asString().c_str(),
358  "--quiet",
359  "--no-tty",
360  "--no-greeting",
361  "--batch",
362  "--status-fd", "1",
363  _dataFile.path().asString().c_str(),
364  NULL
365  };
366  ExternalProgram prog( argv, ExternalProgram::Discard_Stderr, false, -1, true );
367 
368  PublicKeyScanner scanner;
369  for ( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
370  {
371  scanner.scan( line );
372  }
373  prog.close();
374 
375  switch ( scanner._keys.size() )
376  {
377  case 0:
378  ZYPP_THROW( BadKeyException( "File " + _dataFile.path().asString() + " doesn't contain public key data" , _dataFile.path() ) );
379  break;
380 
381  case 1:
382  // ok.
383  _keyData = scanner._keys.back();
384  _hiddenKeys.clear();
385  break;
386 
387  default:
388  WAR << "File " << _dataFile.path().asString() << " contains multiple keys: " << scanner._keys << endl;
389  _keyData = scanner._keys.back();
390  scanner._keys.pop_back();
391  _hiddenKeys.swap( scanner._keys );
392  break;
393  }
394 
395  MIL << "Read pubkey from " << info.path() << ": " << _keyData << endl;
396  }
397 
398  private:
401  std::list<PublicKeyData> _hiddenKeys;
402 
403  public:
405  static shared_ptr<Impl> nullimpl()
406  {
407  static shared_ptr<Impl> _nullimpl( new Impl );
408  return _nullimpl;
409  }
410 
411  private:
412  friend Impl * rwcowClone<Impl>( const Impl * rhs );
414  Impl * clone() const
415  { return new Impl( *this ); }
416  };
418 
420  // class PublicKey
423  : _pimpl( Impl::nullimpl() )
424  {}
425 
426  PublicKey::PublicKey( const Pathname & file )
427  : _pimpl( new Impl( file ) )
428  {}
429 
431  : _pimpl( new Impl( sharedfile ) )
432  {}
433 
434  PublicKey::PublicKey( const filesystem::TmpFile & sharedfile, const PublicKeyData & keydata )
435  : _pimpl( new Impl( sharedfile, keydata ) )
436  {}
437 
439  {}
440 
442  { return _pimpl->keyData(); }
443 
444  Pathname PublicKey::path() const
445  { return _pimpl->path(); }
446 
447  const std::list<PublicKeyData> & PublicKey::hiddenKeys() const
448  { return _pimpl->hiddenKeys(); }
449 
450  std::string PublicKey::id() const
451  { return keyData().id(); }
452 
453  std::string PublicKey::name() const
454  { return keyData().name(); }
455 
456  std::string PublicKey::fingerprint() const
457  { return keyData().fingerprint(); }
458 
460  { return keyData().created(); }
461 
463  { return keyData().expires(); }
464 
465  bool PublicKey::expired() const
466  { return keyData().expired(); }
467 
469  { return keyData().daysToLive(); }
470 
471  std::string PublicKey::expiresAsString() const
472  { return keyData().expiresAsString(); }
473 
474  std::string PublicKey::gpgPubkeyVersion() const
475  { return keyData().gpgPubkeyVersion(); }
476 
477  std::string PublicKey::gpgPubkeyRelease() const
478  { return keyData().gpgPubkeyRelease(); }
479 
480  std::string PublicKey::asString() const
481  { return keyData().asString(); }
482 
483  bool PublicKey::operator==( const PublicKey & rhs ) const
484  { return rhs.keyData() == keyData(); }
485 
486  bool PublicKey::operator==( const std::string & sid ) const
487  { return sid == id(); }
488 
489  std::ostream & dumpOn( std::ostream & str, const PublicKey & obj )
490  { return dumpOn( str, obj.keyData() ); }
491 
493 } // namespace zypp
std::string name() const
Key name.
Definition: PublicKey.cc:82
static const ValueType day
Definition: Date.h:42
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:320
std::string gpgPubkeyRelease() const
Gpg-pubkey release as computed by rpm (hexencoded created)
Definition: PublicKey.cc:137
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:401
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:320
int daysToLive() const
Definition: PublicKey.cc:468
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:447
Date expires() const
Definition: PublicKey.cc:462
std::string asString() const
Definition: PublicKey.cc:480
void scan(std::string line_r)
Feed gpg output line by line into scan.
Definition: PublicKey.cc:289
RW_pointer< Impl, rw_pointer::Scoped< Impl > > _pimpl
Definition: PublicKey.h:191
Date created() const
Definition: PublicKey.cc:459
std::string gpgPubkeyVersion() const
Gpg-pubkey version as computed by rpm (trailing 8 byte id)
Definition: PublicKey.cc:134
PublicKeyScanner implementation.
Definition: PublicKey.cc:171
std::string expiresAsString() const
Definition: PublicKey.cc:107
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:338
PublicKeyData()
Default constructed: empty data.
Definition: PublicKey.cc:69
std::string gpgPubkeyVersion() const
Definition: PublicKey.cc:474
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:450
bool expired() const
Definition: PublicKey.cc:465
Pathname path() const
File containig the ASCII armored key.
Definition: PublicKey.cc:444
RWCOW_pointer< Impl > _pimpl
Pointer to implementation.
Definition: PublicKey.h:275
Store and operate on date (time_t).
Definition: Date.h:31
PublicKeyData _keyData
Definition: PublicKey.cc:400
Provide a new empty temporary directory and recursively delete it when no longer needed.
Definition: TmpPath.h:170
Pathname path() const
Definition: PublicKey.cc:335
Impl(const Pathname &keyFile_r)
Definition: PublicKey.cc:302
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:471
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:405
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 &#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:166
PublicKey()
Default ctor.
Definition: PublicKey.cc:422
std::vector< std::string > _words
Definition: PublicKey.cc:173
bool operator==(const StrMatcher &lhs, const StrMatcher &rhs)
Definition: StrMatcher.cc:309
PublicKey implementation.
Definition: PublicKey.cc:297
int close()
Wait for the progamm to complete.
std::string form(const char *format,...)
Printf style construction of std::string.
Definition: String.cc:34
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:316
const PublicKeyData & keyData() const
The public keys data (.
Definition: PublicKey.cc:441
static Date now()
Return the current time.
Definition: Date.h:76
std::string checksum(const Pathname &file, const std::string &algorithm)
Compute a files checksum.
Definition: PathInfo.cc:980
RWCOW_pointer< Impl > _pimpl
Definition: PublicKey.h:143
Impl * clone() const
clone for RWCOW_pointer
Definition: PublicKey.cc:414
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:182
time_t ValueType
Definition: Date.h:37
PublicKeyData implementation.
Definition: PublicKey.cc:41
std::string fingerprint() const
Definition: PublicKey.cc:456
filesystem::TmpFile _dataFile
Definition: PublicKey.cc:399
Date created() const
Creation / last modification date (latest selfsig).
Definition: PublicKey.cc:88
std::string gpgPubkeyRelease() const
Definition: PublicKey.cc:477
std::string hexstring(char n, int w=4)
Definition: String.h:254
bool operator==(const PublicKey &rhs) const
Definition: PublicKey.cc:483
std::string asString() const
Simple string representation.
Definition: PublicKey.cc:140
std::string name() const
Definition: PublicKey.cc:453
const PublicKeyData & keyData() const
Definition: PublicKey.cc:332
unsigned splitFields(const C_Str &line_r, _OutputIterator result_r, const C_Str &sepchars_r=":")
Split line_r into fields.
Definition: String.h:583