File indexing completed on 2024-05-12 05:22:35

0001 /*
0002     autotests/keyresolvercoretest.cpp
0003 
0004     This file is part of libkleopatra's test suite.
0005     SPDX-FileCopyrightText: 2021 g10 Code GmbH
0006     SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include <Libkleo/Formatting>
0012 #include <Libkleo/KeyCache>
0013 #include <Libkleo/KeyGroup>
0014 #include <Libkleo/KeyResolverCore>
0015 #include <Libkleo/Test>
0016 
0017 #include <QObject>
0018 #include <QProcess>
0019 #include <QTest>
0020 
0021 #include <gpgme++/key.h>
0022 
0023 #include <memory>
0024 
0025 using namespace Kleo;
0026 using namespace GpgME;
0027 
0028 namespace QTest
0029 {
0030 template<>
0031 inline bool qCompare(GpgME::UserID::Validity const &t1, GpgME::UserID::Validity const &t2, const char *actual, const char *expected, const char *file, int line)
0032 {
0033     return qCompare(int(t1), int(t2), actual, expected, file, line);
0034 }
0035 
0036 template<>
0037 inline char *toString(const KeyResolverCore::SolutionFlags &flags)
0038 {
0039     QStringList v;
0040     if (flags & KeyResolverCore::AllResolved) {
0041         v.append(QStringLiteral("KeyResolverCore::AllResolved"));
0042     } else {
0043         v.append(QStringLiteral("KeyResolverCore::SomeUnresolved"));
0044     }
0045     if ((flags & KeyResolverCore::MixedProtocols) == KeyResolverCore::MixedProtocols) {
0046         v.append(QStringLiteral("KeyResolverCore::MixedProtocols"));
0047     } else if (flags & KeyResolverCore::OpenPGPOnly) {
0048         v.append(QStringLiteral("KeyResolverCore::OpenPGPOnly"));
0049     } else if (flags & KeyResolverCore::CMSOnly) {
0050         v.append(QStringLiteral("KeyResolverCore::CMSOnly"));
0051     }
0052     return qstrdup(v.join(QStringLiteral(" | ")).toLocal8Bit().constData());
0053 }
0054 
0055 template<>
0056 inline bool qCompare(int const &t1, KeyResolverCore::SolutionFlags const &t2, const char *actual, const char *expected, const char *file, int line)
0057 {
0058     return qCompare(static_cast<KeyResolverCore::SolutionFlags>(t1), t2, actual, expected, file, line);
0059 }
0060 
0061 template<>
0062 inline char *toString(const GpgME::Protocol &t)
0063 {
0064     return qstrdup(Formatting::displayName(t).toLocal8Bit().constData());
0065 }
0066 
0067 template<>
0068 inline bool qCompare(GpgME::Protocol const &t1, GpgME::Protocol const &t2, const char *actual, const char *expected, const char *file, int line)
0069 {
0070     return compare_helper(t1 == t2, "Compared values are not the same", toString(t1), toString(t2), actual, expected, file, line);
0071 }
0072 }
0073 
0074 namespace
0075 {
0076 KeyGroup createGroup(const QString &name,
0077                      const std::vector<Key> &keys = std::vector<Key>(),
0078                      KeyGroup::Source source = KeyGroup::ApplicationConfig,
0079                      const QString &configName = QString())
0080 {
0081     const KeyGroup::Id groupId = ((source == KeyGroup::ApplicationConfig) //
0082                                       ? (configName.isEmpty() ? name : configName)
0083                                       : name);
0084     KeyGroup g(groupId, name, keys, source);
0085     return g;
0086 }
0087 }
0088 
0089 class KeyResolverCoreTest : public QObject
0090 {
0091     Q_OBJECT
0092 private Q_SLOTS:
0093     void init()
0094     {
0095         mGnupgHome = QTest::qExtractTestData(QStringLiteral("/fixtures/keyresolvercoretest"));
0096         qputenv("GNUPGHOME", mGnupgHome->path().toLocal8Bit());
0097 
0098         // hold a reference to the key cache to avoid rebuilding while the test is running
0099         mKeyCache = KeyCache::instance();
0100         // make sure that the key cache has been populated
0101         (void)mKeyCache->keys();
0102     }
0103 
0104     void cleanup()
0105     {
0106         // verify that nobody else holds a reference to the key cache
0107         QVERIFY(mKeyCache.use_count() == 1);
0108         mKeyCache.reset();
0109 
0110         // kill all running gpg daemons
0111         (void)QProcess::execute(QStringLiteral("gpgconf"), {"--kill", "all"});
0112 
0113         mGnupgHome.reset();
0114         qunsetenv("GNUPGHOME");
0115     }
0116 
0117     void test_verify_test_keys()
0118     {
0119         {
0120             const Key openpgp = testKey("sender-mixed@example.net", OpenPGP);
0121             QVERIFY(openpgp.hasSecret() && openpgp.canEncrypt() && openpgp.canSign());
0122             QCOMPARE(openpgp.userID(0).validity(), UserID::Ultimate);
0123             const Key smime = testKey("sender-mixed@example.net", CMS);
0124             QVERIFY(smime.hasSecret() && smime.canEncrypt() && smime.canSign());
0125             QCOMPARE(smime.userID(0).validity(), UserID::Full);
0126         }
0127         {
0128             const Key openpgp = testKey("sender-openpgp@example.net", OpenPGP);
0129             QVERIFY(openpgp.hasSecret() && openpgp.canEncrypt() && openpgp.canSign());
0130             QCOMPARE(openpgp.userID(0).validity(), UserID::Ultimate);
0131         }
0132         {
0133             const Key smime = testKey("sender-smime@example.net", CMS);
0134             QVERIFY(smime.hasSecret() && smime.canEncrypt() && smime.canSign());
0135             QCOMPARE(smime.userID(0).validity(), UserID::Full);
0136         }
0137         {
0138             const Key openpgp = testKey("prefer-openpgp@example.net", OpenPGP);
0139             QVERIFY(openpgp.canEncrypt());
0140             QCOMPARE(openpgp.userID(0).validity(), UserID::Ultimate);
0141             const Key smime = testKey("prefer-openpgp@example.net", CMS);
0142             QVERIFY(smime.canEncrypt());
0143             QCOMPARE(smime.userID(0).validity(), UserID::Full);
0144         }
0145         {
0146             const Key openpgp = testKey("full-validity@example.net", OpenPGP);
0147             QVERIFY(openpgp.canEncrypt());
0148             QCOMPARE(openpgp.userID(0).validity(), UserID::Full);
0149             const Key smime = testKey("full-validity@example.net", CMS);
0150             QVERIFY(smime.canEncrypt());
0151             QCOMPARE(smime.userID(0).validity(), UserID::Full);
0152         }
0153         {
0154             const Key openpgp = testKey("prefer-smime@example.net", OpenPGP);
0155             QVERIFY(openpgp.canEncrypt());
0156             QCOMPARE(openpgp.userID(0).validity(), UserID::Marginal);
0157             const Key smime = testKey("prefer-smime@example.net", CMS);
0158             QVERIFY(smime.canEncrypt());
0159             QCOMPARE(smime.userID(0).validity(), UserID::Full);
0160         }
0161         {
0162             const Key openpgp = testKey("openpgp-only@example.net", OpenPGP);
0163             QVERIFY(openpgp.canEncrypt());
0164             QCOMPARE(openpgp.userID(0).validity(), UserID::Full);
0165             const Key smime = testKey("openpgp-only@example.net", CMS);
0166             QVERIFY(smime.isNull());
0167         }
0168         {
0169             const Key openpgp = testKey("smime-only@example.net", OpenPGP);
0170             QVERIFY(openpgp.isNull());
0171             const Key smime = testKey("smime-only@example.net", CMS);
0172             QVERIFY(smime.canEncrypt());
0173             QCOMPARE(smime.userID(0).validity(), UserID::Full);
0174         }
0175     }
0176 
0177     void test_openpgp_is_used_if_openpgp_only_and_smime_only_are_both_possible()
0178     {
0179         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/true);
0180         resolver.setAllowMixedProtocols(false);
0181         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
0182 
0183         const auto result = resolver.resolve();
0184 
0185         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0186         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
0187         QCOMPARE(result.solution.protocol, OpenPGP);
0188         QCOMPARE(result.solution.signingKeys.size(), 1);
0189         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
0190         QCOMPARE(result.solution.encryptionKeys.size(), 1);
0191         QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net").size(), 1);
0192         QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
0193                  testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
0194         QCOMPARE(result.alternative.protocol, CMS);
0195         QCOMPARE(result.alternative.signingKeys.size(), 1);
0196         QCOMPARE(result.alternative.signingKeys[0].primaryFingerprint(), testKey("sender-mixed@example.net", CMS).primaryFingerprint());
0197         QCOMPARE(result.alternative.encryptionKeys.size(), 1);
0198         QCOMPARE(result.alternative.encryptionKeys.value("sender-mixed@example.net").size(), 1);
0199         QCOMPARE(result.alternative.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
0200                  testKey("sender-mixed@example.net", CMS).primaryFingerprint());
0201     }
0202 
0203     void test_openpgp_is_used_if_openpgp_only_and_smime_only_are_both_possible_with_preference_for_openpgp()
0204     {
0205         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/true);
0206         resolver.setAllowMixedProtocols(false);
0207         resolver.setPreferredProtocol(OpenPGP);
0208         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
0209 
0210         const auto result = resolver.resolve();
0211 
0212         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0213         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
0214         QCOMPARE(result.solution.protocol, OpenPGP);
0215         QCOMPARE(result.solution.signingKeys.size(), 1);
0216         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
0217         QCOMPARE(result.solution.encryptionKeys.size(), 1);
0218         QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net").size(), 1);
0219         QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
0220                  testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
0221         QCOMPARE(result.alternative.protocol, CMS);
0222         QCOMPARE(result.alternative.signingKeys.size(), 1);
0223         QCOMPARE(result.alternative.signingKeys[0].primaryFingerprint(), testKey("sender-mixed@example.net", CMS).primaryFingerprint());
0224         QCOMPARE(result.alternative.encryptionKeys.size(), 1);
0225         QCOMPARE(result.alternative.encryptionKeys.value("sender-mixed@example.net").size(), 1);
0226         QCOMPARE(result.alternative.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
0227                  testKey("sender-mixed@example.net", CMS).primaryFingerprint());
0228     }
0229 
0230     void test_smime_is_used_if_openpgp_only_and_smime_only_are_both_possible_with_preference_for_smime()
0231     {
0232         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/true);
0233         resolver.setAllowMixedProtocols(false);
0234         resolver.setPreferredProtocol(CMS);
0235         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
0236 
0237         const auto result = resolver.resolve();
0238 
0239         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0240         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
0241         QCOMPARE(result.solution.protocol, CMS);
0242         QCOMPARE(result.solution.signingKeys.size(), 1);
0243         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-mixed@example.net", CMS).primaryFingerprint());
0244         QCOMPARE(result.solution.encryptionKeys.size(), 1);
0245         QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net").size(), 1);
0246         QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
0247                  testKey("sender-mixed@example.net", CMS).primaryFingerprint());
0248         QCOMPARE(result.alternative.protocol, OpenPGP);
0249         QCOMPARE(result.alternative.signingKeys.size(), 1);
0250         QCOMPARE(result.alternative.signingKeys[0].primaryFingerprint(), testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
0251         QCOMPARE(result.alternative.encryptionKeys.size(), 1);
0252         QCOMPARE(result.alternative.encryptionKeys.value("sender-mixed@example.net").size(), 1);
0253         QCOMPARE(result.alternative.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
0254                  testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
0255     }
0256 
0257     void test_in_mixed_mode_openpgp_is_used_if_openpgp_only_and_smime_only_are_both_possible()
0258     {
0259         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/true);
0260         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
0261 
0262         const auto result = resolver.resolve();
0263 
0264         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0265         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
0266         QCOMPARE(result.solution.protocol, OpenPGP);
0267         QCOMPARE(result.solution.signingKeys.size(), 1);
0268         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
0269         QCOMPARE(result.solution.encryptionKeys.size(), 1);
0270         QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net").size(), 1);
0271         QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
0272                  testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
0273         // no alternative solution is proposed
0274         QCOMPARE(result.alternative.protocol, UnknownProtocol);
0275         QCOMPARE(result.alternative.encryptionKeys.size(), 0);
0276     }
0277 
0278     void test_in_mixed_mode_openpgp_is_used_if_openpgp_only_and_smime_only_are_both_possible_with_preference_for_openpgp()
0279     {
0280         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/true);
0281         resolver.setPreferredProtocol(OpenPGP);
0282         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
0283 
0284         const auto result = resolver.resolve();
0285 
0286         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0287         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
0288         QCOMPARE(result.solution.protocol, OpenPGP);
0289         QCOMPARE(result.solution.signingKeys.size(), 1);
0290         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
0291         QCOMPARE(result.solution.encryptionKeys.size(), 1);
0292         QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net").size(), 1);
0293         QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
0294                  testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
0295         // no alternative solution is proposed
0296         QCOMPARE(result.alternative.protocol, UnknownProtocol);
0297         QCOMPARE(result.alternative.encryptionKeys.size(), 0);
0298     }
0299 
0300     void test_in_mixed_mode_smime_is_used_if_openpgp_only_and_smime_only_are_both_possible_with_preference_for_smime()
0301     {
0302         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/true);
0303         resolver.setPreferredProtocol(CMS);
0304         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
0305 
0306         const auto result = resolver.resolve();
0307 
0308         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0309         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
0310         QCOMPARE(result.solution.protocol, CMS);
0311         QCOMPARE(result.solution.signingKeys.size(), 1);
0312         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-mixed@example.net", CMS).primaryFingerprint());
0313         QCOMPARE(result.solution.encryptionKeys.size(), 1);
0314         QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net").size(), 1);
0315         QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
0316                  testKey("sender-mixed@example.net", CMS).primaryFingerprint());
0317         // no alternative solution is proposed
0318         QCOMPARE(result.alternative.protocol, UnknownProtocol);
0319         QCOMPARE(result.alternative.encryptionKeys.size(), 0);
0320     }
0321 
0322     void test_in_mixed_mode_keys_with_higher_validity_are_preferred_if_both_protocols_are_needed()
0323     {
0324         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/false);
0325         resolver.setRecipients({"sender-openpgp@example.net", "sender-smime@example.net", "prefer-openpgp@example.net", "prefer-smime@example.net"});
0326 
0327         const auto result = resolver.resolve();
0328 
0329         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0330         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::MixedProtocols);
0331         QCOMPARE(result.solution.protocol, UnknownProtocol);
0332         QCOMPARE(result.solution.encryptionKeys.size(), 4);
0333         QVERIFY(result.solution.encryptionKeys.contains("sender-openpgp@example.net"));
0334         QVERIFY(result.solution.encryptionKeys.contains("sender-smime@example.net"));
0335         QCOMPARE(result.solution.encryptionKeys.value("prefer-openpgp@example.net").size(), 1);
0336         QCOMPARE(result.solution.encryptionKeys.value("prefer-openpgp@example.net")[0].primaryFingerprint(),
0337                  testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint());
0338         QCOMPARE(result.solution.encryptionKeys.value("prefer-smime@example.net").size(), 1);
0339         QCOMPARE(result.solution.encryptionKeys.value("prefer-smime@example.net")[0].primaryFingerprint(),
0340                  testKey("prefer-smime@example.net", CMS).primaryFingerprint());
0341         // no alternative solution is proposed
0342         QCOMPARE(result.alternative.protocol, UnknownProtocol);
0343         QCOMPARE(result.alternative.encryptionKeys.size(), 0);
0344     }
0345 
0346     void test_reports_unresolved_addresses_if_both_protocols_are_allowed_but_no_keys_are_found_for_an_address()
0347     {
0348         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/false);
0349         resolver.setRecipients({"unknown@example.net"});
0350 
0351         const auto result = resolver.resolve();
0352 
0353         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::SomeUnresolved);
0354         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
0355         QCOMPARE(result.solution.protocol, OpenPGP);
0356         QCOMPARE(result.solution.encryptionKeys.value("unknown@example.net").size(), 0);
0357     }
0358 
0359     void test_reports_unresolved_addresses_if_openpgp_is_requested_and_no_openpgp_keys_are_found_for_an_address()
0360     {
0361         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/false, OpenPGP);
0362         resolver.setRecipients({"sender-openpgp@example.net", "sender-smime@example.net"});
0363 
0364         const auto result = resolver.resolve();
0365 
0366         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::SomeUnresolved);
0367         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
0368         QCOMPARE(result.solution.protocol, OpenPGP);
0369         QCOMPARE(result.solution.encryptionKeys.size(), 2);
0370         QCOMPARE(result.solution.encryptionKeys.value("sender-openpgp@example.net").size(), 1);
0371         QCOMPARE(result.solution.encryptionKeys.value("sender-smime@example.net").size(), 0);
0372         QCOMPARE(result.alternative.encryptionKeys.size(), 0);
0373     }
0374 
0375     void test_reports_unresolved_addresses_if_smime_is_requested_and_no_smime_keys_are_found_for_an_address()
0376     {
0377         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/false, CMS);
0378         resolver.setRecipients({"sender-openpgp@example.net", "sender-smime@example.net"});
0379 
0380         const auto result = resolver.resolve();
0381 
0382         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::SomeUnresolved);
0383         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
0384         QCOMPARE(result.solution.protocol, CMS);
0385         QCOMPARE(result.solution.encryptionKeys.size(), 2);
0386         QCOMPARE(result.solution.encryptionKeys.value("sender-openpgp@example.net").size(), 0);
0387         QCOMPARE(result.solution.encryptionKeys.value("sender-smime@example.net").size(), 1);
0388         QCOMPARE(result.alternative.encryptionKeys.size(), 0);
0389     }
0390 
0391     void test_reports_unresolved_addresses_if_mixed_protocols_are_not_allowed_but_needed()
0392     {
0393         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/false);
0394         resolver.setAllowMixedProtocols(false);
0395         resolver.setRecipients({"sender-openpgp@example.net", "sender-smime@example.net"});
0396 
0397         const auto result = resolver.resolve();
0398 
0399         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::SomeUnresolved);
0400         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
0401         QCOMPARE(result.solution.protocol, OpenPGP);
0402         QCOMPARE(result.solution.encryptionKeys.size(), 2);
0403         QCOMPARE(result.solution.encryptionKeys.value("sender-openpgp@example.net").size(), 1);
0404         QCOMPARE(result.solution.encryptionKeys.value("sender-smime@example.net").size(), 0);
0405         QCOMPARE(result.alternative.encryptionKeys.size(), 2);
0406         QCOMPARE(result.alternative.encryptionKeys.value("sender-openpgp@example.net").size(), 0);
0407         QCOMPARE(result.alternative.encryptionKeys.value("sender-smime@example.net").size(), 1);
0408     }
0409 
0410     void test_openpgp_overrides_are_used_if_both_protocols_are_allowed()
0411     {
0412         const QString override = testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint();
0413         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/true);
0414         resolver.setAllowMixedProtocols(false);
0415         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
0416         resolver.setRecipients({"full-validity@example.net"});
0417         resolver.setOverrideKeys({{OpenPGP, {{QStringLiteral("Needs to be normalized <full-validity@example.net>"), {override}}}}});
0418 
0419         const auto result = resolver.resolve();
0420 
0421         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0422         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
0423         QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net").size(), 1);
0424         QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net")[0].primaryFingerprint(), override);
0425         QCOMPARE(result.alternative.encryptionKeys.value("full-validity@example.net").size(), 1);
0426         QCOMPARE(result.alternative.encryptionKeys.value("full-validity@example.net")[0].primaryFingerprint(),
0427                  testKey("full-validity@example.net", CMS).primaryFingerprint());
0428     }
0429 
0430     void test_openpgp_overrides_are_used_if_openpgp_only_is_requested()
0431     {
0432         const QString override = testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint();
0433         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/true, OpenPGP);
0434         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
0435         resolver.setRecipients({"full-validity@example.net"});
0436         resolver.setOverrideKeys({{OpenPGP, {{QStringLiteral("Needs to be normalized <full-validity@example.net>"), {override}}}}});
0437 
0438         const auto result = resolver.resolve();
0439 
0440         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0441         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
0442         QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net").size(), 1);
0443         QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net")[0].primaryFingerprint(), override);
0444         QCOMPARE(result.alternative.encryptionKeys.size(), 0);
0445     }
0446 
0447     void test_openpgp_overrides_are_ignored_if_smime_only_is_requested()
0448     {
0449         const QString override = testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint();
0450         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/true, CMS);
0451         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
0452         resolver.setRecipients({"full-validity@example.net"});
0453         resolver.setOverrideKeys({{OpenPGP, {{QStringLiteral("Needs to be normalized <full-validity@example.net>"), {override}}}}});
0454 
0455         const auto result = resolver.resolve();
0456 
0457         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0458         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
0459         QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net").size(), 1);
0460         QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net")[0].primaryFingerprint(),
0461                  testKey("full-validity@example.net", CMS).primaryFingerprint());
0462         QCOMPARE(result.alternative.encryptionKeys.size(), 0);
0463     }
0464 
0465     void test_smime_overrides_are_used_if_both_protocols_are_allowed_and_smime_is_preferred()
0466     {
0467         const QString override = testKey("prefer-smime@example.net", CMS).primaryFingerprint();
0468         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/true);
0469         resolver.setAllowMixedProtocols(false);
0470         resolver.setPreferredProtocol(CMS);
0471         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
0472         resolver.setRecipients({"full-validity@example.net"});
0473         resolver.setOverrideKeys({{CMS, {{QStringLiteral("Needs to be normalized <full-validity@example.net>"), {override}}}}});
0474 
0475         const auto result = resolver.resolve();
0476 
0477         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0478         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
0479         QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net").size(), 1);
0480         QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net")[0].primaryFingerprint(), override);
0481         QCOMPARE(result.alternative.encryptionKeys.value("full-validity@example.net").size(), 1);
0482         QCOMPARE(result.alternative.encryptionKeys.value("full-validity@example.net")[0].primaryFingerprint(),
0483                  testKey("full-validity@example.net", OpenPGP).primaryFingerprint());
0484     }
0485 
0486     void test_smime_overrides_are_used_if_smime_only_is_requested()
0487     {
0488         const QString override = testKey("prefer-smime@example.net", CMS).primaryFingerprint();
0489         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/true, CMS);
0490         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
0491         resolver.setRecipients({"full-validity@example.net"});
0492         resolver.setOverrideKeys({{CMS, {{QStringLiteral("Needs to be normalized <full-validity@example.net>"), {override}}}}});
0493 
0494         const auto result = resolver.resolve();
0495 
0496         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0497         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
0498         QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net").size(), 1);
0499         QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net")[0].primaryFingerprint(), override);
0500         QCOMPARE(result.alternative.encryptionKeys.size(), 0);
0501     }
0502 
0503     void test_smime_overrides_are_ignored_if_openpgp_only_is_requested()
0504     {
0505         const QString override = testKey("prefer-smime@example.net", CMS).primaryFingerprint();
0506         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/true, OpenPGP);
0507         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
0508         resolver.setRecipients({"full-validity@example.net"});
0509         resolver.setOverrideKeys({{CMS, {{QStringLiteral("Needs to be normalized <full-validity@example.net>"), {override}}}}});
0510 
0511         const auto result = resolver.resolve();
0512 
0513         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0514         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
0515         QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net").size(), 1);
0516         QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net")[0].primaryFingerprint(),
0517                  testKey("full-validity@example.net", OpenPGP).primaryFingerprint());
0518         QCOMPARE(result.alternative.encryptionKeys.size(), 0);
0519     }
0520 
0521     void test_overrides_for_wrong_protocol_are_ignored()
0522     {
0523         const QString override1 = testKey("full-validity@example.net", CMS).primaryFingerprint();
0524         const QString override2 = testKey("full-validity@example.net", OpenPGP).primaryFingerprint();
0525         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/true);
0526         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
0527         resolver.setRecipients({"sender-openpgp@example.net", "sender-smime@example.net"});
0528         resolver.setOverrideKeys({{OpenPGP, {{QStringLiteral("Needs to be normalized <sender-openpgp@example.net>"), {override1}}}}});
0529         resolver.setOverrideKeys({{CMS, {{QStringLiteral("Needs to be normalized <sender-smime@example.net>"), {override2}}}}});
0530 
0531         const auto result = resolver.resolve();
0532 
0533         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0534         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::MixedProtocols);
0535         QCOMPARE(result.solution.encryptionKeys.value("sender-openpgp@example.net").size(), 1);
0536         QCOMPARE(result.solution.encryptionKeys.value("sender-openpgp@example.net")[0].primaryFingerprint(),
0537                  testKey("sender-openpgp@example.net", OpenPGP).primaryFingerprint());
0538         QCOMPARE(result.solution.encryptionKeys.value("sender-smime@example.net").size(), 1);
0539         QCOMPARE(result.solution.encryptionKeys.value("sender-smime@example.net")[0].primaryFingerprint(),
0540                  testKey("sender-smime@example.net", CMS).primaryFingerprint());
0541     }
0542 
0543     void test_openpgp_only_common_overrides_are_used_for_openpgp()
0544     {
0545         const QString override = testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint();
0546         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/true);
0547         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
0548         resolver.setRecipients({"sender-openpgp@example.net"});
0549         resolver.setOverrideKeys({{UnknownProtocol, {{QStringLiteral("Needs to be normalized <sender-openpgp@example.net>"), {override}}}}});
0550 
0551         const auto result = resolver.resolve();
0552 
0553         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0554         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
0555         QCOMPARE(result.solution.encryptionKeys.value("sender-openpgp@example.net").size(), 1);
0556         QCOMPARE(result.solution.encryptionKeys.value("sender-openpgp@example.net")[0].primaryFingerprint(), override);
0557     }
0558 
0559     void test_smime_only_common_overrides_are_used_for_smime()
0560     {
0561         const QString override = testKey("prefer-smime@example.net", CMS).primaryFingerprint();
0562         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/true);
0563         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
0564         resolver.setRecipients({"sender-smime@example.net"});
0565         resolver.setOverrideKeys({{UnknownProtocol, {{QStringLiteral("Needs to be normalized <sender-smime@example.net>"), {override}}}}});
0566 
0567         const auto result = resolver.resolve();
0568 
0569         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0570         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
0571         QCOMPARE(result.solution.encryptionKeys.value("sender-smime@example.net").size(), 1);
0572         QCOMPARE(result.solution.encryptionKeys.value("sender-smime@example.net")[0].primaryFingerprint(), override);
0573     }
0574 
0575     void test_mixed_protocol_common_overrides_override_protocol_specific_resolution()
0576     {
0577         const QString override1 = testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint();
0578         const QString override2 = testKey("prefer-smime@example.net", CMS).primaryFingerprint();
0579         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/true);
0580         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
0581         resolver.setOverrideKeys({{UnknownProtocol, {{QStringLiteral("sender-mixed@example.net"), {override1, override2}}}}});
0582 
0583         const auto result = resolver.resolve();
0584 
0585         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0586         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::MixedProtocols);
0587         QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net").size(), 2);
0588         QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(), override1);
0589         QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net")[1].primaryFingerprint(), override2);
0590     }
0591 
0592     void test_common_overrides_override_protocol_specific_overrides()
0593     {
0594         const QString override1 = testKey("full-validity@example.net", OpenPGP).primaryFingerprint();
0595         const QString override2 = testKey("full-validity@example.net", CMS).primaryFingerprint();
0596         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/true);
0597         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
0598         resolver.setRecipients({"sender-openpgp@example.net", "sender-smime@example.net"});
0599         resolver.setOverrideKeys({
0600             {
0601                 OpenPGP,
0602                 {
0603                     {QStringLiteral("sender-openpgp@example.net"), {testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint()}},
0604                 },
0605             },
0606             {
0607                 CMS,
0608                 {
0609                     {QStringLiteral("sender-smime@example.net"), {testKey("prefer-smime@example.net", CMS).primaryFingerprint()}},
0610                 },
0611             },
0612             {
0613                 UnknownProtocol,
0614                 {
0615                     {QStringLiteral("sender-openpgp@example.net"), {override1}},
0616                     {QStringLiteral("sender-smime@example.net"), {override2}},
0617                 },
0618             },
0619         });
0620 
0621         const auto result = resolver.resolve();
0622 
0623         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0624         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::MixedProtocols);
0625         QCOMPARE(result.solution.encryptionKeys.value("sender-openpgp@example.net").size(), 1);
0626         QCOMPARE(result.solution.encryptionKeys.value("sender-openpgp@example.net")[0].primaryFingerprint(), override1);
0627         QCOMPARE(result.solution.encryptionKeys.value("sender-smime@example.net").size(), 1);
0628         QCOMPARE(result.solution.encryptionKeys.value("sender-smime@example.net")[0].primaryFingerprint(), override2);
0629     }
0630 
0631     void test_reports_failure_if_openpgp_is_requested_but_common_overrides_require_smime()
0632     {
0633         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/false, OpenPGP);
0634         resolver.setRecipients({"sender-mixed@example.net"});
0635         resolver.setOverrideKeys({{
0636             UnknownProtocol,
0637             {{QStringLiteral("sender-mixed@example.net"), {testKey("prefer-smime@example.net", CMS).primaryFingerprint()}}},
0638         }});
0639 
0640         const auto result = resolver.resolve();
0641 
0642         QVERIFY(result.flags & KeyResolverCore::Error);
0643     }
0644 
0645     void test_reports_failure_if_smime_is_requested_but_common_overrides_require_openpgp()
0646     {
0647         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/false, CMS);
0648         resolver.setRecipients({"sender-mixed@example.net"});
0649         resolver.setOverrideKeys({{
0650             UnknownProtocol,
0651             {{QStringLiteral("sender-mixed@example.net"), {testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint()}}},
0652         }});
0653 
0654         const auto result = resolver.resolve();
0655 
0656         QVERIFY(result.flags & KeyResolverCore::Error);
0657     }
0658 
0659     void test_reports_failure_if_mixed_protocols_are_not_allowed_but_required_by_common_overrides()
0660     {
0661         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/false);
0662         resolver.setAllowMixedProtocols(false);
0663         resolver.setRecipients({"sender-mixed@example.net"});
0664         resolver.setOverrideKeys({{
0665             UnknownProtocol,
0666             {{QStringLiteral("sender-mixed@example.net"),
0667               {
0668                   testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint(),
0669                   testKey("prefer-smime@example.net", CMS).primaryFingerprint(),
0670               }}},
0671         }});
0672 
0673         const auto result = resolver.resolve();
0674 
0675         QVERIFY(result.flags & KeyResolverCore::Error);
0676     }
0677 
0678     void test_groups__openpgp_only_mode__ignores_non_openpgp_only_groups()
0679     {
0680         const std::vector<KeyGroup> groups = {
0681             createGroup("group@example.net",
0682                         {
0683                             testKey("sender-openpgp@example.net", OpenPGP),
0684                             testKey("sender-smime@example.net", CMS),
0685                         }),
0686             createGroup("group@example.net",
0687                         {
0688                             testKey("prefer-smime@example.net", CMS),
0689                         }),
0690             createGroup("group@example.net",
0691                         {
0692                             testKey("prefer-openpgp@example.net", OpenPGP),
0693                         }),
0694         };
0695         KeyCache::mutableInstance()->setGroups(groups);
0696         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/false, OpenPGP);
0697         resolver.setRecipients({"group@example.net"});
0698 
0699         const auto result = resolver.resolve();
0700 
0701         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0702         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
0703         QCOMPARE(result.solution.protocol, OpenPGP);
0704         QCOMPARE(result.solution.encryptionKeys.value("group@example.net").size(), 1);
0705         QCOMPARE(result.solution.encryptionKeys.value("group@example.net")[0].primaryFingerprint(),
0706                  testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint());
0707     }
0708 
0709     void test_groups__smime_only_mode__ignores_non_smime_only_groups()
0710     {
0711         const std::vector<KeyGroup> groups = {
0712             createGroup("group@example.net",
0713                         {
0714                             testKey("sender-openpgp@example.net", OpenPGP),
0715                             testKey("sender-smime@example.net", CMS),
0716                         }),
0717             createGroup("group@example.net",
0718                         {
0719                             testKey("prefer-smime@example.net", CMS),
0720                         }),
0721             createGroup("group@example.net",
0722                         {
0723                             testKey("prefer-openpgp@example.net", OpenPGP),
0724                         }),
0725         };
0726         KeyCache::mutableInstance()->setGroups(groups);
0727         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/false, CMS);
0728         resolver.setRecipients({"group@example.net"});
0729 
0730         const auto result = resolver.resolve();
0731 
0732         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0733         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
0734         QCOMPARE(result.solution.protocol, CMS);
0735         QCOMPARE(result.solution.encryptionKeys.value("group@example.net").size(), 1);
0736         QCOMPARE(result.solution.encryptionKeys.value("group@example.net")[0].primaryFingerprint(),
0737                  testKey("prefer-smime@example.net", CMS).primaryFingerprint());
0738     }
0739 
0740     void test_groups__single_protocol_mode__ignores_mixed_protocol_groups()
0741     {
0742         const std::vector<KeyGroup> groups = {
0743             createGroup("sender-mixed@example.net",
0744                         {
0745                             testKey("sender-openpgp@example.net", OpenPGP),
0746                             testKey("sender-smime@example.net", CMS),
0747                         }),
0748         };
0749         KeyCache::mutableInstance()->setGroups(groups);
0750         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/false);
0751         resolver.setAllowMixedProtocols(false);
0752         resolver.setRecipients({"sender-mixed@example.net"});
0753 
0754         const auto result = resolver.resolve();
0755 
0756         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0757         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
0758         QCOMPARE(result.solution.protocol, OpenPGP);
0759         QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net").size(), 1);
0760         QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
0761                  testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
0762     }
0763 
0764     void test_groups__mixed_mode__single_protocol_groups_are_preferred_over_mixed_protocol_groups()
0765     {
0766         const std::vector<KeyGroup> groups = {
0767             createGroup("group@example.net",
0768                         {
0769                             testKey("sender-openpgp@example.net", OpenPGP),
0770                             testKey("sender-smime@example.net", CMS),
0771                         }),
0772             createGroup("group@example.net",
0773                         {
0774                             testKey("prefer-smime@example.net", CMS),
0775                         }),
0776             createGroup("group@example.net",
0777                         {
0778                             testKey("prefer-openpgp@example.net", OpenPGP),
0779                         }),
0780         };
0781         KeyCache::mutableInstance()->setGroups(groups);
0782         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/false);
0783         resolver.setRecipients({"group@example.net"});
0784 
0785         const auto result = resolver.resolve();
0786 
0787         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0788         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
0789         QCOMPARE(result.solution.protocol, OpenPGP);
0790         QCOMPARE(result.solution.encryptionKeys.value("group@example.net").size(), 1);
0791         QCOMPARE(result.solution.encryptionKeys.value("group@example.net")[0].primaryFingerprint(),
0792                  testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint());
0793     }
0794 
0795     void test_groups__mixed_mode__openpgp_only_group_preferred_over_mixed_protocol_group()
0796     {
0797         const std::vector<KeyGroup> groups = {
0798             createGroup("group@example.net",
0799                         {
0800                             testKey("sender-openpgp@example.net", OpenPGP),
0801                             testKey("sender-smime@example.net", CMS),
0802                         }),
0803             createGroup("group@example.net",
0804                         {
0805                             testKey("sender-openpgp@example.net", OpenPGP),
0806                         }),
0807         };
0808         KeyCache::mutableInstance()->setGroups(groups);
0809         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/false);
0810         resolver.setRecipients({"group@example.net"});
0811 
0812         const auto result = resolver.resolve();
0813 
0814         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0815         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
0816         QCOMPARE(result.solution.encryptionKeys.value("group@example.net").size(), 1);
0817         QCOMPARE(result.solution.encryptionKeys.value("group@example.net")[0].primaryFingerprint(),
0818                  testKey("sender-openpgp@example.net", OpenPGP).primaryFingerprint());
0819     }
0820 
0821     void test_groups__mixed_mode__smime_only_group_preferred_over_mixed_protocol_group()
0822     {
0823         const std::vector<KeyGroup> groups = {
0824             createGroup("group@example.net",
0825                         {
0826                             testKey("sender-openpgp@example.net", OpenPGP),
0827                             testKey("sender-smime@example.net", CMS),
0828                         }),
0829             createGroup("group@example.net",
0830                         {
0831                             testKey("sender-smime@example.net", CMS),
0832                         }),
0833         };
0834         KeyCache::mutableInstance()->setGroups(groups);
0835         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/false);
0836         resolver.setRecipients({"group@example.net"});
0837 
0838         const auto result = resolver.resolve();
0839 
0840         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0841         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
0842         QCOMPARE(result.solution.encryptionKeys.value("group@example.net").size(), 1);
0843         QCOMPARE(result.solution.encryptionKeys.value("group@example.net")[0].primaryFingerprint(),
0844                  testKey("sender-smime@example.net", CMS).primaryFingerprint());
0845     }
0846 
0847     void test_groups__mixed_mode__mixed_protocol_groups_are_used()
0848     {
0849         const std::vector<KeyGroup> groups = {
0850             createGroup("sender-mixed@example.net",
0851                         {
0852                             testKey("sender-openpgp@example.net", OpenPGP),
0853                             testKey("sender-smime@example.net", CMS),
0854                         }),
0855         };
0856         KeyCache::mutableInstance()->setGroups(groups);
0857         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/false);
0858         resolver.setRecipients({"sender-mixed@example.net"});
0859 
0860         const auto result = resolver.resolve();
0861 
0862         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0863         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::MixedProtocols);
0864         QCOMPARE(result.solution.protocol, UnknownProtocol);
0865         QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net").size(), 2);
0866     }
0867 
0868     void test_reports_unresolved_addresses_if_both_protocols_are_allowed_but_no_signing_keys_are_found_for_an_address()
0869     {
0870         KeyResolverCore resolver(/*encrypt=*/false, /*sign=*/true);
0871         resolver.setSender(QStringLiteral("unknown@example.net"));
0872 
0873         const auto result = resolver.resolve();
0874 
0875         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::SomeUnresolved);
0876         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
0877         QCOMPARE(result.solution.protocol, OpenPGP);
0878         QCOMPARE(result.solution.signingKeys.size(), 0);
0879     }
0880 
0881     void test_reports_unresolved_addresses_if_openpgp_is_requested_and_no_openpgp_signing_keys_are_found_for_an_address()
0882     {
0883         KeyResolverCore resolver(/*encrypt=*/false, /*sign=*/true, OpenPGP);
0884         resolver.setSender(QStringLiteral("sender-smime@example.net"));
0885 
0886         const auto result = resolver.resolve();
0887 
0888         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::SomeUnresolved);
0889         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
0890         QCOMPARE(result.solution.protocol, OpenPGP);
0891         QCOMPARE(result.solution.signingKeys.size(), 0);
0892     }
0893 
0894     void test_reports_unresolved_addresses_if_smime_is_requested_and_no_smime_signing_keys_are_found_for_an_address()
0895     {
0896         KeyResolverCore resolver(/*encrypt=*/false, /*sign=*/true, CMS);
0897         resolver.setSender(QStringLiteral("sender-openpgp@example.net"));
0898 
0899         const auto result = resolver.resolve();
0900 
0901         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::SomeUnresolved);
0902         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
0903         QCOMPARE(result.solution.protocol, CMS);
0904         QCOMPARE(result.solution.signingKeys.size(), 0);
0905     }
0906 
0907     void test_reports_unresolved_addresses_if_both_protocols_are_needed_but_no_signing_keys_are_found_for_smime()
0908     {
0909         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/true);
0910         resolver.setSender(QStringLiteral("sender-openpgp@example.net"));
0911         resolver.setRecipients({"smime-only@example.net"});
0912 
0913         const auto result = resolver.resolve();
0914 
0915         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::SomeUnresolved);
0916         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::MixedProtocols);
0917         QCOMPARE(result.solution.protocol, UnknownProtocol);
0918         QCOMPARE(result.solution.signingKeys.size(), 1);
0919         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-openpgp@example.net", OpenPGP).primaryFingerprint());
0920     }
0921 
0922     void test_reports_unresolved_addresses_if_both_protocols_are_needed_but_no_signing_keys_are_found_for_openpgp()
0923     {
0924         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/true);
0925         resolver.setSender(QStringLiteral("sender-smime@example.net"));
0926         resolver.setRecipients({"openpgp-only@example.net"});
0927 
0928         const auto result = resolver.resolve();
0929 
0930         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::SomeUnresolved);
0931         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::MixedProtocols);
0932         QCOMPARE(result.solution.protocol, UnknownProtocol);
0933         QCOMPARE(result.solution.signingKeys.size(), 1);
0934         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-smime@example.net", CMS).primaryFingerprint());
0935     }
0936 
0937     void test_groups_for_signing_key__openpgp_only_mode__prefers_groups_over_keys()
0938     {
0939         const std::vector<KeyGroup> groups = {
0940             createGroup("sender-mixed@example.net",
0941                         {
0942                             testKey("sender-openpgp@example.net", OpenPGP),
0943                         }),
0944         };
0945         KeyCache::mutableInstance()->setGroups(groups);
0946         KeyResolverCore resolver(/*encrypt=*/false, /*sign=*/true, OpenPGP);
0947         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
0948 
0949         const auto result = resolver.resolve();
0950 
0951         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0952         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
0953         QCOMPARE(result.solution.protocol, OpenPGP);
0954         QCOMPARE(result.solution.signingKeys.size(), 1);
0955         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-openpgp@example.net", OpenPGP).primaryFingerprint());
0956     }
0957 
0958     void test_groups_for_signing_key__openpgp_only_mode__prefers_single_protocol_groups()
0959     {
0960         const std::vector<KeyGroup> groups = {
0961             createGroup("sender-alias@example.net",
0962                         {
0963                             testKey("sender-mixed@example.net", OpenPGP),
0964                             testKey("sender-mixed@example.net", CMS),
0965                         }),
0966             createGroup("sender-alias@example.net",
0967                         {
0968                             testKey("sender-openpgp@example.net", OpenPGP),
0969                         }),
0970             createGroup("sender-alias@example.net",
0971                         {
0972                             testKey("sender-smime@example.net", CMS),
0973                         }),
0974         };
0975         KeyCache::mutableInstance()->setGroups(groups);
0976         KeyResolverCore resolver(/*encrypt=*/false, /*sign=*/true, OpenPGP);
0977         resolver.setSender(QStringLiteral("sender-alias@example.net"));
0978 
0979         const auto result = resolver.resolve();
0980 
0981         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
0982         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
0983         QCOMPARE(result.solution.protocol, OpenPGP);
0984         QCOMPARE(result.solution.signingKeys.size(), 1);
0985         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-openpgp@example.net", OpenPGP).primaryFingerprint());
0986     }
0987 
0988     void test_groups_for_signing_key__openpgp_only_mode__takes_key_of_mixed_protocol_groups()
0989     {
0990         const std::vector<KeyGroup> groups = {
0991             createGroup("sender-alias@example.net",
0992                         {
0993                             testKey("sender-mixed@example.net", OpenPGP),
0994                             testKey("sender-mixed@example.net", CMS),
0995                         }),
0996         };
0997         KeyCache::mutableInstance()->setGroups(groups);
0998         KeyResolverCore resolver(/*encrypt=*/false, /*sign=*/true, OpenPGP);
0999         resolver.setSender(QStringLiteral("sender-alias@example.net"));
1000 
1001         const auto result = resolver.resolve();
1002 
1003         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
1004         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
1005         QCOMPARE(result.solution.protocol, OpenPGP);
1006         QCOMPARE(result.solution.signingKeys.size(), 1);
1007         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
1008     }
1009 
1010     void test_groups_for_signing_key__smime_only_mode__prefers_groups_over_keys()
1011     {
1012         const std::vector<KeyGroup> groups = {
1013             createGroup("sender-mixed@example.net",
1014                         {
1015                             testKey("sender-smime@example.net", CMS),
1016                         }),
1017         };
1018         KeyCache::mutableInstance()->setGroups(groups);
1019         KeyResolverCore resolver(/*encrypt=*/false, /*sign=*/true, CMS);
1020         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
1021 
1022         const auto result = resolver.resolve();
1023 
1024         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
1025         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
1026         QCOMPARE(result.solution.protocol, CMS);
1027         QCOMPARE(result.solution.signingKeys.size(), 1);
1028         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-smime@example.net", CMS).primaryFingerprint());
1029     }
1030 
1031     void test_groups_for_signing_key__smime_only_mode__prefers_single_protocol_groups()
1032     {
1033         const std::vector<KeyGroup> groups = {
1034             createGroup("sender-alias@example.net",
1035                         {
1036                             testKey("sender-mixed@example.net", OpenPGP),
1037                             testKey("sender-mixed@example.net", CMS),
1038                         }),
1039             createGroup("sender-alias@example.net",
1040                         {
1041                             testKey("sender-openpgp@example.net", OpenPGP),
1042                         }),
1043             createGroup("sender-alias@example.net",
1044                         {
1045                             testKey("sender-smime@example.net", CMS),
1046                         }),
1047         };
1048         KeyCache::mutableInstance()->setGroups(groups);
1049         KeyResolverCore resolver(/*encrypt=*/false, /*sign=*/true, CMS);
1050         resolver.setSender(QStringLiteral("sender-alias@example.net"));
1051 
1052         const auto result = resolver.resolve();
1053 
1054         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
1055         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
1056         QCOMPARE(result.solution.protocol, CMS);
1057         QCOMPARE(result.solution.signingKeys.size(), 1);
1058         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-smime@example.net", CMS).primaryFingerprint());
1059     }
1060 
1061     void test_groups_for_signing_key__smime_only_mode__takes_key_of_mixed_protocol_groups()
1062     {
1063         const std::vector<KeyGroup> groups = {
1064             createGroup("sender-alias@example.net",
1065                         {
1066                             testKey("sender-mixed@example.net", OpenPGP),
1067                             testKey("sender-mixed@example.net", CMS),
1068                         }),
1069         };
1070         KeyCache::mutableInstance()->setGroups(groups);
1071         KeyResolverCore resolver(/*encrypt=*/false, /*sign=*/true, CMS);
1072         resolver.setSender(QStringLiteral("sender-alias@example.net"));
1073 
1074         const auto result = resolver.resolve();
1075 
1076         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
1077         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
1078         QCOMPARE(result.solution.protocol, CMS);
1079         QCOMPARE(result.solution.signingKeys.size(), 1);
1080         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-mixed@example.net", CMS).primaryFingerprint());
1081     }
1082 
1083     void test_groups_for_signing_key__single_protocol_mode__prefers_groups_over_keys()
1084     {
1085         const std::vector<KeyGroup> groups = {
1086             createGroup("sender-mixed@example.net",
1087                         {
1088                             testKey("sender-openpgp@example.net", OpenPGP),
1089                             testKey("sender-smime@example.net", CMS),
1090                         }),
1091         };
1092         KeyCache::mutableInstance()->setGroups(groups);
1093         KeyResolverCore resolver(/*encrypt=*/false, /*sign=*/true);
1094         resolver.setAllowMixedProtocols(false);
1095         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
1096 
1097         const auto result = resolver.resolve();
1098 
1099         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
1100         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
1101         QCOMPARE(result.solution.protocol, OpenPGP);
1102         QCOMPARE(result.solution.signingKeys.size(), 1);
1103         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-openpgp@example.net", OpenPGP).primaryFingerprint());
1104         QCOMPARE(result.alternative.signingKeys.size(), 1);
1105         QCOMPARE(result.alternative.signingKeys[0].primaryFingerprint(), testKey("sender-smime@example.net", CMS).primaryFingerprint());
1106     }
1107 
1108     void test_groups_for_signing_key__single_protocol_mode__prefers_single_protocol_groups()
1109     {
1110         const std::vector<KeyGroup> groups = {
1111             createGroup("sender-alias@example.net",
1112                         {
1113                             testKey("sender-mixed@example.net", OpenPGP),
1114                             testKey("sender-mixed@example.net", CMS),
1115                         }),
1116             createGroup("sender-alias@example.net",
1117                         {
1118                             testKey("sender-openpgp@example.net", OpenPGP),
1119                         }),
1120             createGroup("sender-alias@example.net",
1121                         {
1122                             testKey("sender-smime@example.net", CMS),
1123                         }),
1124         };
1125         KeyCache::mutableInstance()->setGroups(groups);
1126         KeyResolverCore resolver(/*encrypt=*/false, /*sign=*/true);
1127         resolver.setAllowMixedProtocols(false);
1128         resolver.setSender(QStringLiteral("sender-alias@example.net"));
1129 
1130         const auto result = resolver.resolve();
1131 
1132         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
1133         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
1134         QCOMPARE(result.solution.protocol, OpenPGP);
1135         QCOMPARE(result.solution.signingKeys.size(), 1);
1136         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-openpgp@example.net", OpenPGP).primaryFingerprint());
1137         QCOMPARE(result.alternative.signingKeys.size(), 1);
1138         QCOMPARE(result.alternative.signingKeys[0].primaryFingerprint(), testKey("sender-smime@example.net", CMS).primaryFingerprint());
1139     }
1140 
1141     void test_groups_for_signing_key__mixed_mode__prefers_groups_over_keys()
1142     {
1143         const std::vector<KeyGroup> groups = {
1144             createGroup("sender-mixed@example.net",
1145                         {
1146                             testKey("sender-openpgp@example.net", OpenPGP),
1147                             testKey("sender-smime@example.net", CMS),
1148                         }),
1149         };
1150         KeyCache::mutableInstance()->setGroups(groups);
1151         KeyResolverCore resolver(/*encrypt=*/false, /*sign=*/true);
1152         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
1153 
1154         const auto result = resolver.resolve();
1155 
1156         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
1157         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
1158         QCOMPARE(result.solution.protocol, OpenPGP);
1159         QCOMPARE(result.solution.signingKeys.size(), 1);
1160         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-openpgp@example.net", OpenPGP).primaryFingerprint());
1161     }
1162 
1163     void test_groups_for_signing_key__mixed_mode_with_smime_preferred__prefers_groups_over_keys()
1164     {
1165         const std::vector<KeyGroup> groups = {
1166             createGroup("sender-mixed@example.net",
1167                         {
1168                             testKey("sender-openpgp@example.net", OpenPGP),
1169                             testKey("sender-smime@example.net", CMS),
1170                         }),
1171         };
1172         KeyCache::mutableInstance()->setGroups(groups);
1173         KeyResolverCore resolver(/*encrypt=*/false, /*sign=*/true);
1174         resolver.setPreferredProtocol(CMS);
1175         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
1176 
1177         const auto result = resolver.resolve();
1178 
1179         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
1180         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
1181         QCOMPARE(result.solution.protocol, CMS);
1182         QCOMPARE(result.solution.signingKeys.size(), 1);
1183         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-smime@example.net", CMS).primaryFingerprint());
1184     }
1185 
1186     void test_groups_for_signing_key__mixed_mode__prefers_single_protocol_groups()
1187     {
1188         const std::vector<KeyGroup> groups = {
1189             createGroup("sender-alias@example.net",
1190                         {
1191                             testKey("sender-mixed@example.net", OpenPGP),
1192                             testKey("sender-mixed@example.net", CMS),
1193                         }),
1194             createGroup("sender-alias@example.net",
1195                         {
1196                             testKey("sender-openpgp@example.net", OpenPGP),
1197                         }),
1198             createGroup("sender-alias@example.net",
1199                         {
1200                             testKey("sender-smime@example.net", CMS),
1201                         }),
1202         };
1203         KeyCache::mutableInstance()->setGroups(groups);
1204         KeyResolverCore resolver(/*encrypt=*/false, /*sign=*/true);
1205         resolver.setSender(QStringLiteral("sender-alias@example.net"));
1206 
1207         const auto result = resolver.resolve();
1208 
1209         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
1210         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
1211         QCOMPARE(result.solution.protocol, OpenPGP);
1212         QCOMPARE(result.solution.signingKeys.size(), 1);
1213         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-openpgp@example.net", OpenPGP).primaryFingerprint());
1214     }
1215 
1216     void test_groups_for_signing_key__mixed_mode_with_smime_preferred__prefers_single_protocol_groups()
1217     {
1218         const std::vector<KeyGroup> groups = {
1219             createGroup("sender-alias@example.net",
1220                         {
1221                             testKey("sender-mixed@example.net", OpenPGP),
1222                             testKey("sender-mixed@example.net", CMS),
1223                         }),
1224             createGroup("sender-alias@example.net",
1225                         {
1226                             testKey("sender-openpgp@example.net", OpenPGP),
1227                         }),
1228             createGroup("sender-alias@example.net",
1229                         {
1230                             testKey("sender-smime@example.net", CMS),
1231                         }),
1232         };
1233         KeyCache::mutableInstance()->setGroups(groups);
1234         KeyResolverCore resolver(/*encrypt=*/false, /*sign=*/true);
1235         resolver.setPreferredProtocol(CMS);
1236         resolver.setSender(QStringLiteral("sender-alias@example.net"));
1237 
1238         const auto result = resolver.resolve();
1239 
1240         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
1241         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
1242         QCOMPARE(result.solution.protocol, CMS);
1243         QCOMPARE(result.solution.signingKeys.size(), 1);
1244         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-smime@example.net", CMS).primaryFingerprint());
1245     }
1246 
1247     void test_groups__group_with_marginally_valid_key_is_accepted_by_default()
1248     {
1249         const std::vector<KeyGroup> groups = {
1250             createGroup("group@example.net",
1251                         {
1252                             testKey("prefer-openpgp@example.net", OpenPGP),
1253                             testKey("prefer-smime@example.net", OpenPGP),
1254                         }),
1255         };
1256         KeyCache::mutableInstance()->setGroups(groups);
1257         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/false);
1258         resolver.setPreferredProtocol(OpenPGP);
1259         resolver.setRecipients({"group@example.net"});
1260 
1261         const auto result = resolver.resolve();
1262 
1263         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
1264         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
1265         QCOMPARE(result.solution.protocol, OpenPGP);
1266         QCOMPARE(result.solution.encryptionKeys.size(), 1);
1267         QCOMPARE(result.solution.encryptionKeys.value("group@example.net").size(), 2);
1268     }
1269 
1270     void test_groups__group_with_marginally_valid_key_is_ignored_if_full_validity_required()
1271     {
1272         const std::vector<KeyGroup> groups = {
1273             createGroup("group@example.net",
1274                         {
1275                             testKey("prefer-openpgp@example.net", OpenPGP),
1276                             testKey("prefer-smime@example.net", OpenPGP),
1277                         }),
1278         };
1279         KeyCache::mutableInstance()->setGroups(groups);
1280         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/false);
1281         resolver.setMinimumValidity(UserID::Full);
1282         resolver.setPreferredProtocol(OpenPGP);
1283         resolver.setRecipients({"group@example.net"});
1284 
1285         const auto result = resolver.resolve();
1286 
1287         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::SomeUnresolved);
1288         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
1289         QCOMPARE(result.solution.protocol, OpenPGP);
1290         QCOMPARE(result.solution.encryptionKeys.size(), 1);
1291         QCOMPARE(result.solution.encryptionKeys.value("group@example.net").size(), 0);
1292     }
1293 
1294     void test_groups__group_with_marginally_valid_key_is_ignored_in_de_vs_mode()
1295     {
1296         const std::vector<KeyGroup> groups = {
1297             createGroup("group@example.net",
1298                         {
1299                             testKey("prefer-openpgp@example.net", OpenPGP),
1300                             testKey("prefer-smime@example.net", OpenPGP),
1301                         }),
1302         };
1303         KeyCache::mutableInstance()->setGroups(groups);
1304         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/false);
1305         resolver.setPreferredProtocol(OpenPGP);
1306         resolver.setRecipients({"group@example.net"});
1307 
1308         Tests::FakeCryptoConfigStringValue fakeCompliance{"gpg", "compliance", QStringLiteral("de-vs")};
1309         Tests::FakeCryptoConfigIntValue fakeDeVsCompliance{"gpg", "compliance_de_vs", 1};
1310         const auto result = resolver.resolve();
1311 
1312         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::SomeUnresolved);
1313         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
1314         QCOMPARE(result.solution.protocol, OpenPGP);
1315         QCOMPARE(result.solution.encryptionKeys.size(), 1);
1316         QCOMPARE(result.solution.encryptionKeys.value("group@example.net").size(), 0);
1317     }
1318 
1319     void test_sender_is_set__encrypt_only_mode()
1320     {
1321         KeyResolverCore resolver(/*encrypt=*/true, /*sign=*/false);
1322         resolver.setRecipients({"prefer-openpgp@example.net", "prefer-smime@example.net"});
1323         resolver.setSender(QStringLiteral("sender-mixed@example.net"));
1324 
1325         const auto result = resolver.resolve();
1326 
1327         QCOMPARE(resolver.normalizedSender(), QLatin1StringView{"sender-mixed@example.net"});
1328     }
1329 
1330    void test_setSigningKeys_is_preferred()
1331     {
1332         KeyResolverCore resolver(/*encrypt=*/false, /*sign=*/true);
1333         resolver.setSender(QStringLiteral("sender-openpgp@example.net"));
1334         resolver.setSigningKeys({testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint(), testKey("sender-mixed@example.net", CMS).primaryFingerprint()});
1335 
1336         const auto result = resolver.resolve();
1337 
1338         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
1339         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
1340         QCOMPARE(result.solution.protocol, OpenPGP);
1341         QCOMPARE(result.solution.signingKeys.size(), 1);
1342         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
1343     }
1344 
1345    void test_setSigningKeys_is_preferred_smime()
1346     {
1347         KeyResolverCore resolver(/*encrypt=*/false, /*sign=*/true);
1348         resolver.setSender(QStringLiteral("sender-smime@example.net"));
1349         resolver.setSigningKeys({testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint(), testKey("sender-mixed@example.net", CMS).primaryFingerprint()});
1350         resolver.setPreferredProtocol(CMS);
1351 
1352         const auto result = resolver.resolve();
1353 
1354         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
1355         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
1356         QCOMPARE(result.solution.protocol, CMS);
1357         QCOMPARE(result.solution.signingKeys.size(), 1);
1358         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-mixed@example.net", CMS).primaryFingerprint());
1359     }
1360 
1361    void test_setSigningKeys_is_preferred_only_openpgp()
1362     {
1363         KeyResolverCore resolver(/*encrypt=*/false, /*sign=*/true, OpenPGP);
1364         resolver.setSender(QStringLiteral("sender-openpgp@example.net"));
1365         resolver.setSigningKeys({testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint()});
1366 
1367         const auto result = resolver.resolve();
1368 
1369         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
1370         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
1371         QCOMPARE(result.solution.protocol, OpenPGP);
1372         QCOMPARE(result.solution.signingKeys.size(), 1);
1373         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
1374     }
1375 
1376    void test_setSigningKeys_is_preferred_only_smime()
1377     {
1378         KeyResolverCore resolver(/*encrypt=*/false, /*sign=*/true, CMS);
1379         resolver.setSender(QStringLiteral("sender-smime@example.net"));
1380         resolver.setSigningKeys({testKey("sender-mixed@example.net", CMS).primaryFingerprint()});
1381         resolver.setPreferredProtocol(CMS);
1382 
1383         const auto result = resolver.resolve();
1384 
1385         QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
1386         QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
1387         QCOMPARE(result.solution.protocol, CMS);
1388         QCOMPARE(result.solution.signingKeys.size(), 1);
1389         QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(), testKey("sender-mixed@example.net", CMS).primaryFingerprint());
1390     }
1391 
1392 
1393 private:
1394     Key testKey(const char *email, Protocol protocol = UnknownProtocol)
1395     {
1396         const std::vector<Key> keys = KeyCache::instance()->findByEMailAddress(email);
1397         for (const auto &key : keys) {
1398             if (protocol == UnknownProtocol || key.protocol() == protocol) {
1399                 return key;
1400             }
1401         }
1402         qWarning() << "No" << Formatting::displayName(protocol) << "test key found for" << email;
1403         return {};
1404     }
1405 
1406 private:
1407     QSharedPointer<QTemporaryDir> mGnupgHome;
1408     std::shared_ptr<const KeyCache> mKeyCache;
1409 };
1410 
1411 QTEST_MAIN(KeyResolverCoreTest)
1412 #include "keyresolvercoretest.moc"