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 }