Libkleo

compliance.cpp
1/* -*- mode: c++; c-basic-offset:4 -*-
2 utils/compliance.cpp
3
4 This file is part of libkleopatra
5 SPDX-FileCopyrightText: 2022 g10 Code GmbH
6 SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
7
8 SPDX-License-Identifier: GPL-2.0-or-later
9*/
10
11#include <config-libkleo.h>
12
13#include "compliance.h"
14
15#include "algorithm.h"
16#include "cryptoconfig.h"
17#include "gnupg.h"
18#include "keyhelpers.h"
19#include "stringutils.h"
20#include "systeminfo.h"
21
22#include <libkleo/debug.h>
23#include <libkleo/keyfiltermanager.h>
24
25#include <libkleo_debug.h>
26
27#include <KColorScheme>
28#include <KLocalizedString>
29
30#include <QPushButton>
31
32#include <gpgme++/key.h>
33
34using namespace Kleo;
35
36bool Kleo::DeVSCompliance::isActive()
37{
38 return getCryptoConfigStringValue("gpg", "compliance") == QLatin1StringView{"de-vs"};
39}
40
41bool Kleo::DeVSCompliance::isCompliant()
42{
43 if (!isActive()) {
44 return false;
45 }
46 // The pseudo option compliance_de_vs was fully added in 2.2.34;
47 // For versions between 2.2.28 and 2.2.33 there was a broken config
48 // value with a wrong type. So for them we add an extra check. This
49 // can be removed in future versions because for GnuPG we could assume
50 // non-compliance for older versions as versions of Kleopatra for
51 // which this matters are bundled with new enough versions of GnuPG anyway.
52 if (engineIsVersion(2, 2, 28) && !engineIsVersion(2, 2, 34)) {
53 return true;
54 }
55 return getCryptoConfigIntValue("gpg", "compliance_de_vs", 0) != 0;
56}
57
58bool Kleo::DeVSCompliance::isBetaCompliance()
59{
60 if (!isActive()) {
61 return false;
62 }
63 // compliance_de_vs > 2000: GnuPG has not yet been approved for VS-NfD or is beta, but we shall assume approval
64 return getCryptoConfigIntValue("gpg", "compliance_de_vs", 0) > 2000;
65}
66
67bool Kleo::DeVSCompliance::algorithmIsCompliant(std::string_view algo)
68{
69 return !isActive() || Kleo::contains(compliantAlgorithms(), algo);
70}
71
72bool Kleo::DeVSCompliance::allSubkeysAreCompliant(const GpgME::Key &key)
73{
74 if (!isActive()) {
75 return true;
76 }
77 // there is at least one usable subkey
78 const auto usableSubkeys = Kleo::count_if(key.subkeys(), [](const auto &sub) {
79 return !sub.isExpired() && !sub.isRevoked();
80 });
81 if (usableSubkeys == 0) {
82 qCDebug(LIBKLEO_LOG) << __func__ << "No usable subkeys found for key" << key;
83 return false;
84 }
85 // and all usable subkeys are compliant
86 return Kleo::all_of(key.subkeys(), [](const auto &sub) {
87 return sub.isDeVs() || sub.isExpired() || sub.isRevoked() || (!sub.canSign() && !sub.canEncrypt() && !sub.canCertify() && sub.canAuthenticate());
88 });
89}
90
91bool Kleo::DeVSCompliance::userIDIsCompliant(const GpgME::UserID &id)
92{
93 if (!isActive()) {
94 return true;
95 }
96 return (id.parent().keyListMode() & GpgME::Validate) //
97 && !id.isRevoked() //
98 && id.validity() >= GpgME::UserID::Full //
99 && allSubkeysAreCompliant(id.parent());
100}
101
102bool Kleo::DeVSCompliance::keyIsCompliant(const GpgME::Key &key)
103{
104 if (!isActive()) {
105 return true;
106 }
107 return (key.keyListMode() & GpgME::Validate) //
108 && allUserIDsHaveFullValidity(key) //
109 && allSubkeysAreCompliant(key);
110}
111
112const std::vector<std::string> &Kleo::DeVSCompliance::compliantAlgorithms()
113{
114 static std::vector<std::string> compliantAlgos;
115 if (!isActive()) {
116 return Kleo::availableAlgorithms();
117 }
118 if (compliantAlgos.empty()) {
119 compliantAlgos.reserve(7);
120 compliantAlgos = {
121 "brainpoolP256r1",
122 "brainpoolP384r1",
123 "brainpoolP512r1",
124 "rsa3072",
125 "rsa4096",
126 };
127#if GPGMEPP_SUPPORTS_KYBER
128 if (engineIsVersion(2, 5, 2)) {
129 compliantAlgos.insert(compliantAlgos.end(),
130 {
131 "ky768_bp256",
132 "ky1024_bp384",
133 });
134 }
135#endif
136 };
137 return compliantAlgos;
138}
139
140const std::vector<std::string> &Kleo::DeVSCompliance::preferredCompliantAlgorithms()
141{
142 static std::vector<std::string> result;
143 if (result.empty()) {
144 const auto &preferredAlgos = Kleo::preferredAlgorithms();
145 result.reserve(preferredAlgos.size());
146 Kleo::copy_if(preferredAlgos, std::back_inserter(result), Kleo::DeVSCompliance::algorithmIsCompliant);
147 }
148 return result;
149}
150
151void Kleo::DeVSCompliance::decorate(QPushButton *button)
152{
153 decorate(button, isCompliant());
154}
155
156void Kleo::DeVSCompliance::decorate(QPushButton *button, bool compliant)
157{
158 if (!button) {
159 return;
160 }
161 if (compliant) {
162 button->setIcon(QIcon::fromTheme(QStringLiteral("security-high")));
163 if (!SystemInfo::isHighContrastModeActive()) {
165 button->setStyleSheet(QStringLiteral("QPushButton { background-color: %1; };").arg(bgColor));
166 }
167 } else {
168 button->setIcon(QIcon::fromTheme(QStringLiteral("security-medium")));
169 if (!SystemInfo::isHighContrastModeActive()) {
171 button->setStyleSheet(QStringLiteral("QPushButton { background-color: %1; };").arg(bgColor));
172 }
173 }
174}
175
176QString Kleo::DeVSCompliance::name()
177{
178 return name(isCompliant());
179}
180
181static QString complianceName(bool compliant)
182{
183 const auto filterId = compliant ? QStringLiteral("de-vs-filter") : QStringLiteral("not-de-vs-filter");
184 if (auto filter = KeyFilterManager::instance()->keyFilterByID(filterId)) {
185 return filter->name();
186 }
187 return compliant ? i18n("VS-NfD compliant") : i18n("Not VS-NfD compliant");
188}
189
190QString Kleo::DeVSCompliance::name(bool compliant)
191{
192 if (!isActive()) {
193 return {};
194 }
195 if (compliant && isBetaCompliance()) {
196 return i18nc("@info append beta-marker to compliance", "%1 (beta)", complianceName(compliant));
197 }
198 return complianceName(compliant);
199}
QBrush background(BackgroundRole=NormalBackground) const
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
void setIcon(const QIcon &icon)
const QColor & color() const const
QString name(NameFormat format) const const
QIcon fromTheme(const QString &name)
QFuture< void > filter(QThreadPool *pool, Sequence &sequence, KeepFunctor &&filterFunction)
void setStyleSheet(const QString &styleSheet)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:09:14 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.