7 #include "composer/nearexpirychecker.h"
8 #include "composer/nearexpirychecker_p.h"
10 #include "messagecomposer_debug.h"
14 #include <QGpgME/KeyListJob>
15 #include <QGpgME/Protocol>
17 #include <gpgme++/keylistresult.h>
19 #include <KLocalizedString>
25 NearExpiryChecker::NearExpiryChecker(
int encrOwnKeyNearExpiryThresholdDays,
26 int encrKeyNearExpiryThresholdDays,
27 int encrRootCertNearExpiryThresholdDays,
28 int encrChainCertNearExpiryThresholdDays)
29 : d(new NearExpiryCheckerPrivate)
31 d->encryptOwnKeyNearExpiryWarningThreshold = encrOwnKeyNearExpiryThresholdDays;
32 d->encryptKeyNearExpiryWarningThreshold = encrKeyNearExpiryThresholdDays;
33 d->encryptRootCertNearExpiryWarningThreshold = encrRootCertNearExpiryThresholdDays;
34 d->encryptChainCertNearExpiryWarningThreshold = encrChainCertNearExpiryThresholdDays;
37 NearExpiryChecker::~NearExpiryChecker() =
default;
39 int NearExpiryChecker::encryptOwnKeyNearExpiryWarningThresholdInDays()
const
41 return d->encryptOwnKeyNearExpiryWarningThreshold;
44 int NearExpiryChecker::encryptKeyNearExpiryWarningThresholdInDays()
const
46 return d->encryptKeyNearExpiryWarningThreshold;
49 int NearExpiryChecker::encryptRootCertNearExpiryWarningThresholdInDays()
const
51 return d->encryptRootCertNearExpiryWarningThreshold;
54 int NearExpiryChecker::encryptChainCertNearExpiryWarningThresholdInDays()
const
56 return d->encryptChainCertNearExpiryWarningThreshold;
59 QString formatOpenPGPMessage(
const GpgME::Key &key,
int secsTillExpiry,
bool isOwnKey,
bool isSigningKey)
62 static const double secsPerDay = 24 * 60 * 60;
63 const int daysTillExpiry = 1 + int(abs(secsTillExpiry) / secsPerDay);
64 if (secsTillExpiry <= 0) {
65 qCDebug(MESSAGECOMPOSER_LOG) <<
"Key 0x" << key.keyID() <<
" expired " << daysTillExpiry <<
" days ago";
68 "<p>Your OpenPGP signing key</p><p align=center><b>%2</b> (KeyID 0x%3)</p>"
69 "<p>expired less than a day ago.</p>",
70 "<p>Your OpenPGP signing key</p><p align=center><b>%2</b> (KeyID 0x%3)</p>"
71 "<p>expired %1 days ago.</p>");
72 }
else if (isOwnKey) {
74 "<p>Your OpenPGP encryption key</p><p align=center><b>%2</b> (KeyID 0x%3)</p>"
75 "<p>expired less than a day ago.</p>",
76 "<p>Your OpenPGP encryption key</p><p align=center><b>%2</b> (KeyID 0x%3)</p>"
77 "<p>expired %1 days ago.</p>");
80 "<p>The OpenPGP key for</p><p align=center><b>%2</b> (KeyID 0x%3)</p>"
81 "<p>expired less than a day ago.</p>",
82 "<p>The OpenPGP key for</p><p align=center><b>%2</b> (KeyID 0x%3)</p>"
83 "<p>expired %1 days ago.</p>");
86 qCDebug(MESSAGECOMPOSER_LOG) <<
"Key 0x" << key.keyID() <<
" expires in less than " << daysTillExpiry <<
" days";
89 "<p>Your OpenPGP signing key</p><p align=center><b>%2</b> (KeyID 0x%3)</p>"
90 "<p>expires in less than a day.</p>",
91 "<p>Your OpenPGP signing key</p><p align=center><b>%2</b> (KeyID 0x%3)</p>"
92 "<p>expires in less than %1 days.</p>");
93 }
else if (isOwnKey) {
95 "<p>Your OpenPGP encryption key</p><p align=center><b>%2</b> (KeyID 0x%3)</p>"
96 "<p>expires in less than a day.</p>",
97 "<p>Your OpenPGP encryption key</p><p align=center><b>%2</b> (KeyID 0x%3)</p>"
98 "<p>expires in less than %1 days.</p>");
101 "<p>The OpenPGP key for</p><p align=center><b>%2</b> (KeyID 0x%3)</p>"
102 "<p>expires in less than a day.</p>",
103 "<p>The OpenPGP key for</p><p align=center><b>%2</b> (KeyID 0x%3)</p>"
104 "<p>expires in less than %1 days.</p>");
110 QString formatSMIMEMessage(
const GpgME::Key &key,
const GpgME::Key &orig_key,
int secsTillExpiry,
bool isOwnKey,
bool isSigningKey,
bool ca)
113 static const double secsPerDay = 24 * 60 * 60;
114 const int daysTillExpiry = 1 + int(abs(secsTillExpiry) / secsPerDay);
115 if (secsTillExpiry <= 0) {
116 qCDebug(MESSAGECOMPOSER_LOG) <<
"Key 0x" << key.keyID() <<
" expired " << daysTillExpiry <<
" days ago";
121 "<p>The root certificate</p><p align=center><b>%4</b></p>"
122 "<p>for your S/MIME signing certificate</p><p align=center><b>%2</b> (serial number %3)</p>"
123 "<p>expired less than a day ago.</p>",
124 "<p>The root certificate</p><p align=center><b>%4</b></p>"
125 "<p>for your S/MIME signing certificate</p><p align=center><b>%2</b> (serial number %3)</p>"
126 "<p>expired %1 days ago.</p>");
127 }
else if (isOwnKey) {
129 "<p>The root certificate</p><p align=center><b>%4</b></p>"
130 "<p>for your S/MIME encryption certificate</p><p align=center><b>%2</b> (serial number %3)</p>"
131 "<p>expired less than a day ago.</p>",
132 "<p>The root certificate</p><p align=center><b>%4</b></p>"
133 "<p>for your S/MIME encryption certificate</p><p align=center><b>%2</b> (serial number %3)</p>"
134 "<p>expired %1 days ago.</p>");
137 "<p>The root certificate</p><p align=center><b>%4</b></p>"
138 "<p>for S/MIME certificate</p><p align=center><b>%2</b> (serial number %3)</p>"
139 "<p>expired less than a day ago.</p>",
140 "<p>The root certificate</p><p align=center><b>%4</b></p>"
141 "<p>for S/MIME certificate</p><p align=center><b>%2</b> (serial number %3)</p>"
142 "<p>expired %1 days ago.</p>");
147 "<p>The intermediate CA certificate</p><p align=center><b>%4</b></p>"
148 "<p>for your S/MIME signing certificate</p><p align=center><b>%2</b> (serial number %3)</p>"
149 "<p>expired less than a day ago.</p>",
150 "<p>The intermediate CA certificate</p><p align=center><b>%4</b></p>"
151 "<p>for your S/MIME signing certificate</p><p align=center><b>%2</b> (serial number %3)</p>"
152 "<p>expired %1 days ago.</p>");
153 }
else if (isOwnKey) {
155 "<p>The intermediate CA certificate</p><p align=center><b>%4</b></p>"
156 "<p>for your S/MIME encryption certificate</p><p align=center><b>%2</b> (serial number %3)</p>"
157 "<p>expired less than a day ago.</p>",
158 "<p>The intermediate CA certificate</p><p align=center><b>%4</b></p>"
159 "<p>for your S/MIME encryption certificate</p><p align=center><b>%2</b> (serial number %3)</p>"
160 "<p>expired %1 days ago.</p>");
163 "<p>The intermediate CA certificate</p><p align=center><b>%4</b></p>"
164 "<p>for S/MIME certificate</p><p align=center><b>%2</b> (serial number %3)</p>"
165 "<p>expired less than a day ago.</p>",
166 "<p>The intermediate CA certificate</p><p align=center><b>%4</b></p>"
167 "<p>for S/MIME certificate</p><p align=center><b>%2</b> (serial number %3)</p>"
168 "<p>expired %1 days ago.</p>");
171 return msg.
subs(daysTillExpiry)
179 "<p>Your S/MIME signing certificate</p><p align=center><b>%2</b> (serial number %3)</p>"
180 "<p>expired less than a day ago.</p>",
181 "<p>Your S/MIME signing certificate</p><p align=center><b>%2</b> (serial number %3)</p>"
182 "<p>expired %1 days ago.</p>");
183 }
else if (isOwnKey) {
185 "<p>Your S/MIME encryption certificate</p><p align=center><b>%2</b> (serial number %3)</p>"
186 "<p>expired less than a day ago.</p>",
187 "<p>Your S/MIME encryption certificate</p><p align=center><b>%2</b> (serial number %3)</p>"
188 "<p>expired %1 days ago.</p>");
191 "<p>The S/MIME certificate for</p><p align=center><b>%2</b> (serial number %3)</p>"
192 "<p>expired less than a day ago.</p>",
193 "<p>The S/MIME certificate for</p><p align=center><b>%2</b> (serial number %3)</p>"
194 "<p>expired %1 days ago.</p>");
199 qCDebug(MESSAGECOMPOSER_LOG) <<
"Key 0x" << key.keyID() <<
" expires in less than " << daysTillExpiry <<
" days";
204 "<p>The root certificate</p><p align=center><b>%4</b></p>"
205 "<p>for your S/MIME signing certificate</p><p align=center><b>%2</b> (serial number %3);</p>"
206 "<p>expires in less than a day.</p>",
207 "<p>The root certificate</p><p align=center><b>%4</b></p>"
208 "<p>for your S/MIME signing certificate</p><p align=center><b>%2</b> (serial number %3);</p>"
209 "<p>expires in less than %1 days.</p>");
210 }
else if (isOwnKey) {
212 "<p>The root certificate</p><p align=center><b>%4</b></p>"
213 "<p>for your S/MIME encryption certificate</p><p align=center><b>%2</b> (serial number %3);</p>"
214 "<p>expires in less than a day.</p>",
215 "<p>The root certificate</p><p align=center><b>%4</b></p>"
216 "<p>for your S/MIME encryption certificate</p><p align=center><b>%2</b> (serial number %3);</p>"
217 "<p>expires in less than %1 days.</p>");
220 "<p>The root certificate</p><p align=center><b>%4</b></p>"
221 "<p>for S/MIME certificate</p><p align=center><b>%2</b> (serial number %3);</p>"
222 "<p>expires in less than a day.</p>",
223 "<p>The root certificate</p><p align=center><b>%4</b></p>"
224 "<p>for S/MIME certificate</p><p align=center><b>%2</b> (serial number %3);</p>"
225 "<p>expires in less than %1 days.</p>");
230 "<p>The intermediate CA certificate</p><p align=center><b>%4</b></p>"
231 "<p>for your S/MIME signing certificate</p><p align=center><b>%2</b> (serial number %3);</p>"
232 "<p>expires in less than a day.</p>",
233 "<p>The intermediate CA certificate</p><p align=center><b>%4</b></p>"
234 "<p>for your S/MIME signing certificate</p><p align=center><b>%2</b> (serial number %3);</p>"
235 "<p>expires in less than %1 days.</p>");
236 }
else if (isOwnKey) {
238 "<p>The intermediate CA certificate</p><p align=center><b>%4</b></p>"
239 "<p>for your S/MIME encryption certificate</p><p align=center><b>%2</b> (serial number %3);</p>"
240 "<p>expires in less than a day.</p>",
241 "<p>The intermediate CA certificate</p><p align=center><b>%4</b></p>"
242 "<p>for your S/MIME encryption certificate</p><p align=center><b>%2</b> (serial number %3);</p>"
243 "<p>expires in less than %1 days.</p>");
246 "<p>The intermediate CA certificate</p><p align=center><b>%4</b></p>"
247 "<p>for S/MIME certificate</p><p align=center><b>%2</b> (serial number %3);</p>"
248 "<p>expires in less than a day.</p>",
249 "<p>The intermediate CA certificate</p><p align=center><b>%4</b></p>"
250 "<p>for S/MIME certificate</p><p align=center><b>%2</b> (serial number %3);</p>"
251 "<p>expires in less than %1 days.</p>");
254 return msg.
subs(daysTillExpiry)
262 "<p>Your S/MIME signing certificate</p><p align=center><b>%2</b> (serial number %3);</p>"
263 "<p>expires in less than a day.</p>",
264 "<p>Your S/MIME signing certificate</p><p align=center><b>%2</b> (serial number %3);</p>"
265 "<p>expires in less than %1 days.</p>");
266 }
else if (isOwnKey) {
268 "<p>Your S/MIME encryption certificate</p><p align=center><b>%2</b> (serial number %3);</p>"
269 "<p>expires in less than a day.</p>",
270 "<p>Your S/MIME encryption certificate</p><p align=center><b>%2</b> (serial number %3);</p>"
271 "<p>expires in less than %1 days.</p>");
274 "<p>The S/MIME certificate for</p><p align=center><b>%2</b> (serial number %3);</p>"
275 "<p>expires in less than a day.</p>",
276 "<p>The S/MIME certificate for</p><p align=center><b>%2</b> (serial number %3);</p>"
277 "<p>expires in less than %1 days.</p>");
284 double MessageComposer::NearExpiryChecker::calculateSecsTillExpiriy(
const GpgME::Subkey &key)
const
290 return ::difftime(key.expirationTime(), time(
nullptr));
293 void NearExpiryChecker::checkKeyNearExpiry(
const GpgME::Key &key,
bool isOwnKey,
bool isSigningKey,
bool ca,
int recur_limit,
const GpgME::Key &orig_key)
const
295 if (recur_limit <= 0) {
296 qCDebug(MESSAGECOMPOSER_LOG) <<
"Key chain too long (>100 certs)";
299 const GpgME::Subkey subkey = key.subkey(0);
301 const bool newMessage = !d->alreadyWarnedFingerprints.count(subkey.fingerprint());
303 if (subkey.neverExpires()) {
306 static const double secsPerDay = 24 * 60 * 60;
307 const double secsTillExpiry = calculateSecsTillExpiriy(subkey);
308 if (secsTillExpiry <= 0) {
309 const QString msg = key.protocol() == GpgME::OpenPGP ? formatOpenPGPMessage(key, secsTillExpiry, isOwnKey, isSigningKey)
310 : formatSMIMEMessage(key, orig_key, secsTillExpiry, isOwnKey, isSigningKey, ca);
311 d->alreadyWarnedFingerprints.
insert(subkey.fingerprint());
312 Q_EMIT expiryMessage(key, msg, isOwnKey ? OwnKeyExpired : OtherKeyExpired, newMessage);
314 const int daysTillExpiry = 1 + int(secsTillExpiry / secsPerDay);
315 const int threshold = ca ? (key.isRoot() ? encryptRootCertNearExpiryWarningThresholdInDays() : encryptChainCertNearExpiryWarningThresholdInDays())
316 : (isOwnKey ? encryptOwnKeyNearExpiryWarningThresholdInDays() : encryptKeyNearExpiryWarningThresholdInDays());
317 if (threshold > -1 && daysTillExpiry <= threshold) {
318 const QString msg = key.protocol() == GpgME::OpenPGP ? formatOpenPGPMessage(key, secsTillExpiry, isOwnKey, isSigningKey)
319 : formatSMIMEMessage(key, orig_key, secsTillExpiry, isOwnKey, isSigningKey, ca);
320 d->alreadyWarnedFingerprints.
insert(subkey.fingerprint());
321 Q_EMIT expiryMessage(key, msg, isOwnKey ? OwnKeyNearExpiry : OtherKeyNearExpiry, newMessage);
326 }
else if (key.protocol() != GpgME::CMS) {
328 }
else if (
const char *chain_id = key.chainID()) {
329 QGpgME::Protocol *p = QGpgME::smime();
331 std::unique_ptr<QGpgME::KeyListJob> job(p->keyListJob(
false,
false,
true));
333 std::vector<GpgME::Key> keys;
336 return checkKeyNearExpiry(keys.front(), isOwnKey, isSigningKey,
true, recur_limit - 1, ca ? orig_key : key);
342 void NearExpiryChecker::checkOwnSigningKey(
const GpgME::Key &key)
const
344 checkKeyNearExpiry(key,
true,
true);
347 void NearExpiryChecker::checkOwnKey(
const GpgME::Key &key)
const
349 checkKeyNearExpiry(key,
true,
false);
352 void NearExpiryChecker::checkKey(
const GpgME::Key &key)
const
354 checkKeyNearExpiry(key,
false,
false);