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 <boost/format.hpp>
00019
00020 #include "zypp/TmpPath.h"
00021 #include "zypp/ZYppFactory.h"
00022 #include "zypp/ZYpp.h"
00023
00024 #include "zypp/base/Logger.h"
00025 #include "zypp/base/IOStream.h"
00026 #include "zypp/base/String.h"
00027 #include "zypp/base/Regex.h"
00028 #include "zypp/base/Gettext.h"
00029 #include "zypp/PathInfo.h"
00030 #include "zypp/KeyRing.h"
00031 #include "zypp/ExternalProgram.h"
00032 #include "zypp/TmpPath.h"
00033
00034 using namespace std;
00035 using namespace zypp::filesystem;
00036
00037 #undef ZYPP_BASE_LOGGER_LOGGROUP
00038 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::KeyRing"
00039
00040 #define GPG_BINARY "/usr/bin/gpg2"
00041
00043 namespace zypp
00044 {
00045
00046 IMPL_PTR_TYPE(KeyRing);
00047
00048 namespace
00049 {
00050 KeyRing::DefaultAccept _keyRingDefaultAccept( KeyRing::ACCEPT_NOTHING );
00051 }
00052
00053 KeyRing::DefaultAccept KeyRing::defaultAccept()
00054 { return _keyRingDefaultAccept; }
00055
00056 void KeyRing::setDefaultAccept( DefaultAccept value_r )
00057 {
00058 MIL << "Set new KeyRing::DefaultAccept: " << value_r << endl;
00059 _keyRingDefaultAccept = value_r;
00060 }
00061
00062 bool KeyRingReport::askUserToAcceptUnsignedFile( const string &file, const KeyContext &keycontext )
00063 { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_UNSIGNED_FILE ); }
00064
00065 KeyRingReport::KeyTrust
00066 KeyRingReport::askUserToAcceptKey( const PublicKey &key, const KeyContext &keycontext )
00067 {
00068 if ( _keyRingDefaultAccept.testFlag( KeyRing::TRUST_KEY_TEMPORARILY ) )
00069 return KEY_TRUST_TEMPORARILY;
00070 if ( _keyRingDefaultAccept.testFlag( KeyRing::TRUST_AND_IMPORT_KEY ) )
00071 return KEY_TRUST_AND_IMPORT;
00072 return KEY_DONT_TRUST;
00073 }
00074
00075 bool KeyRingReport::askUserToAcceptUnknownKey( const string &file, const string &id, const KeyContext &keycontext )
00076 { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_UNKNOWNKEY ); }
00077
00078 bool KeyRingReport::askUserToAcceptVerificationFailed( const string &file, const PublicKey &key, const KeyContext &keycontext )
00079 { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_VERIFICATION_FAILED ); }
00080
00082
00083
00084
00086 struct KeyRing::Impl
00087 {
00088 Impl( const Pathname & baseTmpDir )
00089 : _trusted_tmp_dir( baseTmpDir, "zypp-trusted-kr" )
00090 , _general_tmp_dir( baseTmpDir, "zypp-general-kr" )
00091 , _base_dir( baseTmpDir )
00092 {
00093 MIL << "Current KeyRing::DefaultAccept: " << _keyRingDefaultAccept << endl;
00094 }
00095
00096 void importKey( const PublicKey &key, bool trusted = false);
00097 void deleteKey( const string &id, bool trusted );
00098
00099 string readSignatureKeyId( const Pathname &signature );
00100
00101 bool isKeyTrusted( const string &id);
00102 bool isKeyKnown( const string &id );
00103
00104 list<PublicKey> trustedPublicKeys();
00105 list<PublicKey> publicKeys();
00106
00107 list<string> trustedPublicKeyIds();
00108 list<string> publicKeyIds();
00109
00110 void dumpPublicKey( const string &id, bool trusted, ostream &stream );
00111
00112 bool verifyFileSignatureWorkflow(
00113 const Pathname &file,
00114 const string filedesc,
00115 const Pathname &signature,
00116 const KeyContext &keycontext = KeyContext());
00117
00118 bool verifyFileSignature( const Pathname &file, const Pathname &signature);
00119 bool verifyFileTrustedSignature( const Pathname &file, const Pathname &signature);
00120 private:
00121
00122 bool verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring);
00123 void importKey( const Pathname &keyfile, const Pathname &keyring);
00124 PublicKey exportKey( string id, const Pathname &keyring);
00125 void dumpPublicKey( const string &id, const Pathname &keyring, ostream &stream );
00126 void deleteKey( const string &id, const Pathname &keyring );
00127
00128 list<PublicKey> publicKeys(const Pathname &keyring);
00129 list<string> publicKeyIds(const Pathname &keyring);
00130
00131 bool publicKeyExists( string id, const Pathname &keyring);
00132
00133 const Pathname generalKeyRing() const;
00134 const Pathname trustedKeyRing() const;
00135
00136
00137 TmpDir _trusted_tmp_dir;
00138 TmpDir _general_tmp_dir;
00139 Pathname _base_dir;
00140 public:
00142 static shared_ptr<Impl> nullimpl()
00143 {
00144 static shared_ptr<Impl> _nullimpl( new Impl( TmpPath::defaultLocation() ) );
00145 return _nullimpl;
00146 }
00147
00148 private:
00149 friend Impl * rwcowClone<Impl>( const Impl * rhs );
00151 Impl * clone() const
00152 { return new Impl( *this ); }
00153 };
00154
00155
00156 const Pathname KeyRing::Impl::generalKeyRing() const
00157 {
00158 return _general_tmp_dir.path();
00159 }
00160
00161 const Pathname KeyRing::Impl::trustedKeyRing() const
00162 {
00163 return _trusted_tmp_dir.path();
00164 }
00165
00166 void KeyRing::Impl::importKey( const PublicKey &key, bool trusted)
00167 {
00168 callback::SendReport<target::rpm::KeyRingSignals> rpmdbEmitSignal;
00169 callback::SendReport<KeyRingSignals> emitSignal;
00170
00171 importKey( key.path(), trusted ? trustedKeyRing() : generalKeyRing() );
00172
00173 if ( trusted )
00174 {
00175 rpmdbEmitSignal->trustedKeyAdded( key );
00176 emitSignal->trustedKeyAdded( key );
00177 }
00178 }
00179
00180 void KeyRing::Impl::deleteKey( const string &id, bool trusted)
00181 {
00182 PublicKey key;
00183
00184 if (trusted)
00185 {
00186 key = exportKey(id, trustedKeyRing());
00187 }
00188
00189 deleteKey( id, trusted ? trustedKeyRing() : generalKeyRing() );
00190
00191 if ( trusted )
00192 {
00193 callback::SendReport<target::rpm::KeyRingSignals> rpmdbEmitSignal;
00194 callback::SendReport<KeyRingSignals> emitSignal;
00195
00196 rpmdbEmitSignal->trustedKeyRemoved( key );
00197 emitSignal->trustedKeyRemoved( key );
00198 }
00199 }
00200
00201 list<PublicKey> KeyRing::Impl::publicKeys()
00202 {
00203 return publicKeys( generalKeyRing() );
00204 }
00205
00206 list<PublicKey> KeyRing::Impl::trustedPublicKeys()
00207 {
00208 return publicKeys( trustedKeyRing() );
00209 }
00210
00211 list<string> KeyRing::Impl::publicKeyIds()
00212 {
00213 return publicKeyIds( generalKeyRing() );
00214 }
00215
00216 list<string> KeyRing::Impl::trustedPublicKeyIds()
00217 {
00218 return publicKeyIds( trustedKeyRing() );
00219 }
00220
00221 bool KeyRing::Impl::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
00222 {
00223 return verifyFile( file, signature, trustedKeyRing() );
00224 }
00225
00226 bool KeyRing::Impl::verifyFileSignature( const Pathname &file, const Pathname &signature)
00227 {
00228 return verifyFile( file, signature, generalKeyRing() );
00229 }
00230
00231 bool KeyRing::Impl::isKeyTrusted( const string &id)
00232 {
00233 return publicKeyExists( id, trustedKeyRing() );
00234 }
00235
00236 bool KeyRing::Impl::isKeyKnown( const string &id )
00237 {
00238 MIL << endl;
00239 if ( publicKeyExists( id, trustedKeyRing() ) )
00240 return true;
00241 else
00242 return publicKeyExists( id, generalKeyRing() );
00243 }
00244
00245 bool KeyRing::Impl::publicKeyExists( string id, const Pathname &keyring)
00246 {
00247 MIL << "Searching key [" << id << "] in keyring " << keyring << endl;
00248 list<PublicKey> keys = publicKeys(keyring);
00249 for (list<PublicKey>::const_iterator it = keys.begin(); it != keys.end(); it++)
00250 {
00251 if ( id == (*it).id() )
00252
00253 return true;
00254 }
00255 return false;
00256 }
00257
00258 PublicKey KeyRing::Impl::exportKey( string id, const Pathname &keyring)
00259 {
00260 TmpFile tmp_file( _base_dir, "pubkey-"+id+"-" );
00261 MIL << "Going to export key " << id << " from " << keyring << " to " << tmp_file.path() << endl;
00262
00263 try {
00264 ofstream os(tmp_file.path().c_str());
00265 dumpPublicKey( id, keyring, os );
00266 os.close();
00267 return PublicKey( tmp_file );
00268 }
00269 catch (BadKeyException &e)
00270 {
00271 ERR << "Cannot create public key " << id << " from " << keyring << " keyring to file " << e.keyFile() << endl;
00272
00273
00274 ZYPP_THROW(Exception(boost::str(boost::format(
00275 _("Cannot create public key %s from %s keyring to file %s"))
00276 % id % keyring.asString() % e.keyFile().asString())));
00277 }
00278 catch (exception &e)
00279 {
00280 ERR << "Cannot export key " << id << " from " << keyring << " keyring to file " << tmp_file.path() << endl;
00281 }
00282 return PublicKey();
00283 }
00284
00285 void KeyRing::Impl::dumpPublicKey( const string &id, bool trusted, ostream &stream )
00286 {
00287 dumpPublicKey( id, ( trusted ? trustedKeyRing() : generalKeyRing() ), stream );
00288 }
00289
00290 void KeyRing::Impl::dumpPublicKey( const string &id, const Pathname &keyring, ostream &stream )
00291 {
00292 const char* argv[] =
00293 {
00294 GPG_BINARY,
00295 "--no-default-keyring",
00296 "--quiet",
00297 "--no-tty",
00298 "--no-greeting",
00299 "--no-permission-warning",
00300 "--batch",
00301 "--homedir",
00302 keyring.asString().c_str(),
00303 "-a",
00304 "--export",
00305 id.c_str(),
00306 NULL
00307 };
00308 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00309 string line;
00310 int count;
00311 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
00312 {
00313 stream << line;
00314 }
00315 prog.close();
00316 }
00317
00318
00319 bool KeyRing::Impl::verifyFileSignatureWorkflow(
00320 const Pathname &file,
00321 const string filedesc,
00322 const Pathname &signature,
00323 const KeyContext &context)
00324 {
00325 callback::SendReport<KeyRingReport> report;
00326
00327 MIL << "Going to verify signature for " << filedesc << " ( " << file << " ) with " << signature << endl;
00328
00329
00330 if( signature.empty() || (!PathInfo(signature).isExist()) )
00331 {
00332 bool res = report->askUserToAcceptUnsignedFile( filedesc, context );
00333 MIL << "User decision on unsigned file: " << res << endl;
00334 return res;
00335 }
00336
00337
00338 string id = readSignatureKeyId(signature);
00339
00340
00341 if ( publicKeyExists( id, trustedKeyRing() ) )
00342 {
00343 PublicKey key = exportKey( id, trustedKeyRing() );
00344
00345
00346
00347 if ( publicKeyExists( id, generalKeyRing() ) )
00348 {
00349
00350
00351 PublicKey untkey = exportKey( id, generalKeyRing() );
00352 if ( untkey.fingerprint() == key.fingerprint()
00353 && untkey.created() > key.created() )
00354 {
00355 MIL << "Key " << key << " was updated. Saving new version into trusted keyring." << endl;
00356 importKey( untkey, true );
00357 key = untkey;
00358 }
00359 }
00360
00361 MIL << "Key " << id << " " << key.name() << " is trusted" << endl;
00362
00363 if ( verifyFile( file, signature, trustedKeyRing() ) )
00364 return true;
00365 else
00366 return report->askUserToAcceptVerificationFailed( filedesc, key, context );
00367 }
00368 else
00369 {
00370 if ( publicKeyExists( id, generalKeyRing() ) )
00371 {
00372 PublicKey key = exportKey( id, generalKeyRing());
00373 MIL << "Exported key " << id << " to " << key.path() << endl;
00374 MIL << "Key " << id << " " << key.name() << " is not trusted" << endl;
00375
00376
00377 KeyRingReport::KeyTrust reply = report->askUserToAcceptKey(key, context);
00378 if (reply == KeyRingReport::KEY_TRUST_TEMPORARILY ||
00379 reply == KeyRingReport::KEY_TRUST_AND_IMPORT)
00380 {
00381 MIL << "User wants to trust key " << id << " " << key.name() << endl;
00382
00383
00384 Pathname which_keyring;
00385 if (reply == KeyRingReport::KEY_TRUST_AND_IMPORT)
00386 {
00387 MIL << "User wants to import key " << id << " " << key.name() << endl;
00388 importKey( key, true );
00389 which_keyring = trustedKeyRing();
00390 }
00391 else
00392 which_keyring = generalKeyRing();
00393
00394
00395 if ( verifyFile( file, signature, which_keyring ) )
00396 {
00397 MIL << "File signature is verified" << endl;
00398 return true;
00399 }
00400 else
00401 {
00402 MIL << "File signature check fails" << endl;
00403 if ( report->askUserToAcceptVerificationFailed( filedesc, key, context ) )
00404 {
00405 MIL << "User continues anyway." << endl;
00406 return true;
00407 }
00408 else
00409 {
00410 MIL << "User does not want to continue" << endl;
00411 return false;
00412 }
00413 }
00414 }
00415 else
00416 {
00417 MIL << "User does not want to trust key " << id << " " << key.name() << endl;
00418 return false;
00419 }
00420 }
00421 else
00422 {
00423
00424 MIL << "File [" << file << "] ( " << filedesc << " ) signed with unknown key [" << id << "]" << endl;
00425 if ( report->askUserToAcceptUnknownKey( filedesc, id, context ) )
00426 {
00427 MIL << "User wants to accept unknown key " << id << endl;
00428 return true;
00429 }
00430 else
00431 {
00432 MIL << "User does not want to accept unknown key " << id << endl;
00433 return false;
00434 }
00435 }
00436 }
00437 return false;
00438 }
00439
00440 list<string> KeyRing::Impl::publicKeyIds(const Pathname &keyring)
00441 {
00442 static str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
00443 static str::regex rxColonsFpr("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
00444
00445 list<string> ids;
00446
00447 const char* argv[] =
00448 {
00449 GPG_BINARY,
00450 "--no-default-keyring",
00451 "--quiet",
00452 "--list-public-keys",
00453 "--fixed-list-mode",
00454 "--with-colons",
00455 "--with-fingerprint",
00456 "--no-tty",
00457 "--no-greeting",
00458 "--batch",
00459 "--status-fd",
00460 "1",
00461 "--homedir",
00462 keyring.asString().c_str(),
00463 NULL
00464 };
00465
00466 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00467 string line;
00468 int count = 0;
00469
00470 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
00471 {
00472
00473 str::smatch what;
00474 if(str::regex_match(line, what, rxColons))
00475 {
00476 string id;
00477 string fingerprint;
00478 if ( what[1] == "pub" )
00479 {
00480 id = what[5];
00481
00482 string line2;
00483 for(line2 = prog.receiveLine(); !line2.empty(); line2 = prog.receiveLine(), count++ )
00484 {
00485 str::smatch what2;
00486 if (str::regex_match(line2, what2, rxColonsFpr))
00487 {
00488 if ( (what2[1] == "fpr") && (what2[1] != "pub") && (what2[1] !="sub"))
00489 {
00490 fingerprint = what2[10];
00491 break;
00492 }
00493 }
00494 }
00495
00496 ids.push_back(id);
00497 MIL << "Found key " << "[" << id << "]" << endl;
00498 }
00499
00500 }
00501 }
00502 prog.close();
00503 return ids;
00504 }
00505
00506 list<PublicKey> KeyRing::Impl::publicKeys(const Pathname &keyring)
00507 {
00508
00509 list<PublicKey> keys;
00510
00511 list<string> ids = publicKeyIds(keyring);
00512
00513 for ( list<string>::const_iterator it = ids.begin(); it != ids.end(); ++it )
00514 {
00515 PublicKey key(exportKey( *it, keyring ));
00516 keys.push_back(key);
00517 MIL << "Found key " << "[" << key.id() << "]" << " [" << key.name() << "]" << " [" << key.fingerprint() << "]" << endl;
00518 }
00519 return keys;
00520 }
00521
00522 void KeyRing::Impl::importKey( const Pathname &keyfile, const Pathname &keyring)
00523 {
00524 if ( ! PathInfo(keyfile).isExist() )
00525
00526 ZYPP_THROW(KeyRingException(boost::str(boost::format(
00527 _("Tried to import not existant key %s into keyring %s"))
00528 % keyfile.asString() % keyring.asString())));
00529
00530 const char* argv[] =
00531 {
00532 GPG_BINARY,
00533 "--no-default-keyring",
00534 "--quiet",
00535 "--no-tty",
00536 "--no-greeting",
00537 "--no-permission-warning",
00538 "--status-fd",
00539 "1",
00540 "--homedir",
00541 keyring.asString().c_str(),
00542 "--import",
00543 keyfile.asString().c_str(),
00544 NULL
00545 };
00546
00547 int code;
00548 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00549 code = prog.close();
00550
00551
00552
00553 }
00554
00555 void KeyRing::Impl::deleteKey( const string &id, const Pathname &keyring )
00556 {
00557 const char* argv[] =
00558 {
00559 GPG_BINARY,
00560 "--no-default-keyring",
00561 "--yes",
00562 "--quiet",
00563 "--no-tty",
00564 "--batch",
00565 "--status-fd",
00566 "1",
00567 "--homedir",
00568 keyring.asString().c_str(),
00569 "--delete-keys",
00570 id.c_str(),
00571 NULL
00572 };
00573
00574 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00575
00576 int code = prog.close();
00577 if ( code )
00578 ZYPP_THROW(Exception(_("Failed to delete key.")));
00579 else
00580 MIL << "Deleted key " << id << " from keyring " << keyring << endl;
00581 }
00582
00583
00584 string KeyRing::Impl::readSignatureKeyId(const Pathname &signature )
00585 {
00586 if ( ! PathInfo(signature).isFile() )
00587 ZYPP_THROW(Exception(boost::str(boost::format(
00588 _("Signature file %s not found"))% signature.asString())));
00589
00590 MIL << "Determining key id if signature " << signature << endl;
00591
00592 TmpDir dir(_base_dir, "fake-keyring");
00593
00594 const char* argv[] =
00595 {
00596 GPG_BINARY,
00597 "--no-default-keyring",
00598 "--quiet",
00599 "--no-tty",
00600 "--no-greeting",
00601 "--batch",
00602 "--status-fd",
00603 "1",
00604 "--homedir",
00605 dir.path().asString().c_str(),
00606 signature.asString().c_str(),
00607 NULL
00608 };
00609
00610 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00611
00612 string line;
00613 int count = 0;
00614
00615 str::regex rxNoKey("^\\[GNUPG:\\] NO_PUBKEY (.+)\n$");
00616 string id;
00617 for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
00618 {
00619
00620 str::smatch what;
00621 if(str::regex_match(line, what, rxNoKey))
00622 {
00623 if ( what.size() >= 1 )
00624 id = what[1];
00625
00626 }
00627 else
00628 {
00629 MIL << "'" << line << "'" << endl;
00630 }
00631 }
00632
00633 if ( count == 0 )
00634 {
00635 MIL << "no output" << endl;
00636 }
00637
00638 MIL << "Determined key id [" << id << "] for signature " << signature << endl;
00639 prog.close();
00640 return id;
00641 }
00642
00643 bool KeyRing::Impl::verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring)
00644 {
00645 const char* argv[] =
00646 {
00647 GPG_BINARY,
00648 "--no-default-keyring",
00649 "--quiet",
00650 "--no-tty",
00651 "--batch",
00652 "--no-greeting",
00653 "--status-fd",
00654 "1",
00655 "--homedir",
00656 keyring.asString().c_str(),
00657 "--verify",
00658 signature.asString().c_str(),
00659 file.asString().c_str(),
00660 NULL
00661 };
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00674
00675 return (prog.close() == 0) ? true : false;
00676 }
00677
00679
00681
00682
00683
00685
00687
00688
00689
00690
00691 KeyRing::KeyRing(const Pathname &baseTmpDir)
00692 : _pimpl( new Impl(baseTmpDir) )
00693 {}
00694
00696
00697
00698
00699
00700
00701
00702
00703
00705
00706
00707
00708
00709 KeyRing::~KeyRing()
00710 {}
00711
00713
00714
00715
00717
00718
00719 void KeyRing::importKey( const PublicKey &key, bool trusted )
00720 {
00721 _pimpl->importKey( key, trusted );
00722 }
00723
00724 string KeyRing::readSignatureKeyId( const Pathname &signature )
00725 {
00726 return _pimpl->readSignatureKeyId(signature);
00727 }
00728
00729 void KeyRing::deleteKey( const string &id, bool trusted )
00730 {
00731 _pimpl->deleteKey(id, trusted);
00732 }
00733
00734 list<PublicKey> KeyRing::publicKeys()
00735 {
00736 return _pimpl->publicKeys();
00737 }
00738
00739 list<PublicKey> KeyRing::trustedPublicKeys()
00740 {
00741 return _pimpl->trustedPublicKeys();
00742 }
00743
00744 list<string> KeyRing::publicKeyIds()
00745 {
00746 return _pimpl->publicKeyIds();
00747 }
00748
00749 list<string> KeyRing::trustedPublicKeyIds()
00750 {
00751 return _pimpl->trustedPublicKeyIds();
00752 }
00753
00754 bool KeyRing::verifyFileSignatureWorkflow(
00755 const Pathname &file,
00756 const string filedesc,
00757 const Pathname &signature,
00758 const KeyContext &keycontext)
00759 {
00760 return _pimpl->verifyFileSignatureWorkflow(file, filedesc, signature, keycontext);
00761 }
00762
00763 bool KeyRing::verifyFileSignature( const Pathname &file, const Pathname &signature)
00764 {
00765 return _pimpl->verifyFileSignature(file, signature);
00766 }
00767
00768 bool KeyRing::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
00769 {
00770 return _pimpl->verifyFileTrustedSignature(file, signature);
00771 }
00772
00773 void KeyRing::dumpPublicKey( const string &id, bool trusted, ostream &stream )
00774 {
00775 _pimpl->dumpPublicKey( id, trusted, stream);
00776 }
00777
00778 bool KeyRing::isKeyTrusted( const string &id )
00779 {
00780 return _pimpl->isKeyTrusted(id);
00781 }
00782
00783 bool KeyRing::isKeyKnown( const string &id )
00784 {
00785 return _pimpl->isKeyKnown(id);
00786 }
00787
00789 }