File indexing completed on 2024-06-16 04:55:58
0001 /* -*- mode: c++; c-basic-offset:4 -*- 0002 crypto/sender.cpp 0003 0004 This file is part of Kleopatra, the KDE keymanager 0005 SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include <config-kleopatra.h> 0011 0012 #include "sender.h" 0013 0014 #include <Libkleo/KeyCache> 0015 #include <Libkleo/Predicates> 0016 #include <Libkleo/Stl_Util> 0017 0018 #include <utils/cached.h> 0019 #include <utils/kleo_assert.h> 0020 0021 #include <KMime/Types> 0022 0023 #include <gpgme++/key.h> 0024 0025 #include <algorithm> 0026 0027 using namespace Kleo; 0028 using namespace Kleo::Crypto; 0029 using namespace KMime::Types; 0030 using namespace GpgME; 0031 0032 namespace KMime 0033 { 0034 namespace Types 0035 { 0036 static bool operator==(const AddrSpec &lhs, const AddrSpec &rhs) 0037 { 0038 return lhs.localPart == rhs.localPart && lhs.domain == rhs.domain; 0039 } 0040 0041 static bool operator==(const Mailbox &lhs, const Mailbox &rhs) 0042 { 0043 return lhs.name() == rhs.name() && lhs.addrSpec() == rhs.addrSpec(); 0044 } 0045 0046 static bool determine_ambiguous(const Mailbox &mb, const std::vector<Key> &keys) 0047 { 0048 Q_UNUSED(mb) 0049 // ### really do check when we don't only show matching keys 0050 return keys.size() != 1; 0051 } 0052 } // namespace Types 0053 } // namespace KMime 0054 0055 class Sender::Private 0056 { 0057 friend class ::Kleo::Crypto::Sender; 0058 0059 public: 0060 explicit Private(const Mailbox &mb) 0061 : mailbox(mb) 0062 { 0063 // ### also fill up to a certain number of keys with those 0064 // ### that don't match, for the case where there's a low 0065 // ### total number of keys 0066 const QString email = mb.addrSpec().asString(); 0067 const std::vector<Key> signers = KeyCache::instance()->findSigningKeysByMailbox(email); 0068 const std::vector<Key> encrypt = KeyCache::instance()->findEncryptionKeysByMailbox(email); 0069 kdtools::separate_if(signers.cbegin(), signers.cend(), std::back_inserter(pgpSigners), std::back_inserter(cmsSigners), [](const Key &key) { 0070 return key.protocol() == OpenPGP; 0071 }); 0072 kdtools::separate_if(encrypt.cbegin(), 0073 encrypt.cend(), 0074 std::back_inserter(pgpEncryptToSelfKeys), 0075 std::back_inserter(cmsEncryptToSelfKeys), 0076 [](const Key &key) { 0077 return key.protocol() == OpenPGP; 0078 }); 0079 } 0080 0081 private: 0082 const Mailbox mailbox; 0083 std::vector<Key> pgpSigners, cmsSigners, pgpEncryptToSelfKeys, cmsEncryptToSelfKeys; 0084 cached<bool> signingAmbiguous[2], encryptionAmbiguous[2]; 0085 Key signingKey[2], cmsEncryptionKey; 0086 UserID pgpEncryptionUid; 0087 }; 0088 0089 Sender::Sender(const Mailbox &mb) 0090 : d(new Private(mb)) 0091 { 0092 } 0093 0094 void Sender::detach() 0095 { 0096 if (d && !d.unique()) { 0097 d.reset(new Private(*d)); 0098 } 0099 } 0100 0101 bool Sender::deepEquals(const Sender &other) const 0102 { 0103 static const _detail::ByFingerprint<std::equal_to> compare = {}; 0104 return mailbox() == other.mailbox() // 0105 && compare(d->signingKey[CMS], other.d->signingKey[CMS]) // 0106 && compare(d->signingKey[OpenPGP], other.d->signingKey[OpenPGP]) // 0107 && compare(d->cmsEncryptionKey, other.d->cmsEncryptionKey) // 0108 && compare(d->pgpEncryptionUid.parent(), other.d->pgpEncryptionUid.parent()) && strcmp(d->pgpEncryptionUid.id(), other.d->pgpEncryptionUid.id()) == 0 0109 && std::equal(d->pgpSigners.cbegin(), d->pgpSigners.cend(), other.d->pgpSigners.cbegin(), compare) 0110 && std::equal(d->cmsSigners.cbegin(), d->cmsSigners.cend(), other.d->cmsSigners.cbegin(), compare) 0111 && std::equal(d->pgpEncryptToSelfKeys.cbegin(), d->pgpEncryptToSelfKeys.cend(), other.d->pgpEncryptToSelfKeys.cbegin(), compare) 0112 && std::equal(d->cmsEncryptToSelfKeys.cbegin(), d->cmsEncryptToSelfKeys.cend(), other.d->cmsEncryptToSelfKeys.cbegin(), compare); 0113 } 0114 0115 bool Sender::isSigningAmbiguous(GpgME::Protocol proto) const 0116 { 0117 if (d->signingAmbiguous[proto].dirty()) { 0118 d->signingAmbiguous[proto] = determine_ambiguous(d->mailbox, signingCertificateCandidates(proto)); 0119 } 0120 return d->signingAmbiguous[proto]; 0121 } 0122 0123 bool Sender::isEncryptionAmbiguous(GpgME::Protocol proto) const 0124 { 0125 if (d->encryptionAmbiguous[proto].dirty()) { 0126 d->encryptionAmbiguous[proto] = determine_ambiguous(d->mailbox, encryptToSelfCertificateCandidates(proto)); 0127 } 0128 return d->encryptionAmbiguous[proto]; 0129 } 0130 0131 const Mailbox &Sender::mailbox() const 0132 { 0133 return d->mailbox; 0134 } 0135 0136 const std::vector<Key> &Sender::signingCertificateCandidates(GpgME::Protocol proto) const 0137 { 0138 if (proto == OpenPGP) { 0139 return d->pgpSigners; 0140 } 0141 if (proto == CMS) { 0142 return d->cmsSigners; 0143 } 0144 kleo_assert_fail(proto == OpenPGP || proto == CMS); 0145 #if 0 0146 return 0147 proto == OpenPGP ? d->pgpSigners : 0148 proto == CMS ? d->cmsSigners : 0149 // even though gcc warns about this line, it's completely ok, promise: 0150 kleo_assert_fail(proto == OpenPGP || proto == CMS); 0151 #endif 0152 } 0153 0154 const std::vector<Key> &Sender::encryptToSelfCertificateCandidates(GpgME::Protocol proto) const 0155 { 0156 if (proto == OpenPGP) { 0157 return d->pgpEncryptToSelfKeys; 0158 } 0159 if (proto == CMS) { 0160 return d->cmsEncryptToSelfKeys; 0161 } 0162 kleo_assert_fail(proto == OpenPGP || proto == CMS); 0163 #if 0 0164 return 0165 proto == OpenPGP ? d->pgpEncryptToSelfKeys : 0166 proto == CMS ? d->cmsEncryptToSelfKeys : 0167 // even though gcc warns about this line, it's completely ok, promise: 0168 kleo_assert_fail(proto == OpenPGP || proto == CMS); 0169 #endif 0170 } 0171 0172 void Sender::setResolvedSigningKey(const Key &key) 0173 { 0174 if (key.isNull()) { 0175 return; 0176 } 0177 const Protocol proto = key.protocol(); 0178 kleo_assert(proto == OpenPGP || proto == CMS); 0179 detach(); 0180 d->signingKey[proto] = key; 0181 d->signingAmbiguous[proto] = false; 0182 } 0183 0184 Key Sender::resolvedSigningKey(GpgME::Protocol proto) const 0185 { 0186 kleo_assert(proto == OpenPGP || proto == CMS); 0187 return d->signingKey[proto]; 0188 } 0189 0190 void Sender::setResolvedEncryptionKey(const Key &key) 0191 { 0192 if (key.isNull()) { 0193 return; 0194 } 0195 const Protocol proto = key.protocol(); 0196 kleo_assert(proto == OpenPGP || proto == CMS); 0197 detach(); 0198 if (proto == OpenPGP) { 0199 d->pgpEncryptionUid = key.userID(0); 0200 } else { 0201 d->cmsEncryptionKey = key; 0202 } 0203 d->encryptionAmbiguous[proto] = false; 0204 } 0205 0206 Key Sender::resolvedEncryptionKey(GpgME::Protocol proto) const 0207 { 0208 kleo_assert(proto == OpenPGP || proto == CMS); 0209 if (proto == OpenPGP) { 0210 return d->pgpEncryptionUid.parent(); 0211 } else { 0212 return d->cmsEncryptionKey; 0213 } 0214 } 0215 0216 void Sender::setResolvedOpenPGPEncryptionUserID(const UserID &uid) 0217 { 0218 if (uid.isNull()) { 0219 return; 0220 } 0221 detach(); 0222 d->pgpEncryptionUid = uid; 0223 } 0224 0225 UserID Sender::resolvedOpenPGPEncryptionUserID() const 0226 { 0227 return d->pgpEncryptionUid; 0228 }