00001
00002
00003
00004
00005
00006
00007
00008
00012 #include <iostream>
00013 #include <fstream>
00014 #include <sys/file.h>
00015 #include <cstdio>
00016 #include <unistd.h>
00017
00018 #include "zypp/ZYppFactory.h"
00019 #include "zypp/ZYpp.h"
00020
00021 #include "zypp/base/Logger.h"
00022 #include "zypp/base/IOStream.h"
00023 #include "zypp/base/String.h"
00024 #include "zypp/Pathname.h"
00025 #include "zypp/KeyRing.h"
00026 #include "zypp/ExternalProgram.h"
00027 #include "zypp/TmpPath.h"
00028
00029 using std::endl;
00030 using namespace zypp::filesystem;
00031 using namespace std;
00032
00033 #undef ZYPP_BASE_LOGGER_LOGGROUP
00034 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::KeyRing"
00035
00037 namespace zypp
00038 {
00039
00040 IMPL_PTR_TYPE(KeyRing);
00041
00042 static void dumpRegexpResults( const str::smatch &what )
00043 {
00044 for ( unsigned int k=0; k < what.size(); k++)
00045 {
00046 XXX << "[match "<< k << "] [" << what[k] << "]" << std::endl;
00047 }
00048 }
00049
00050 static bool printLine( const std::string &line )
00051 {
00052 MIL << line << std::endl;
00053 }
00054
00055 static void dumpFile(const Pathname &file)
00056 {
00057 std::ifstream is(file.asString().c_str());
00058 iostr::forEachLine( is, printLine);
00059 }
00060
00061 namespace
00062 {
00063 bool _keyRingDefaultAccept( getenv("ZYPP_KEYRING_DEFAULT_ACCEPT_ALL") );
00064 }
00065
00066 bool KeyRingReport::askUserToAcceptUnsignedFile( const std::string &file )
00067 { return _keyRingDefaultAccept; }
00068
00069 bool KeyRingReport::askUserToAcceptUnknownKey( const std::string &file, const std::string &keyid, const std::string &keyname, const std::string &fingerprint )
00070 { return _keyRingDefaultAccept; }
00071
00072 bool KeyRingReport::askUserToTrustKey( const std::string &keyid, const std::string &keyname, const std::string &fingerprint )
00073 { return _keyRingDefaultAccept; }
00074
00075 bool KeyRingReport::askUserToAcceptVerificationFailed( const std::string &file, const std::string &keyid, const std::string &keyname, const std::string &fingerprint )
00076 { return _keyRingDefaultAccept; }
00077
00079
00080
00081
00083 struct KeyRing::Impl
00084 {
00085 Impl()
00086 {
00087 _general_kr = _general_tmp_dir.path();
00088 _trusted_kr = _trusted_tmp_dir.path();
00089 }
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 void importKey( const Pathname &keyfile, bool trusted = false);
00103 PublicKey readPublicKey( const Pathname &keyfile );
00104 std::string readSignatureKeyId( const Pathname &signature );
00105
00106 void deleteKey( const std::string &id, bool trusted );
00107 std::list<PublicKey> trustedPublicKeys();
00108 std::list<PublicKey> publicKeys();
00109
00110 void dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream );
00111
00112 bool verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature);
00113
00114 bool verifyFileSignature( const Pathname &file, const Pathname &signature);
00115 bool verifyFileTrustedSignature( const Pathname &file, const Pathname &signature);
00116 private:
00117
00118 bool verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring);
00119 void importKey( const Pathname &keyfile, const Pathname &keyring);
00120
00121 void exportKey( std::string id, const Pathname &keyfile, bool trusted);
00122
00123 void deleteKey( const std::string &id, const Pathname &keyring );
00124 std::list<PublicKey> publicKeys(const Pathname &keyring);
00125
00126 bool publicKeyExists( std::string id, const Pathname &keyring);
00127
00128 Pathname _general_kr;
00129 Pathname _trusted_kr;
00130
00131
00132 TmpDir _trusted_tmp_dir;
00133 TmpDir _general_tmp_dir;
00134 public:
00136 static shared_ptr<Impl> nullimpl()
00137 {
00138 static shared_ptr<Impl> _nullimpl( new Impl );
00139 return _nullimpl;
00140 }
00141
00142 private:
00143 friend Impl * rwcowClone<Impl>( const Impl * rhs );
00145 Impl * clone() const
00146 { return new Impl( *this ); }
00147 };
00148
00149 void KeyRing::Impl::importKey( const Pathname &keyfile, bool trusted)
00150 {
00151 importKey( keyfile, trusted ? _trusted_kr : _general_kr );
00152 }
00153
00154 void KeyRing::Impl::deleteKey( const std::string &id, bool trusted)
00155 {
00156 deleteKey( id, trusted ? _trusted_kr : _general_kr );
00157 }
00158
00159 std::list<PublicKey> KeyRing::Impl::publicKeys()
00160 {
00161 return publicKeys( _general_kr );
00162 }
00163
00164 std::list<PublicKey> KeyRing::Impl::trustedPublicKeys()
00165 {
00166 return publicKeys( _trusted_kr );
00167 }
00168
00169 bool KeyRing::Impl::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
00170 {
00171 return verifyFile( file, signature, _trusted_kr );
00172 }
00173
00174 bool KeyRing::Impl::verifyFileSignature( const Pathname &file, const Pathname &signature)
00175 {
00176 return verifyFile( file, signature, _general_kr );
00177 }
00178
00179 bool KeyRing::Impl::publicKeyExists( std::string id, const Pathname &keyring)
00180 {
00181 MIL << "Searching key [" << id << "] in keyring " << keyring << std::endl;
00182 std::list<PublicKey> keys = publicKeys(keyring);
00183 for (std::list<PublicKey>::const_iterator it = keys.begin(); it != keys.end(); it++)
00184 {
00185 if ( id == (*it).id )
00186 return true;
00187 }
00188 return false;
00189 }
00190
00191 void KeyRing::Impl::exportKey( std::string id, const Pathname &keyfile, bool trusted)
00192 {
00193 try {
00194 std::ofstream os(keyfile.asString().c_str());
00195 dumpPublicKey( id, trusted, os );
00196 os.close();
00197 }
00198 catch (std::exception &e)
00199 {
00200 ERR << "Cannot export key " << id << " from " << (trusted ? "trusted" : "untrusted ") << " keyring to file " << keyfile << std::endl;
00201 }
00202 }
00203
00204 void KeyRing::Impl::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
00205 {
00206 Pathname keyring = trusted ? _trusted_kr : _general_kr;
00207 const char* argv[] =
00208 {
00209 "gpg",
00210 "--no-default-keyring",
00211 "--quiet",
00212 "--no-tty",
00213 "--no-greeting",
00214 "--no-permission-warning",
00215 "--batch",
00216 "--homedir",
00217 keyring.asString().c_str(),
00218 "-a",
00219 "--export",
00220 id.c_str(),
00221 NULL
00222 };
00223 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00224 std::string line;
00225 int count;
00226 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
00227 {
00228 stream << line;
00229 }
00230 prog.close();
00231 }
00232
00233
00234 bool KeyRing::Impl::verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature)
00235 {
00236 callback::SendReport<KeyRingReport> report;
00237 callback::SendReport<KeyRingSignals> emitSignal;
00238 MIL << "Going to verify signature for " << file << " with " << signature << std::endl;
00239
00240
00241 if( signature.empty() || (!PathInfo(signature).isExist()) )
00242 {
00243 bool res = report->askUserToAcceptUnsignedFile( filedesc );
00244 MIL << "User decision on unsigned file: " << res << endl;
00245 return res;
00246 }
00247
00248
00249 std::string id = readSignatureKeyId(signature);
00250
00251
00252 if ( publicKeyExists( id, _trusted_kr ) )
00253 {
00254 TmpFile trustedKey;
00255 exportKey( id, trustedKey.path(), true);
00256 PublicKey key = readPublicKey(trustedKey.path());
00257 MIL << "Key " << id << " " << key.name << " is trusted" << std::endl;
00258
00259 if ( verifyFile( file, signature, _trusted_kr ) )
00260 return true;
00261 else
00262 return report->askUserToAcceptVerificationFailed( filedesc, key.id, key.name, key.fingerprint );
00263 }
00264 else
00265 {
00266 if ( publicKeyExists( id, _general_kr ) )
00267 {
00268 TmpFile unKey;
00269 exportKey( id, unKey.path(), false);
00270 MIL << "Exported key " << id << " to " << unKey << std::endl;
00271
00272 PublicKey key = readPublicKey(unKey.path());
00273 MIL << "Key " << id << " " << key.name << " is not trusted" << std::endl;
00274
00275 #warning We need the key details passed to the callback
00276 if ( report->askUserToTrustKey(key.id, key.name, key.fingerprint) )
00277 {
00278 MIL << "User wants to trust key " << id << " " << key.name << std::endl;
00279
00280
00281 importKey( unKey.path(), _trusted_kr );
00282 emitSignal->trustedKeyAdded( (const KeyRing &)(*this), id, key.name, key.fingerprint );
00283
00284
00285 if ( verifyFile( file, signature, _trusted_kr ) )
00286 {
00287 MIL << "File signature is verified" << std::endl;
00288 return true;
00289 }
00290 else
00291 {
00292 MIL << "File signature check fails" << std::endl;
00293 if ( report->askUserToAcceptVerificationFailed( filedesc, key.id, key.name, key.fingerprint ) )
00294 {
00295 MIL << "User continues anyway." << std::endl;
00296 return true;
00297 }
00298 else
00299 {
00300 MIL << "User does not want to continue" << std::endl;
00301 return false;
00302 }
00303 }
00304 }
00305 else
00306 {
00307 MIL << "User does not want to trust key " << id << " " << key.name << std::endl;
00308 return false;
00309 }
00310 }
00311 else
00312 {
00313
00314 MIL << "File [" << file << "] ( " << filedesc << " ) signed with unknown key [" << id << "]" << std::endl;
00315 if ( report->askUserToAcceptUnknownKey( filedesc, id, "", "" ) )
00316 {
00317 MIL << "User wants to accept unknown key " << id << std::endl;
00318 return true;
00319 }
00320 else
00321 {
00322 MIL << "User does not want to accept unknown key " << id << std::endl;
00323 return false;
00324 }
00325 }
00326 }
00327 return false;
00328 }
00329
00330
00331 PublicKey KeyRing::Impl::readPublicKey( const Pathname &keyfile )
00332 {
00333 const char* argv[] =
00334 {
00335 "gpg",
00336 "--no-default-keyring",
00337 "--with-fingerprint",
00338 "--with-colons",
00339 "--quiet",
00340 "--no-tty",
00341 "--no-greeting",
00342 "--batch",
00343 "--status-fd",
00344 "1",
00345 keyfile.asString().c_str(),
00346 NULL
00347 };
00348
00349 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00350
00351 std::string line;
00352 int count = 0;
00353
00354 str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
00355
00356
00357
00358 PublicKey key;
00359 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
00360 {
00361
00362 str::smatch what;
00363 if(str::regex_match(line, what, rxColons, str::match_extra))
00364 {
00365 if ( what[1] == "pub" )
00366 {
00367 key.id = what[5];
00368 key.name = what[10];
00369
00370 }
00371 else if ( what[1] == "fpr" )
00372 {
00373 key.fingerprint = what[10];
00374 }
00375
00376 }
00377 }
00378 prog.close();
00379 return key;
00380 }
00381
00382 std::list<PublicKey> KeyRing::Impl::publicKeys(const Pathname &keyring)
00383 {
00384 const char* argv[] =
00385 {
00386 "gpg",
00387 "--no-default-keyring",
00388 "--quiet",
00389 "--list-public-keys",
00390 "--with-colons",
00391 "--with-fingerprint",
00392 "--no-tty",
00393 "--no-greeting",
00394 "--batch",
00395 "--status-fd",
00396 "1",
00397 "--homedir",
00398 keyring.asString().c_str(),
00399 NULL
00400 };
00401 std::list<PublicKey> keys;
00402
00403 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00404 std::string line;
00405 int count = 0;
00406
00407 str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
00408 str::regex rxColonsFpr("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
00409
00410 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
00411 {
00412
00413 str::smatch what;
00414 if(str::regex_match(line, what, rxColons, str::match_extra))
00415 {
00416 PublicKey key;
00417 if ( what[1] == "pub" )
00418 {
00419 key.id = what[5];
00420 key.name = what[10];
00421
00422 std::string line2;
00423 for(line2 = prog.receiveLine(); !line2.empty(); line2 = prog.receiveLine(), count++ )
00424 {
00425 str::smatch what2;
00426 if (str::regex_match(line2, what2, rxColonsFpr, str::match_extra))
00427 {
00428 if ( (what2[1] == "fpr") && (what2[1] != "pub") && (what2[1] !="sub"))
00429 {
00430 key.fingerprint = what2[10];
00431 break;
00432 }
00433 }
00434 }
00435 keys.push_back(key);
00436 MIL << "Found key " << "[" << key.id << "]" << " [" << key.name << "]" << " [" << key.fingerprint << "]" << std::endl;
00437 }
00438
00439 }
00440 }
00441 prog.close();
00442 return keys;
00443 }
00444
00445 void KeyRing::Impl::importKey( const Pathname &keyfile, const Pathname &keyring)
00446 {
00447 const char* argv[] =
00448 {
00449 "gpg",
00450 "--no-default-keyring",
00451 "--quiet",
00452 "--no-tty",
00453 "--no-greeting",
00454 "--no-permission-warning",
00455 "--status-fd",
00456 "1",
00457 "--homedir",
00458 keyring.asString().c_str(),
00459 "--import",
00460 keyfile.asString().c_str(),
00461 NULL
00462 };
00463
00464 int code;
00465 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00466 code = prog.close();
00467
00468
00469
00470 }
00471
00472 void KeyRing::Impl::deleteKey( const std::string &id, const Pathname &keyring )
00473 {
00474 const char* argv[] =
00475 {
00476 "gpg",
00477 "--no-default-keyring",
00478 "--yes",
00479 "--quiet",
00480 "--no-tty",
00481 "--batch",
00482 "--status-fd",
00483 "1",
00484 "--homedir",
00485 keyring.asString().c_str(),
00486 "--delete-keys",
00487 id.c_str(),
00488 NULL
00489 };
00490
00491 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00492
00493 int code = prog.close();
00494 if ( code )
00495 ZYPP_THROW(Exception("Failed to delete key."));
00496 else
00497 MIL << "Deleted key " << id << " from keyring " << keyring << std::endl;
00498 }
00499
00500
00501 std::string KeyRing::Impl::readSignatureKeyId(const Pathname &signature )
00502 {
00503 MIL << "Deetermining key id if signature " << signature << std::endl;
00504
00505 TmpDir dir;
00506 TmpFile fakeData;
00507
00508 const char* argv[] =
00509 {
00510 "gpg",
00511 "--no-default-keyring",
00512 "--quiet",
00513 "--no-tty",
00514 "--no-greeting",
00515 "--batch",
00516 "--status-fd",
00517 "1",
00518 "--homedir",
00519 dir.path().asString().c_str(),
00520 "--verify",
00521 signature.asString().c_str(),
00522 fakeData.path().asString().c_str(),
00523 NULL
00524 };
00525
00526 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00527
00528 std::string line;
00529 int count = 0;
00530
00531 str::regex rxNoKey("^\\[GNUPG:\\] NO_PUBKEY (.+)\n$");
00532 std::string id;
00533 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
00534 {
00535
00536 str::smatch what;
00537 if(str::regex_match(line, what, rxNoKey, str::match_extra))
00538 {
00539 if ( what.size() > 1 )
00540 id = what[1];
00541
00542 }
00543 }
00544 MIL << "Determined key id [" << id << "] for signature " << signature << std::endl;
00545 prog.close();
00546 return id;
00547 }
00548
00549 bool KeyRing::Impl::verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring)
00550 {
00551 const char* argv[] =
00552 {
00553 "gpg",
00554 "--no-default-keyring",
00555 "--quiet",
00556 "--no-tty",
00557 "--batch",
00558 "--no-greeting",
00559 "--status-fd",
00560 "1",
00561 "--homedir",
00562 keyring.asString().c_str(),
00563 "--verify",
00564 signature.asString().c_str(),
00565 file.asString().c_str(),
00566 NULL
00567 };
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00580
00581 return (prog.close() == 0) ? true : false;
00582 }
00583
00585
00587
00588
00589
00591
00593
00594
00595
00596
00597 KeyRing::KeyRing()
00598 : _pimpl( new Impl() )
00599 {}
00600
00602
00603
00604
00605
00606
00607
00608
00609
00611
00612
00613
00614
00615 KeyRing::~KeyRing()
00616 {}
00617
00619
00620
00621
00623
00624 void KeyRing::importKey( const Pathname &keyfile, bool trusted)
00625 {
00626 _pimpl->importKey(keyfile, trusted);
00627 }
00628
00629 PublicKey KeyRing::readPublicKey( const Pathname &keyfile )
00630 {
00631 return _pimpl->readPublicKey(keyfile);
00632 }
00633
00634 std::string KeyRing::readSignatureKeyId( const Pathname &signature )
00635 {
00636 return _pimpl->readSignatureKeyId(signature);
00637 }
00638
00639 void KeyRing::deleteKey( const std::string &id, bool trusted )
00640 {
00641 _pimpl->deleteKey(id, trusted);
00642 }
00643
00644 std::list<PublicKey> KeyRing::publicKeys()
00645 {
00646 return _pimpl->publicKeys();
00647 }
00648
00649 std::list<PublicKey> KeyRing::trustedPublicKeys()
00650 {
00651 return _pimpl->trustedPublicKeys();
00652 }
00653
00654 bool KeyRing::verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature)
00655 {
00656 return _pimpl->verifyFileSignatureWorkflow(file, filedesc, signature);
00657 }
00658
00659 bool KeyRing::verifyFileSignature( const Pathname &file, const Pathname &signature)
00660 {
00661 return _pimpl->verifyFileSignature(file, signature);
00662 }
00663
00664 bool KeyRing::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
00665 {
00666 return _pimpl->verifyFileTrustedSignature(file, signature);
00667 }
00668
00669 void KeyRing::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
00670 {
00671 _pimpl->dumpPublicKey( id, trusted, stream);
00672 }
00673
00675 }