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