Libkleo

expirychecker.cpp
1/*
2 This file is part of libkleopatra, the KDE keymanagement library
3 SPDX-FileCopyrightText: 2004 Klarälvdalens Datakonsult AB
4 SPDX-FileCopyrightText: 2021 Sandro Knauß <sknauss@kde.org>
5 SPDX-FileCopyrightText: 2023 g10 Code GmbH
6 SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
7
8 Based on kpgp.h
9 Copyright (C) 2001,2002 the KPGP authors
10 See file libkdenetwork/AUTHORS.kpgp for details
11
12 SPDX-License-Identifier: LGPL-2.0-or-later
13*/
14
15#include "expirychecker.h"
16
17#include "debug.h"
18#include "dn.h"
19#include "expirycheckersettings.h"
20
21#include <libkleo/algorithm.h>
22#include <libkleo/keycache.h>
23#include <libkleo_debug.h>
24
25#include <KLocalizedString>
26
27#include <QGpgME/KeyListJob>
28#include <QGpgME/Protocol>
29
30#include <gpgme++/keylistresult.h>
31
32#include <set>
33
34#include <cmath>
35#include <ctime>
36
37using namespace Kleo;
38
39class Kleo::ExpiryCheckerPrivate
40{
41 Kleo::ExpiryChecker *q;
42
43public:
44 ExpiryCheckerPrivate(ExpiryChecker *qq, const ExpiryCheckerSettings &settings_)
45 : q{qq}
46 , settings{settings_}
47 {
48 }
49
50 ExpiryChecker::Expiration calculateExpiration(const GpgME::Subkey &subkey) const;
51 ExpiryChecker::Expiration checkForExpiration(const GpgME::Key &key, Kleo::chrono::days threshold, ExpiryChecker::CheckFlags flags) const;
52
53 ExpiryChecker::Result checkKeyNearExpiry(const GpgME::Key &key, ExpiryChecker::CheckFlags flags);
54
55 ExpiryCheckerSettings settings;
56 std::set<QByteArray> alreadyWarnedFingerprints;
57 std::shared_ptr<TimeProvider> timeProvider;
58};
59
60ExpiryChecker::ExpiryChecker(const ExpiryCheckerSettings &settings, QObject *parent)
61 : QObject{parent}
62 , d{new ExpiryCheckerPrivate{this, settings}}
63{
64}
65
66ExpiryChecker::~ExpiryChecker() = default;
67
68ExpiryCheckerSettings ExpiryChecker::settings() const
69{
70 return d->settings;
71}
72
73QString formatOpenPGPMessage(ExpiryChecker::Expiration expiration, ExpiryChecker::CheckFlags flags)
74{
75 const GpgME::Key key = expiration.certificate;
76 const bool isOwnKey = flags & ExpiryChecker::OwnKey;
77 const bool isSigningKey = flags & ExpiryChecker::SigningKey;
78 const auto keyInfo = ki18nc("<b>User ID of key</b> (KeyID key ID of key in hex notation)", "<b>%1</b> (KeyID 0x%2)")
79 .subs(QString::fromUtf8(key.userID(0).id()))
80 .subs(QString::fromLatin1(key.keyID()));
81 if (expiration.status == ExpiryChecker::Expired) {
82 qCDebug(LIBKLEO_LOG) << "Key" << key << "expired" << expiration.duration.count() << "days ago";
83 if (expiration.duration.count() == 0) {
85 if (isSigningKey) {
86 msg = ki18n("<p>Your OpenPGP signing key</p><p align=center>%1</p><p>expired less than a day ago.</p>");
87 } else if (isOwnKey) {
88 msg = ki18n("<p>Your OpenPGP encryption key</p><p align=center>%1</p><p>expired less than a day ago.</p>");
89 } else {
90 msg = ki18n("<p>The OpenPGP key for</p><p align=center>%1</p><p>expired less than a day ago.</p>");
91 }
92 return msg.subs(keyInfo).toString();
93 }
95 if (isSigningKey) {
96 msg = ki18np("<p>Your OpenPGP signing key</p><p align=center>%2</p><p>expired yesterday.</p>",
97 "<p>Your OpenPGP signing key</p><p align=center>%2</p><p>expired %1 days ago.</p>");
98 } else if (isOwnKey) {
99 msg = ki18np("<p>Your OpenPGP encryption key</p><p align=center>%2</p><p>expired yesterday.</p>",
100 "<p>Your OpenPGP encryption key</p><p align=center>%2</p><p>expired %1 days ago.</p>");
101 } else {
102 msg = ki18np("<p>The OpenPGP key for</p><p align=center>%2</p><p>expired yesterday.</p>",
103 "<p>The OpenPGP key for</p><p align=center>%2</p><p>expired %1 days ago.</p>");
104 }
105 return msg.subs(expiration.duration.count()).subs(keyInfo).toString();
106 }
107 qCDebug(LIBKLEO_LOG) << "Key" << key << "expires in" << expiration.duration.count() << "days";
108 if (expiration.duration.count() == 0) {
110 if (isSigningKey) {
111 msg = ki18n("<p>Your OpenPGP signing key</p><p align=center>%1</p><p>expires today.</p>");
112 } else if (isOwnKey) {
113 msg = ki18n("<p>Your OpenPGP encryption key</p><p align=center>%1</p><p>expires today.</p>");
114 } else {
115 msg = ki18n("<p>The OpenPGP key for</p><p align=center>%1</p><p>expires today.</p>");
116 }
117 return msg.subs(keyInfo).toString();
118 }
120 if (isSigningKey) {
121 msg = ki18np("<p>Your OpenPGP signing key</p><p align=center>%2</p><p>expires tomorrow.</p>",
122 "<p>Your OpenPGP signing key</p><p align=center>%2</p><p>expires in %1 days.</p>");
123 } else if (isOwnKey) {
124 msg = ki18np("<p>Your OpenPGP encryption key</p><p align=center>%2</p><p>expires tomorrow.</p>",
125 "<p>Your OpenPGP encryption key</p><p align=center>%2</p><p>expires in %1 days.</p>");
126 } else {
127 msg = ki18np("<p>The OpenPGP key for</p><p align=center>%2</p><p>expires tomorrow.</p>",
128 "<p>The OpenPGP key for</p><p align=center>%2</p><p>expires in %1 days.</p>");
129 }
130 return msg.subs(expiration.duration.count()).subs(keyInfo).toString();
131}
132
133QString formatSMIMEMessage(const GpgME::Key &orig_key, ExpiryChecker::Expiration expiration, ExpiryChecker::CheckFlags flags, bool ca)
134{
135 const GpgME::Key key = expiration.certificate;
136 const bool isOwnKey = flags & ExpiryChecker::OwnKey;
137 const bool isSigningKey = flags & ExpiryChecker::SigningKey;
138 const auto userCert = orig_key.isNull() ? key : orig_key;
139 const auto userCertInfo = ki18nc("<b>User ID of certificate</b> (serial number serial no. of certificate)", "<b>%1</b> (serial number %2)")
140 .subs(Kleo::DN(userCert.userID(0).id()).prettyDN())
141 .subs(QString::fromLatin1(userCert.issuerSerial()));
142 if (expiration.status == ExpiryChecker::Expired) {
143 qCDebug(LIBKLEO_LOG) << "Certificate" << key << "expired" << expiration.duration.count() << "days ago";
144 if (ca) {
145 if (key.isRoot()) {
146 if (expiration.duration.count() == 0) {
148 if (isSigningKey) {
149 msg = ki18n(
150 "<p>The root certificate</p><p align=center><b>%2</b></p>"
151 "<p>for your S/MIME signing certificate</p><p align=center>%1</p>"
152 "<p>expired less than a day ago.</p>");
153 } else if (isOwnKey) {
154 msg = ki18n(
155 "<p>The root certificate</p><p align=center><b>%2</b></p>"
156 "<p>for your S/MIME encryption certificate</p><p align=center>%1</p>"
157 "<p>expired less than a day ago.</p>");
158 } else {
159 msg = ki18n(
160 "<p>The root certificate</p><p align=center><b>%2</b></p>"
161 "<p>for S/MIME certificate</p><p align=center>%1</p>"
162 "<p>expired less than a day ago.</p>");
163 }
164 return msg.subs(userCertInfo).subs(Kleo::DN(key.userID(0).id()).prettyDN()).toString();
165 }
167 if (isSigningKey) {
168 msg = ki18np(
169 "<p>The root certificate</p><p align=center><b>%3</b></p>"
170 "<p>for your S/MIME signing certificate</p><p align=center>%2</p>"
171 "<p>expired yesterday.</p>",
172 "<p>The root certificate</p><p align=center><b>%3</b></p>"
173 "<p>for your S/MIME signing certificate</p><p align=center>%2</p>"
174 "<p>expired %1 days ago.</p>");
175 } else if (isOwnKey) {
176 msg = ki18np(
177 "<p>The root certificate</p><p align=center><b>%3</b></p>"
178 "<p>for your S/MIME encryption certificate</p><p align=center>%2</p>"
179 "<p>expired yesterday.</p>",
180 "<p>The root certificate</p><p align=center><b>%3</b></p>"
181 "<p>for your S/MIME encryption certificate</p><p align=center>%2</p>"
182 "<p>expired %1 days ago.</p>");
183 } else {
184 msg = ki18np(
185 "<p>The root certificate</p><p align=center><b>%3</b></p>"
186 "<p>for S/MIME certificate</p><p align=center>%2</p>"
187 "<p>expired yesterday.</p>",
188 "<p>The root certificate</p><p align=center><b>%3</b></p>"
189 "<p>for S/MIME certificate</p><p align=center>%2</p>"
190 "<p>expired %1 days ago.</p>");
191 }
192 return msg.subs(expiration.duration.count()).subs(userCertInfo).subs(Kleo::DN(key.userID(0).id()).prettyDN()).toString();
193 } else {
194 if (expiration.duration.count() == 0) {
196 if (isSigningKey) {
197 msg = ki18n(
198 "<p>The intermediate CA certificate</p><p align=center><b>%2</b></p>"
199 "<p>for your S/MIME signing certificate</p><p align=center>%1</p>"
200 "<p>expired less than a day ago.</p>");
201 } else if (isOwnKey) {
202 msg = ki18n(
203 "<p>The intermediate CA certificate</p><p align=center><b>%2</b></p>"
204 "<p>for your S/MIME encryption certificate</p><p align=center>%1</p>"
205 "<p>expired less than a day ago.</p>");
206 } else {
207 msg = ki18n(
208 "<p>The intermediate CA certificate</p><p align=center><b>%2</b></p>"
209 "<p>for S/MIME certificate</p><p align=center>%1</p>"
210 "<p>expired less than a day ago.</p>");
211 }
212 return msg.subs(userCertInfo).subs(Kleo::DN(key.userID(0).id()).prettyDN()).toString();
213 }
215 if (isSigningKey) {
216 msg = ki18np(
217 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
218 "<p>for your S/MIME signing certificate</p><p align=center>%2</p>"
219 "<p>expired yesterday.</p>",
220 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
221 "<p>for your S/MIME signing certificate</p><p align=center>%2</p>"
222 "<p>expired %1 days ago.</p>");
223 } else if (isOwnKey) {
224 msg = ki18np(
225 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
226 "<p>for your S/MIME encryption certificate</p><p align=center>%2</p>"
227 "<p>expired yesterday.</p>",
228 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
229 "<p>for your S/MIME encryption certificate</p><p align=center>%2</p>"
230 "<p>expired %1 days ago.</p>");
231 } else {
232 msg = ki18np(
233 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
234 "<p>for S/MIME certificate</p><p align=center>%2</p>"
235 "<p>expired yesterday.</p>",
236 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
237 "<p>for S/MIME certificate</p><p align=center>%2</p>"
238 "<p>expired %1 days ago.</p>");
239 }
240 return msg.subs(expiration.duration.count()).subs(userCertInfo).subs(Kleo::DN(key.userID(0).id()).prettyDN()).toString();
241 }
242 } else {
243 if (expiration.duration.count() == 0) {
245 if (isSigningKey) {
246 msg = ki18n("<p>Your S/MIME signing certificate</p><p align=center>%1</p><p>expired less than a day ago.</p>");
247 } else if (isOwnKey) {
248 msg = ki18n("<p>Your S/MIME encryption certificate</p><p align=center>%1</p><p>expired less than a day ago.</p>");
249 } else {
250 msg = ki18n("<p>The S/MIME certificate for</p><p align=center>%1</p><p>expired less than a day ago.</p>");
251 }
252 return msg.subs(userCertInfo).toString();
253 }
255 if (isSigningKey) {
256 msg = ki18np("<p>Your S/MIME signing certificate</p><p align=center>%2</p><p>expired yesterday.</p>",
257 "<p>Your S/MIME signing certificate</p><p align=center>%2</p><p>expired %1 days ago.</p>");
258 } else if (isOwnKey) {
259 msg = ki18np("<p>Your S/MIME encryption certificate</p><p align=center>%2</p><p>expired yesterday.</p>",
260 "<p>Your S/MIME encryption certificate</p><p align=center>%2</p><p>expired %1 days ago.</p>");
261 } else {
262 msg = ki18np("<p>The S/MIME certificate for</p><p align=center>%2</p><p>expired yesterday.</p>",
263 "<p>The S/MIME certificate for</p><p align=center>%2</p><p>expired %1 days ago.</p>");
264 }
265 return msg.subs(expiration.duration.count()).subs(userCertInfo).toString();
266 }
267 }
268 qCDebug(LIBKLEO_LOG) << "Certificate" << key << "expires in" << expiration.duration.count() << "days";
269 if (ca) {
270 if (key.isRoot()) {
271 if (expiration.duration.count() == 0) {
273 if (isSigningKey) {
274 msg = ki18n(
275 "<p>The root certificate</p><p align=center><b>%3</b></p>"
276 "<p>for your S/MIME signing certificate</p><p align=center>%2</p>"
277 "<p>expires today.</p>");
278 } else if (isOwnKey) {
279 msg = ki18n(
280 "<p>The root certificate</p><p align=center><b>%3</b></p>"
281 "<p>for your S/MIME encryption certificate</p><p align=center>%2</p>"
282 "<p>expires today.</p>");
283 } else {
284 msg = ki18n(
285 "<p>The root certificate</p><p align=center><b>%3</b></p>"
286 "<p>for S/MIME certificate</p><p align=center>%2</p>"
287 "<p>expires today.</p>");
288 }
289 return msg.subs(userCertInfo).subs(Kleo::DN(key.userID(0).id()).prettyDN()).toString();
290 }
292 if (isSigningKey) {
293 msg = ki18np(
294 "<p>The root certificate</p><p align=center><b>%3</b></p>"
295 "<p>for your S/MIME signing certificate</p><p align=center>%2</p>"
296 "<p>expires tomorrow.</p>",
297 "<p>The root certificate</p><p align=center><b>%3</b></p>"
298 "<p>for your S/MIME signing certificate</p><p align=center>%2</p>"
299 "<p>expires in %1 days.</p>");
300 } else if (isOwnKey) {
301 msg = ki18np(
302 "<p>The root certificate</p><p align=center><b>%3</b></p>"
303 "<p>for your S/MIME encryption certificate</p><p align=center>%2</p>"
304 "<p>expires tomorrow.</p>",
305 "<p>The root certificate</p><p align=center><b>%3</b></p>"
306 "<p>for your S/MIME encryption certificate</p><p align=center>%2</p>"
307 "<p>expires in %1 days.</p>");
308 } else {
309 msg = ki18np(
310 "<p>The root certificate</p><p align=center><b>%3</b></p>"
311 "<p>for S/MIME certificate</p><p align=center>%2</p>"
312 "<p>expires tomorrow.</p>",
313 "<p>The root certificate</p><p align=center><b>%3</b></p>"
314 "<p>for S/MIME certificate</p><p align=center>%2</p>"
315 "<p>expires in %1 days.</p>");
316 }
317 return msg.subs(expiration.duration.count()).subs(userCertInfo).subs(Kleo::DN(key.userID(0).id()).prettyDN()).toString();
318 }
319 if (expiration.duration.count() == 0) {
321 if (isSigningKey) {
322 msg = ki18n(
323 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
324 "<p>for your S/MIME signing certificate</p><p align=center>%2</p>"
325 "<p>expires today.</p>");
326 } else if (isOwnKey) {
327 msg = ki18n(
328 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
329 "<p>for your S/MIME encryption certificate</p><p align=center>%2</p>"
330 "<p>expires today.</p>");
331 } else {
332 msg = ki18n(
333 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
334 "<p>for S/MIME certificate</p><p align=center>%2</p>"
335 "<p>expires today.</p>");
336 }
337 }
339 if (isSigningKey) {
340 msg = ki18np(
341 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
342 "<p>for your S/MIME signing certificate</p><p align=center>%2</p>"
343 "<p>expires tomorrow.</p>",
344 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
345 "<p>for your S/MIME signing certificate</p><p align=center>%2</p>"
346 "<p>expires in %1 days.</p>");
347 } else if (isOwnKey) {
348 msg = ki18np(
349 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
350 "<p>for your S/MIME encryption certificate</p><p align=center>%2</p>"
351 "<p>expires tomorrow.</p>",
352 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
353 "<p>for your S/MIME encryption certificate</p><p align=center>%2</p>"
354 "<p>expires in %1 days.</p>");
355 } else {
356 msg = ki18np(
357 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
358 "<p>for S/MIME certificate</p><p align=center>%2</p>"
359 "<p>expires tomorrow.</p>",
360 "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
361 "<p>for S/MIME certificate</p><p align=center>%2</p>"
362 "<p>expires in %1 days.</p>");
363 }
364 return msg.subs(expiration.duration.count()).subs(userCertInfo).subs(Kleo::DN(key.userID(0).id()).prettyDN()).toString();
365 }
366 if (expiration.duration.count() == 0) {
368 if (isSigningKey) {
369 msg = ki18n("<p>Your S/MIME signing certificate</p><p align=center>%2</p><p>expires today.</p>");
370 } else if (isOwnKey) {
371 msg = ki18n("<p>Your S/MIME encryption certificate</p><p align=center>%2</p><p>expires today.</p>");
372 } else {
373 msg = ki18n("<p>The S/MIME certificate for</p><p align=center>%2</p><p>expires today.</p>");
374 }
375 return msg.subs(userCertInfo).toString();
376 }
378 if (isSigningKey) {
379 msg = ki18np(
380 "<p>Your S/MIME signing certificate</p><p align=center>%2</p>"
381 "<p>expires tomorrow.</p>",
382 "<p>Your S/MIME signing certificate</p><p align=center>%2</p>"
383 "<p>expires in %1 days.</p>");
384 } else if (isOwnKey) {
385 msg = ki18np(
386 "<p>Your S/MIME encryption certificate</p><p align=center>%2</p>"
387 "<p>expires tomorrow.</p>",
388 "<p>Your S/MIME encryption certificate</p><p align=center>%2</p>"
389 "<p>expires in %1 days.</p>");
390 } else {
391 msg = ki18np(
392 "<p>The S/MIME certificate for</p><p align=center>%2</p>"
393 "<p>expires tomorrow.</p>",
394 "<p>The S/MIME certificate for</p><p align=center>%2</p>"
395 "<p>expires in %1 days.</p>");
396 }
397 return msg.subs(expiration.duration.count()).subs(userCertInfo).toString();
398}
399
400static GpgME::Subkey findBestSubkey(const GpgME::Key &key, ExpiryChecker::CheckFlags usageFlags)
401{
402 // find the subkey with the latest expiration date for the given usage flags
403 if (!(usageFlags & ExpiryChecker::UsageMask)) {
404 // return primary key if no specific usage is specified (as for chain certificates)
405 return key.subkey(0);
406 }
407 GpgME::Subkey result;
408 for (unsigned int i = 0; i < key.numSubkeys(); ++i) {
409 const auto subkey = key.subkey(i);
410 if (subkey.isRevoked() || subkey.isInvalid() || subkey.isDisabled()) {
411 // unusable subkey
412 continue;
413 }
414 if (((usageFlags & ExpiryChecker::EncryptionKey) && !subkey.canEncrypt()) //
415 || ((usageFlags & ExpiryChecker::SigningKey) && !subkey.canSign()) //
416 || ((usageFlags & ExpiryChecker::CertificationKey) && !subkey.canCertify())) {
417 // unsuitable subkey for requested usage
418 continue;
419 }
420 if (subkey.neverExpires()) {
421 // stop looking for the best subkey if we found a suitable subkey that doesn't expire;
422 // return the primary key because a non-expiring subkey inherits the primary key's expiration
423 return key.subkey(0);
424 }
425 if (quint32(subkey.expirationTime()) > quint32(result.expirationTime())) {
426 result = subkey;
427 }
428 }
429 return result;
430}
431
432ExpiryChecker::Expiration ExpiryCheckerPrivate::calculateExpiration(const GpgME::Subkey &subkey) const
433{
434 if (subkey.neverExpires()) {
435 return {subkey.parent(), ExpiryChecker::NotNearExpiry, Kleo::chrono::days::zero()};
436 }
437 const time_t currentTime = timeProvider ? timeProvider->currentTime() : std::time(nullptr);
438 const auto currentDate = timeProvider ? timeProvider->currentDate() : QDate::currentDate();
439 const auto timeSpec = timeProvider ? timeProvider->timeSpec() : Qt::LocalTime;
440 const time_t expirationTime = subkey.expirationTime();
441 const auto expirationDate = QDateTime::fromSecsSinceEpoch(quint32(expirationTime), timeSpec).date();
442 // use std::difftime to avoid problems with negative values on 32-bit systems
443 if (std::difftime(expirationTime, currentTime) <= 0) {
444 return {subkey.parent(), ExpiryChecker::Expired, Kleo::chrono::days{expirationDate.daysTo(currentDate)}};
445 } else {
446 return {subkey.parent(), ExpiryChecker::ExpiresSoon, Kleo::chrono::days{currentDate.daysTo(expirationDate)}};
447 }
448}
449
450ExpiryChecker::Expiration ExpiryCheckerPrivate::checkForExpiration(const GpgME::Key &key, //
451 Kleo::chrono::days threshold,
452 ExpiryChecker::CheckFlags usageFlags) const
453{
454 const auto subkey = findBestSubkey(key, usageFlags);
455 if (subkey.isNull()) {
456 return {key, ExpiryChecker::NoSuitableSubkey, {}};
457 }
458 ExpiryChecker::Expiration expiration = calculateExpiration(subkey);
459 if ((expiration.status == ExpiryChecker::ExpiresSoon) && (expiration.duration > threshold)) {
460 // key expires, but not too soon
461 expiration.status = ExpiryChecker::NotNearExpiry;
462 }
463 return expiration;
464}
465
466ExpiryChecker::Result ExpiryCheckerPrivate::checkKeyNearExpiry(const GpgME::Key &orig_key, ExpiryChecker::CheckFlags flags)
467{
468 static const int maximumCertificateChainLength = 100;
469 const bool isOwnKey = flags & ExpiryChecker::OwnKey;
470
471 ExpiryChecker::Result result;
472 result.checkFlags = flags;
473 result.expiration.certificate = orig_key;
474
475 // use vector instead of set because certificate chains are usually very short
476 std::vector<std::string> checkedCertificates;
477 auto key = orig_key;
478 for (int chainCount = 0; chainCount < maximumCertificateChainLength; ++chainCount) {
479 checkedCertificates.push_back(key.primaryFingerprint());
480
481 const GpgME::Subkey subkey = key.subkey(0);
482
483 const bool newMessage = !alreadyWarnedFingerprints.count(subkey.fingerprint());
484
485 const auto threshold = chainCount > 0 //
486 ? (key.isRoot() ? settings.rootCertThreshold() : settings.chainCertThreshold()) //
487 : (isOwnKey ? settings.ownKeyThreshold() : settings.otherKeyThreshold());
488 const auto usageFlags = (chainCount == 0) ? (flags & ExpiryChecker::UsageMask) : ExpiryChecker::CheckFlags{};
489 const auto expiration = checkForExpiration(key, threshold, usageFlags);
490 if (chainCount == 0) {
491 result.expiration = expiration;
492 } else if (expiration.status != ExpiryChecker::NotNearExpiry) {
493 result.chainExpiration.push_back(expiration);
494 }
495 if (expiration.status == ExpiryChecker::Expired) {
496 const QString msg = key.protocol() == GpgME::OpenPGP //
497 ? formatOpenPGPMessage(expiration, flags)
498 : formatSMIMEMessage(orig_key, expiration, flags, chainCount > 0);
499 alreadyWarnedFingerprints.insert(subkey.fingerprint());
500 Q_EMIT q->expiryMessage(key, msg, isOwnKey ? ExpiryChecker::OwnKeyExpired : ExpiryChecker::OtherKeyExpired, newMessage);
501 } else if (expiration.status == ExpiryChecker::ExpiresSoon) {
502 const QString msg = key.protocol() == GpgME::OpenPGP //
503 ? formatOpenPGPMessage(expiration, flags)
504 : formatSMIMEMessage(orig_key, expiration, flags, chainCount > 0);
505 alreadyWarnedFingerprints.insert(subkey.fingerprint());
506 Q_EMIT q->expiryMessage(key, msg, isOwnKey ? ExpiryChecker::OwnKeyNearExpiry : ExpiryChecker::OtherKeyNearExpiry, newMessage);
507 } else if (expiration.status == ExpiryChecker::NoSuitableSubkey) {
508 break;
509 }
510 if (!(flags & ExpiryChecker::CheckChain) || key.isRoot() || (key.protocol() != GpgME::CMS)) {
511 break;
512 }
513 const auto keys = KeyCache::instance()->findIssuers(key, KeyCache::NoOption);
514 if (keys.empty()) {
515 break;
516 }
517 key = keys.front();
518 if (Kleo::contains(checkedCertificates, key.primaryFingerprint())) {
519 break; // this certificate was already checked (looks like a circle in the chain)
520 }
521 }
522 return result;
523}
524
525ExpiryChecker::Result ExpiryChecker::checkKey(const GpgME::Key &key, CheckFlags flags) const
526{
527 if (key.isNull()) {
528 qWarning(LIBKLEO_LOG) << __func__ << "called with null key";
529 return {flags, {key, InvalidKey, {}}, {}};
530 }
531 if (!(flags & UsageMask)) {
532 qWarning(LIBKLEO_LOG) << __func__ << "called with invalid flags:" << flags;
533 return {flags, {key, InvalidCheckFlags, {}}, {}};
534 }
535 return d->checkKeyNearExpiry(key, flags);
536}
537
538void ExpiryChecker::setTimeProviderForTest(const std::shared_ptr<TimeProvider> &timeProvider)
539{
540 d->timeProvider = timeProvider;
541}
542
543#include "moc_expirychecker.cpp"
QString toString() const
KLocalizedString subs(const KLocalizedString &a, int fieldWidth=0, QChar fillChar=QLatin1Char(' ')) const
DN parser and reorderer.
Definition dn.h:27
QString prettyDN() const
Definition dn.cpp:439
KLocalizedString KI18N_EXPORT ki18np(const char *singular, const char *plural)
KLocalizedString KI18N_EXPORT ki18n(const char *text)
KLocalizedString KI18N_EXPORT ki18nc(const char *context, const char *text)
QDate currentDate()
qint64 daysTo(QDate d) const const
QDate date() const const
QDateTime fromSecsSinceEpoch(qint64 secs)
QString fromLatin1(QByteArrayView str)
QString fromUtf8(QByteArrayView str)
LocalTime
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 3 2024 11:44:55 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.