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 TmpDir dir;
00334
00335 const char* argv[] =
00336 {
00337 "gpg",
00338 "--no-default-keyring",
00339 "--homedir",
00340 dir.path().asString().c_str(),
00341 "--with-fingerprint",
00342 "--with-colons",
00343 "--quiet",
00344 "--no-tty",
00345 "--no-greeting",
00346 "--batch",
00347 "--status-fd",
00348 "1",
00349 keyfile.asString().c_str(),
00350 NULL
00351 };
00352
00353 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00354
00355 std::string line;
00356 int count = 0;
00357
00358 str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
00359
00360
00361
00362 PublicKey key;
00363 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
00364 {
00365
00366 str::smatch what;
00367 if(str::regex_match(line, what, rxColons, str::match_extra))
00368 {
00369 if ( what[1] == "pub" )
00370 {
00371 key.id = what[5];
00372 key.name = what[10];
00373
00374 }
00375 else if ( what[1] == "fpr" )
00376 {
00377 key.fingerprint = what[10];
00378 }
00379
00380 }
00381 }
00382 prog.close();
00383 return key;
00384 }
00385
00386 std::list<PublicKey> KeyRing::Impl::publicKeys(const Pathname &keyring)
00387 {
00388 const char* argv[] =
00389 {
00390 "gpg",
00391 "--no-default-keyring",
00392 "--quiet",
00393 "--list-public-keys",
00394 "--with-colons",
00395 "--with-fingerprint",
00396 "--no-tty",
00397 "--no-greeting",
00398 "--batch",
00399 "--status-fd",
00400 "1",
00401 "--homedir",
00402 keyring.asString().c_str(),
00403 NULL
00404 };
00405 std::list<PublicKey> keys;
00406
00407 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00408 std::string line;
00409 int count = 0;
00410
00411 str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
00412 str::regex rxColonsFpr("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
00413
00414 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
00415 {
00416
00417 str::smatch what;
00418 if(str::regex_match(line, what, rxColons, str::match_extra))
00419 {
00420 PublicKey key;
00421 if ( what[1] == "pub" )
00422 {
00423 key.id = what[5];
00424 key.name = what[10];
00425
00426 std::string line2;
00427 for(line2 = prog.receiveLine(); !line2.empty(); line2 = prog.receiveLine(), count++ )
00428 {
00429 str::smatch what2;
00430 if (str::regex_match(line2, what2, rxColonsFpr, str::match_extra))
00431 {
00432 if ( (what2[1] == "fpr") && (what2[1] != "pub") && (what2[1] !="sub"))
00433 {
00434 key.fingerprint = what2[10];
00435 break;
00436 }
00437 }
00438 }
00439 keys.push_back(key);
00440 MIL << "Found key " << "[" << key.id << "]" << " [" << key.name << "]" << " [" << key.fingerprint << "]" << std::endl;
00441 }
00442
00443 }
00444 }
00445 prog.close();
00446 return keys;
00447 }
00448
00449 void KeyRing::Impl::importKey( const Pathname &keyfile, const Pathname &keyring)
00450 {
00451 const char* argv[] =
00452 {
00453 "gpg",
00454 "--no-default-keyring",
00455 "--quiet",
00456 "--no-tty",
00457 "--no-greeting",
00458 "--no-permission-warning",
00459 "--status-fd",
00460 "1",
00461 "--homedir",
00462 keyring.asString().c_str(),
00463 "--import",
00464 keyfile.asString().c_str(),
00465 NULL
00466 };
00467
00468 int code;
00469 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00470 code = prog.close();
00471
00472
00473
00474 }
00475
00476 void KeyRing::Impl::deleteKey( const std::string &id, const Pathname &keyring )
00477 {
00478 const char* argv[] =
00479 {
00480 "gpg",
00481 "--no-default-keyring",
00482 "--yes",
00483 "--quiet",
00484 "--no-tty",
00485 "--batch",
00486 "--status-fd",
00487 "1",
00488 "--homedir",
00489 keyring.asString().c_str(),
00490 "--delete-keys",
00491 id.c_str(),
00492 NULL
00493 };
00494
00495 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00496
00497 int code = prog.close();
00498 if ( code )
00499 ZYPP_THROW(Exception("Failed to delete key."));
00500 else
00501 MIL << "Deleted key " << id << " from keyring " << keyring << std::endl;
00502 }
00503
00504
00505 std::string KeyRing::Impl::readSignatureKeyId(const Pathname &signature )
00506 {
00507 MIL << "Deetermining key id if signature " << signature << std::endl;
00508
00509 TmpDir dir;
00510 TmpFile fakeData;
00511
00512 const char* argv[] =
00513 {
00514 "gpg",
00515 "--no-default-keyring",
00516 "--quiet",
00517 "--no-tty",
00518 "--no-greeting",
00519 "--batch",
00520 "--status-fd",
00521 "1",
00522 "--homedir",
00523 dir.path().asString().c_str(),
00524 "--verify",
00525 signature.asString().c_str(),
00526 fakeData.path().asString().c_str(),
00527 NULL
00528 };
00529
00530 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00531
00532 std::string line;
00533 int count = 0;
00534
00535 str::regex rxNoKey("^\\[GNUPG:\\] NO_PUBKEY (.+)\n$");
00536 std::string id;
00537 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
00538 {
00539
00540 str::smatch what;
00541 if(str::regex_match(line, what, rxNoKey, str::match_extra))
00542 {
00543 if ( what.size() > 1 )
00544 id = what[1];
00545
00546 }
00547 }
00548 MIL << "Determined key id [" << id << "] for signature " << signature << std::endl;
00549 prog.close();
00550 return id;
00551 }
00552
00553 bool KeyRing::Impl::verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring)
00554 {
00555 const char* argv[] =
00556 {
00557 "gpg",
00558 "--no-default-keyring",
00559 "--quiet",
00560 "--no-tty",
00561 "--batch",
00562 "--no-greeting",
00563 "--status-fd",
00564 "1",
00565 "--homedir",
00566 keyring.asString().c_str(),
00567 "--verify",
00568 signature.asString().c_str(),
00569 file.asString().c_str(),
00570 NULL
00571 };
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00584
00585 return (prog.close() == 0) ? true : false;
00586 }
00587
00589
00591
00592
00593
00595
00597
00598
00599
00600
00601 KeyRing::KeyRing()
00602 : _pimpl( new Impl() )
00603 {}
00604
00606
00607
00608
00609
00610
00611
00612
00613
00615
00616
00617
00618
00619 KeyRing::~KeyRing()
00620 {}
00621
00623
00624
00625
00627
00628 void KeyRing::importKey( const Pathname &keyfile, bool trusted)
00629 {
00630 _pimpl->importKey(keyfile, trusted);
00631 }
00632
00633 PublicKey KeyRing::readPublicKey( const Pathname &keyfile )
00634 {
00635 return _pimpl->readPublicKey(keyfile);
00636 }
00637
00638 std::string KeyRing::readSignatureKeyId( const Pathname &signature )
00639 {
00640 return _pimpl->readSignatureKeyId(signature);
00641 }
00642
00643 void KeyRing::deleteKey( const std::string &id, bool trusted )
00644 {
00645 _pimpl->deleteKey(id, trusted);
00646 }
00647
00648 std::list<PublicKey> KeyRing::publicKeys()
00649 {
00650 return _pimpl->publicKeys();
00651 }
00652
00653 std::list<PublicKey> KeyRing::trustedPublicKeys()
00654 {
00655 return _pimpl->trustedPublicKeys();
00656 }
00657
00658 bool KeyRing::verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature)
00659 {
00660 return _pimpl->verifyFileSignatureWorkflow(file, filedesc, signature);
00661 }
00662
00663 bool KeyRing::verifyFileSignature( const Pathname &file, const Pathname &signature)
00664 {
00665 return _pimpl->verifyFileSignature(file, signature);
00666 }
00667
00668 bool KeyRing::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
00669 {
00670 return _pimpl->verifyFileTrustedSignature(file, signature);
00671 }
00672
00673 void KeyRing::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
00674 {
00675 _pimpl->dumpPublicKey( id, trusted, stream);
00676 }
00677
00679 }