File indexing completed on 2024-11-17 04:50:26
0001 /* 0002 kleo/enum.cpp 0003 0004 This file is part of libkleopatra, the KDE keymanagement library 0005 SPDX-FileCopyrightText: 2004 Klarälvdalens Datakonsult AB 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include <config-libkleo.h> 0011 0012 #include "enum.h" 0013 0014 #include <libkleo/keycache.h> 0015 0016 #include <libkleo_debug.h> 0017 0018 #include <KLazyLocalizedString> 0019 #include <KLocalizedString> 0020 0021 #include <QEventLoop> 0022 #include <QString> 0023 0024 #include <gpgme++/key.h> 0025 #include <gpgme++/tofuinfo.h> 0026 0027 #include <functional> 0028 0029 static const struct { 0030 Kleo::CryptoMessageFormat format; 0031 const KLazyLocalizedString displayName; 0032 const char *configName; 0033 } cryptoMessageFormats[] = { 0034 // clang-format off 0035 {Kleo::InlineOpenPGPFormat, kli18n("Inline OpenPGP (deprecated)"), "inline openpgp"}, 0036 {Kleo::OpenPGPMIMEFormat, kli18n("OpenPGP/MIME"), "openpgp/mime" }, 0037 {Kleo::SMIMEFormat, kli18n("S/MIME"), "s/mime" }, 0038 {Kleo::SMIMEOpaqueFormat, kli18n("S/MIME Opaque"), "s/mime opaque" }, 0039 {Kleo::AnySMIME, kli18n("Any S/MIME"), "any s/mime" }, 0040 {Kleo::AnyOpenPGP, kli18n("Any OpenPGP"), "any openpgp" }, 0041 // clang-format on 0042 }; 0043 static const unsigned int numCryptoMessageFormats = sizeof cryptoMessageFormats / sizeof *cryptoMessageFormats; 0044 0045 const char *Kleo::cryptoMessageFormatToString(Kleo::CryptoMessageFormat f) 0046 { 0047 if (f == AutoFormat) { 0048 return "auto"; 0049 } 0050 for (unsigned int i = 0; i < numCryptoMessageFormats; ++i) { 0051 if (f == cryptoMessageFormats[i].format) { 0052 return cryptoMessageFormats[i].configName; 0053 } 0054 } 0055 return nullptr; 0056 } 0057 0058 QStringList Kleo::cryptoMessageFormatsToStringList(unsigned int f) 0059 { 0060 QStringList result; 0061 for (unsigned int i = 0; i < numCryptoMessageFormats; ++i) { 0062 if (f & cryptoMessageFormats[i].format) { 0063 result.push_back(QLatin1StringView(cryptoMessageFormats[i].configName)); 0064 } 0065 } 0066 return result; 0067 } 0068 0069 QString Kleo::cryptoMessageFormatToLabel(Kleo::CryptoMessageFormat f) 0070 { 0071 if (f == AutoFormat) { 0072 return i18n("Any"); 0073 } 0074 for (unsigned int i = 0; i < numCryptoMessageFormats; ++i) { 0075 if (f == cryptoMessageFormats[i].format) { 0076 return KLocalizedString(cryptoMessageFormats[i].displayName).toString(); 0077 } 0078 } 0079 return QString(); 0080 } 0081 0082 Kleo::CryptoMessageFormat Kleo::stringToCryptoMessageFormat(const QString &s) 0083 { 0084 const QString t = s.toLower(); 0085 for (unsigned int i = 0; i < numCryptoMessageFormats; ++i) { 0086 if (t == QLatin1StringView(cryptoMessageFormats[i].configName)) { 0087 return cryptoMessageFormats[i].format; 0088 } 0089 } 0090 return AutoFormat; 0091 } 0092 0093 unsigned int Kleo::stringListToCryptoMessageFormats(const QStringList &sl) 0094 { 0095 unsigned int result = 0; 0096 for (QStringList::const_iterator it = sl.begin(); it != sl.end(); ++it) { 0097 result |= stringToCryptoMessageFormat(*it); 0098 } 0099 return result; 0100 } 0101 0102 // For the config values used below, see also kaddressbook/editors/cryptowidget.cpp 0103 0104 const char *Kleo::encryptionPreferenceToString(EncryptionPreference pref) 0105 { 0106 switch (pref) { 0107 case UnknownPreference: 0108 return nullptr; 0109 case NeverEncrypt: 0110 return "never"; 0111 case AlwaysEncrypt: 0112 return "always"; 0113 case AlwaysEncryptIfPossible: 0114 return "alwaysIfPossible"; 0115 case AlwaysAskForEncryption: 0116 return "askAlways"; 0117 case AskWheneverPossible: 0118 return "askWhenPossible"; 0119 } 0120 return nullptr; // keep the compiler happy 0121 } 0122 0123 Kleo::EncryptionPreference Kleo::stringToEncryptionPreference(const QString &str) 0124 { 0125 if (str == QLatin1StringView("never")) { 0126 return NeverEncrypt; 0127 } 0128 if (str == QLatin1StringView("always")) { 0129 return AlwaysEncrypt; 0130 } 0131 if (str == QLatin1StringView("alwaysIfPossible")) { 0132 return AlwaysEncryptIfPossible; 0133 } 0134 if (str == QLatin1StringView("askAlways")) { 0135 return AlwaysAskForEncryption; 0136 } 0137 if (str == QLatin1StringView("askWhenPossible")) { 0138 return AskWheneverPossible; 0139 } 0140 return UnknownPreference; 0141 } 0142 0143 QString Kleo::encryptionPreferenceToLabel(EncryptionPreference pref) 0144 { 0145 switch (pref) { 0146 case NeverEncrypt: 0147 return i18n("Never Encrypt"); 0148 case AlwaysEncrypt: 0149 return i18n("Always Encrypt"); 0150 case AlwaysEncryptIfPossible: 0151 return i18n("Always Encrypt If Possible"); 0152 case AlwaysAskForEncryption: 0153 return i18n("Ask"); 0154 case AskWheneverPossible: 0155 return i18n("Ask Whenever Possible"); 0156 default: 0157 return xi18nc("no specific preference", "<placeholder>none</placeholder>"); 0158 } 0159 } 0160 0161 const char *Kleo::signingPreferenceToString(SigningPreference pref) 0162 { 0163 switch (pref) { 0164 case UnknownSigningPreference: 0165 return nullptr; 0166 case NeverSign: 0167 return "never"; 0168 case AlwaysSign: 0169 return "always"; 0170 case AlwaysSignIfPossible: 0171 return "alwaysIfPossible"; 0172 case AlwaysAskForSigning: 0173 return "askAlways"; 0174 case AskSigningWheneverPossible: 0175 return "askWhenPossible"; 0176 } 0177 return nullptr; // keep the compiler happy 0178 } 0179 0180 Kleo::SigningPreference Kleo::stringToSigningPreference(const QString &str) 0181 { 0182 if (str == QLatin1StringView("never")) { 0183 return NeverSign; 0184 } 0185 if (str == QLatin1StringView("always")) { 0186 return AlwaysSign; 0187 } 0188 if (str == QLatin1StringView("alwaysIfPossible")) { 0189 return AlwaysSignIfPossible; 0190 } 0191 if (str == QLatin1StringView("askAlways")) { 0192 return AlwaysAskForSigning; 0193 } 0194 if (str == QLatin1StringView("askWhenPossible")) { 0195 return AskSigningWheneverPossible; 0196 } 0197 return UnknownSigningPreference; 0198 } 0199 0200 QString Kleo::signingPreferenceToLabel(SigningPreference pref) 0201 { 0202 switch (pref) { 0203 case NeverSign: 0204 return i18n("Never Sign"); 0205 case AlwaysSign: 0206 return i18n("Always Sign"); 0207 case AlwaysSignIfPossible: 0208 return i18n("Always Sign If Possible"); 0209 case AlwaysAskForSigning: 0210 return i18n("Ask"); 0211 case AskSigningWheneverPossible: 0212 return i18n("Ask Whenever Possible"); 0213 default: 0214 return i18nc("no specific preference", "<none>"); 0215 } 0216 } 0217 0218 Kleo::TrustLevel Kleo::trustLevel(const GpgME::Key &key) 0219 { 0220 TrustLevel maxTl = Level0; 0221 for (int i = 0, c = key.numUserIDs(); i < c; ++i) { 0222 const auto tl = trustLevel(key.userID(i)); 0223 maxTl = qMax(maxTl, tl); 0224 if (maxTl == Level4) { 0225 break; 0226 } 0227 } 0228 0229 return maxTl; 0230 } 0231 0232 namespace 0233 { 0234 0235 bool hasTrustedSignature(const GpgME::UserID &uid) 0236 { 0237 // lazily initialized cache 0238 static std::shared_ptr<const Kleo::KeyCache> keyCache; 0239 if (!keyCache) { 0240 keyCache = Kleo::KeyCache::instance(); 0241 } 0242 0243 const auto signatures = uid.signatures(); 0244 std::vector<std::string> sigKeyIDs; 0245 std::transform(signatures.cbegin(), 0246 signatures.cend(), 0247 std::back_inserter(sigKeyIDs), 0248 std::bind(&GpgME::UserID::Signature::signerKeyID, std::placeholders::_1)); 0249 0250 const auto keys = keyCache->findByKeyIDOrFingerprint(sigKeyIDs); 0251 return std::any_of(keys.cbegin(), keys.cend(), [](const GpgME::Key &key) { 0252 return key.ownerTrust() == GpgME::Key::Ultimate; 0253 }); 0254 } 0255 0256 } 0257 0258 Kleo::TrustLevel Kleo::trustLevel(const GpgME::UserID &uid) 0259 { 0260 // Modelled after https://wiki.gnupg.org/EasyGpg2016/AutomatedEncryption, 0261 // but modified to cover all cases, unlike the pseudocode in the document. 0262 // 0263 // TODO: Check whether the key comes from a trusted source (Cert/PKA/DANE/WKD) 0264 0265 switch (uid.validity()) { 0266 case GpgME::UserID::Unknown: 0267 case GpgME::UserID::Undefined: 0268 case GpgME::UserID::Never: 0269 // Not enough trust -> level 0 0270 return Level0; 0271 0272 case GpgME::UserID::Marginal: 0273 // Marginal trust without TOFU data means the key is still trusted 0274 // through the Web of Trust -> level 2 0275 if (uid.tofuInfo().isNull()) { 0276 return Level2; 0277 } 0278 // Marginal trust with TOFU, level will depend on TOFU history 0279 switch (uid.tofuInfo().validity()) { 0280 case GpgME::TofuInfo::ValidityUnknown: 0281 case GpgME::TofuInfo::Conflict: 0282 case GpgME::TofuInfo::NoHistory: 0283 // Marginal trust, but not enough history -> level 0 0284 return Level0; 0285 case GpgME::TofuInfo::LittleHistory: 0286 // Marginal trust, but too little history -> level 1 0287 return Level1; 0288 case GpgME::TofuInfo::BasicHistory: 0289 case GpgME::TofuInfo::LargeHistory: 0290 // Marginal trust and enough history -> level 2 0291 return Level2; 0292 } 0293 return Level2; // Not reached, but avoids fallthrough warnings 0294 case GpgME::UserID::Full: 0295 // Full trust, trust level depends whether the UserID is signed with 0296 // at least one key with Ultimate ownertrust. 0297 return hasTrustedSignature(uid) ? Level4 : Level3; 0298 0299 case GpgME::UserID::Ultimate: 0300 // Ultimate trust -> leve 4 0301 return Level4; 0302 } 0303 0304 Q_UNREACHABLE(); 0305 }