kmail

keyresolver.cpp
1/*
2 keyresolver.cpp
3
4 This file is part of libkleopatra, the KDE keymanagement library
5 Copyright (c) 2004 Klarälvdalens Datakonsult AB
6
7 Based on kpgp.cpp
8 Copyright (C) 2001,2002 the KPGP authors
9 See file libtdenetwork/AUTHORS.kpgp for details
10
11 Libkleopatra is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2 of the
14 License, or (at your option) any later version.
15
16 Libkleopatra is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24
25 In addition, as a special exception, the copyright holders give
26 permission to link the code of this program with any edition of
27 the TQt library by Trolltech AS, Norway (or with modified versions
28 of TQt that use the same license as TQt), and distribute linked
29 combinations including the two. You must obey the GNU General
30 Public License in all respects for all of the code used other than
31 TQt. If you modify this file, you may extend this exception to
32 your version of the file, but you are not obligated to do so. If
33 you do not wish to do so, delete this exception statement from
34 your version.
35*/
36
37#ifdef HAVE_CONFIG_H
38#include <config.h>
39#endif
40
41#include "keyresolver.h"
42
43#include "kcursorsaver.h"
44#include "kleo_util.h"
45#include "stl_util.h"
46
47#include <libemailfunctions/email.h>
48#include <ui/keyselectiondialog.h>
49#include <kleo/cryptobackendfactory.h>
50#include <kleo/keylistjob.h>
51#include <kleo/dn.h>
52
53#include <gpgmepp/key.h>
54#include <gpgmepp/keylistresult.h>
55
56#include <tdeabc/stdaddressbook.h>
57#include <tdelocale.h>
58#include <kdebug.h>
59#include <kinputdialog.h>
60#include <tdemessagebox.h>
61
62#include <tqstringlist.h>
63#include <tqtl.h>
64
65#include <time.h>
66
67#include <algorithm>
68#include <memory>
69#include <iterator>
70#include <functional>
71#include <map>
72#include <set>
73#include <iostream>
74#include <cassert>
75
76
77//
78// some predicates to be used in STL algorithms:
79//
80
81static inline bool EmptyKeyList( const Kleo::KeyApprovalDialog::Item & item ) {
82 return item.keys.empty();
83}
84
85static inline TQString ItemDotAddress( const Kleo::KeyResolver::Item & item ) {
86 return item.address;
87}
88
89static inline bool ApprovalNeeded( const Kleo::KeyResolver::Item & item ) {
90 return item.pref == Kleo::UnknownPreference || item.pref == Kleo::NeverEncrypt || item.keys.empty() ;
91}
92
93static inline Kleo::KeyResolver::Item
94CopyKeysAndEncryptionPreferences( const Kleo::KeyResolver::Item & oldItem,
95 const Kleo::KeyApprovalDialog::Item & newItem ) {
96 return Kleo::KeyResolver::Item( oldItem.address, newItem.keys, newItem.pref, oldItem.signPref, oldItem.format );
97}
98
99static inline bool ByKeyID( const GpgME::Key & left, const GpgME::Key & right ) {
100 return qstrcmp( left.keyID(), right.keyID() ) < 0 ;
101}
102
103static inline bool WithRespectToKeyID( const GpgME::Key & left, const GpgME::Key & right ) {
104 return qstrcmp( left.keyID(), right.keyID() ) == 0 ;
105}
106
107static bool ValidOpenPGPEncryptionKey( const GpgME::Key & key ) {
108 if ( key.protocol() != GpgME::Context::OpenPGP ) {
109 return false;
110 }
111#if 0
112 if ( key.isRevoked() )
113 kdWarning() << " is revoked" << endl;
114 if ( key.isExpired() )
115 kdWarning() << " is expired" << endl;
116 if ( key.isDisabled() )
117 kdWarning() << " is disabled" << endl;
118 if ( !key.canEncrypt() )
119 kdWarning() << " can't encrypt" << endl;
120#endif
121 if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canEncrypt() )
122 return false;
123 return true;
124}
125
126static bool ValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
127 if ( !ValidOpenPGPEncryptionKey( key ) )
128 return false;
129 const std::vector<GpgME::UserID> uids = key.userIDs();
130 for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it ) {
131 if ( !it->isRevoked() && it->validity() >= GpgME::UserID::Marginal )
132 return true;
133#if 0
134 else
135 if ( it->isRevoked() )
136 kdWarning() << "a userid is revoked" << endl;
137 else
138 kdWarning() << "bad validity " << it->validity() << endl;
139#endif
140 }
141 return false;
142}
143
144static bool ValidSMIMEEncryptionKey( const GpgME::Key & key ) {
145 if ( key.protocol() != GpgME::Context::CMS )
146 return false;
147 if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canEncrypt() )
148 return false;
149 return true;
150}
151
152static bool ValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
153 if ( !ValidSMIMEEncryptionKey( key ) )
154 return false;
155 return true;
156}
157
158static inline bool ValidTrustedEncryptionKey( const GpgME::Key & key ) {
159 switch ( key.protocol() ) {
160 case GpgME::Context::OpenPGP:
161 return ValidTrustedOpenPGPEncryptionKey( key );
162 case GpgME::Context::CMS:
163 return ValidTrustedSMIMEEncryptionKey( key );
164 default:
165 return false;
166 }
167}
168
169static inline bool ValidEncryptionKey( const GpgME::Key & key ) {
170 switch ( key.protocol() ) {
171 case GpgME::Context::OpenPGP:
172 return ValidOpenPGPEncryptionKey( key );
173 case GpgME::Context::CMS:
174 return ValidSMIMEEncryptionKey( key );
175 default:
176 return false;
177 }
178}
179
180static inline bool ValidSigningKey( const GpgME::Key & key ) {
181 if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canSign() )
182 return false;
183 return key.hasSecret();
184}
185
186static inline bool ValidOpenPGPSigningKey( const GpgME::Key & key ) {
187 return key.protocol() == GpgME::Context::OpenPGP && ValidSigningKey( key );
188}
189
190static inline bool ValidSMIMESigningKey( const GpgME::Key & key ) {
191 return key.protocol() == GpgME::Context::CMS && ValidSigningKey( key );
192}
193
194static inline bool NotValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
195 return !ValidTrustedOpenPGPEncryptionKey( key );
196}
197
198static inline bool NotValidOpenPGPEncryptionKey( const GpgME::Key & key ) {
199 return !ValidOpenPGPEncryptionKey( key );
200}
201
202static inline bool NotValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
203 return !ValidTrustedSMIMEEncryptionKey( key );
204}
205
206static inline bool NotValidSMIMEEncryptionKey( const GpgME::Key & key ) {
207 return !ValidSMIMEEncryptionKey( key );
208}
209
210static inline bool NotValidTrustedEncryptionKey( const GpgME::Key & key ) {
211 return !ValidTrustedEncryptionKey( key );
212}
213
214static inline bool NotValidEncryptionKey( const GpgME::Key & key ) {
215 return !ValidEncryptionKey( key );
216}
217
218static inline bool NotValidSigningKey( const GpgME::Key & key ) {
219 return !ValidSigningKey( key );
220}
221
222static inline bool NotValidOpenPGPSigningKey( const GpgME::Key & key ) {
223 return !ValidOpenPGPSigningKey( key );
224}
225
226static inline bool NotValidSMIMESigningKey( const GpgME::Key & key ) {
227 return !ValidSMIMESigningKey( key );
228}
229
230namespace {
231 struct ByTrustScore {
232 static int score( const GpgME::UserID & uid ) {
233 return uid.isRevoked() || uid.isInvalid() ? -1 : uid.validity() ;
234 }
235 bool operator()( const GpgME::UserID & lhs, const GpgME::UserID & rhs ) const {
236 return score( lhs ) < score( rhs ) ;
237 }
238 };
239}
240
241static std::vector<GpgME::UserID> matchingUIDs( const std::vector<GpgME::UserID> & uids, const TQString & address ) {
242 if ( address.isEmpty() )
243 return std::vector<GpgME::UserID>();
244
245 std::vector<GpgME::UserID> result;
246 result.reserve( uids.size() );
247 for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin(), end = uids.end() ; it != end ; ++it )
248 // PENDING(marc) check DN for an EMAIL, too, in case of X.509 certs... :/
249 if ( const char * email = it->email() )
250 if ( *email && TQString::fromUtf8( email ).stripWhiteSpace().lower() == address )
251 result.push_back( *it );
252 return result;
253}
254
255static GpgME::UserID findBestMatchUID( const GpgME::Key & key, const TQString & address ) {
256 const std::vector<GpgME::UserID> all = key.userIDs();
257 if ( all.empty() )
258 return GpgME::UserID();
259 const std::vector<GpgME::UserID> matching = matchingUIDs( all, address.lower() );
260 const std::vector<GpgME::UserID> & v = matching.empty() ? all : matching ;
261 return *std::max_element( v.begin(), v.end(), ByTrustScore() );
262}
263
264static TQStringList keysAsStrings( const std::vector<GpgME::Key>& keys ) {
265 TQStringList strings;
266 for ( std::vector<GpgME::Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it ) {
267 assert( !(*it).userID(0).isNull() );
268 TQString keyLabel = TQString::fromUtf8( (*it).userID(0).email() );
269 if ( keyLabel.isEmpty() )
270 keyLabel = TQString::fromUtf8( (*it).userID(0).name() );
271 if ( keyLabel.isEmpty() )
272 keyLabel = TQString::fromUtf8( (*it).userID(0).id() );
273 strings.append( keyLabel );
274 }
275 return strings;
276}
277
278static std::vector<GpgME::Key> trustedOrConfirmed( const std::vector<GpgME::Key> & keys, const TQString & address, bool & canceled ) {
279
280 // PENDING(marc) work on UserIDs here?
281 std::vector<GpgME::Key> fishies;
282 std::vector<GpgME::Key> ickies;
283 std::vector<GpgME::Key> rewookies;
284 std::vector<GpgME::Key>::const_iterator it = keys.begin();
285 const std::vector<GpgME::Key>::const_iterator end = keys.end();
286 for ( ; it != end ; it++ ) {
287 const GpgME::Key & key = *it;
288 assert( ValidEncryptionKey( key ) );
289 const GpgME::UserID uid = findBestMatchUID( key, address );
290 if ( uid.isRevoked() ) {
291 rewookies.push_back( key );
292 }
293 if ( !uid.isRevoked() && uid.validity() == GpgME::UserID::Marginal ) {
294 fishies.push_back( key );
295 }
296 if ( !uid.isRevoked() && uid.validity() < GpgME::UserID::Never ) {
297 ickies.push_back( key );
298 }
299 }
300
301 if ( fishies.empty() && ickies.empty() && rewookies.empty() )
302 return keys;
303
304 // if some keys are not fully trusted, let the user confirm their use
305 TQString msg = address.isEmpty()
306 ? i18n("One or more of your configured OpenPGP encryption "
307 "keys or S/MIME certificates is not fully trusted "
308 "for encryption.")
309 : i18n("One or more of the OpenPGP encryption keys or S/MIME "
310 "certificates for recipient \"%1\" is not fully trusted "
311 "for encryption.").arg(address) ;
312
313 if ( !fishies.empty() ) {
314 // certificates can't have marginal trust
315 msg += i18n( "\nThe following keys are only marginally trusted: \n");
316 msg += keysAsStrings( fishies ).join(",");
317 }
318 if ( !ickies.empty() ) {
319 msg += i18n( "\nThe following keys or certificates have unknown trust level: \n");
320 msg += keysAsStrings( ickies ).join(",");
321 }
322 if ( !rewookies.empty() ) {
323 msg += i18n( "\nThe following keys or certificates are <b>revoked</b>: \n");
324 msg += keysAsStrings( rewookies ).join(",");
325 }
326
327 if( KMessageBox::warningContinueCancel( 0, msg, i18n("Not Fully Trusted Encryption Keys"),
328 KStdGuiItem::cont(),
329 "not fully trusted encryption key warning" )
330 == KMessageBox::Continue )
331 return keys;
332 else
333 canceled = true;
334 return std::vector<GpgME::Key>();
335}
336
337namespace {
338 struct IsNotForFormat : public std::function<bool(GpgME::Key)> {
339 IsNotForFormat( Kleo::CryptoMessageFormat f ) : format( f ) {}
340
341 bool operator()( const GpgME::Key & key ) const {
342 return
343 ( isOpenPGP( format ) && key.protocol() != GpgME::Context::OpenPGP ) ||
344 ( isSMIME( format ) && key.protocol() != GpgME::Context::CMS );
345 }
346
347 const Kleo::CryptoMessageFormat format;
348 };
349
350 struct IsForFormat : std::function<bool(GpgME::Key)> {
351 explicit IsForFormat( Kleo::CryptoMessageFormat f )
352 : protocol( isOpenPGP( f ) ? GpgME::Context::OpenPGP :
353 isSMIME( f ) ? GpgME::Context::CMS :
354 /* else */ GpgME::Context::Unknown ) {}
355
356 bool operator()( const GpgME::Key & key ) const {
357 return key.protocol() == protocol ;
358 }
359
360 const GpgME::Context::Protocol protocol;
361 };
362
363}
364
365
366
367class Kleo::KeyResolver::SigningPreferenceCounter : public std::function<void(Kleo::KeyResolver::Item)> {
368public:
369 SigningPreferenceCounter()
370 : mTotal( 0 ),
371 mUnknownSigningPreference( 0 ),
372 mNeverSign( 0 ),
373 mAlwaysSign( 0 ),
374 mAlwaysSignIfPossible( 0 ),
375 mAlwaysAskForSigning( 0 ),
376 mAskSigningWheneverPossible( 0 )
377 {
378
379 }
380 void operator()( const Kleo::KeyResolver::Item & item );
381#define make_int_accessor(x) unsigned int num##x() const { return m##x; }
382 make_int_accessor(UnknownSigningPreference)
383 make_int_accessor(NeverSign)
384 make_int_accessor(AlwaysSign)
385 make_int_accessor(AlwaysSignIfPossible)
386 make_int_accessor(AlwaysAskForSigning)
387 make_int_accessor(AskSigningWheneverPossible)
388 make_int_accessor(Total)
389#undef make_int_accessor
390private:
391 unsigned int mTotal;
392 unsigned int mUnknownSigningPreference, mNeverSign, mAlwaysSign,
393 mAlwaysSignIfPossible, mAlwaysAskForSigning, mAskSigningWheneverPossible;
394};
395
396void Kleo::KeyResolver::SigningPreferenceCounter::operator()( const Kleo::KeyResolver::Item & item ) {
397 switch ( item.signPref ) {
398#define CASE(x) case x: ++m##x; break
399 CASE(UnknownSigningPreference);
400 CASE(NeverSign);
401 CASE(AlwaysSign);
402 CASE(AlwaysSignIfPossible);
403 CASE(AlwaysAskForSigning);
404 CASE(AskSigningWheneverPossible);
405#undef CASE
406 }
407 ++mTotal;
408}
409
410
411
412class Kleo::KeyResolver::EncryptionPreferenceCounter : public std::function<void(Item)> {
413 const Kleo::KeyResolver * _this;
414public:
415 EncryptionPreferenceCounter( const Kleo::KeyResolver * kr, EncryptionPreference defaultPreference )
416 : _this( kr ),
417 mDefaultPreference( defaultPreference ),
418 mTotal( 0 ),
419 mNoKey( 0 ),
420 mNeverEncrypt( 0 ),
421 mUnknownPreference( 0 ),
422 mAlwaysEncrypt( 0 ),
423 mAlwaysEncryptIfPossible( 0 ),
424 mAlwaysAskForEncryption( 0 ),
425 mAskWheneverPossible( 0 )
426 {
427
428 }
429 void operator()( Item & item );
430
431 template <typename Container>
432 void process( Container & c ) {
433 *this = std::for_each( c.begin(), c.end(), *this );
434 }
435
436#define make_int_accessor(x) unsigned int num##x() const { return m##x; }
437 make_int_accessor(NoKey)
438 make_int_accessor(NeverEncrypt)
439 make_int_accessor(UnknownPreference)
440 make_int_accessor(AlwaysEncrypt)
441 make_int_accessor(AlwaysEncryptIfPossible)
442 make_int_accessor(AlwaysAskForEncryption)
443 make_int_accessor(AskWheneverPossible)
444 make_int_accessor(Total)
445#undef make_int_accessor
446private:
447 EncryptionPreference mDefaultPreference;
448 bool mNoOps;
449 unsigned int mTotal;
450 unsigned int mNoKey;
451 unsigned int mNeverEncrypt, mUnknownPreference, mAlwaysEncrypt,
452 mAlwaysEncryptIfPossible, mAlwaysAskForEncryption, mAskWheneverPossible;
453};
454
455void Kleo::KeyResolver::EncryptionPreferenceCounter::operator()( Item & item ) {
456 if ( _this ) {
457 if ( item.needKeys )
458 item.keys = _this->getEncryptionKeys( item.address, true );
459 if ( item.keys.empty() ) {
460 ++mNoKey;
461 return;
462 }
463 }
464 switch ( !item.pref ? mDefaultPreference : item.pref ) {
465#define CASE(x) case Kleo::x: ++m##x; break
466 CASE(NeverEncrypt);
467 CASE(UnknownPreference);
468 CASE(AlwaysEncrypt);
469 CASE(AlwaysEncryptIfPossible);
470 CASE(AlwaysAskForEncryption);
471 CASE(AskWheneverPossible);
472#undef CASE
473 }
474 ++mTotal;
475}
476
477namespace {
478
479 class FormatPreferenceCounterBase : public std::function<void(Kleo::KeyResolver::Item)> {
480 public:
481 FormatPreferenceCounterBase()
482 : mTotal( 0 ),
483 mInlineOpenPGP( 0 ),
484 mOpenPGPMIME( 0 ),
485 mSMIME( 0 ),
486 mSMIMEOpaque( 0 )
487 {
488
489 }
490
491#define make_int_accessor(x) unsigned int num##x() const { return m##x; }
492 make_int_accessor(Total)
493 make_int_accessor(InlineOpenPGP)
494 make_int_accessor(OpenPGPMIME)
495 make_int_accessor(SMIME)
496 make_int_accessor(SMIMEOpaque)
497#undef make_int_accessor
498
499 unsigned int numOf( Kleo::CryptoMessageFormat f ) const {
500 switch ( f ) {
501#define CASE(x) case Kleo::x##Format: return m##x
502 CASE(InlineOpenPGP);
503 CASE(OpenPGPMIME);
504 CASE(SMIME);
505 CASE(SMIMEOpaque);
506#undef CASE
507 default: return 0;
508 }
509 }
510
511 protected:
512 unsigned int mTotal;
513 unsigned int mInlineOpenPGP, mOpenPGPMIME, mSMIME, mSMIMEOpaque;
514 };
515
516 class EncryptionFormatPreferenceCounter : public FormatPreferenceCounterBase {
517 public:
518 EncryptionFormatPreferenceCounter() : FormatPreferenceCounterBase() {}
519 void operator()( const Kleo::KeyResolver::Item & item );
520 };
521
522 class SigningFormatPreferenceCounter : public FormatPreferenceCounterBase {
523 public:
524 SigningFormatPreferenceCounter() : FormatPreferenceCounterBase() {}
525 void operator()( const Kleo::KeyResolver::Item & item );
526 };
527
528#define CASE(x) if ( item.format & Kleo::x##Format ) ++m##x;
529 void EncryptionFormatPreferenceCounter::operator()( const Kleo::KeyResolver::Item & item ) {
530 if ( item.format & (Kleo::InlineOpenPGPFormat|Kleo::OpenPGPMIMEFormat) &&
531 std::find_if( item.keys.begin(), item.keys.end(),
532 ValidTrustedOpenPGPEncryptionKey ) != item.keys.end() ) { // -= trusted?
533 CASE(OpenPGPMIME);
534 CASE(InlineOpenPGP);
535 }
536 if ( item.format & (Kleo::SMIMEFormat|Kleo::SMIMEOpaqueFormat) &&
537 std::find_if( item.keys.begin(), item.keys.end(),
538 ValidTrustedSMIMEEncryptionKey ) != item.keys.end() ) { // -= trusted?
539 CASE(SMIME);
540 CASE(SMIMEOpaque);
541 }
542 ++mTotal;
543 }
544
545 void SigningFormatPreferenceCounter::operator()( const Kleo::KeyResolver::Item & item ) {
546 CASE(InlineOpenPGP);
547 CASE(OpenPGPMIME);
548 CASE(SMIME);
549 CASE(SMIMEOpaque);
550 ++mTotal;
551 }
552#undef CASE
553
554} // anon namespace
555
556static TQString canonicalAddress( const TQString & _address ) {
557 const TQString address = KPIM::getEmailAddress( _address );
558 if ( address.find('@') == -1 ) {
559 // local address
560 //char hostname[1024];
561 //gethostname(hostname,1024);
562 //return address + '@' + hostname;
563 return address + "@localdomain";
564 }
565 else
566 return address;
567}
568
569
570struct FormatInfo {
571 std::vector<Kleo::KeyResolver::SplitInfo> splitInfos;
572 std::vector<GpgME::Key> signKeys;
573};
574
575struct Kleo::KeyResolver::Private {
576 std::set<TQCString> alreadyWarnedFingerprints;
577
578 std::vector<GpgME::Key> mOpenPGPSigningKeys; // signing
579 std::vector<GpgME::Key> mSMIMESigningKeys; // signing
580
581 std::vector<GpgME::Key> mOpenPGPEncryptToSelfKeys; // encryption to self
582 std::vector<GpgME::Key> mSMIMEEncryptToSelfKeys; // encryption to self
583
584 std::vector<Item> mPrimaryEncryptionKeys; // encryption to To/CC
585 std::vector<Item> mSecondaryEncryptionKeys; // encryption to BCC
586
587 std::map<CryptoMessageFormat,FormatInfo> mFormatInfoMap;
588
589 // key=email address, value=crypto preferences for this contact (from tdeabc)
590 typedef std::map<TQString, ContactPreferences> ContactPreferencesMap;
591 ContactPreferencesMap mContactPreferencesMap;
592};
593
594
595Kleo::KeyResolver::KeyResolver( bool encToSelf, bool showApproval, bool oppEncryption,
596 unsigned int f,
597 int encrWarnThresholdKey, int signWarnThresholdKey,
598 int encrWarnThresholdRootCert, int signWarnThresholdRootCert,
599 int encrWarnThresholdChainCert, int signWarnThresholdChainCert )
600 : mEncryptToSelf( encToSelf ),
601 mShowApprovalDialog( showApproval ),
602 mOpportunisticEncyption( oppEncryption ),
603 mCryptoMessageFormats( f ),
604 mEncryptKeyNearExpiryWarningThreshold( encrWarnThresholdKey ),
605 mSigningKeyNearExpiryWarningThreshold( signWarnThresholdKey ),
606 mEncryptRootCertNearExpiryWarningThreshold( encrWarnThresholdRootCert ),
607 mSigningRootCertNearExpiryWarningThreshold( signWarnThresholdRootCert ),
608 mEncryptChainCertNearExpiryWarningThreshold( encrWarnThresholdChainCert ),
609 mSigningChainCertNearExpiryWarningThreshold( signWarnThresholdChainCert )
610{
611 d = new Private();
612}
613
614Kleo::KeyResolver::~KeyResolver() {
615 delete d; d = 0;
616}
617
618Kpgp::Result Kleo::KeyResolver::checkKeyNearExpiry( const GpgME::Key & key, const char * dontAskAgainName,
619 bool mine, bool sign, bool ca,
620 int recur_limit, const GpgME::Key & orig ) const {
621 if ( recur_limit <= 0 ) {
622 kdDebug() << "Kleo::KeyResolver::checkKeyNearExpiry(): key chain too long (>100 certs)" << endl;
623 return Kpgp::Ok;
624 }
625 const GpgME::Subkey subkey = key.subkey(0);
626 if ( d->alreadyWarnedFingerprints.count( subkey.fingerprint() ) )
627 return Kpgp::Ok; // already warned about this one (and so about it's issuers)
628
629 if ( subkey.neverExpires() )
630 return Kpgp::Ok;
631 static const double secsPerDay = 24 * 60 * 60;
632 const double secsTillExpiry = ::difftime( subkey.expirationTime(), time(0) );
633 if ( secsTillExpiry <= 0 ) {
634 const int daysSinceExpiry = 1 + int( -secsTillExpiry / secsPerDay );
635 kdDebug() << "Key 0x" << key.shortKeyID() << " expired less than "
636 << daysSinceExpiry << " days ago" << endl;
637 const TQString msg =
638 key.protocol() == GpgME::Context::OpenPGP
639 ? ( mine ? sign
640 ? i18n("<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
641 "<p>expired less than a day ago.</p>",
642 "<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
643 "<p>expired %n days ago.</p>",
644 daysSinceExpiry )
645 : i18n("<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
646 "<p>expired less than a day ago.</p>",
647 "<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
648 "<p>expired %n days ago.</p>",
649 daysSinceExpiry )
650 : i18n("<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
651 "<p>expired less than a day ago.</p>",
652 "<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
653 "<p>expired %n days ago.</p>",
654 daysSinceExpiry ) ).arg( TQString::fromUtf8( key.userID(0).id() ),
655 key.shortKeyID() )
656 : ( ca
657 ? ( key.isRoot()
658 ? ( mine ? sign
659 ? i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
660 "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
661 "<p>expired less than a day ago.</p>",
662 "<p>The root certificate</p><p align=center><b>%3</b></p>"
663 "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
664 "<p>expired %n days ago.</p>",
665 daysSinceExpiry )
666 : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
667 "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
668 "<p>expired less than a day ago.</p>",
669 "<p>The root certificate</p><p align=center><b>%3</b></p>"
670 "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
671 "<p>expired %n days ago.</p>",
672 daysSinceExpiry )
673 : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
674 "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
675 "<p>expired less than a day ago.</p>",
676 "<p>The root certificate</p><p align=center><b>%3</b></p>"
677 "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
678 "<p>expired %n days ago.</p>",
679 daysSinceExpiry ) )
680 : ( mine ? sign
681 ? i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
682 "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
683 "<p>expired less than a day ago.</p>",
684 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
685 "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
686 "<p>expired %n days ago.</p>",
687 daysSinceExpiry )
688 : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
689 "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
690 "<p>expired less than a day ago.</p>",
691 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
692 "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
693 "<p>expired %n days ago.</p>",
694 daysSinceExpiry )
695 : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
696 "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
697 "<p>expired less than a day ago.</p>",
698 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
699 "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
700 "<p>expired %n days ago.</p>",
701 daysSinceExpiry ) ) ).arg( Kleo::DN( orig.userID(0).id() ).prettyDN(),
702 orig.issuerSerial(),
703 Kleo::DN( key.userID(0).id() ).prettyDN() )
704 : ( mine ? sign
705 ? i18n("<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
706 "<p>expired less than a day ago.</p>",
707 "<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
708 "<p>expired %n days ago.</p>",
709 daysSinceExpiry )
710 : i18n("<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
711 "<p>expired less than a day ago.</p>",
712 "<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
713 "<p>expired %n days ago.</p>",
714 daysSinceExpiry )
715 : i18n("<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>"
716 "<p>expired less than a day ago.</p>",
717 "<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>"
718 "<p>expired %n days ago.</p>",
719 daysSinceExpiry ) ).arg( Kleo::DN( key.userID(0).id() ).prettyDN(),
720 key.issuerSerial() ) );
721 d->alreadyWarnedFingerprints.insert( subkey.fingerprint() );
722 if ( KMessageBox::warningContinueCancel( 0, msg,
723 key.protocol() == GpgME::Context::OpenPGP
724 ? i18n("OpenPGP Key Expired" )
725 : i18n("S/MIME Certificate Expired" ),
726 KStdGuiItem::cont(), dontAskAgainName ) == KMessageBox::Cancel )
727 return Kpgp::Canceled;
728 } else {
729 const int daysTillExpiry = 1 + int( secsTillExpiry / secsPerDay );
730 kdDebug() << "Key 0x" << key.shortKeyID() << " expires in less than "
731 << daysTillExpiry << " days" << endl;
732 const int threshold =
733 ca
734 ? ( key.isRoot()
735 ? ( sign
736 ? signingRootCertNearExpiryWarningThresholdInDays()
737 : encryptRootCertNearExpiryWarningThresholdInDays() )
738 : ( sign
739 ? signingChainCertNearExpiryWarningThresholdInDays()
740 : encryptChainCertNearExpiryWarningThresholdInDays() ) )
741 : ( sign
742 ? signingKeyNearExpiryWarningThresholdInDays()
743 : encryptKeyNearExpiryWarningThresholdInDays() );
744 if ( threshold > -1 && daysTillExpiry <= threshold ) {
745 const TQString msg =
746 key.protocol() == GpgME::Context::OpenPGP
747 ? ( mine ? sign
748 ? i18n("<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
749 "<p>expires in less than a day.</p>",
750 "<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
751 "<p>expires in less than %n days.</p>",
752 daysTillExpiry )
753 : i18n("<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
754 "<p>expires in less than a day.</p>",
755 "<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
756 "<p>expires in less than %n days.</p>",
757 daysTillExpiry )
758 : i18n("<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
759 "<p>expires in less than a day.</p>",
760 "<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
761 "<p>expires in less than %n days.</p>",
762 daysTillExpiry ) ).arg( TQString::fromUtf8( key.userID(0).id() ),
763 key.shortKeyID() )
764 : ( ca
765 ? ( key.isRoot()
766 ? ( mine ? sign
767 ? i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
768 "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
769 "<p>expires in less than a day.</p>",
770 "<p>The root certificate</p><p align=center><b>%3</b></p>"
771 "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
772 "<p>expires in less than %n days.</p>",
773 daysTillExpiry )
774 : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
775 "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
776 "<p>expires in less than a day.</p>",
777 "<p>The root certificate</p><p align=center><b>%3</b></p>"
778 "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
779 "<p>expires in less than %n days.</p>",
780 daysTillExpiry )
781 : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
782 "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
783 "<p>expires in less than a day.</p>",
784 "<p>The root certificate</p><p align=center><b>%3</b></p>"
785 "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
786 "<p>expires in less than %n days.</p>",
787 daysTillExpiry ) )
788 : ( mine ? sign
789 ? i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
790 "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
791 "<p>expires in less than a day.</p>",
792 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
793 "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
794 "<p>expires in less than %n days.</p>",
795 daysTillExpiry )
796 : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
797 "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
798 "<p>expires in less than a day.</p>",
799 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
800 "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
801 "<p>expires in less than %n days.</p>",
802 daysTillExpiry )
803 : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
804 "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
805 "<p>expires in less than a day.</p>",
806 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
807 "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
808 "<p>expires in less than %n days.</p>",
809 daysTillExpiry ) ) ).arg( Kleo::DN( orig.userID(0).id() ).prettyDN(),
810 orig.issuerSerial(),
811 Kleo::DN( key.userID(0).id() ).prettyDN() )
812 : ( mine ? sign
813 ? i18n("<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
814 "<p>expires in less than a day.</p>",
815 "<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
816 "<p>expires in less than %n days.</p>",
817 daysTillExpiry )
818 : i18n("<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
819 "<p>expires in less than a day.</p>",
820 "<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
821 "<p>expires in less than %n days.</p>",
822 daysTillExpiry )
823 : i18n("<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>"
824 "<p>expires in less than a day.</p>",
825 "<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>"
826 "<p>expires in less than %n days.</p>",
827 daysTillExpiry ) ).arg( Kleo::DN( key.userID(0).id() ).prettyDN(),
828 key.issuerSerial() ) );
829 d->alreadyWarnedFingerprints.insert( subkey.fingerprint() );
830 if ( KMessageBox::warningContinueCancel( 0, msg,
831 key.protocol() == GpgME::Context::OpenPGP
832 ? i18n("OpenPGP Key Expires Soon" )
833 : i18n("S/MIME Certificate Expires Soon" ),
834 KStdGuiItem::cont(), dontAskAgainName )
835 == KMessageBox::Cancel )
836 return Kpgp::Canceled;
837 }
838 }
839 if ( key.isRoot() )
840 return Kpgp::Ok;
841 else if ( const char * chain_id = key.chainID() ) {
842 const std::vector<GpgME::Key> issuer = lookup( chain_id, false );
843 if ( issuer.empty() )
844 return Kpgp::Ok;
845 else
846 return checkKeyNearExpiry( issuer.front(), dontAskAgainName, mine, sign,
847 true, recur_limit-1, ca ? orig : key );
848 }
849 return Kpgp::Ok;
850}
851
852Kpgp::Result Kleo::KeyResolver::setEncryptToSelfKeys( const TQStringList & fingerprints ) {
853 if ( !encryptToSelf() )
854 return Kpgp::Ok;
855
856 std::vector<GpgME::Key> keys = lookup( fingerprints );
857 std::remove_copy_if( keys.begin(), keys.end(),
858 std::back_inserter( d->mOpenPGPEncryptToSelfKeys ),
859 NotValidTrustedOpenPGPEncryptionKey ); // -= trusted?
860 std::remove_copy_if( keys.begin(), keys.end(),
861 std::back_inserter( d->mSMIMEEncryptToSelfKeys ),
862 NotValidTrustedSMIMEEncryptionKey ); // -= trusted?
863
864 if ( d->mOpenPGPEncryptToSelfKeys.size() + d->mSMIMEEncryptToSelfKeys.size()
865 < keys.size() ) {
866 // too few keys remain...
867 const TQString msg = i18n("One or more of your configured OpenPGP encryption "
868 "keys or S/MIME certificates is not usable for "
869 "encryption. Please reconfigure your encryption keys "
870 "and certificates for this identity in the identity "
871 "configuration dialog.\n"
872 "If you choose to continue, and the keys are needed "
873 "later on, you will be prompted to specify the keys "
874 "to use.");
875 return KMessageBox::warningContinueCancel( 0, msg, i18n("Unusable Encryption Keys"),
876 KStdGuiItem::cont(),
877 "unusable own encryption key warning" )
878 == KMessageBox::Continue ? Kpgp::Ok : Kpgp::Canceled ;
879 }
880
881 // check for near-expiry:
882
883 for ( std::vector<GpgME::Key>::const_iterator it = d->mOpenPGPEncryptToSelfKeys.begin() ; it != d->mOpenPGPEncryptToSelfKeys.end() ; ++it ) {
884 const Kpgp::Result r = checkKeyNearExpiry( *it, "own encryption key expires soon warning",
885 true, false );
886 if ( r != Kpgp::Ok )
887 return r;
888 }
889
890 for ( std::vector<GpgME::Key>::const_iterator it = d->mSMIMEEncryptToSelfKeys.begin() ; it != d->mSMIMEEncryptToSelfKeys.end() ; ++it ) {
891 const Kpgp::Result r = checkKeyNearExpiry( *it, "own encryption key expires soon warning",
892 true, false );
893 if ( r != Kpgp::Ok )
894 return r;
895 }
896
897 return Kpgp::Ok;
898}
899
900Kpgp::Result Kleo::KeyResolver::setSigningKeys( const TQStringList & fingerprints ) {
901 std::vector<GpgME::Key> keys = lookup( fingerprints, true ); // secret keys
902 std::remove_copy_if( keys.begin(), keys.end(),
903 std::back_inserter( d->mOpenPGPSigningKeys ),
904 NotValidOpenPGPSigningKey );
905 std::remove_copy_if( keys.begin(), keys.end(),
906 std::back_inserter( d->mSMIMESigningKeys ),
907 NotValidSMIMESigningKey );
908
909 if ( d->mOpenPGPSigningKeys.size() + d->mSMIMESigningKeys.size() < keys.size() ) {
910 // too few keys remain...
911 const TQString msg = i18n("One or more of your configured OpenPGP signing keys "
912 "or S/MIME signing certificates is not usable for "
913 "signing. Please reconfigure your signing keys "
914 "and certificates for this identity in the identity "
915 "configuration dialog.\n"
916 "If you choose to continue, and the keys are needed "
917 "later on, you will be prompted to specify the keys "
918 "to use.");
919 return KMessageBox::warningContinueCancel( 0, msg, i18n("Unusable Signing Keys"),
920 KStdGuiItem::cont(),
921 "unusable signing key warning" )
922 == KMessageBox::Continue ? Kpgp::Ok : Kpgp::Canceled ;
923 }
924
925 // check for near expiry:
926
927 for ( std::vector<GpgME::Key>::const_iterator it = d->mOpenPGPSigningKeys.begin() ; it != d->mOpenPGPSigningKeys.end() ; ++it ) {
928 const Kpgp::Result r = checkKeyNearExpiry( *it, "signing key expires soon warning",
929 true, true );
930 if ( r != Kpgp::Ok )
931 return r;
932 }
933
934 for ( std::vector<GpgME::Key>::const_iterator it = d->mSMIMESigningKeys.begin() ; it != d->mSMIMESigningKeys.end() ; ++it ) {
935 const Kpgp::Result r = checkKeyNearExpiry( *it, "signing key expires soon warning",
936 true, true );
937 if ( r != Kpgp::Ok )
938 return r;
939 }
940
941 return Kpgp::Ok;
942}
943
944void Kleo::KeyResolver::setPrimaryRecipients( const TQStringList & addresses ) {
945 d->mPrimaryEncryptionKeys = getEncryptionItems( addresses );
946}
947
948void Kleo::KeyResolver::setSecondaryRecipients( const TQStringList & addresses ) {
949 d->mSecondaryEncryptionKeys = getEncryptionItems( addresses );
950}
951
952std::vector<Kleo::KeyResolver::Item> Kleo::KeyResolver::getEncryptionItems( const TQStringList & addresses ) {
953 std::vector<Item> items;
954 items.reserve( addresses.size() );
955 for ( TQStringList::const_iterator it = addresses.begin() ; it != addresses.end() ; ++it ) {
956 TQString addr = canonicalAddress( *it ).lower();
957 const ContactPreferences pref = lookupContactPreferences( addr );
958
959 items.push_back( Item( *it, /*getEncryptionKeys( *it, true ),*/
960 pref.encryptionPreference,
961 pref.signingPreference,
962 pref.cryptoMessageFormat ) );
963 }
964 return items;
965}
966
967static Kleo::Action action( bool doit, bool ask, bool dont, bool requested ) {
968 if ( requested && !dont )
969 return Kleo::DoIt;
970 if ( doit && !ask && !dont )
971 return Kleo::DoIt;
972 if ( !doit && ask && !dont )
973 return Kleo::Ask;
974 if ( !doit && !ask && dont )
975 return requested ? Kleo::Conflict : Kleo::DontDoIt ;
976 if ( !doit && !ask && !dont )
977 return Kleo::DontDoIt ;
978 return Kleo::Conflict;
979}
980
981Kleo::Action Kleo::KeyResolver::checkSigningPreferences( bool signingRequested ) const {
982
983 if ( signingRequested && d->mOpenPGPSigningKeys.empty() && d->mSMIMESigningKeys.empty() )
984 return Impossible;
985
986 SigningPreferenceCounter count;
987 count = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
988 count );
989 count = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
990 count );
991
992 unsigned int sign = count.numAlwaysSign();
993 unsigned int ask = count.numAlwaysAskForSigning();
994 const unsigned int dontSign = count.numNeverSign();
995 if ( signingPossible() ) {
996 sign += count.numAlwaysSignIfPossible();
997 ask += count.numAskSigningWheneverPossible();
998 }
999
1000 return action( sign, ask, dontSign, signingRequested );
1001}
1002
1003bool Kleo::KeyResolver::signingPossible() const {
1004 return !d->mOpenPGPSigningKeys.empty() || !d->mSMIMESigningKeys.empty() ;
1005}
1006
1007Kleo::Action Kleo::KeyResolver::checkEncryptionPreferences( bool encryptionRequested ) const {
1008
1009 if ( d->mPrimaryEncryptionKeys.empty() && d->mSecondaryEncryptionKeys.empty() )
1010 return DontDoIt;
1011
1012 if ( encryptionRequested && encryptToSelf() &&
1013 d->mOpenPGPEncryptToSelfKeys.empty() && d->mSMIMEEncryptToSelfKeys.empty() )
1014 return Impossible;
1015
1016 if ( !encryptionRequested && !mOpportunisticEncyption ) {
1017 // try to minimize crypto ops (including key lookups) by only
1018 // looking up keys when at least one the the encryption
1019 // preferences needs it:
1020 EncryptionPreferenceCounter count( 0, UnknownPreference );
1021 count.process( d->mPrimaryEncryptionKeys );
1022 count.process( d->mSecondaryEncryptionKeys );
1023 if ( !count.numAlwaysEncrypt() &&
1024 !count.numAlwaysAskForEncryption() && // this guy might not need a lookup, when declined, but it's too complex to implement that here
1025 !count.numAlwaysEncryptIfPossible() &&
1026 !count.numAskWheneverPossible() )
1027 return DontDoIt;
1028 }
1029
1030 EncryptionPreferenceCounter count( this, mOpportunisticEncyption ? AskWheneverPossible : UnknownPreference );
1031 count = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
1032 count );
1033 count = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
1034 count );
1035
1036 unsigned int encrypt = count.numAlwaysEncrypt();
1037 unsigned int ask = count.numAlwaysAskForEncryption();
1038 const unsigned int dontEncrypt = count.numNeverEncrypt() + count.numNoKey();
1039 if ( encryptionPossible() ) {
1040 encrypt += count.numAlwaysEncryptIfPossible();
1041 ask += count.numAskWheneverPossible();
1042 }
1043
1044 const Action act = action( encrypt, ask, dontEncrypt, encryptionRequested );
1045 if ( act != Ask ||
1046 std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
1047 std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
1048 EncryptionPreferenceCounter( this, UnknownPreference ) ) ).numAlwaysAskForEncryption() )
1049 return act;
1050 else
1051 return AskOpportunistic;
1052}
1053
1054bool Kleo::KeyResolver::encryptionPossible() const {
1055 return std::find_if( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
1056 EmptyKeyList ) == d->mPrimaryEncryptionKeys.end()
1057 && std::find_if( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
1058 EmptyKeyList ) == d->mSecondaryEncryptionKeys.end() ;
1059}
1060
1061Kpgp::Result Kleo::KeyResolver::resolveAllKeys( bool& signingRequested, bool& encryptionRequested ) {
1062 if ( !encryptionRequested && !signingRequested ) {
1063 // make a dummy entry with all recipients, but no signing or
1064 // encryption keys to avoid special-casing on the caller side:
1065 dump();
1066 d->mFormatInfoMap[OpenPGPMIMEFormat].splitInfos.push_back( SplitInfo( allRecipients() ) );
1067 dump();
1068 return Kpgp::Ok;
1069 }
1070 Kpgp::Result result = Kpgp::Ok;
1071 if ( encryptionRequested )
1072 result = resolveEncryptionKeys( signingRequested );
1073 if ( result != Kpgp::Ok )
1074 return result;
1075 if ( signingRequested ) {
1076 if ( encryptionRequested ) {
1077 result = resolveSigningKeysForEncryption();
1078 }
1079 else {
1080 result = resolveSigningKeysForSigningOnly();
1081 if ( result == Kpgp::Failure ) {
1082 signingRequested = false;
1083 return Kpgp::Ok;
1084 }
1085 }
1086 }
1087 return result;
1088}
1089
1090Kpgp::Result Kleo::KeyResolver::resolveEncryptionKeys( bool signingRequested ) {
1091 //
1092 // 1. Get keys for all recipients:
1093 //
1094
1095 for ( std::vector<Item>::iterator it = d->mPrimaryEncryptionKeys.begin() ; it != d->mPrimaryEncryptionKeys.end() ; ++it ) {
1096 if ( !it->needKeys )
1097 continue;
1098 it->keys = getEncryptionKeys( it->address, false );
1099 if ( it->keys.empty() )
1100 return Kpgp::Canceled;
1101 TQString addr = canonicalAddress( it->address ).lower();
1102 const ContactPreferences pref = lookupContactPreferences( addr );
1103 it->pref = pref.encryptionPreference;
1104 it->signPref = pref.signingPreference;
1105 it->format = pref.cryptoMessageFormat;
1106 }
1107
1108 for ( std::vector<Item>::iterator it = d->mSecondaryEncryptionKeys.begin() ; it != d->mSecondaryEncryptionKeys.end() ; ++it ) {
1109 if ( !it->needKeys )
1110 continue;
1111 it->keys = getEncryptionKeys( it->address, false );
1112 if ( it->keys.empty() )
1113 return Kpgp::Canceled;
1114 TQString addr = canonicalAddress( it->address ).lower();
1115 const ContactPreferences pref = lookupContactPreferences( addr );
1116 it->pref = pref.encryptionPreference;
1117 it->signPref = pref.signingPreference;
1118 it->format = pref.cryptoMessageFormat;
1119 }
1120
1121 // 1a: Present them to the user
1122
1123 const Kpgp::Result res = showKeyApprovalDialog();
1124 if ( res != Kpgp::Ok )
1125 return res;
1126
1127 //
1128 // 2. Check what the primary recipients need
1129 //
1130
1131 // 2a. Try to find a common format for all primary recipients,
1132 // else use as many formats as needed
1133
1134 const EncryptionFormatPreferenceCounter primaryCount
1135 = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
1136 EncryptionFormatPreferenceCounter() );
1137
1138 CryptoMessageFormat commonFormat = AutoFormat;
1139 for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
1140 if ( !( concreteCryptoMessageFormats[i] & mCryptoMessageFormats ) )
1141 continue;
1142 if ( signingRequested && signingKeysFor( concreteCryptoMessageFormats[i] ).empty() )
1143 continue;
1144 if ( encryptToSelf() && encryptToSelfKeysFor( concreteCryptoMessageFormats[i] ).empty() )
1145 continue;
1146 if ( primaryCount.numOf( concreteCryptoMessageFormats[i] ) == primaryCount.numTotal() ) {
1147 commonFormat = concreteCryptoMessageFormats[i];
1148 break;
1149 }
1150 }
1151 if ( commonFormat != AutoFormat )
1152 addKeys( d->mPrimaryEncryptionKeys, commonFormat );
1153 else
1154 addKeys( d->mPrimaryEncryptionKeys );
1155
1156 collapseAllSplitInfos(); // these can be encrypted together
1157
1158 // 2b. Just try to find _something_ for each secondary recipient,
1159 // with a preference to a common format (if that exists)
1160
1161 const EncryptionFormatPreferenceCounter secondaryCount
1162 = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
1163 EncryptionFormatPreferenceCounter() );
1164
1165 if ( commonFormat != AutoFormat &&
1166 secondaryCount.numOf( commonFormat ) == secondaryCount.numTotal() )
1167 addKeys( d->mSecondaryEncryptionKeys, commonFormat );
1168 else
1169 addKeys( d->mSecondaryEncryptionKeys );
1170
1171 // 3. Check for expiry:
1172
1173 for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
1174 const std::vector<SplitInfo> si_list = encryptionItems( concreteCryptoMessageFormats[i] );
1175 for ( std::vector<SplitInfo>::const_iterator sit = si_list.begin() ; sit != si_list.end() ; ++sit )
1176 for ( std::vector<GpgME::Key>::const_iterator kit = sit->keys.begin() ; kit != sit->keys.end() ; ++kit ) {
1177 const Kpgp::Result r = checkKeyNearExpiry( *kit, "other encryption key near expiry warning",
1178 false, false );
1179 if ( r != Kpgp::Ok )
1180 return r;
1181 }
1182 }
1183
1184 // 4. Check that we have the right keys for encryptToSelf()
1185
1186 if ( !encryptToSelf() )
1187 return Kpgp::Ok;
1188
1189 // 4a. Check for OpenPGP keys
1190
1191 if ( !encryptionItems( InlineOpenPGPFormat ).empty() ||
1192 !encryptionItems( OpenPGPMIMEFormat ).empty() ) {
1193 // need them
1194 if ( d->mOpenPGPEncryptToSelfKeys.empty() ) {
1195 const TQString msg = i18n("Examination of recipient's encryption preferences "
1196 "yielded that the message should be encrypted using "
1197 "OpenPGP, at least for some recipients;\n"
1198 "however, you have not configured valid trusted "
1199 "OpenPGP encryption keys for this identity.\n"
1200 "You may continue without encrypting to yourself, "
1201 "but be aware that you will not be able to read your "
1202 "own messages if you do so.");
1203 if ( KMessageBox::warningContinueCancel( 0, msg,
1204 i18n("Unusable Encryption Keys"),
1205 KStdGuiItem::cont(),
1206 "encrypt-to-self will fail warning" )
1207 == KMessageBox::Cancel )
1208 return Kpgp::Canceled;
1209 // FIXME: Allow selection
1210 }
1211 addToAllSplitInfos( d->mOpenPGPEncryptToSelfKeys,
1212 InlineOpenPGPFormat|OpenPGPMIMEFormat );
1213 }
1214
1215 // 4b. Check for S/MIME certs:
1216
1217 if ( !encryptionItems( SMIMEFormat ).empty() ||
1218 !encryptionItems( SMIMEOpaqueFormat ).empty() ) {
1219 // need them
1220 if ( d->mSMIMEEncryptToSelfKeys.empty() ) {
1221 // don't have one
1222 const TQString msg = i18n("Examination of recipient's encryption preferences "
1223 "yielded that the message should be encrypted using "
1224 "S/MIME, at least for some recipients;\n"
1225 "however, you have not configured valid "
1226 "S/MIME encryption certificates for this identity.\n"
1227 "You may continue without encrypting to yourself, "
1228 "but be aware that you will not be able to read your "
1229 "own messages if you do so.");
1230 if ( KMessageBox::warningContinueCancel( 0, msg,
1231 i18n("Unusable Encryption Keys"),
1232 KStdGuiItem::cont(),
1233 "encrypt-to-self will fail warning" )
1234 == KMessageBox::Cancel )
1235 return Kpgp::Canceled;
1236 // FIXME: Allow selection
1237 }
1238 addToAllSplitInfos( d->mSMIMEEncryptToSelfKeys,
1239 SMIMEFormat|SMIMEOpaqueFormat );
1240 }
1241
1242 // FIXME: Present another message if _both_ OpenPGP and S/MIME keys
1243 // are missing.
1244
1245 return Kpgp::Ok;
1246}
1247
1248Kpgp::Result Kleo::KeyResolver::resolveSigningKeysForEncryption() {
1249 if ( ( !encryptionItems( InlineOpenPGPFormat ).empty() ||
1250 !encryptionItems( OpenPGPMIMEFormat ).empty() )
1251 && d->mOpenPGPSigningKeys.empty() ) {
1252 const TQString msg = i18n("Examination of recipient's signing preferences "
1253 "yielded that the message should be signed using "
1254 "OpenPGP, at least for some recipients;\n"
1255 "however, you have not configured valid "
1256 "OpenPGP signing certificates for this identity.");
1257 if ( KMessageBox::warningContinueCancel( 0, msg,
1258 i18n("Unusable Signing Keys"),
1259 i18n("Do Not OpenPGP-Sign"),
1260 "signing will fail warning" )
1261 == KMessageBox::Cancel )
1262 return Kpgp::Canceled;
1263 // FIXME: Allow selection
1264 }
1265 if ( ( !encryptionItems( SMIMEFormat ).empty() ||
1266 !encryptionItems( SMIMEOpaqueFormat ).empty() )
1267 && d->mSMIMESigningKeys.empty() ) {
1268 const TQString msg = i18n("Examination of recipient's signing preferences "
1269 "yielded that the message should be signed using "
1270 "S/MIME, at least for some recipients;\n"
1271 "however, you have not configured valid "
1272 "S/MIME signing certificates for this identity.");
1273 if ( KMessageBox::warningContinueCancel( 0, msg,
1274 i18n("Unusable Signing Keys"),
1275 i18n("Do Not S/MIME-Sign"),
1276 "signing will fail warning" )
1277 == KMessageBox::Cancel )
1278 return Kpgp::Canceled;
1279 // FIXME: Allow selection
1280 }
1281
1282 // FIXME: Present another message if _both_ OpenPGP and S/MIME keys
1283 // are missing.
1284
1285 for ( std::map<CryptoMessageFormat,FormatInfo>::iterator it = d->mFormatInfoMap.begin() ; it != d->mFormatInfoMap.end() ; ++it )
1286 if ( !it->second.splitInfos.empty() ) {
1287 dump();
1288 it->second.signKeys = signingKeysFor( it->first );
1289 dump();
1290 }
1291
1292 return Kpgp::Ok;
1293}
1294
1295Kpgp::Result Kleo::KeyResolver::resolveSigningKeysForSigningOnly() {
1296 //
1297 // we don't need to distinguish between primary and secondary
1298 // recipients here:
1299 //
1300 SigningFormatPreferenceCounter count;
1301 count = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
1302 count );
1303 count = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
1304 count );
1305
1306 // try to find a common format that works for all (and that we have signing keys for):
1307
1308 CryptoMessageFormat commonFormat = AutoFormat;
1309
1310 for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
1311 if ( !(mCryptoMessageFormats & concreteCryptoMessageFormats[i]) )
1312 continue; // skip
1313 if ( signingKeysFor( concreteCryptoMessageFormats[i] ).empty() )
1314 continue; // skip
1315 if ( count.numOf( concreteCryptoMessageFormats[i] ) == count.numTotal() ) {
1316 commonFormat = concreteCryptoMessageFormats[i];
1317 break;
1318 }
1319 }
1320
1321 if ( commonFormat != AutoFormat ) { // found
1322 dump();
1323 FormatInfo & fi = d->mFormatInfoMap[ commonFormat ];
1324 fi.signKeys = signingKeysFor( commonFormat );
1325 fi.splitInfos.resize( 1 );
1326 fi.splitInfos.front() = SplitInfo( allRecipients() );
1327 dump();
1328 return Kpgp::Ok;
1329 }
1330
1331 const TQString msg = i18n("Examination of recipient's signing preferences "
1332 "showed no common type of signature matching your "
1333 "available signing keys.\n"
1334 "Send message without signing?" );
1335 if ( KMessageBox::warningContinueCancel( 0, msg, i18n("No signing possible"),
1336 KStdGuiItem::cont() )
1337 == KMessageBox::Continue ) {
1338 d->mFormatInfoMap[OpenPGPMIMEFormat].splitInfos.push_back( SplitInfo( allRecipients() ) );
1339 return Kpgp::Failure; // means "Ok, but without signing"
1340 }
1341 return Kpgp::Canceled;
1342}
1343
1344std::vector<GpgME::Key> Kleo::KeyResolver::signingKeysFor( CryptoMessageFormat f ) const {
1345 if ( isOpenPGP( f ) )
1346 return d->mOpenPGPSigningKeys;
1347 if ( isSMIME( f ) )
1348 return d->mSMIMESigningKeys;
1349 return std::vector<GpgME::Key>();
1350}
1351
1352std::vector<GpgME::Key> Kleo::KeyResolver::encryptToSelfKeysFor( CryptoMessageFormat f ) const {
1353 if ( isOpenPGP( f ) )
1354 return d->mOpenPGPEncryptToSelfKeys;
1355 if ( isSMIME( f ) )
1356 return d->mSMIMEEncryptToSelfKeys;
1357 return std::vector<GpgME::Key>();
1358}
1359
1360TQStringList Kleo::KeyResolver::allRecipients() const {
1361 TQStringList result;
1362 std::transform( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
1363 std::back_inserter( result ), ItemDotAddress );
1364 std::transform( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
1365 std::back_inserter( result ), ItemDotAddress );
1366 return result;
1367}
1368
1369void Kleo::KeyResolver::collapseAllSplitInfos() {
1370 dump();
1371 for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
1372 std::map<CryptoMessageFormat,FormatInfo>::iterator pos =
1373 d->mFormatInfoMap.find( concreteCryptoMessageFormats[i] );
1374 if ( pos == d->mFormatInfoMap.end() )
1375 continue;
1376 std::vector<SplitInfo> & v = pos->second.splitInfos;
1377 if ( v.size() < 2 )
1378 continue;
1379 SplitInfo & si = v.front();
1380 for ( std::vector<SplitInfo>::const_iterator it = v.begin() + 1; it != v.end() ; ++it ) {
1381 si.keys.insert( si.keys.end(), it->keys.begin(), it->keys.end() );
1382 tqCopy( it->recipients.begin(), it->recipients.end(), std::back_inserter( si.recipients ) );
1383 }
1384 v.resize( 1 );
1385 }
1386 dump();
1387}
1388
1389void Kleo::KeyResolver::addToAllSplitInfos( const std::vector<GpgME::Key> & keys, unsigned int f ) {
1390 dump();
1391 if ( !f || keys.empty() )
1392 return;
1393 for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
1394 if ( !( f & concreteCryptoMessageFormats[i] ) )
1395 continue;
1396 std::map<CryptoMessageFormat,FormatInfo>::iterator pos =
1397 d->mFormatInfoMap.find( concreteCryptoMessageFormats[i] );
1398 if ( pos == d->mFormatInfoMap.end() )
1399 continue;
1400 std::vector<SplitInfo> & v = pos->second.splitInfos;
1401 for ( std::vector<SplitInfo>::iterator it = v.begin() ; it != v.end() ; ++it )
1402 it->keys.insert( it->keys.end(), keys.begin(), keys.end() );
1403 }
1404 dump();
1405}
1406
1407void Kleo::KeyResolver::dump() const {
1408#ifndef NDEBUG
1409 if ( d->mFormatInfoMap.empty() )
1410 std::cerr << "Keyresolver: Format info empty" << std::endl;
1411 for ( std::map<CryptoMessageFormat,FormatInfo>::const_iterator it = d->mFormatInfoMap.begin() ; it != d->mFormatInfoMap.end() ; ++it ) {
1412 std::cerr << "Format info for " << Kleo::cryptoMessageFormatToString( it->first )
1413 << ":" << std::endl
1414 << " Signing keys: ";
1415 for ( std::vector<GpgME::Key>::const_iterator sit = it->second.signKeys.begin() ; sit != it->second.signKeys.end() ; ++sit )
1416 std::cerr << sit->shortKeyID() << " ";
1417 std::cerr << std::endl;
1418 unsigned int i = 0;
1419 for ( std::vector<SplitInfo>::const_iterator sit = it->second.splitInfos.begin() ; sit != it->second.splitInfos.end() ; ++sit, ++i ) {
1420 std::cerr << " SplitInfo #" << i << " encryption keys: ";
1421 for ( std::vector<GpgME::Key>::const_iterator kit = sit->keys.begin() ; kit != sit->keys.end() ; ++kit )
1422 std::cerr << kit->shortKeyID() << " ";
1423 std::cerr << std::endl
1424 << " SplitInfo #" << i << " recipients: "
1425 << sit->recipients.join(", ").utf8().data() << std::endl;
1426 }
1427 }
1428#endif
1429}
1430
1431Kpgp::Result Kleo::KeyResolver::showKeyApprovalDialog() {
1432 const bool showKeysForApproval = showApprovalDialog()
1433 || std::find_if( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
1434 ApprovalNeeded ) != d->mPrimaryEncryptionKeys.end()
1435 || std::find_if( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
1436 ApprovalNeeded ) != d->mSecondaryEncryptionKeys.end() ;
1437
1438 if ( !showKeysForApproval )
1439 return Kpgp::Ok;
1440
1441 std::vector<Kleo::KeyApprovalDialog::Item> items;
1442 items.reserve( d->mPrimaryEncryptionKeys.size() +
1443 d->mSecondaryEncryptionKeys.size() );
1444 std::copy( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
1445 std::back_inserter( items ) );
1446 std::copy( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
1447 std::back_inserter( items ) );
1448
1449 std::vector<GpgME::Key> senderKeys;
1450 senderKeys.reserve( d->mOpenPGPEncryptToSelfKeys.size() +
1451 d->mSMIMEEncryptToSelfKeys.size() );
1452 std::copy( d->mOpenPGPEncryptToSelfKeys.begin(), d->mOpenPGPEncryptToSelfKeys.end(),
1453 std::back_inserter( senderKeys ) );
1454 std::copy( d->mSMIMEEncryptToSelfKeys.begin(), d->mSMIMEEncryptToSelfKeys.end(),
1455 std::back_inserter( senderKeys ) );
1456
1457 const KCursorSaver idle( KBusyPtr::idle() );
1458
1459 Kleo::KeyApprovalDialog dlg( items, senderKeys );
1460
1461 if ( dlg.exec() == TQDialog::Rejected )
1462 return Kpgp::Canceled;
1463
1464 items = dlg.items();
1465 senderKeys = dlg.senderKeys();
1466
1467 if ( dlg.preferencesChanged() ) {
1468 for ( uint i = 0; i < items.size(); ++i ) {
1469 ContactPreferences pref = lookupContactPreferences( items[i].address );
1470 pref.encryptionPreference = items[i].pref;
1471 pref.pgpKeyFingerprints.clear();
1472 pref.smimeCertFingerprints.clear();
1473 const std::vector<GpgME::Key> & keys = items[i].keys;
1474 for ( std::vector<GpgME::Key>::const_iterator it = keys.begin(), end = keys.end() ; it != end ; ++it ) {
1475 if ( it->protocol() == GpgME::Context::OpenPGP ) {
1476 if ( const char * fpr = it->primaryFingerprint() )
1477 pref.pgpKeyFingerprints.push_back( fpr );
1478 } else if ( it->protocol() == GpgME::Context::CMS ) {
1479 if ( const char * fpr = it->primaryFingerprint() )
1480 pref.smimeCertFingerprints.push_back( fpr );
1481 }
1482 }
1483 saveContactPreference( items[i].address, pref );
1484 }
1485 }
1486
1487 // show a warning if the user didn't select an encryption key for
1488 // herself:
1489 if ( encryptToSelf() && senderKeys.empty() ) {
1490 const TQString msg = i18n("You did not select an encryption key for yourself "
1491 "(encrypt to self). You will not be able to decrypt "
1492 "your own message if you encrypt it.");
1493 if ( KMessageBox::warningContinueCancel( 0, msg,
1494 i18n("Missing Key Warning"),
1495 i18n("&Encrypt") )
1496 == KMessageBox::Cancel )
1497 return Kpgp::Canceled;
1498 else
1499 mEncryptToSelf = false;
1500 }
1501
1502 // count empty key ID lists
1503 const unsigned int emptyListCount =
1504 std::count_if( items.begin(), items.end(), EmptyKeyList );
1505
1506 // show a warning if the user didn't select an encryption key for
1507 // some of the recipients
1508 if ( items.size() == emptyListCount ) {
1509 const TQString msg = ( d->mPrimaryEncryptionKeys.size() +
1510 d->mSecondaryEncryptionKeys.size() == 1 )
1511 ? i18n("You did not select an encryption key for the "
1512 "recipient of this message; therefore, the message "
1513 "will not be encrypted.")
1514 : i18n("You did not select an encryption key for any of the "
1515 "recipients of this message; therefore, the message "
1516 "will not be encrypted.");
1517 if ( KMessageBox::warningContinueCancel( 0, msg,
1518 i18n("Missing Key Warning"),
1519 i18n("Send &Unencrypted") )
1520 == KMessageBox::Cancel )
1521 return Kpgp::Canceled;
1522 } else if ( emptyListCount > 0 ) {
1523 const TQString msg = ( emptyListCount == 1 )
1524 ? i18n("You did not select an encryption key for one of "
1525 "the recipients: this person will not be able to "
1526 "decrypt the message if you encrypt it.")
1527 : i18n("You did not select encryption keys for some of "
1528 "the recipients: these persons will not be able to "
1529 "decrypt the message if you encrypt it." );
1530 KCursorSaver idle( KBusyPtr::idle() );
1531 if ( KMessageBox::warningContinueCancel( 0, msg,
1532 i18n("Missing Key Warning"),
1533 i18n("&Encrypt") )
1534 == KMessageBox::Cancel )
1535 return Kpgp::Canceled;
1536 }
1537
1538 std::transform( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
1539 items.begin(),
1540 d->mPrimaryEncryptionKeys.begin(),
1541 CopyKeysAndEncryptionPreferences );
1542 std::transform( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
1543 items.begin() + d->mPrimaryEncryptionKeys.size(),
1544 d->mSecondaryEncryptionKeys.begin(),
1545 CopyKeysAndEncryptionPreferences );
1546
1547 d->mOpenPGPEncryptToSelfKeys.clear();
1548 d->mSMIMEEncryptToSelfKeys.clear();
1549
1550 std::remove_copy_if( senderKeys.begin(), senderKeys.end(),
1551 std::back_inserter( d->mOpenPGPEncryptToSelfKeys ),
1552 NotValidTrustedOpenPGPEncryptionKey ); // -= trusted (see above, too)?
1553 std::remove_copy_if( senderKeys.begin(), senderKeys.end(),
1554 std::back_inserter( d->mSMIMEEncryptToSelfKeys ),
1555 NotValidTrustedSMIMEEncryptionKey ); // -= trusted (see above, too)?
1556
1557 return Kpgp::Ok;
1558}
1559
1560std::vector<Kleo::KeyResolver::SplitInfo> Kleo::KeyResolver::encryptionItems( Kleo::CryptoMessageFormat f ) const {
1561 dump();
1562 std::map<CryptoMessageFormat,FormatInfo>::const_iterator it =
1563 d->mFormatInfoMap.find( f );
1564 return it != d->mFormatInfoMap.end() ? it->second.splitInfos : std::vector<SplitInfo>() ;
1565}
1566
1567std::vector<GpgME::Key> Kleo::KeyResolver::signingKeys( CryptoMessageFormat f ) const {
1568 dump();
1569 std::map<CryptoMessageFormat,FormatInfo>::const_iterator it =
1570 d->mFormatInfoMap.find( f );
1571 return it != d->mFormatInfoMap.end() ? it->second.signKeys : std::vector<GpgME::Key>() ;
1572}
1573
1574//
1575//
1576// Private helper methods below:
1577//
1578//
1579
1580
1581std::vector<GpgME::Key> Kleo::KeyResolver::selectKeys( const TQString & person, const TQString & msg, const std::vector<GpgME::Key> & selectedKeys ) const {
1582 const bool opgp = containsOpenPGP( mCryptoMessageFormats );
1583 const bool x509 = containsSMIME( mCryptoMessageFormats );
1584
1585 Kleo::KeySelectionDialog dlg( i18n("Encryption Key Selection"),
1586 msg, KPIM::getEmailAddress(person), selectedKeys,
1587 Kleo::KeySelectionDialog::ValidEncryptionKeys
1588 & ~(opgp ? 0 : Kleo::KeySelectionDialog::OpenPGPKeys)
1589 & ~(x509 ? 0 : Kleo::KeySelectionDialog::SMIMEKeys),
1590 true, true ); // multi-selection and "remember choice" box
1591
1592 if ( dlg.exec() != TQDialog::Accepted )
1593 return std::vector<GpgME::Key>();
1594 std::vector<GpgME::Key> keys = dlg.selectedKeys();
1595 keys.erase( std::remove_if( keys.begin(), keys.end(),
1596 NotValidTrustedEncryptionKey ), // -= trusted?
1597 keys.end() );
1598 if ( !keys.empty() && dlg.rememberSelection() )
1599 setKeysForAddress( person, dlg.pgpKeyFingerprints(), dlg.smimeFingerprints() );
1600 return keys;
1601}
1602
1603
1604std::vector<GpgME::Key> Kleo::KeyResolver::getEncryptionKeys( const TQString & person, bool quiet ) const {
1605
1606 const TQString address = canonicalAddress( person ).lower();
1607
1608 // First look for this person's address in the address->key dictionary
1609 const TQStringList fingerprints = keysForAddress( address );
1610
1611 if ( !fingerprints.empty() ) {
1612 kdDebug() << "Using encryption keys 0x"
1613 << fingerprints.join( ", 0x" )
1614 << " for " << person << endl;
1615 std::vector<GpgME::Key> keys = lookup( fingerprints );
1616 if ( !keys.empty() ) {
1617 // Check if all of the keys are trusted and valid encryption keys
1618 if ( std::find_if( keys.begin(), keys.end(),
1619 NotValidTrustedEncryptionKey ) != keys.end() ) { // -= trusted?
1620
1621 // not ok, let the user select: this is not conditional on !quiet,
1622 // since it's a bug in the configuration and the user should be
1623 // notified about it as early as possible:
1624 keys = selectKeys( person,
1625 i18n("if in your language something like "
1626 "'certificate(s)' isn't possible please "
1627 "use the plural in the translation",
1628 "There is a problem with the "
1629 "encryption certificate(s) for \"%1\".\n\n"
1630 "Please re-select the certificate(s) which should "
1631 "be used for this recipient.").arg(person),
1632 keys );
1633 }
1634 bool canceled = false;
1635 keys = trustedOrConfirmed( keys, address, canceled );
1636 if ( canceled )
1637 return std::vector<GpgME::Key>();
1638
1639 if ( !keys.empty() )
1640 return keys;
1641 // keys.empty() is considered cancel by callers, so go on
1642 }
1643 }
1644
1645 // Now search all public keys for matching keys
1646 std::vector<GpgME::Key> matchingKeys = lookup( person );
1647 matchingKeys.erase( std::remove_if( matchingKeys.begin(), matchingKeys.end(),
1648 NotValidEncryptionKey ),
1649 matchingKeys.end() );
1650 // if no keys match the complete address look for keys which match
1651 // the canonical mail address
1652 if ( matchingKeys.empty() ) {
1653 matchingKeys = lookup( address );
1654 matchingKeys.erase( std::remove_if( matchingKeys.begin(), matchingKeys.end(),
1655 NotValidEncryptionKey ),
1656 matchingKeys.end() );
1657 }
1658
1659 // if called with quite == true (from EncryptionPreferenceCounter), we only want to
1660 // check if there are keys for this recipients, not (yet) their validity, so
1661 // don't show the untrusted encryption key warning in that case
1662 bool canceled = false;
1663 if ( !quiet )
1664 matchingKeys = trustedOrConfirmed( matchingKeys, address, canceled );
1665 if ( canceled )
1666 return std::vector<GpgME::Key>();
1667 if ( quiet || matchingKeys.size() == 1 )
1668 return matchingKeys;
1669
1670 // no match until now, or more than one key matches; let the user
1671 // choose the key(s)
1672 // FIXME: let user get the key from keyserver
1673 return trustedOrConfirmed( selectKeys( person,
1674 matchingKeys.empty()
1675 ? i18n("if in your language something like "
1676 "'certificate(s)' isn't possible please "
1677 "use the plural in the translation",
1678 "<qt>No valid and trusted encryption certificate was "
1679 "found for \"%1\".<br/><br/>"
1680 "Select the certificate(s) which should "
1681 "be used for this recipient. If there is no suitable certificate in the list "
1682 "you can also search for external certificates by clicking the button: search for external certificates.</qt>")
1683 .arg( TQStyleSheet::escape(person) )
1684 : i18n("if in your language something like "
1685 "'certificate(s)' isn't possible please "
1686 "use the plural in the translation",
1687 "More than one certificate matches \"%1\".\n\n"
1688 "Select the certificate(s) which should "
1689 "be used for this recipient.").arg( TQStyleSheet::escape(person) ),
1690 matchingKeys ), address, canceled );
1691 // we can ignore 'canceled' here, since trustedOrConfirmed() returns
1692 // an empty vector when canceled == true, and we'd just do the same
1693}
1694
1695
1696std::vector<GpgME::Key> Kleo::KeyResolver::lookup( const TQStringList & patterns, bool secret ) const {
1697 if ( patterns.empty() )
1698 return std::vector<GpgME::Key>();
1699 kdDebug() << "Kleo::KeyResolver::lookup( \"" << patterns.join( "\", \"" )
1700 << "\", " << secret << " )" << endl;
1701 std::vector<GpgME::Key> result;
1702 if ( mCryptoMessageFormats & (InlineOpenPGPFormat|OpenPGPMIMEFormat) )
1703 if ( const Kleo::CryptoBackend::Protocol * p = Kleo::CryptoBackendFactory::instance()->openpgp() ) {
1704 std::unique_ptr<Kleo::KeyListJob> job( p->keyListJob( false, false, true ) ); // use validating keylisting
1705 if ( job ) {
1706 std::vector<GpgME::Key> keys;
1707 job->exec( patterns, secret, keys );
1708 result.insert( result.end(), keys.begin(), keys.end() );
1709 }
1710 }
1711 if ( mCryptoMessageFormats & (SMIMEFormat|SMIMEOpaqueFormat) )
1712 if ( const Kleo::CryptoBackend::Protocol * p = Kleo::CryptoBackendFactory::instance()->smime() ) {
1713 std::unique_ptr<Kleo::KeyListJob> job( p->keyListJob( false, false, true ) ); // use validating keylisting
1714 if ( job ) {
1715 std::vector<GpgME::Key> keys;
1716 job->exec( patterns, secret, keys );
1717 result.insert( result.end(), keys.begin(), keys.end() );
1718 }
1719 }
1720 kdDebug() << " returned " << result.size() << " keys" << endl;
1721 return result;
1722}
1723
1724void Kleo::KeyResolver::addKeys( const std::vector<Item> & items, CryptoMessageFormat f ) {
1725 dump();
1726 for ( std::vector<Item>::const_iterator it = items.begin() ; it != items.end() ; ++it ) {
1727 SplitInfo si( it->address );
1728 std::remove_copy_if( it->keys.begin(), it->keys.end(),
1729 std::back_inserter( si.keys ), IsNotForFormat( f ) );
1730 dump();
1731 kdWarning( si.keys.empty() )
1732 << "Kleo::KeyResolver::addKeys(): Fix EncryptionFormatPreferenceCounter. "
1733 << "It detected a common format, but the list of such keys for recipient \""
1734 << it->address << "\" is empty!" << endl;
1735 d->mFormatInfoMap[ f ].splitInfos.push_back( si );
1736 }
1737 dump();
1738}
1739
1740void Kleo::KeyResolver::addKeys( const std::vector<Item> & items ) {
1741 dump();
1742 for ( std::vector<Item>::const_iterator it = items.begin() ; it != items.end() ; ++it ) {
1743 SplitInfo si( it->address );
1744 CryptoMessageFormat f = AutoFormat;
1745 for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
1746 const CryptoMessageFormat fmt = concreteCryptoMessageFormats[i];
1747 if ( ( fmt & it->format ) &&
1748 kdtools::any( it->keys.begin(), it->keys.end(), IsForFormat( fmt ) ) )
1749 {
1750 f = fmt;
1751 break;
1752 }
1753 }
1754 if ( f == AutoFormat )
1755 kdWarning() << "Kleo::KeyResolver::addKeys(): Something went wrong. Didn't find a format for \""
1756 << it->address << "\"" << endl;
1757 else
1758 std::remove_copy_if( it->keys.begin(), it->keys.end(),
1759 std::back_inserter( si.keys ), IsNotForFormat( f ) );
1760 d->mFormatInfoMap[ f ].splitInfos.push_back( si );
1761 }
1762 dump();
1763}
1764
1765Kleo::KeyResolver::ContactPreferences Kleo::KeyResolver::lookupContactPreferences( const TQString& address ) const
1766{
1767 const Private::ContactPreferencesMap::iterator it =
1768 d->mContactPreferencesMap.find( address );
1769 if ( it != d->mContactPreferencesMap.end() )
1770 return it->second;
1771
1772 TDEABC::AddressBook *ab = TDEABC::StdAddressBook::self( true );
1773 const TDEABC::Addressee::List res = ab->findByEmail( address );
1774 ContactPreferences pref;
1775 if ( !res.isEmpty() ) {
1776 TDEABC::Addressee addr = res.first();
1777 TQString encryptPref = addr.custom( "KADDRESSBOOK", "CRYPTOENCRYPTPREF" );
1778 pref.encryptionPreference = Kleo::stringToEncryptionPreference( encryptPref );
1779 TQString signPref = addr.custom( "KADDRESSBOOK", "CRYPTOSIGNPREF" );
1780 pref.signingPreference = Kleo::stringToSigningPreference( signPref );
1781 TQString cryptoFormats = addr.custom( "KADDRESSBOOK", "CRYPTOPROTOPREF" );
1782 pref.cryptoMessageFormat = Kleo::stringToCryptoMessageFormat( cryptoFormats );
1783 pref.pgpKeyFingerprints = TQStringList::split( ',', addr.custom( "KADDRESSBOOK", "OPENPGPFP" ) );
1784 pref.smimeCertFingerprints = TQStringList::split( ',', addr.custom( "KADDRESSBOOK", "SMIMEFP" ) );
1785 }
1786 // insert into map and grab resulting iterator
1787 d->mContactPreferencesMap.insert( std::make_pair( address, pref ) );
1788 return pref;
1789}
1790
1791void Kleo::KeyResolver::saveContactPreference( const TQString& email, const ContactPreferences& pref ) const
1792{
1793 d->mContactPreferencesMap.insert( std::make_pair( email, pref ) );
1794 TDEABC::AddressBook *ab = TDEABC::StdAddressBook::self( true );
1795 TDEABC::Addressee::List res = ab->findByEmail( email );
1796
1797 TDEABC::Addressee addr;
1798 if ( res.isEmpty() ) {
1799 bool ok = true;
1800 TQString fullName = KInputDialog::getText( i18n( "Name Selection" ), i18n( "Which name shall the contact '%1' have in your addressbook?" ).arg( email ), TQString(), &ok );
1801 if ( ok ) {
1802 addr.setNameFromString( fullName );
1803 addr.insertEmail( email, true );
1804 } else
1805 return;
1806 } else
1807 addr = res.first();
1808
1809 addr.insertCustom( "KADDRESSBOOK", "CRYPTOENCRYPTPREF", Kleo::encryptionPreferenceToString( pref.encryptionPreference ) );
1810 addr.insertCustom( "KADDRESSBOOK", "CRYPTOSIGNPREF", Kleo::signingPreferenceToString( pref.signingPreference ) );
1811 addr.insertCustom( "KADDRESSBOOK", "CRYPTOPROTOPREF", cryptoMessageFormatToString( pref.cryptoMessageFormat ) );
1812 addr.insertCustom( "KADDRESSBOOK", "OPENPGPFP", pref.pgpKeyFingerprints.join( "," ) );
1813 addr.insertCustom( "KADDRESSBOOK", "SMIMEFP", pref.smimeCertFingerprints.join( "," ) );
1814
1815 ab->insertAddressee( addr );
1816 TDEABC::Ticket *ticket = ab->requestSaveTicket( addr.resource() );
1817 if ( ticket )
1818 ab->save( ticket );
1819
1820 // Assumption: 'pref' comes from d->mContactPreferencesMap already, no need to update that
1821}
1822
1823Kleo::KeyResolver::ContactPreferences::ContactPreferences()
1824 : encryptionPreference( UnknownPreference ),
1825 signingPreference( UnknownSigningPreference ),
1826 cryptoMessageFormat( AutoFormat )
1827{
1828}
1829
1830TQStringList Kleo::KeyResolver::keysForAddress( const TQString & address ) const {
1831 if( address.isEmpty() ) {
1832 return TQStringList();
1833 }
1834 TQString addr = canonicalAddress( address ).lower();
1835 const ContactPreferences pref = lookupContactPreferences( addr );
1836 return pref.pgpKeyFingerprints + pref.smimeCertFingerprints;
1837}
1838
1839void Kleo::KeyResolver::setKeysForAddress( const TQString& address, const TQStringList& pgpKeyFingerprints, const TQStringList& smimeCertFingerprints ) const {
1840 if( address.isEmpty() ) {
1841 return;
1842 }
1843 TQString addr = canonicalAddress( address ).lower();
1844 ContactPreferences pref = lookupContactPreferences( addr );
1845 pref.pgpKeyFingerprints = pgpKeyFingerprints;
1846 pref.smimeCertFingerprints = smimeCertFingerprints;
1847 saveContactPreference( addr, pref );
1848}
sets a cursor and makes sure it's restored on destruction Create a KCursorSaver object when you want ...
Definition: kcursorsaver.h:14
A class to resolve signing/encryption keys w.r.t.
Definition: keyresolver.h:127
std::vector< SplitInfo > encryptionItems(CryptoMessageFormat f) const
std::vector< GpgME::Key > signingKeys(CryptoMessageFormat f) const
void setSecondaryRecipients(const TQStringList &addresses)
Set the list of secondary (BCC) recipient addresses.
Action checkSigningPreferences(bool signingRequested) const
Determine whether to sign or not, depending on the per-recipient signing preferences,...
Kpgp::Result setEncryptToSelfKeys(const TQStringList &fingerprints)
Set the fingerprints of keys to be used for encrypting to self.
Action checkEncryptionPreferences(bool encryptionRequested) const
Determine whether to encrypt or not, depending on the per-recipient encryption preferences,...
Kpgp::Result setSigningKeys(const TQStringList &fingerprints)
Set the fingerprints of keys to be used for signing.
Kpgp::Result resolveAllKeys(bool &signingRequested, bool &encryptionRequested)
Queries the user for missing keys and displays a key approval dialog if needed.
void setPrimaryRecipients(const TQStringList &addresses)
Set the list of primary (To/CC) recipient addresses.