keyresolver.cpp
00001 /* -*- c++ -*- 00002 keyresolver.cpp 00003 00004 This file is part of libkleopatra, the KDE keymanagement library 00005 Copyright (c) 2004 Klarälvdalens Datakonsult AB 00006 00007 Based on kpgp.cpp 00008 Copyright (C) 2001,2002 the KPGP authors 00009 See file libtdenetwork/AUTHORS.kpgp for details 00010 00011 Libkleopatra is free software; you can redistribute it and/or 00012 modify it under the terms of the GNU General Public License as 00013 published by the Free Software Foundation; either version 2 of the 00014 License, or (at your option) any later version. 00015 00016 Libkleopatra is distributed in the hope that it will be useful, 00017 but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00019 General Public License for more details. 00020 00021 You should have received a copy of the GNU General Public License 00022 along with this program; if not, write to the Free Software 00023 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00024 00025 In addition, as a special exception, the copyright holders give 00026 permission to link the code of this program with any edition of 00027 the TQt library by Trolltech AS, Norway (or with modified versions 00028 of TQt that use the same license as TQt), and distribute linked 00029 combinations including the two. You must obey the GNU General 00030 Public License in all respects for all of the code used other than 00031 TQt. If you modify this file, you may extend this exception to 00032 your version of the file, but you are not obligated to do so. If 00033 you do not wish to do so, delete this exception statement from 00034 your version. 00035 */ 00036 00037 #ifdef HAVE_CONFIG_H 00038 #include <config.h> 00039 #endif 00040 00041 #include "keyresolver.h" 00042 00043 #include "kcursorsaver.h" 00044 #include "kleo_util.h" 00045 #include "stl_util.h" 00046 00047 #include <libemailfunctions/email.h> 00048 #include <ui/keyselectiondialog.h> 00049 #include <kleo/cryptobackendfactory.h> 00050 #include <kleo/keylistjob.h> 00051 #include <kleo/dn.h> 00052 00053 #include <gpgmepp/key.h> 00054 #include <gpgmepp/keylistresult.h> 00055 00056 #include <tdeabc/stdaddressbook.h> 00057 #include <tdelocale.h> 00058 #include <kdebug.h> 00059 #include <kinputdialog.h> 00060 #include <tdemessagebox.h> 00061 00062 #include <tqstringlist.h> 00063 #include <tqtl.h> 00064 00065 #include <time.h> 00066 00067 #include <algorithm> 00068 #include <memory> 00069 #include <iterator> 00070 #include <functional> 00071 #include <map> 00072 #include <set> 00073 #include <iostream> 00074 #include <cassert> 00075 00076 00077 // 00078 // some predicates to be used in STL algorithms: 00079 // 00080 00081 static inline bool EmptyKeyList( const Kleo::KeyApprovalDialog::Item & item ) { 00082 return item.keys.empty(); 00083 } 00084 00085 static inline TQString ItemDotAddress( const Kleo::KeyResolver::Item & item ) { 00086 return item.address; 00087 } 00088 00089 static inline bool ApprovalNeeded( const Kleo::KeyResolver::Item & item ) { 00090 return item.pref == Kleo::UnknownPreference || item.pref == Kleo::NeverEncrypt || item.keys.empty() ; 00091 } 00092 00093 static inline Kleo::KeyResolver::Item 00094 CopyKeysAndEncryptionPreferences( const Kleo::KeyResolver::Item & oldItem, 00095 const Kleo::KeyApprovalDialog::Item & newItem ) { 00096 return Kleo::KeyResolver::Item( oldItem.address, newItem.keys, newItem.pref, oldItem.signPref, oldItem.format ); 00097 } 00098 00099 static inline bool ByKeyID( const GpgME::Key & left, const GpgME::Key & right ) { 00100 return qstrcmp( left.keyID(), right.keyID() ) < 0 ; 00101 } 00102 00103 static inline bool WithRespectToKeyID( const GpgME::Key & left, const GpgME::Key & right ) { 00104 return qstrcmp( left.keyID(), right.keyID() ) == 0 ; 00105 } 00106 00107 static bool ValidOpenPGPEncryptionKey( const GpgME::Key & key ) { 00108 if ( key.protocol() != GpgME::Context::OpenPGP ) { 00109 return false; 00110 } 00111 #if 0 00112 if ( key.isRevoked() ) 00113 kdWarning() << " is revoked" << endl; 00114 if ( key.isExpired() ) 00115 kdWarning() << " is expired" << endl; 00116 if ( key.isDisabled() ) 00117 kdWarning() << " is disabled" << endl; 00118 if ( !key.canEncrypt() ) 00119 kdWarning() << " can't encrypt" << endl; 00120 #endif 00121 if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canEncrypt() ) 00122 return false; 00123 return true; 00124 } 00125 00126 static bool ValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) { 00127 if ( !ValidOpenPGPEncryptionKey( key ) ) 00128 return false; 00129 const std::vector<GpgME::UserID> uids = key.userIDs(); 00130 for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it ) { 00131 if ( !it->isRevoked() && it->validity() >= GpgME::UserID::Marginal ) 00132 return true; 00133 #if 0 00134 else 00135 if ( it->isRevoked() ) 00136 kdWarning() << "a userid is revoked" << endl; 00137 else 00138 kdWarning() << "bad validity " << it->validity() << endl; 00139 #endif 00140 } 00141 return false; 00142 } 00143 00144 static bool ValidSMIMEEncryptionKey( const GpgME::Key & key ) { 00145 if ( key.protocol() != GpgME::Context::CMS ) 00146 return false; 00147 if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canEncrypt() ) 00148 return false; 00149 return true; 00150 } 00151 00152 static bool ValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) { 00153 if ( !ValidSMIMEEncryptionKey( key ) ) 00154 return false; 00155 return true; 00156 } 00157 00158 static inline bool ValidTrustedEncryptionKey( const GpgME::Key & key ) { 00159 switch ( key.protocol() ) { 00160 case GpgME::Context::OpenPGP: 00161 return ValidTrustedOpenPGPEncryptionKey( key ); 00162 case GpgME::Context::CMS: 00163 return ValidTrustedSMIMEEncryptionKey( key ); 00164 default: 00165 return false; 00166 } 00167 } 00168 00169 static inline bool ValidEncryptionKey( const GpgME::Key & key ) { 00170 switch ( key.protocol() ) { 00171 case GpgME::Context::OpenPGP: 00172 return ValidOpenPGPEncryptionKey( key ); 00173 case GpgME::Context::CMS: 00174 return ValidSMIMEEncryptionKey( key ); 00175 default: 00176 return false; 00177 } 00178 } 00179 00180 static inline bool ValidSigningKey( const GpgME::Key & key ) { 00181 if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canSign() ) 00182 return false; 00183 return key.hasSecret(); 00184 } 00185 00186 static inline bool ValidOpenPGPSigningKey( const GpgME::Key & key ) { 00187 return key.protocol() == GpgME::Context::OpenPGP && ValidSigningKey( key ); 00188 } 00189 00190 static inline bool ValidSMIMESigningKey( const GpgME::Key & key ) { 00191 return key.protocol() == GpgME::Context::CMS && ValidSigningKey( key ); 00192 } 00193 00194 static inline bool NotValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) { 00195 return !ValidTrustedOpenPGPEncryptionKey( key ); 00196 } 00197 00198 static inline bool NotValidOpenPGPEncryptionKey( const GpgME::Key & key ) { 00199 return !ValidOpenPGPEncryptionKey( key ); 00200 } 00201 00202 static inline bool NotValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) { 00203 return !ValidTrustedSMIMEEncryptionKey( key ); 00204 } 00205 00206 static inline bool NotValidSMIMEEncryptionKey( const GpgME::Key & key ) { 00207 return !ValidSMIMEEncryptionKey( key ); 00208 } 00209 00210 static inline bool NotValidTrustedEncryptionKey( const GpgME::Key & key ) { 00211 return !ValidTrustedEncryptionKey( key ); 00212 } 00213 00214 static inline bool NotValidEncryptionKey( const GpgME::Key & key ) { 00215 return !ValidEncryptionKey( key ); 00216 } 00217 00218 static inline bool NotValidSigningKey( const GpgME::Key & key ) { 00219 return !ValidSigningKey( key ); 00220 } 00221 00222 static inline bool NotValidOpenPGPSigningKey( const GpgME::Key & key ) { 00223 return !ValidOpenPGPSigningKey( key ); 00224 } 00225 00226 static inline bool NotValidSMIMESigningKey( const GpgME::Key & key ) { 00227 return !ValidSMIMESigningKey( key ); 00228 } 00229 00230 namespace { 00231 struct ByTrustScore { 00232 static int score( const GpgME::UserID & uid ) { 00233 return uid.isRevoked() || uid.isInvalid() ? -1 : uid.validity() ; 00234 } 00235 bool operator()( const GpgME::UserID & lhs, const GpgME::UserID & rhs ) const { 00236 return score( lhs ) < score( rhs ) ; 00237 } 00238 }; 00239 } 00240 00241 static std::vector<GpgME::UserID> matchingUIDs( const std::vector<GpgME::UserID> & uids, const TQString & address ) { 00242 if ( address.isEmpty() ) 00243 return std::vector<GpgME::UserID>(); 00244 00245 std::vector<GpgME::UserID> result; 00246 result.reserve( uids.size() ); 00247 for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin(), end = uids.end() ; it != end ; ++it ) 00248 // PENDING(marc) check DN for an EMAIL, too, in case of X.509 certs... :/ 00249 if ( const char * email = it->email() ) 00250 if ( *email && TQString::fromUtf8( email ).stripWhiteSpace().lower() == address ) 00251 result.push_back( *it ); 00252 return result; 00253 } 00254 00255 static GpgME::UserID findBestMatchUID( const GpgME::Key & key, const TQString & address ) { 00256 const std::vector<GpgME::UserID> all = key.userIDs(); 00257 if ( all.empty() ) 00258 return GpgME::UserID(); 00259 const std::vector<GpgME::UserID> matching = matchingUIDs( all, address.lower() ); 00260 const std::vector<GpgME::UserID> & v = matching.empty() ? all : matching ; 00261 return *std::max_element( v.begin(), v.end(), ByTrustScore() ); 00262 } 00263 00264 static TQStringList keysAsStrings( const std::vector<GpgME::Key>& keys ) { 00265 TQStringList strings; 00266 for ( std::vector<GpgME::Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it ) { 00267 assert( !(*it).userID(0).isNull() ); 00268 TQString keyLabel = TQString::fromUtf8( (*it).userID(0).email() ); 00269 if ( keyLabel.isEmpty() ) 00270 keyLabel = TQString::fromUtf8( (*it).userID(0).name() ); 00271 if ( keyLabel.isEmpty() ) 00272 keyLabel = TQString::fromUtf8( (*it).userID(0).id() ); 00273 strings.append( keyLabel ); 00274 } 00275 return strings; 00276 } 00277 00278 static std::vector<GpgME::Key> trustedOrConfirmed( const std::vector<GpgME::Key> & keys, const TQString & address, bool & canceled ) { 00279 00280 // PENDING(marc) work on UserIDs here? 00281 std::vector<GpgME::Key> fishies; 00282 std::vector<GpgME::Key> ickies; 00283 std::vector<GpgME::Key> rewookies; 00284 std::vector<GpgME::Key>::const_iterator it = keys.begin(); 00285 const std::vector<GpgME::Key>::const_iterator end = keys.end(); 00286 for ( ; it != end ; it++ ) { 00287 const GpgME::Key & key = *it; 00288 assert( ValidEncryptionKey( key ) ); 00289 const GpgME::UserID uid = findBestMatchUID( key, address ); 00290 if ( uid.isRevoked() ) { 00291 rewookies.push_back( key ); 00292 } 00293 if ( !uid.isRevoked() && uid.validity() == GpgME::UserID::Marginal ) { 00294 fishies.push_back( key ); 00295 } 00296 if ( !uid.isRevoked() && uid.validity() < GpgME::UserID::Never ) { 00297 ickies.push_back( key ); 00298 } 00299 } 00300 00301 if ( fishies.empty() && ickies.empty() && rewookies.empty() ) 00302 return keys; 00303 00304 // if some keys are not fully trusted, let the user confirm their use 00305 TQString msg = address.isEmpty() 00306 ? i18n("One or more of your configured OpenPGP encryption " 00307 "keys or S/MIME certificates is not fully trusted " 00308 "for encryption.") 00309 : i18n("One or more of the OpenPGP encryption keys or S/MIME " 00310 "certificates for recipient \"%1\" is not fully trusted " 00311 "for encryption.").arg(address) ; 00312 00313 if ( !fishies.empty() ) { 00314 // certificates can't have marginal trust 00315 msg += i18n( "\nThe following keys are only marginally trusted: \n"); 00316 msg += keysAsStrings( fishies ).join(","); 00317 } 00318 if ( !ickies.empty() ) { 00319 msg += i18n( "\nThe following keys or certificates have unknown trust level: \n"); 00320 msg += keysAsStrings( ickies ).join(","); 00321 } 00322 if ( !rewookies.empty() ) { 00323 msg += i18n( "\nThe following keys or certificates are <b>revoked</b>: \n"); 00324 msg += keysAsStrings( rewookies ).join(","); 00325 } 00326 00327 if( KMessageBox::warningContinueCancel( 0, msg, i18n("Not Fully Trusted Encryption Keys"), 00328 KStdGuiItem::cont(), 00329 "not fully trusted encryption key warning" ) 00330 == KMessageBox::Continue ) 00331 return keys; 00332 else 00333 canceled = true; 00334 return std::vector<GpgME::Key>(); 00335 } 00336 00337 namespace { 00338 struct IsNotForFormat : public std::unary_function<GpgME::Key,bool> { 00339 IsNotForFormat( Kleo::CryptoMessageFormat f ) : format( f ) {} 00340 00341 bool operator()( const GpgME::Key & key ) const { 00342 return 00343 ( isOpenPGP( format ) && key.protocol() != GpgME::Context::OpenPGP ) || 00344 ( isSMIME( format ) && key.protocol() != GpgME::Context::CMS ); 00345 } 00346 00347 const Kleo::CryptoMessageFormat format; 00348 }; 00349 00350 struct IsForFormat : std::unary_function<GpgME::Key,bool> { 00351 explicit IsForFormat( Kleo::CryptoMessageFormat f ) 00352 : protocol( isOpenPGP( f ) ? GpgME::Context::OpenPGP : 00353 isSMIME( f ) ? GpgME::Context::CMS : 00354 /* else */ GpgME::Context::Unknown ) {} 00355 00356 bool operator()( const GpgME::Key & key ) const { 00357 return key.protocol() == protocol ; 00358 } 00359 00360 const GpgME::Context::Protocol protocol; 00361 }; 00362 00363 } 00364 00365 00366 00367 class Kleo::KeyResolver::SigningPreferenceCounter : public std::unary_function<Kleo::KeyResolver::Item,void> { 00368 public: 00369 SigningPreferenceCounter() 00370 : mTotal( 0 ), 00371 mUnknownSigningPreference( 0 ), 00372 mNeverSign( 0 ), 00373 mAlwaysSign( 0 ), 00374 mAlwaysSignIfPossible( 0 ), 00375 mAlwaysAskForSigning( 0 ), 00376 mAskSigningWheneverPossible( 0 ) 00377 { 00378 00379 } 00380 void operator()( const Kleo::KeyResolver::Item & item ); 00381 #define make_int_accessor(x) unsigned int num##x() const { return m##x; } 00382 make_int_accessor(UnknownSigningPreference) 00383 make_int_accessor(NeverSign) 00384 make_int_accessor(AlwaysSign) 00385 make_int_accessor(AlwaysSignIfPossible) 00386 make_int_accessor(AlwaysAskForSigning) 00387 make_int_accessor(AskSigningWheneverPossible) 00388 make_int_accessor(Total) 00389 #undef make_int_accessor 00390 private: 00391 unsigned int mTotal; 00392 unsigned int mUnknownSigningPreference, mNeverSign, mAlwaysSign, 00393 mAlwaysSignIfPossible, mAlwaysAskForSigning, mAskSigningWheneverPossible; 00394 }; 00395 00396 void Kleo::KeyResolver::SigningPreferenceCounter::operator()( const Kleo::KeyResolver::Item & item ) { 00397 switch ( item.signPref ) { 00398 #define CASE(x) case x: ++m##x; break 00399 CASE(UnknownSigningPreference); 00400 CASE(NeverSign); 00401 CASE(AlwaysSign); 00402 CASE(AlwaysSignIfPossible); 00403 CASE(AlwaysAskForSigning); 00404 CASE(AskSigningWheneverPossible); 00405 #undef CASE 00406 } 00407 ++mTotal; 00408 } 00409 00410 00411 00412 class Kleo::KeyResolver::EncryptionPreferenceCounter : public std::unary_function<Item,void> { 00413 const Kleo::KeyResolver * _this; 00414 public: 00415 EncryptionPreferenceCounter( const Kleo::KeyResolver * kr, EncryptionPreference defaultPreference ) 00416 : _this( kr ), 00417 mDefaultPreference( defaultPreference ), 00418 mTotal( 0 ), 00419 mNoKey( 0 ), 00420 mNeverEncrypt( 0 ), 00421 mUnknownPreference( 0 ), 00422 mAlwaysEncrypt( 0 ), 00423 mAlwaysEncryptIfPossible( 0 ), 00424 mAlwaysAskForEncryption( 0 ), 00425 mAskWheneverPossible( 0 ) 00426 { 00427 00428 } 00429 void operator()( Item & item ); 00430 00431 template <typename Container> 00432 void process( Container & c ) { 00433 *this = std::for_each( c.begin(), c.end(), *this ); 00434 } 00435 00436 #define make_int_accessor(x) unsigned int num##x() const { return m##x; } 00437 make_int_accessor(NoKey) 00438 make_int_accessor(NeverEncrypt) 00439 make_int_accessor(UnknownPreference) 00440 make_int_accessor(AlwaysEncrypt) 00441 make_int_accessor(AlwaysEncryptIfPossible) 00442 make_int_accessor(AlwaysAskForEncryption) 00443 make_int_accessor(AskWheneverPossible) 00444 make_int_accessor(Total) 00445 #undef make_int_accessor 00446 private: 00447 EncryptionPreference mDefaultPreference; 00448 bool mNoOps; 00449 unsigned int mTotal; 00450 unsigned int mNoKey; 00451 unsigned int mNeverEncrypt, mUnknownPreference, mAlwaysEncrypt, 00452 mAlwaysEncryptIfPossible, mAlwaysAskForEncryption, mAskWheneverPossible; 00453 }; 00454 00455 void Kleo::KeyResolver::EncryptionPreferenceCounter::operator()( Item & item ) { 00456 if ( _this ) { 00457 if ( item.needKeys ) 00458 item.keys = _this->getEncryptionKeys( item.address, true ); 00459 if ( item.keys.empty() ) { 00460 ++mNoKey; 00461 return; 00462 } 00463 } 00464 switch ( !item.pref ? mDefaultPreference : item.pref ) { 00465 #define CASE(x) case Kleo::x: ++m##x; break 00466 CASE(NeverEncrypt); 00467 CASE(UnknownPreference); 00468 CASE(AlwaysEncrypt); 00469 CASE(AlwaysEncryptIfPossible); 00470 CASE(AlwaysAskForEncryption); 00471 CASE(AskWheneverPossible); 00472 #undef CASE 00473 } 00474 ++mTotal; 00475 } 00476 00477 namespace { 00478 00479 class FormatPreferenceCounterBase : public std::unary_function<Kleo::KeyResolver::Item,void> { 00480 public: 00481 FormatPreferenceCounterBase() 00482 : mTotal( 0 ), 00483 mInlineOpenPGP( 0 ), 00484 mOpenPGPMIME( 0 ), 00485 mSMIME( 0 ), 00486 mSMIMEOpaque( 0 ) 00487 { 00488 00489 } 00490 00491 #define make_int_accessor(x) unsigned int num##x() const { return m##x; } 00492 make_int_accessor(Total) 00493 make_int_accessor(InlineOpenPGP) 00494 make_int_accessor(OpenPGPMIME) 00495 make_int_accessor(SMIME) 00496 make_int_accessor(SMIMEOpaque) 00497 #undef make_int_accessor 00498 00499 unsigned int numOf( Kleo::CryptoMessageFormat f ) const { 00500 switch ( f ) { 00501 #define CASE(x) case Kleo::x##Format: return m##x 00502 CASE(InlineOpenPGP); 00503 CASE(OpenPGPMIME); 00504 CASE(SMIME); 00505 CASE(SMIMEOpaque); 00506 #undef CASE 00507 default: return 0; 00508 } 00509 } 00510 00511 protected: 00512 unsigned int mTotal; 00513 unsigned int mInlineOpenPGP, mOpenPGPMIME, mSMIME, mSMIMEOpaque; 00514 }; 00515 00516 class EncryptionFormatPreferenceCounter : public FormatPreferenceCounterBase { 00517 public: 00518 EncryptionFormatPreferenceCounter() : FormatPreferenceCounterBase() {} 00519 void operator()( const Kleo::KeyResolver::Item & item ); 00520 }; 00521 00522 class SigningFormatPreferenceCounter : public FormatPreferenceCounterBase { 00523 public: 00524 SigningFormatPreferenceCounter() : FormatPreferenceCounterBase() {} 00525 void operator()( const Kleo::KeyResolver::Item & item ); 00526 }; 00527 00528 #define CASE(x) if ( item.format & Kleo::x##Format ) ++m##x; 00529 void EncryptionFormatPreferenceCounter::operator()( const Kleo::KeyResolver::Item & item ) { 00530 if ( item.format & (Kleo::InlineOpenPGPFormat|Kleo::OpenPGPMIMEFormat) && 00531 std::find_if( item.keys.begin(), item.keys.end(), 00532 ValidTrustedOpenPGPEncryptionKey ) != item.keys.end() ) { // -= trusted? 00533 CASE(OpenPGPMIME); 00534 CASE(InlineOpenPGP); 00535 } 00536 if ( item.format & (Kleo::SMIMEFormat|Kleo::SMIMEOpaqueFormat) && 00537 std::find_if( item.keys.begin(), item.keys.end(), 00538 ValidTrustedSMIMEEncryptionKey ) != item.keys.end() ) { // -= trusted? 00539 CASE(SMIME); 00540 CASE(SMIMEOpaque); 00541 } 00542 ++mTotal; 00543 } 00544 00545 void SigningFormatPreferenceCounter::operator()( const Kleo::KeyResolver::Item & item ) { 00546 CASE(InlineOpenPGP); 00547 CASE(OpenPGPMIME); 00548 CASE(SMIME); 00549 CASE(SMIMEOpaque); 00550 ++mTotal; 00551 } 00552 #undef CASE 00553 00554 } // anon namespace 00555 00556 static TQString canonicalAddress( const TQString & _address ) { 00557 const TQString address = KPIM::getEmailAddress( _address ); 00558 if ( address.find('@') == -1 ) { 00559 // local address 00560 //char hostname[1024]; 00561 //gethostname(hostname,1024); 00562 //return address + '@' + hostname; 00563 return address + "@localdomain"; 00564 } 00565 else 00566 return address; 00567 } 00568 00569 00570 struct FormatInfo { 00571 std::vector<Kleo::KeyResolver::SplitInfo> splitInfos; 00572 std::vector<GpgME::Key> signKeys; 00573 }; 00574 00575 struct Kleo::KeyResolver::Private { 00576 std::set<TQCString> alreadyWarnedFingerprints; 00577 00578 std::vector<GpgME::Key> mOpenPGPSigningKeys; // signing 00579 std::vector<GpgME::Key> mSMIMESigningKeys; // signing 00580 00581 std::vector<GpgME::Key> mOpenPGPEncryptToSelfKeys; // encryption to self 00582 std::vector<GpgME::Key> mSMIMEEncryptToSelfKeys; // encryption to self 00583 00584 std::vector<Item> mPrimaryEncryptionKeys; // encryption to To/CC 00585 std::vector<Item> mSecondaryEncryptionKeys; // encryption to BCC 00586 00587 std::map<CryptoMessageFormat,FormatInfo> mFormatInfoMap; 00588 00589 // key=email address, value=crypto preferences for this contact (from tdeabc) 00590 typedef std::map<TQString, ContactPreferences> ContactPreferencesMap; 00591 ContactPreferencesMap mContactPreferencesMap; 00592 }; 00593 00594 00595 Kleo::KeyResolver::KeyResolver( bool encToSelf, bool showApproval, bool oppEncryption, 00596 unsigned int f, 00597 int encrWarnThresholdKey, int signWarnThresholdKey, 00598 int encrWarnThresholdRootCert, int signWarnThresholdRootCert, 00599 int encrWarnThresholdChainCert, int signWarnThresholdChainCert ) 00600 : mEncryptToSelf( encToSelf ), 00601 mShowApprovalDialog( showApproval ), 00602 mOpportunisticEncyption( oppEncryption ), 00603 mCryptoMessageFormats( f ), 00604 mEncryptKeyNearExpiryWarningThreshold( encrWarnThresholdKey ), 00605 mSigningKeyNearExpiryWarningThreshold( signWarnThresholdKey ), 00606 mEncryptRootCertNearExpiryWarningThreshold( encrWarnThresholdRootCert ), 00607 mSigningRootCertNearExpiryWarningThreshold( signWarnThresholdRootCert ), 00608 mEncryptChainCertNearExpiryWarningThreshold( encrWarnThresholdChainCert ), 00609 mSigningChainCertNearExpiryWarningThreshold( signWarnThresholdChainCert ) 00610 { 00611 d = new Private(); 00612 } 00613 00614 Kleo::KeyResolver::~KeyResolver() { 00615 delete d; d = 0; 00616 } 00617 00618 Kpgp::Result Kleo::KeyResolver::checkKeyNearExpiry( const GpgME::Key & key, const char * dontAskAgainName, 00619 bool mine, bool sign, bool ca, 00620 int recur_limit, const GpgME::Key & orig ) const { 00621 if ( recur_limit <= 0 ) { 00622 kdDebug() << "Kleo::KeyResolver::checkKeyNearExpiry(): key chain too long (>100 certs)" << endl; 00623 return Kpgp::Ok; 00624 } 00625 const GpgME::Subkey subkey = key.subkey(0); 00626 if ( d->alreadyWarnedFingerprints.count( subkey.fingerprint() ) ) 00627 return Kpgp::Ok; // already warned about this one (and so about it's issuers) 00628 00629 if ( subkey.neverExpires() ) 00630 return Kpgp::Ok; 00631 static const double secsPerDay = 24 * 60 * 60; 00632 const double secsTillExpiry = ::difftime( subkey.expirationTime(), time(0) ); 00633 if ( secsTillExpiry <= 0 ) { 00634 const int daysSinceExpiry = 1 + int( -secsTillExpiry / secsPerDay ); 00635 kdDebug() << "Key 0x" << key.shortKeyID() << " expired less than " 00636 << daysSinceExpiry << " days ago" << endl; 00637 const TQString msg = 00638 key.protocol() == GpgME::Context::OpenPGP 00639 ? ( mine ? sign 00640 ? i18n("<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>" 00641 "<p>expired less than a day ago.</p>", 00642 "<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>" 00643 "<p>expired %n days ago.</p>", 00644 daysSinceExpiry ) 00645 : i18n("<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>" 00646 "<p>expired less than a day ago.</p>", 00647 "<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>" 00648 "<p>expired %n days ago.</p>", 00649 daysSinceExpiry ) 00650 : i18n("<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>" 00651 "<p>expired less than a day ago.</p>", 00652 "<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>" 00653 "<p>expired %n days ago.</p>", 00654 daysSinceExpiry ) ).arg( TQString::fromUtf8( key.userID(0).id() ), 00655 key.shortKeyID() ) 00656 : ( ca 00657 ? ( key.isRoot() 00658 ? ( mine ? sign 00659 ? i18n("<p>The root certificate</p><p align=center><b>%3</b></p>" 00660 "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00661 "<p>expired less than a day ago.</p>", 00662 "<p>The root certificate</p><p align=center><b>%3</b></p>" 00663 "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00664 "<p>expired %n days ago.</p>", 00665 daysSinceExpiry ) 00666 : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>" 00667 "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00668 "<p>expired less than a day ago.</p>", 00669 "<p>The root certificate</p><p align=center><b>%3</b></p>" 00670 "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00671 "<p>expired %n days ago.</p>", 00672 daysSinceExpiry ) 00673 : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>" 00674 "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00675 "<p>expired less than a day ago.</p>", 00676 "<p>The root certificate</p><p align=center><b>%3</b></p>" 00677 "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00678 "<p>expired %n days ago.</p>", 00679 daysSinceExpiry ) ) 00680 : ( mine ? sign 00681 ? i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>" 00682 "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00683 "<p>expired less than a day ago.</p>", 00684 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>" 00685 "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00686 "<p>expired %n days ago.</p>", 00687 daysSinceExpiry ) 00688 : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>" 00689 "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00690 "<p>expired less than a day ago.</p>", 00691 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>" 00692 "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00693 "<p>expired %n days ago.</p>", 00694 daysSinceExpiry ) 00695 : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>" 00696 "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00697 "<p>expired less than a day ago.</p>", 00698 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>" 00699 "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00700 "<p>expired %n days ago.</p>", 00701 daysSinceExpiry ) ) ).arg( Kleo::DN( orig.userID(0).id() ).prettyDN(), 00702 orig.issuerSerial(), 00703 Kleo::DN( key.userID(0).id() ).prettyDN() ) 00704 : ( mine ? sign 00705 ? i18n("<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00706 "<p>expired less than a day ago.</p>", 00707 "<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00708 "<p>expired %n days ago.</p>", 00709 daysSinceExpiry ) 00710 : i18n("<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00711 "<p>expired less than a day ago.</p>", 00712 "<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00713 "<p>expired %n days ago.</p>", 00714 daysSinceExpiry ) 00715 : i18n("<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>" 00716 "<p>expired less than a day ago.</p>", 00717 "<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>" 00718 "<p>expired %n days ago.</p>", 00719 daysSinceExpiry ) ).arg( Kleo::DN( key.userID(0).id() ).prettyDN(), 00720 key.issuerSerial() ) ); 00721 d->alreadyWarnedFingerprints.insert( subkey.fingerprint() ); 00722 if ( KMessageBox::warningContinueCancel( 0, msg, 00723 key.protocol() == GpgME::Context::OpenPGP 00724 ? i18n("OpenPGP Key Expired" ) 00725 : i18n("S/MIME Certificate Expired" ), 00726 KStdGuiItem::cont(), dontAskAgainName ) == KMessageBox::Cancel ) 00727 return Kpgp::Canceled; 00728 } else { 00729 const int daysTillExpiry = 1 + int( secsTillExpiry / secsPerDay ); 00730 kdDebug() << "Key 0x" << key.shortKeyID() << " expires in less than " 00731 << daysTillExpiry << " days" << endl; 00732 const int threshold = 00733 ca 00734 ? ( key.isRoot() 00735 ? ( sign 00736 ? signingRootCertNearExpiryWarningThresholdInDays() 00737 : encryptRootCertNearExpiryWarningThresholdInDays() ) 00738 : ( sign 00739 ? signingChainCertNearExpiryWarningThresholdInDays() 00740 : encryptChainCertNearExpiryWarningThresholdInDays() ) ) 00741 : ( sign 00742 ? signingKeyNearExpiryWarningThresholdInDays() 00743 : encryptKeyNearExpiryWarningThresholdInDays() ); 00744 if ( threshold > -1 && daysTillExpiry <= threshold ) { 00745 const TQString msg = 00746 key.protocol() == GpgME::Context::OpenPGP 00747 ? ( mine ? sign 00748 ? i18n("<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>" 00749 "<p>expires in less than a day.</p>", 00750 "<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>" 00751 "<p>expires in less than %n days.</p>", 00752 daysTillExpiry ) 00753 : i18n("<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>" 00754 "<p>expires in less than a day.</p>", 00755 "<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>" 00756 "<p>expires in less than %n days.</p>", 00757 daysTillExpiry ) 00758 : i18n("<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>" 00759 "<p>expires in less than a day.</p>", 00760 "<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>" 00761 "<p>expires in less than %n days.</p>", 00762 daysTillExpiry ) ).arg( TQString::fromUtf8( key.userID(0).id() ), 00763 key.shortKeyID() ) 00764 : ( ca 00765 ? ( key.isRoot() 00766 ? ( mine ? sign 00767 ? i18n("<p>The root certificate</p><p align=center><b>%3</b></p>" 00768 "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00769 "<p>expires in less than a day.</p>", 00770 "<p>The root certificate</p><p align=center><b>%3</b></p>" 00771 "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00772 "<p>expires in less than %n days.</p>", 00773 daysTillExpiry ) 00774 : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>" 00775 "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00776 "<p>expires in less than a day.</p>", 00777 "<p>The root certificate</p><p align=center><b>%3</b></p>" 00778 "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00779 "<p>expires in less than %n days.</p>", 00780 daysTillExpiry ) 00781 : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>" 00782 "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00783 "<p>expires in less than a day.</p>", 00784 "<p>The root certificate</p><p align=center><b>%3</b></p>" 00785 "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00786 "<p>expires in less than %n days.</p>", 00787 daysTillExpiry ) ) 00788 : ( mine ? sign 00789 ? i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>" 00790 "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00791 "<p>expires in less than a day.</p>", 00792 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>" 00793 "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00794 "<p>expires in less than %n days.</p>", 00795 daysTillExpiry ) 00796 : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>" 00797 "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00798 "<p>expires in less than a day.</p>", 00799 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>" 00800 "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00801 "<p>expires in less than %n days.</p>", 00802 daysTillExpiry ) 00803 : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>" 00804 "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00805 "<p>expires in less than a day.</p>", 00806 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>" 00807 "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00808 "<p>expires in less than %n days.</p>", 00809 daysTillExpiry ) ) ).arg( Kleo::DN( orig.userID(0).id() ).prettyDN(), 00810 orig.issuerSerial(), 00811 Kleo::DN( key.userID(0).id() ).prettyDN() ) 00812 : ( mine ? sign 00813 ? i18n("<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00814 "<p>expires in less than a day.</p>", 00815 "<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00816 "<p>expires in less than %n days.</p>", 00817 daysTillExpiry ) 00818 : i18n("<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00819 "<p>expires in less than a day.</p>", 00820 "<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>" 00821 "<p>expires in less than %n days.</p>", 00822 daysTillExpiry ) 00823 : i18n("<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>" 00824 "<p>expires in less than a day.</p>", 00825 "<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>" 00826 "<p>expires in less than %n days.</p>", 00827 daysTillExpiry ) ).arg( Kleo::DN( key.userID(0).id() ).prettyDN(), 00828 key.issuerSerial() ) ); 00829 d->alreadyWarnedFingerprints.insert( subkey.fingerprint() ); 00830 if ( KMessageBox::warningContinueCancel( 0, msg, 00831 key.protocol() == GpgME::Context::OpenPGP 00832 ? i18n("OpenPGP Key Expires Soon" ) 00833 : i18n("S/MIME Certificate Expires Soon" ), 00834 KStdGuiItem::cont(), dontAskAgainName ) 00835 == KMessageBox::Cancel ) 00836 return Kpgp::Canceled; 00837 } 00838 } 00839 if ( key.isRoot() ) 00840 return Kpgp::Ok; 00841 else if ( const char * chain_id = key.chainID() ) { 00842 const std::vector<GpgME::Key> issuer = lookup( chain_id, false ); 00843 if ( issuer.empty() ) 00844 return Kpgp::Ok; 00845 else 00846 return checkKeyNearExpiry( issuer.front(), dontAskAgainName, mine, sign, 00847 true, recur_limit-1, ca ? orig : key ); 00848 } 00849 return Kpgp::Ok; 00850 } 00851 00852 Kpgp::Result Kleo::KeyResolver::setEncryptToSelfKeys( const TQStringList & fingerprints ) { 00853 if ( !encryptToSelf() ) 00854 return Kpgp::Ok; 00855 00856 std::vector<GpgME::Key> keys = lookup( fingerprints ); 00857 std::remove_copy_if( keys.begin(), keys.end(), 00858 std::back_inserter( d->mOpenPGPEncryptToSelfKeys ), 00859 NotValidTrustedOpenPGPEncryptionKey ); // -= trusted? 00860 std::remove_copy_if( keys.begin(), keys.end(), 00861 std::back_inserter( d->mSMIMEEncryptToSelfKeys ), 00862 NotValidTrustedSMIMEEncryptionKey ); // -= trusted? 00863 00864 if ( d->mOpenPGPEncryptToSelfKeys.size() + d->mSMIMEEncryptToSelfKeys.size() 00865 < keys.size() ) { 00866 // too few keys remain... 00867 const TQString msg = i18n("One or more of your configured OpenPGP encryption " 00868 "keys or S/MIME certificates is not usable for " 00869 "encryption. Please reconfigure your encryption keys " 00870 "and certificates for this identity in the identity " 00871 "configuration dialog.\n" 00872 "If you choose to continue, and the keys are needed " 00873 "later on, you will be prompted to specify the keys " 00874 "to use."); 00875 return KMessageBox::warningContinueCancel( 0, msg, i18n("Unusable Encryption Keys"), 00876 KStdGuiItem::cont(), 00877 "unusable own encryption key warning" ) 00878 == KMessageBox::Continue ? Kpgp::Ok : Kpgp::Canceled ; 00879 } 00880 00881 // check for near-expiry: 00882 00883 for ( std::vector<GpgME::Key>::const_iterator it = d->mOpenPGPEncryptToSelfKeys.begin() ; it != d->mOpenPGPEncryptToSelfKeys.end() ; ++it ) { 00884 const Kpgp::Result r = checkKeyNearExpiry( *it, "own encryption key expires soon warning", 00885 true, false ); 00886 if ( r != Kpgp::Ok ) 00887 return r; 00888 } 00889 00890 for ( std::vector<GpgME::Key>::const_iterator it = d->mSMIMEEncryptToSelfKeys.begin() ; it != d->mSMIMEEncryptToSelfKeys.end() ; ++it ) { 00891 const Kpgp::Result r = checkKeyNearExpiry( *it, "own encryption key expires soon warning", 00892 true, false ); 00893 if ( r != Kpgp::Ok ) 00894 return r; 00895 } 00896 00897 return Kpgp::Ok; 00898 } 00899 00900 Kpgp::Result Kleo::KeyResolver::setSigningKeys( const TQStringList & fingerprints ) { 00901 std::vector<GpgME::Key> keys = lookup( fingerprints, true ); // secret keys 00902 std::remove_copy_if( keys.begin(), keys.end(), 00903 std::back_inserter( d->mOpenPGPSigningKeys ), 00904 NotValidOpenPGPSigningKey ); 00905 std::remove_copy_if( keys.begin(), keys.end(), 00906 std::back_inserter( d->mSMIMESigningKeys ), 00907 NotValidSMIMESigningKey ); 00908 00909 if ( d->mOpenPGPSigningKeys.size() + d->mSMIMESigningKeys.size() < keys.size() ) { 00910 // too few keys remain... 00911 const TQString msg = i18n("One or more of your configured OpenPGP signing keys " 00912 "or S/MIME signing certificates is not usable for " 00913 "signing. Please reconfigure your signing keys " 00914 "and certificates for this identity in the identity " 00915 "configuration dialog.\n" 00916 "If you choose to continue, and the keys are needed " 00917 "later on, you will be prompted to specify the keys " 00918 "to use."); 00919 return KMessageBox::warningContinueCancel( 0, msg, i18n("Unusable Signing Keys"), 00920 KStdGuiItem::cont(), 00921 "unusable signing key warning" ) 00922 == KMessageBox::Continue ? Kpgp::Ok : Kpgp::Canceled ; 00923 } 00924 00925 // check for near expiry: 00926 00927 for ( std::vector<GpgME::Key>::const_iterator it = d->mOpenPGPSigningKeys.begin() ; it != d->mOpenPGPSigningKeys.end() ; ++it ) { 00928 const Kpgp::Result r = checkKeyNearExpiry( *it, "signing key expires soon warning", 00929 true, true ); 00930 if ( r != Kpgp::Ok ) 00931 return r; 00932 } 00933 00934 for ( std::vector<GpgME::Key>::const_iterator it = d->mSMIMESigningKeys.begin() ; it != d->mSMIMESigningKeys.end() ; ++it ) { 00935 const Kpgp::Result r = checkKeyNearExpiry( *it, "signing key expires soon warning", 00936 true, true ); 00937 if ( r != Kpgp::Ok ) 00938 return r; 00939 } 00940 00941 return Kpgp::Ok; 00942 } 00943 00944 void Kleo::KeyResolver::setPrimaryRecipients( const TQStringList & addresses ) { 00945 d->mPrimaryEncryptionKeys = getEncryptionItems( addresses ); 00946 } 00947 00948 void Kleo::KeyResolver::setSecondaryRecipients( const TQStringList & addresses ) { 00949 d->mSecondaryEncryptionKeys = getEncryptionItems( addresses ); 00950 } 00951 00952 std::vector<Kleo::KeyResolver::Item> Kleo::KeyResolver::getEncryptionItems( const TQStringList & addresses ) { 00953 std::vector<Item> items; 00954 items.reserve( addresses.size() ); 00955 for ( TQStringList::const_iterator it = addresses.begin() ; it != addresses.end() ; ++it ) { 00956 TQString addr = canonicalAddress( *it ).lower(); 00957 const ContactPreferences pref = lookupContactPreferences( addr ); 00958 00959 items.push_back( Item( *it, /*getEncryptionKeys( *it, true ),*/ 00960 pref.encryptionPreference, 00961 pref.signingPreference, 00962 pref.cryptoMessageFormat ) ); 00963 } 00964 return items; 00965 } 00966 00967 static Kleo::Action action( bool doit, bool ask, bool dont, bool requested ) { 00968 if ( requested && !dont ) 00969 return Kleo::DoIt; 00970 if ( doit && !ask && !dont ) 00971 return Kleo::DoIt; 00972 if ( !doit && ask && !dont ) 00973 return Kleo::Ask; 00974 if ( !doit && !ask && dont ) 00975 return requested ? Kleo::Conflict : Kleo::DontDoIt ; 00976 if ( !doit && !ask && !dont ) 00977 return Kleo::DontDoIt ; 00978 return Kleo::Conflict; 00979 } 00980 00981 Kleo::Action Kleo::KeyResolver::checkSigningPreferences( bool signingRequested ) const { 00982 00983 if ( signingRequested && d->mOpenPGPSigningKeys.empty() && d->mSMIMESigningKeys.empty() ) 00984 return Impossible; 00985 00986 SigningPreferenceCounter count; 00987 count = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(), 00988 count ); 00989 count = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(), 00990 count ); 00991 00992 unsigned int sign = count.numAlwaysSign(); 00993 unsigned int ask = count.numAlwaysAskForSigning(); 00994 const unsigned int dontSign = count.numNeverSign(); 00995 if ( signingPossible() ) { 00996 sign += count.numAlwaysSignIfPossible(); 00997 ask += count.numAskSigningWheneverPossible(); 00998 } 00999 01000 return action( sign, ask, dontSign, signingRequested ); 01001 } 01002 01003 bool Kleo::KeyResolver::signingPossible() const { 01004 return !d->mOpenPGPSigningKeys.empty() || !d->mSMIMESigningKeys.empty() ; 01005 } 01006 01007 Kleo::Action Kleo::KeyResolver::checkEncryptionPreferences( bool encryptionRequested ) const { 01008 01009 if ( d->mPrimaryEncryptionKeys.empty() && d->mSecondaryEncryptionKeys.empty() ) 01010 return DontDoIt; 01011 01012 if ( encryptionRequested && encryptToSelf() && 01013 d->mOpenPGPEncryptToSelfKeys.empty() && d->mSMIMEEncryptToSelfKeys.empty() ) 01014 return Impossible; 01015 01016 if ( !encryptionRequested && !mOpportunisticEncyption ) { 01017 // try to minimize crypto ops (including key lookups) by only 01018 // looking up keys when at least one the the encryption 01019 // preferences needs it: 01020 EncryptionPreferenceCounter count( 0, UnknownPreference ); 01021 count.process( d->mPrimaryEncryptionKeys ); 01022 count.process( d->mSecondaryEncryptionKeys ); 01023 if ( !count.numAlwaysEncrypt() && 01024 !count.numAlwaysAskForEncryption() && // this guy might not need a lookup, when declined, but it's too complex to implement that here 01025 !count.numAlwaysEncryptIfPossible() && 01026 !count.numAskWheneverPossible() ) 01027 return DontDoIt; 01028 } 01029 01030 EncryptionPreferenceCounter count( this, mOpportunisticEncyption ? AskWheneverPossible : UnknownPreference ); 01031 count = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(), 01032 count ); 01033 count = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(), 01034 count ); 01035 01036 unsigned int encrypt = count.numAlwaysEncrypt(); 01037 unsigned int ask = count.numAlwaysAskForEncryption(); 01038 const unsigned int dontEncrypt = count.numNeverEncrypt() + count.numNoKey(); 01039 if ( encryptionPossible() ) { 01040 encrypt += count.numAlwaysEncryptIfPossible(); 01041 ask += count.numAskWheneverPossible(); 01042 } 01043 01044 const Action act = action( encrypt, ask, dontEncrypt, encryptionRequested ); 01045 if ( act != Ask || 01046 std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(), 01047 std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(), 01048 EncryptionPreferenceCounter( this, UnknownPreference ) ) ).numAlwaysAskForEncryption() ) 01049 return act; 01050 else 01051 return AskOpportunistic; 01052 } 01053 01054 bool Kleo::KeyResolver::encryptionPossible() const { 01055 return std::find_if( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(), 01056 EmptyKeyList ) == d->mPrimaryEncryptionKeys.end() 01057 && std::find_if( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(), 01058 EmptyKeyList ) == d->mSecondaryEncryptionKeys.end() ; 01059 } 01060 01061 Kpgp::Result Kleo::KeyResolver::resolveAllKeys( bool& signingRequested, bool& encryptionRequested ) { 01062 if ( !encryptionRequested && !signingRequested ) { 01063 // make a dummy entry with all recipients, but no signing or 01064 // encryption keys to avoid special-casing on the caller side: 01065 dump(); 01066 d->mFormatInfoMap[OpenPGPMIMEFormat].splitInfos.push_back( SplitInfo( allRecipients() ) ); 01067 dump(); 01068 return Kpgp::Ok; 01069 } 01070 Kpgp::Result result = Kpgp::Ok; 01071 if ( encryptionRequested ) 01072 result = resolveEncryptionKeys( signingRequested ); 01073 if ( result != Kpgp::Ok ) 01074 return result; 01075 if ( signingRequested ) { 01076 if ( encryptionRequested ) { 01077 result = resolveSigningKeysForEncryption(); 01078 } 01079 else { 01080 result = resolveSigningKeysForSigningOnly(); 01081 if ( result == Kpgp::Failure ) { 01082 signingRequested = false; 01083 return Kpgp::Ok; 01084 } 01085 } 01086 } 01087 return result; 01088 } 01089 01090 Kpgp::Result Kleo::KeyResolver::resolveEncryptionKeys( bool signingRequested ) { 01091 // 01092 // 1. Get keys for all recipients: 01093 // 01094 01095 for ( std::vector<Item>::iterator it = d->mPrimaryEncryptionKeys.begin() ; it != d->mPrimaryEncryptionKeys.end() ; ++it ) { 01096 if ( !it->needKeys ) 01097 continue; 01098 it->keys = getEncryptionKeys( it->address, false ); 01099 if ( it->keys.empty() ) 01100 return Kpgp::Canceled; 01101 TQString addr = canonicalAddress( it->address ).lower(); 01102 const ContactPreferences pref = lookupContactPreferences( addr ); 01103 it->pref = pref.encryptionPreference; 01104 it->signPref = pref.signingPreference; 01105 it->format = pref.cryptoMessageFormat; 01106 } 01107 01108 for ( std::vector<Item>::iterator it = d->mSecondaryEncryptionKeys.begin() ; it != d->mSecondaryEncryptionKeys.end() ; ++it ) { 01109 if ( !it->needKeys ) 01110 continue; 01111 it->keys = getEncryptionKeys( it->address, false ); 01112 if ( it->keys.empty() ) 01113 return Kpgp::Canceled; 01114 TQString addr = canonicalAddress( it->address ).lower(); 01115 const ContactPreferences pref = lookupContactPreferences( addr ); 01116 it->pref = pref.encryptionPreference; 01117 it->signPref = pref.signingPreference; 01118 it->format = pref.cryptoMessageFormat; 01119 } 01120 01121 // 1a: Present them to the user 01122 01123 const Kpgp::Result res = showKeyApprovalDialog(); 01124 if ( res != Kpgp::Ok ) 01125 return res; 01126 01127 // 01128 // 2. Check what the primary recipients need 01129 // 01130 01131 // 2a. Try to find a common format for all primary recipients, 01132 // else use as many formats as needed 01133 01134 const EncryptionFormatPreferenceCounter primaryCount 01135 = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(), 01136 EncryptionFormatPreferenceCounter() ); 01137 01138 CryptoMessageFormat commonFormat = AutoFormat; 01139 for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) { 01140 if ( !( concreteCryptoMessageFormats[i] & mCryptoMessageFormats ) ) 01141 continue; 01142 if ( signingRequested && signingKeysFor( concreteCryptoMessageFormats[i] ).empty() ) 01143 continue; 01144 if ( encryptToSelf() && encryptToSelfKeysFor( concreteCryptoMessageFormats[i] ).empty() ) 01145 continue; 01146 if ( primaryCount.numOf( concreteCryptoMessageFormats[i] ) == primaryCount.numTotal() ) { 01147 commonFormat = concreteCryptoMessageFormats[i]; 01148 break; 01149 } 01150 } 01151 if ( commonFormat != AutoFormat ) 01152 addKeys( d->mPrimaryEncryptionKeys, commonFormat ); 01153 else 01154 addKeys( d->mPrimaryEncryptionKeys ); 01155 01156 collapseAllSplitInfos(); // these can be encrypted together 01157 01158 // 2b. Just try to find _something_ for each secondary recipient, 01159 // with a preference to a common format (if that exists) 01160 01161 const EncryptionFormatPreferenceCounter secondaryCount 01162 = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(), 01163 EncryptionFormatPreferenceCounter() ); 01164 01165 if ( commonFormat != AutoFormat && 01166 secondaryCount.numOf( commonFormat ) == secondaryCount.numTotal() ) 01167 addKeys( d->mSecondaryEncryptionKeys, commonFormat ); 01168 else 01169 addKeys( d->mSecondaryEncryptionKeys ); 01170 01171 // 3. Check for expiry: 01172 01173 for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) { 01174 const std::vector<SplitInfo> si_list = encryptionItems( concreteCryptoMessageFormats[i] ); 01175 for ( std::vector<SplitInfo>::const_iterator sit = si_list.begin() ; sit != si_list.end() ; ++sit ) 01176 for ( std::vector<GpgME::Key>::const_iterator kit = sit->keys.begin() ; kit != sit->keys.end() ; ++kit ) { 01177 const Kpgp::Result r = checkKeyNearExpiry( *kit, "other encryption key near expiry warning", 01178 false, false ); 01179 if ( r != Kpgp::Ok ) 01180 return r; 01181 } 01182 } 01183 01184 // 4. Check that we have the right keys for encryptToSelf() 01185 01186 if ( !encryptToSelf() ) 01187 return Kpgp::Ok; 01188 01189 // 4a. Check for OpenPGP keys 01190 01191 if ( !encryptionItems( InlineOpenPGPFormat ).empty() || 01192 !encryptionItems( OpenPGPMIMEFormat ).empty() ) { 01193 // need them 01194 if ( d->mOpenPGPEncryptToSelfKeys.empty() ) { 01195 const TQString msg = i18n("Examination of recipient's encryption preferences " 01196 "yielded that the message should be encrypted using " 01197 "OpenPGP, at least for some recipients;\n" 01198 "however, you have not configured valid trusted " 01199 "OpenPGP encryption keys for this identity.\n" 01200 "You may continue without encrypting to yourself, " 01201 "but be aware that you will not be able to read your " 01202 "own messages if you do so."); 01203 if ( KMessageBox::warningContinueCancel( 0, msg, 01204 i18n("Unusable Encryption Keys"), 01205 KStdGuiItem::cont(), 01206 "encrypt-to-self will fail warning" ) 01207 == KMessageBox::Cancel ) 01208 return Kpgp::Canceled; 01209 // FIXME: Allow selection 01210 } 01211 addToAllSplitInfos( d->mOpenPGPEncryptToSelfKeys, 01212 InlineOpenPGPFormat|OpenPGPMIMEFormat ); 01213 } 01214 01215 // 4b. Check for S/MIME certs: 01216 01217 if ( !encryptionItems( SMIMEFormat ).empty() || 01218 !encryptionItems( SMIMEOpaqueFormat ).empty() ) { 01219 // need them 01220 if ( d->mSMIMEEncryptToSelfKeys.empty() ) { 01221 // don't have one 01222 const TQString msg = i18n("Examination of recipient's encryption preferences " 01223 "yielded that the message should be encrypted using " 01224 "S/MIME, at least for some recipients;\n" 01225 "however, you have not configured valid " 01226 "S/MIME encryption certificates for this identity.\n" 01227 "You may continue without encrypting to yourself, " 01228 "but be aware that you will not be able to read your " 01229 "own messages if you do so."); 01230 if ( KMessageBox::warningContinueCancel( 0, msg, 01231 i18n("Unusable Encryption Keys"), 01232 KStdGuiItem::cont(), 01233 "encrypt-to-self will fail warning" ) 01234 == KMessageBox::Cancel ) 01235 return Kpgp::Canceled; 01236 // FIXME: Allow selection 01237 } 01238 addToAllSplitInfos( d->mSMIMEEncryptToSelfKeys, 01239 SMIMEFormat|SMIMEOpaqueFormat ); 01240 } 01241 01242 // FIXME: Present another message if _both_ OpenPGP and S/MIME keys 01243 // are missing. 01244 01245 return Kpgp::Ok; 01246 } 01247 01248 Kpgp::Result Kleo::KeyResolver::resolveSigningKeysForEncryption() { 01249 if ( ( !encryptionItems( InlineOpenPGPFormat ).empty() || 01250 !encryptionItems( OpenPGPMIMEFormat ).empty() ) 01251 && d->mOpenPGPSigningKeys.empty() ) { 01252 const TQString msg = i18n("Examination of recipient's signing preferences " 01253 "yielded that the message should be signed using " 01254 "OpenPGP, at least for some recipients;\n" 01255 "however, you have not configured valid " 01256 "OpenPGP signing certificates for this identity."); 01257 if ( KMessageBox::warningContinueCancel( 0, msg, 01258 i18n("Unusable Signing Keys"), 01259 i18n("Do Not OpenPGP-Sign"), 01260 "signing will fail warning" ) 01261 == KMessageBox::Cancel ) 01262 return Kpgp::Canceled; 01263 // FIXME: Allow selection 01264 } 01265 if ( ( !encryptionItems( SMIMEFormat ).empty() || 01266 !encryptionItems( SMIMEOpaqueFormat ).empty() ) 01267 && d->mSMIMESigningKeys.empty() ) { 01268 const TQString msg = i18n("Examination of recipient's signing preferences " 01269 "yielded that the message should be signed using " 01270 "S/MIME, at least for some recipients;\n" 01271 "however, you have not configured valid " 01272 "S/MIME signing certificates for this identity."); 01273 if ( KMessageBox::warningContinueCancel( 0, msg, 01274 i18n("Unusable Signing Keys"), 01275 i18n("Do Not S/MIME-Sign"), 01276 "signing will fail warning" ) 01277 == KMessageBox::Cancel ) 01278 return Kpgp::Canceled; 01279 // FIXME: Allow selection 01280 } 01281 01282 // FIXME: Present another message if _both_ OpenPGP and S/MIME keys 01283 // are missing. 01284 01285 for ( std::map<CryptoMessageFormat,FormatInfo>::iterator it = d->mFormatInfoMap.begin() ; it != d->mFormatInfoMap.end() ; ++it ) 01286 if ( !it->second.splitInfos.empty() ) { 01287 dump(); 01288 it->second.signKeys = signingKeysFor( it->first ); 01289 dump(); 01290 } 01291 01292 return Kpgp::Ok; 01293 } 01294 01295 Kpgp::Result Kleo::KeyResolver::resolveSigningKeysForSigningOnly() { 01296 // 01297 // we don't need to distinguish between primary and secondary 01298 // recipients here: 01299 // 01300 SigningFormatPreferenceCounter count; 01301 count = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(), 01302 count ); 01303 count = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(), 01304 count ); 01305 01306 // try to find a common format that works for all (and that we have signing keys for): 01307 01308 CryptoMessageFormat commonFormat = AutoFormat; 01309 01310 for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) { 01311 if ( !(mCryptoMessageFormats & concreteCryptoMessageFormats[i]) ) 01312 continue; // skip 01313 if ( signingKeysFor( concreteCryptoMessageFormats[i] ).empty() ) 01314 continue; // skip 01315 if ( count.numOf( concreteCryptoMessageFormats[i] ) == count.numTotal() ) { 01316 commonFormat = concreteCryptoMessageFormats[i]; 01317 break; 01318 } 01319 } 01320 01321 if ( commonFormat != AutoFormat ) { // found 01322 dump(); 01323 FormatInfo & fi = d->mFormatInfoMap[ commonFormat ]; 01324 fi.signKeys = signingKeysFor( commonFormat ); 01325 fi.splitInfos.resize( 1 ); 01326 fi.splitInfos.front() = SplitInfo( allRecipients() ); 01327 dump(); 01328 return Kpgp::Ok; 01329 } 01330 01331 const TQString msg = i18n("Examination of recipient's signing preferences " 01332 "showed no common type of signature matching your " 01333 "available signing keys.\n" 01334 "Send message without signing?" ); 01335 if ( KMessageBox::warningContinueCancel( 0, msg, i18n("No signing possible"), 01336 KStdGuiItem::cont() ) 01337 == KMessageBox::Continue ) { 01338 d->mFormatInfoMap[OpenPGPMIMEFormat].splitInfos.push_back( SplitInfo( allRecipients() ) ); 01339 return Kpgp::Failure; // means "Ok, but without signing" 01340 } 01341 return Kpgp::Canceled; 01342 } 01343 01344 std::vector<GpgME::Key> Kleo::KeyResolver::signingKeysFor( CryptoMessageFormat f ) const { 01345 if ( isOpenPGP( f ) ) 01346 return d->mOpenPGPSigningKeys; 01347 if ( isSMIME( f ) ) 01348 return d->mSMIMESigningKeys; 01349 return std::vector<GpgME::Key>(); 01350 } 01351 01352 std::vector<GpgME::Key> Kleo::KeyResolver::encryptToSelfKeysFor( CryptoMessageFormat f ) const { 01353 if ( isOpenPGP( f ) ) 01354 return d->mOpenPGPEncryptToSelfKeys; 01355 if ( isSMIME( f ) ) 01356 return d->mSMIMEEncryptToSelfKeys; 01357 return std::vector<GpgME::Key>(); 01358 } 01359 01360 TQStringList Kleo::KeyResolver::allRecipients() const { 01361 TQStringList result; 01362 std::transform( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(), 01363 std::back_inserter( result ), ItemDotAddress ); 01364 std::transform( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(), 01365 std::back_inserter( result ), ItemDotAddress ); 01366 return result; 01367 } 01368 01369 void Kleo::KeyResolver::collapseAllSplitInfos() { 01370 dump(); 01371 for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) { 01372 std::map<CryptoMessageFormat,FormatInfo>::iterator pos = 01373 d->mFormatInfoMap.find( concreteCryptoMessageFormats[i] ); 01374 if ( pos == d->mFormatInfoMap.end() ) 01375 continue; 01376 std::vector<SplitInfo> & v = pos->second.splitInfos; 01377 if ( v.size() < 2 ) 01378 continue; 01379 SplitInfo & si = v.front(); 01380 for ( std::vector<SplitInfo>::const_iterator it = v.begin() + 1; it != v.end() ; ++it ) { 01381 si.keys.insert( si.keys.end(), it->keys.begin(), it->keys.end() ); 01382 tqCopy( it->recipients.begin(), it->recipients.end(), std::back_inserter( si.recipients ) ); 01383 } 01384 v.resize( 1 ); 01385 } 01386 dump(); 01387 } 01388 01389 void Kleo::KeyResolver::addToAllSplitInfos( const std::vector<GpgME::Key> & keys, unsigned int f ) { 01390 dump(); 01391 if ( !f || keys.empty() ) 01392 return; 01393 for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) { 01394 if ( !( f & concreteCryptoMessageFormats[i] ) ) 01395 continue; 01396 std::map<CryptoMessageFormat,FormatInfo>::iterator pos = 01397 d->mFormatInfoMap.find( concreteCryptoMessageFormats[i] ); 01398 if ( pos == d->mFormatInfoMap.end() ) 01399 continue; 01400 std::vector<SplitInfo> & v = pos->second.splitInfos; 01401 for ( std::vector<SplitInfo>::iterator it = v.begin() ; it != v.end() ; ++it ) 01402 it->keys.insert( it->keys.end(), keys.begin(), keys.end() ); 01403 } 01404 dump(); 01405 } 01406 01407 void Kleo::KeyResolver::dump() const { 01408 #ifndef NDEBUG 01409 if ( d->mFormatInfoMap.empty() ) 01410 std::cerr << "Keyresolver: Format info empty" << std::endl; 01411 for ( std::map<CryptoMessageFormat,FormatInfo>::const_iterator it = d->mFormatInfoMap.begin() ; it != d->mFormatInfoMap.end() ; ++it ) { 01412 std::cerr << "Format info for " << Kleo::cryptoMessageFormatToString( it->first ) 01413 << ":" << std::endl 01414 << " Signing keys: "; 01415 for ( std::vector<GpgME::Key>::const_iterator sit = it->second.signKeys.begin() ; sit != it->second.signKeys.end() ; ++sit ) 01416 std::cerr << sit->shortKeyID() << " "; 01417 std::cerr << std::endl; 01418 unsigned int i = 0; 01419 for ( std::vector<SplitInfo>::const_iterator sit = it->second.splitInfos.begin() ; sit != it->second.splitInfos.end() ; ++sit, ++i ) { 01420 std::cerr << " SplitInfo #" << i << " encryption keys: "; 01421 for ( std::vector<GpgME::Key>::const_iterator kit = sit->keys.begin() ; kit != sit->keys.end() ; ++kit ) 01422 std::cerr << kit->shortKeyID() << " "; 01423 std::cerr << std::endl 01424 << " SplitInfo #" << i << " recipients: " 01425 << sit->recipients.join(", ").utf8().data() << std::endl; 01426 } 01427 } 01428 #endif 01429 } 01430 01431 Kpgp::Result Kleo::KeyResolver::showKeyApprovalDialog() { 01432 const bool showKeysForApproval = showApprovalDialog() 01433 || std::find_if( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(), 01434 ApprovalNeeded ) != d->mPrimaryEncryptionKeys.end() 01435 || std::find_if( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(), 01436 ApprovalNeeded ) != d->mSecondaryEncryptionKeys.end() ; 01437 01438 if ( !showKeysForApproval ) 01439 return Kpgp::Ok; 01440 01441 std::vector<Kleo::KeyApprovalDialog::Item> items; 01442 items.reserve( d->mPrimaryEncryptionKeys.size() + 01443 d->mSecondaryEncryptionKeys.size() ); 01444 std::copy( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(), 01445 std::back_inserter( items ) ); 01446 std::copy( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(), 01447 std::back_inserter( items ) ); 01448 01449 std::vector<GpgME::Key> senderKeys; 01450 senderKeys.reserve( d->mOpenPGPEncryptToSelfKeys.size() + 01451 d->mSMIMEEncryptToSelfKeys.size() ); 01452 std::copy( d->mOpenPGPEncryptToSelfKeys.begin(), d->mOpenPGPEncryptToSelfKeys.end(), 01453 std::back_inserter( senderKeys ) ); 01454 std::copy( d->mSMIMEEncryptToSelfKeys.begin(), d->mSMIMEEncryptToSelfKeys.end(), 01455 std::back_inserter( senderKeys ) ); 01456 01457 const KCursorSaver idle( KBusyPtr::idle() ); 01458 01459 Kleo::KeyApprovalDialog dlg( items, senderKeys ); 01460 01461 if ( dlg.exec() == TQDialog::Rejected ) 01462 return Kpgp::Canceled; 01463 01464 items = dlg.items(); 01465 senderKeys = dlg.senderKeys(); 01466 01467 if ( dlg.preferencesChanged() ) { 01468 for ( uint i = 0; i < items.size(); ++i ) { 01469 ContactPreferences pref = lookupContactPreferences( items[i].address ); 01470 pref.encryptionPreference = items[i].pref; 01471 pref.pgpKeyFingerprints.clear(); 01472 pref.smimeCertFingerprints.clear(); 01473 const std::vector<GpgME::Key> & keys = items[i].keys; 01474 for ( std::vector<GpgME::Key>::const_iterator it = keys.begin(), end = keys.end() ; it != end ; ++it ) { 01475 if ( it->protocol() == GpgME::Context::OpenPGP ) { 01476 if ( const char * fpr = it->primaryFingerprint() ) 01477 pref.pgpKeyFingerprints.push_back( fpr ); 01478 } else if ( it->protocol() == GpgME::Context::CMS ) { 01479 if ( const char * fpr = it->primaryFingerprint() ) 01480 pref.smimeCertFingerprints.push_back( fpr ); 01481 } 01482 } 01483 saveContactPreference( items[i].address, pref ); 01484 } 01485 } 01486 01487 // show a warning if the user didn't select an encryption key for 01488 // herself: 01489 if ( encryptToSelf() && senderKeys.empty() ) { 01490 const TQString msg = i18n("You did not select an encryption key for yourself " 01491 "(encrypt to self). You will not be able to decrypt " 01492 "your own message if you encrypt it."); 01493 if ( KMessageBox::warningContinueCancel( 0, msg, 01494 i18n("Missing Key Warning"), 01495 i18n("&Encrypt") ) 01496 == KMessageBox::Cancel ) 01497 return Kpgp::Canceled; 01498 else 01499 mEncryptToSelf = false; 01500 } 01501 01502 // count empty key ID lists 01503 const unsigned int emptyListCount = 01504 std::count_if( items.begin(), items.end(), EmptyKeyList ); 01505 01506 // show a warning if the user didn't select an encryption key for 01507 // some of the recipients 01508 if ( items.size() == emptyListCount ) { 01509 const TQString msg = ( d->mPrimaryEncryptionKeys.size() + 01510 d->mSecondaryEncryptionKeys.size() == 1 ) 01511 ? i18n("You did not select an encryption key for the " 01512 "recipient of this message; therefore, the message " 01513 "will not be encrypted.") 01514 : i18n("You did not select an encryption key for any of the " 01515 "recipients of this message; therefore, the message " 01516 "will not be encrypted."); 01517 if ( KMessageBox::warningContinueCancel( 0, msg, 01518 i18n("Missing Key Warning"), 01519 i18n("Send &Unencrypted") ) 01520 == KMessageBox::Cancel ) 01521 return Kpgp::Canceled; 01522 } else if ( emptyListCount > 0 ) { 01523 const TQString msg = ( emptyListCount == 1 ) 01524 ? i18n("You did not select an encryption key for one of " 01525 "the recipients: this person will not be able to " 01526 "decrypt the message if you encrypt it.") 01527 : i18n("You did not select encryption keys for some of " 01528 "the recipients: these persons will not be able to " 01529 "decrypt the message if you encrypt it." ); 01530 KCursorSaver idle( KBusyPtr::idle() ); 01531 if ( KMessageBox::warningContinueCancel( 0, msg, 01532 i18n("Missing Key Warning"), 01533 i18n("&Encrypt") ) 01534 == KMessageBox::Cancel ) 01535 return Kpgp::Canceled; 01536 } 01537 01538 std::transform( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(), 01539 items.begin(), 01540 d->mPrimaryEncryptionKeys.begin(), 01541 CopyKeysAndEncryptionPreferences ); 01542 std::transform( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(), 01543 items.begin() + d->mPrimaryEncryptionKeys.size(), 01544 d->mSecondaryEncryptionKeys.begin(), 01545 CopyKeysAndEncryptionPreferences ); 01546 01547 d->mOpenPGPEncryptToSelfKeys.clear(); 01548 d->mSMIMEEncryptToSelfKeys.clear(); 01549 01550 std::remove_copy_if( senderKeys.begin(), senderKeys.end(), 01551 std::back_inserter( d->mOpenPGPEncryptToSelfKeys ), 01552 NotValidTrustedOpenPGPEncryptionKey ); // -= trusted (see above, too)? 01553 std::remove_copy_if( senderKeys.begin(), senderKeys.end(), 01554 std::back_inserter( d->mSMIMEEncryptToSelfKeys ), 01555 NotValidTrustedSMIMEEncryptionKey ); // -= trusted (see above, too)? 01556 01557 return Kpgp::Ok; 01558 } 01559 01560 std::vector<Kleo::KeyResolver::SplitInfo> Kleo::KeyResolver::encryptionItems( Kleo::CryptoMessageFormat f ) const { 01561 dump(); 01562 std::map<CryptoMessageFormat,FormatInfo>::const_iterator it = 01563 d->mFormatInfoMap.find( f ); 01564 return it != d->mFormatInfoMap.end() ? it->second.splitInfos : std::vector<SplitInfo>() ; 01565 } 01566 01567 std::vector<GpgME::Key> Kleo::KeyResolver::signingKeys( CryptoMessageFormat f ) const { 01568 dump(); 01569 std::map<CryptoMessageFormat,FormatInfo>::const_iterator it = 01570 d->mFormatInfoMap.find( f ); 01571 return it != d->mFormatInfoMap.end() ? it->second.signKeys : std::vector<GpgME::Key>() ; 01572 } 01573 01574 // 01575 // 01576 // Private helper methods below: 01577 // 01578 // 01579 01580 01581 std::vector<GpgME::Key> Kleo::KeyResolver::selectKeys( const TQString & person, const TQString & msg, const std::vector<GpgME::Key> & selectedKeys ) const { 01582 const bool opgp = containsOpenPGP( mCryptoMessageFormats ); 01583 const bool x509 = containsSMIME( mCryptoMessageFormats ); 01584 01585 Kleo::KeySelectionDialog dlg( i18n("Encryption Key Selection"), 01586 msg, KPIM::getEmailAddress(person), selectedKeys, 01587 Kleo::KeySelectionDialog::ValidEncryptionKeys 01588 & ~(opgp ? 0 : Kleo::KeySelectionDialog::OpenPGPKeys) 01589 & ~(x509 ? 0 : Kleo::KeySelectionDialog::SMIMEKeys), 01590 true, true ); // multi-selection and "remember choice" box 01591 01592 if ( dlg.exec() != TQDialog::Accepted ) 01593 return std::vector<GpgME::Key>(); 01594 std::vector<GpgME::Key> keys = dlg.selectedKeys(); 01595 keys.erase( std::remove_if( keys.begin(), keys.end(), 01596 NotValidTrustedEncryptionKey ), // -= trusted? 01597 keys.end() ); 01598 if ( !keys.empty() && dlg.rememberSelection() ) 01599 setKeysForAddress( person, dlg.pgpKeyFingerprints(), dlg.smimeFingerprints() ); 01600 return keys; 01601 } 01602 01603 01604 std::vector<GpgME::Key> Kleo::KeyResolver::getEncryptionKeys( const TQString & person, bool quiet ) const { 01605 01606 const TQString address = canonicalAddress( person ).lower(); 01607 01608 // First look for this person's address in the address->key dictionary 01609 const TQStringList fingerprints = keysForAddress( address ); 01610 01611 if ( !fingerprints.empty() ) { 01612 kdDebug() << "Using encryption keys 0x" 01613 << fingerprints.join( ", 0x" ) 01614 << " for " << person << endl; 01615 std::vector<GpgME::Key> keys = lookup( fingerprints ); 01616 if ( !keys.empty() ) { 01617 // Check if all of the keys are trusted and valid encryption keys 01618 if ( std::find_if( keys.begin(), keys.end(), 01619 NotValidTrustedEncryptionKey ) != keys.end() ) { // -= trusted? 01620 01621 // not ok, let the user select: this is not conditional on !quiet, 01622 // since it's a bug in the configuration and the user should be 01623 // notified about it as early as possible: 01624 keys = selectKeys( person, 01625 i18n("if in your language something like " 01626 "'certificate(s)' isn't possible please " 01627 "use the plural in the translation", 01628 "There is a problem with the " 01629 "encryption certificate(s) for \"%1\".\n\n" 01630 "Please re-select the certificate(s) which should " 01631 "be used for this recipient.").arg(person), 01632 keys ); 01633 } 01634 bool canceled = false; 01635 keys = trustedOrConfirmed( keys, address, canceled ); 01636 if ( canceled ) 01637 return std::vector<GpgME::Key>(); 01638 01639 if ( !keys.empty() ) 01640 return keys; 01641 // keys.empty() is considered cancel by callers, so go on 01642 } 01643 } 01644 01645 // Now search all public keys for matching keys 01646 std::vector<GpgME::Key> matchingKeys = lookup( person ); 01647 matchingKeys.erase( std::remove_if( matchingKeys.begin(), matchingKeys.end(), 01648 NotValidEncryptionKey ), 01649 matchingKeys.end() ); 01650 // if no keys match the complete address look for keys which match 01651 // the canonical mail address 01652 if ( matchingKeys.empty() ) { 01653 matchingKeys = lookup( address ); 01654 matchingKeys.erase( std::remove_if( matchingKeys.begin(), matchingKeys.end(), 01655 NotValidEncryptionKey ), 01656 matchingKeys.end() ); 01657 } 01658 01659 // if called with quite == true (from EncryptionPreferenceCounter), we only want to 01660 // check if there are keys for this recipients, not (yet) their validity, so 01661 // don't show the untrusted encryption key warning in that case 01662 bool canceled = false; 01663 if ( !quiet ) 01664 matchingKeys = trustedOrConfirmed( matchingKeys, address, canceled ); 01665 if ( canceled ) 01666 return std::vector<GpgME::Key>(); 01667 if ( quiet || matchingKeys.size() == 1 ) 01668 return matchingKeys; 01669 01670 // no match until now, or more than one key matches; let the user 01671 // choose the key(s) 01672 // FIXME: let user get the key from keyserver 01673 return trustedOrConfirmed( selectKeys( person, 01674 matchingKeys.empty() 01675 ? i18n("if in your language something like " 01676 "'certificate(s)' isn't possible please " 01677 "use the plural in the translation", 01678 "<qt>No valid and trusted encryption certificate was " 01679 "found for \"%1\".<br/><br/>" 01680 "Select the certificate(s) which should " 01681 "be used for this recipient. If there is no suitable certificate in the list " 01682 "you can also search for external certificates by clicking the button: search for external certificates.</qt>") 01683 .arg( TQStyleSheet::escape(person) ) 01684 : i18n("if in your language something like " 01685 "'certificate(s)' isn't possible please " 01686 "use the plural in the translation", 01687 "More than one certificate matches \"%1\".\n\n" 01688 "Select the certificate(s) which should " 01689 "be used for this recipient.").arg( TQStyleSheet::escape(person) ), 01690 matchingKeys ), address, canceled ); 01691 // we can ignore 'canceled' here, since trustedOrConfirmed() returns 01692 // an empty vector when canceled == true, and we'd just do the same 01693 } 01694 01695 01696 std::vector<GpgME::Key> Kleo::KeyResolver::lookup( const TQStringList & patterns, bool secret ) const { 01697 if ( patterns.empty() ) 01698 return std::vector<GpgME::Key>(); 01699 kdDebug() << "Kleo::KeyResolver::lookup( \"" << patterns.join( "\", \"" ) 01700 << "\", " << secret << " )" << endl; 01701 std::vector<GpgME::Key> result; 01702 if ( mCryptoMessageFormats & (InlineOpenPGPFormat|OpenPGPMIMEFormat) ) 01703 if ( const Kleo::CryptoBackend::Protocol * p = Kleo::CryptoBackendFactory::instance()->openpgp() ) { 01704 std::auto_ptr<Kleo::KeyListJob> job( p->keyListJob( false, false, true ) ); // use validating keylisting 01705 if ( job.get() ) { 01706 std::vector<GpgME::Key> keys; 01707 job->exec( patterns, secret, keys ); 01708 result.insert( result.end(), keys.begin(), keys.end() ); 01709 } 01710 } 01711 if ( mCryptoMessageFormats & (SMIMEFormat|SMIMEOpaqueFormat) ) 01712 if ( const Kleo::CryptoBackend::Protocol * p = Kleo::CryptoBackendFactory::instance()->smime() ) { 01713 std::auto_ptr<Kleo::KeyListJob> job( p->keyListJob( false, false, true ) ); // use validating keylisting 01714 if ( job.get() ) { 01715 std::vector<GpgME::Key> keys; 01716 job->exec( patterns, secret, keys ); 01717 result.insert( result.end(), keys.begin(), keys.end() ); 01718 } 01719 } 01720 kdDebug() << " returned " << result.size() << " keys" << endl; 01721 return result; 01722 } 01723 01724 void Kleo::KeyResolver::addKeys( const std::vector<Item> & items, CryptoMessageFormat f ) { 01725 dump(); 01726 for ( std::vector<Item>::const_iterator it = items.begin() ; it != items.end() ; ++it ) { 01727 SplitInfo si( it->address ); 01728 std::remove_copy_if( it->keys.begin(), it->keys.end(), 01729 std::back_inserter( si.keys ), IsNotForFormat( f ) ); 01730 dump(); 01731 kdWarning( si.keys.empty() ) 01732 << "Kleo::KeyResolver::addKeys(): Fix EncryptionFormatPreferenceCounter. " 01733 << "It detected a common format, but the list of such keys for recipient \"" 01734 << it->address << "\" is empty!" << endl; 01735 d->mFormatInfoMap[ f ].splitInfos.push_back( si ); 01736 } 01737 dump(); 01738 } 01739 01740 void Kleo::KeyResolver::addKeys( const std::vector<Item> & items ) { 01741 dump(); 01742 for ( std::vector<Item>::const_iterator it = items.begin() ; it != items.end() ; ++it ) { 01743 SplitInfo si( it->address ); 01744 CryptoMessageFormat f = AutoFormat; 01745 for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) { 01746 const CryptoMessageFormat fmt = concreteCryptoMessageFormats[i]; 01747 if ( ( fmt & it->format ) && 01748 kdtools::any( it->keys.begin(), it->keys.end(), IsForFormat( fmt ) ) ) 01749 { 01750 f = fmt; 01751 break; 01752 } 01753 } 01754 if ( f == AutoFormat ) 01755 kdWarning() << "Kleo::KeyResolver::addKeys(): Something went wrong. Didn't find a format for \"" 01756 << it->address << "\"" << endl; 01757 else 01758 std::remove_copy_if( it->keys.begin(), it->keys.end(), 01759 std::back_inserter( si.keys ), IsNotForFormat( f ) ); 01760 d->mFormatInfoMap[ f ].splitInfos.push_back( si ); 01761 } 01762 dump(); 01763 } 01764 01765 Kleo::KeyResolver::ContactPreferences Kleo::KeyResolver::lookupContactPreferences( const TQString& address ) const 01766 { 01767 const Private::ContactPreferencesMap::iterator it = 01768 d->mContactPreferencesMap.find( address ); 01769 if ( it != d->mContactPreferencesMap.end() ) 01770 return it->second; 01771 01772 TDEABC::AddressBook *ab = TDEABC::StdAddressBook::self( true ); 01773 const TDEABC::Addressee::List res = ab->findByEmail( address ); 01774 ContactPreferences pref; 01775 if ( !res.isEmpty() ) { 01776 TDEABC::Addressee addr = res.first(); 01777 TQString encryptPref = addr.custom( "KADDRESSBOOK", "CRYPTOENCRYPTPREF" ); 01778 pref.encryptionPreference = Kleo::stringToEncryptionPreference( encryptPref ); 01779 TQString signPref = addr.custom( "KADDRESSBOOK", "CRYPTOSIGNPREF" ); 01780 pref.signingPreference = Kleo::stringToSigningPreference( signPref ); 01781 TQString cryptoFormats = addr.custom( "KADDRESSBOOK", "CRYPTOPROTOPREF" ); 01782 pref.cryptoMessageFormat = Kleo::stringToCryptoMessageFormat( cryptoFormats ); 01783 pref.pgpKeyFingerprints = TQStringList::split( ',', addr.custom( "KADDRESSBOOK", "OPENPGPFP" ) ); 01784 pref.smimeCertFingerprints = TQStringList::split( ',', addr.custom( "KADDRESSBOOK", "SMIMEFP" ) ); 01785 } 01786 // insert into map and grab resulting iterator 01787 d->mContactPreferencesMap.insert( std::make_pair( address, pref ) ); 01788 return pref; 01789 } 01790 01791 void Kleo::KeyResolver::saveContactPreference( const TQString& email, const ContactPreferences& pref ) const 01792 { 01793 d->mContactPreferencesMap.insert( std::make_pair( email, pref ) ); 01794 TDEABC::AddressBook *ab = TDEABC::StdAddressBook::self( true ); 01795 TDEABC::Addressee::List res = ab->findByEmail( email ); 01796 01797 TDEABC::Addressee addr; 01798 if ( res.isEmpty() ) { 01799 bool ok = true; 01800 TQString fullName = KInputDialog::getText( i18n( "Name Selection" ), i18n( "Which name shall the contact '%1' have in your addressbook?" ).arg( email ), TQString(), &ok ); 01801 if ( ok ) { 01802 addr.setNameFromString( fullName ); 01803 addr.insertEmail( email, true ); 01804 } else 01805 return; 01806 } else 01807 addr = res.first(); 01808 01809 addr.insertCustom( "KADDRESSBOOK", "CRYPTOENCRYPTPREF", Kleo::encryptionPreferenceToString( pref.encryptionPreference ) ); 01810 addr.insertCustom( "KADDRESSBOOK", "CRYPTOSIGNPREF", Kleo::signingPreferenceToString( pref.signingPreference ) ); 01811 addr.insertCustom( "KADDRESSBOOK", "CRYPTOPROTOPREF", cryptoMessageFormatToString( pref.cryptoMessageFormat ) ); 01812 addr.insertCustom( "KADDRESSBOOK", "OPENPGPFP", pref.pgpKeyFingerprints.join( "," ) ); 01813 addr.insertCustom( "KADDRESSBOOK", "SMIMEFP", pref.smimeCertFingerprints.join( "," ) ); 01814 01815 ab->insertAddressee( addr ); 01816 TDEABC::Ticket *ticket = ab->requestSaveTicket( addr.resource() ); 01817 if ( ticket ) 01818 ab->save( ticket ); 01819 01820 // Assumption: 'pref' comes from d->mContactPreferencesMap already, no need to update that 01821 } 01822 01823 Kleo::KeyResolver::ContactPreferences::ContactPreferences() 01824 : encryptionPreference( UnknownPreference ), 01825 signingPreference( UnknownSigningPreference ), 01826 cryptoMessageFormat( AutoFormat ) 01827 { 01828 } 01829 01830 TQStringList Kleo::KeyResolver::keysForAddress( const TQString & address ) const { 01831 if( address.isEmpty() ) { 01832 return TQStringList(); 01833 } 01834 TQString addr = canonicalAddress( address ).lower(); 01835 const ContactPreferences pref = lookupContactPreferences( addr ); 01836 return pref.pgpKeyFingerprints + pref.smimeCertFingerprints; 01837 } 01838 01839 void Kleo::KeyResolver::setKeysForAddress( const TQString& address, const TQStringList& pgpKeyFingerprints, const TQStringList& smimeCertFingerprints ) const { 01840 if( address.isEmpty() ) { 01841 return; 01842 } 01843 TQString addr = canonicalAddress( address ).lower(); 01844 ContactPreferences pref = lookupContactPreferences( addr ); 01845 pref.pgpKeyFingerprints = pgpKeyFingerprints; 01846 pref.smimeCertFingerprints = smimeCertFingerprints; 01847 saveContactPreference( addr, pref ); 01848 }