File indexing completed on 2024-06-23 05:13:58
0001 /* -*- mode: c++; c-basic-offset:4 -*- 0002 crypto/recipient.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 "recipient.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 using namespace Kleo; 0026 using namespace Kleo::Crypto; 0027 using namespace KMime::Types; 0028 using namespace GpgME; 0029 0030 namespace KMime 0031 { 0032 namespace Types 0033 { 0034 static bool operator==(const AddrSpec &lhs, const AddrSpec &rhs) 0035 { 0036 return lhs.localPart == rhs.localPart && lhs.domain == rhs.domain; 0037 } 0038 0039 static bool operator==(const Mailbox &lhs, const Mailbox &rhs) 0040 { 0041 return lhs.name() == rhs.name() && lhs.addrSpec() == rhs.addrSpec(); 0042 } 0043 0044 static bool determine_ambiguous(const Mailbox &mb, const std::vector<Key> &keys) 0045 { 0046 Q_UNUSED(mb) 0047 // ### really do check when we don't only show matching keys 0048 return keys.size() != 1; 0049 } 0050 0051 } // namespace Types 0052 } // namespace KMime 0053 0054 class Recipient::Private 0055 { 0056 friend class ::Kleo::Crypto::Recipient; 0057 0058 public: 0059 explicit Private(const Mailbox &mb) 0060 : mailbox(mb) 0061 { 0062 // ### also fill up to a certain number of keys with those 0063 // ### that don't match, for the case where there's a low 0064 // ### total number of keys 0065 const std::vector<Key> encrypt = KeyCache::instance()->findEncryptionKeysByMailbox(mb.addrSpec().asString()); 0066 kdtools::separate_if(encrypt.cbegin(), 0067 encrypt.cend(), 0068 std::back_inserter(pgpEncryptionKeys), 0069 std::back_inserter(cmsEncryptionKeys), 0070 [](const Key &key) { 0071 return key.protocol() == OpenPGP; 0072 }); 0073 } 0074 0075 private: 0076 const Mailbox mailbox; 0077 std::vector<Key> pgpEncryptionKeys, cmsEncryptionKeys; 0078 Key cmsEncryptionKey; 0079 UserID pgpEncryptionUid; 0080 cached<bool> encryptionAmbiguous[2]; 0081 }; 0082 0083 Recipient::Recipient(const Mailbox &mb) 0084 : d(new Private(mb)) 0085 { 0086 } 0087 0088 void Recipient::detach() 0089 { 0090 if (d && !d.unique()) { 0091 d.reset(new Private(*d)); 0092 } 0093 } 0094 0095 bool Recipient::deepEquals(const Recipient &other) const 0096 { 0097 static const _detail::ByFingerprint<std::equal_to> compare = {}; 0098 return mailbox() == other.mailbox() // 0099 && compare(d->cmsEncryptionKey, other.d->cmsEncryptionKey) // 0100 && compare(d->pgpEncryptionUid.parent(), other.d->pgpEncryptionUid.parent()) // 0101 && strcmp(d->pgpEncryptionUid.id(), other.d->pgpEncryptionUid.id()) // 0102 && std::equal(d->pgpEncryptionKeys.cbegin(), d->pgpEncryptionKeys.cend(), other.d->pgpEncryptionKeys.cbegin(), compare) 0103 && std::equal(d->cmsEncryptionKeys.cbegin(), d->pgpEncryptionKeys.cend(), other.d->cmsEncryptionKeys.cbegin(), compare); 0104 } 0105 0106 bool Recipient::isEncryptionAmbiguous(GpgME::Protocol proto) const 0107 { 0108 if (d->encryptionAmbiguous[proto].dirty()) { 0109 d->encryptionAmbiguous[proto] = determine_ambiguous(d->mailbox, encryptionCertificateCandidates(proto)); 0110 } 0111 return d->encryptionAmbiguous[proto]; 0112 } 0113 0114 const Mailbox &Recipient::mailbox() const 0115 { 0116 return d->mailbox; 0117 } 0118 0119 const std::vector<Key> &Recipient::encryptionCertificateCandidates(GpgME::Protocol proto) const 0120 { 0121 if (proto == OpenPGP) { 0122 return d->pgpEncryptionKeys; 0123 } 0124 if (proto == CMS) { 0125 return d->cmsEncryptionKeys; 0126 } 0127 kleo_assert_fail(proto == OpenPGP || proto == CMS); 0128 #if 0 0129 return 0130 proto == OpenPGP ? d->pgpEncryptionKeys : 0131 proto == CMS ? d->cmsEncryptionKeys : 0132 // even though gcc warns about this line, it's completely ok, promise: 0133 kleo_assert_fail(proto == OpenPGP || proto == CMS); 0134 #endif 0135 } 0136 0137 void Recipient::setResolvedEncryptionKey(const Key &key) 0138 { 0139 if (key.isNull()) { 0140 return; 0141 } 0142 const Protocol proto = key.protocol(); 0143 kleo_assert(proto == OpenPGP || proto == CMS); 0144 detach(); 0145 if (proto == OpenPGP) { 0146 d->pgpEncryptionUid = key.userID(0); 0147 } else { 0148 d->cmsEncryptionKey = key; 0149 } 0150 d->encryptionAmbiguous[proto] = false; 0151 } 0152 0153 Key Recipient::resolvedEncryptionKey(GpgME::Protocol proto) const 0154 { 0155 kleo_assert(proto == OpenPGP || proto == CMS); 0156 if (proto == OpenPGP) { 0157 return d->pgpEncryptionUid.parent(); 0158 } else { 0159 return d->cmsEncryptionKey; 0160 } 0161 } 0162 0163 void Recipient::setResolvedOpenPGPEncryptionUserID(const UserID &uid) 0164 { 0165 if (uid.isNull()) { 0166 return; 0167 } 0168 detach(); 0169 d->pgpEncryptionUid = uid; 0170 } 0171 0172 UserID Recipient::resolvedOpenPGPEncryptionUserID() const 0173 { 0174 return d->pgpEncryptionUid; 0175 }