Libkleo

keyparameters.cpp
1/* -*- mode: c++; c-basic-offset:4 -*-
2 utils/keyparameters.cpp
3
4 This file is part of Libkleo
5 SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
6
7 SPDX-FileCopyrightText: 2020, 2022 g10 Code GmbH
8 SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
9
10 SPDX-License-Identifier: GPL-2.0-or-later
11*/
12
13#include "keyparameters.h"
14
15#include <Libkleo/KeyUsage>
16
17#include <QDate>
18#include <QUrl>
19
20#include "libkleo_debug.h"
21
22using namespace Kleo;
23using namespace GpgME;
24using namespace Qt::StringLiterals;
25
26namespace
27{
28QString encodeDomainName(const QString &domain)
29{
30 const QByteArray encodedDomain = QUrl::toAce(domain);
31 return encodedDomain.isEmpty() ? domain : QString::fromLatin1(encodedDomain);
32}
33
34QString encodeEmail(const QString &email)
35{
36 const int at = email.lastIndexOf(QLatin1Char('@'));
37 if (at < 0) {
38 return email;
39 }
40 return email.left(at + 1) + encodeDomainName(email.mid(at + 1));
41}
42}
43
44class KeyParameters::Private
45{
46 friend class ::Kleo::KeyParameters;
47
48 Protocol protocol;
49
50 Subkey::PubkeyAlgo keyType = Subkey::AlgoUnknown;
51 QString cardKeyRef;
52 unsigned int keyLength = 0;
53 QString keyCurve;
54 KeyUsage keyUsage;
55
56 Subkey::PubkeyAlgo subkeyType = Subkey::AlgoUnknown;
57 unsigned int subkeyLength = 0;
58 QString subkeyCurve;
59 KeyUsage subkeyUsage;
60
61 QString name;
62 QString comment;
63 QString dn;
64 std::vector<QString> emailAdresses;
65 std::vector<QString> domainNames;
66 std::vector<QString> uris;
67 QString serial;
68 QString signingKey;
69
70 QDate expirationDate;
71
72 QString issuerDN;
73 QStringList controlStatements;
74
75public:
76 explicit Private(Protocol proto)
77 : protocol(proto)
78 {
79 }
80};
81
82KeyParameters::KeyParameters()
83 : KeyParameters{NoProtocol}
84{
85}
86
87KeyParameters::KeyParameters(Protocol protocol)
88 : d{new Private{protocol}}
89{
90}
91
92KeyParameters::~KeyParameters() = default;
93
94KeyParameters::KeyParameters(const KeyParameters &other)
95 : d{new Private{*other.d}}
96{
97}
98
99KeyParameters &KeyParameters::operator=(const KeyParameters &other)
100{
101 *d = *other.d;
102 return *this;
103}
104
105KeyParameters::KeyParameters(KeyParameters &&other) = default;
106
107KeyParameters &KeyParameters::operator=(KeyParameters &&other) = default;
108
109KeyParameters::Protocol KeyParameters::protocol() const
110{
111 return d->protocol;
112}
113
114void KeyParameters::setKeyType(Subkey::PubkeyAlgo type)
115{
116 d->keyType = type;
117}
118
119GpgME::Subkey::PubkeyAlgo KeyParameters::keyType() const
120{
121 return d->keyType;
122}
123
124void KeyParameters::setCardKeyRef(const QString &cardKeyRef)
125{
126 d->cardKeyRef = cardKeyRef;
127}
128
129QString KeyParameters::cardKeyRef() const
130{
131 return d->cardKeyRef;
132}
133
134void KeyParameters::setKeyLength(unsigned int length)
135{
136 d->keyLength = length;
137}
138
139unsigned int KeyParameters::keyLength() const
140{
141 return d->keyLength;
142}
143
144void KeyParameters::setKeyCurve(const QString &curve)
145{
146 d->keyCurve = curve;
147}
148
149QString KeyParameters::keyCurve() const
150{
151 return d->keyCurve;
152}
153
154void KeyParameters::setKeyUsage(const KeyUsage &usage)
155{
156 d->keyUsage = usage;
157}
158
159KeyUsage KeyParameters::keyUsage() const
160{
161 return d->keyUsage;
162}
163
164void KeyParameters::setSubkeyType(Subkey::PubkeyAlgo type)
165{
166 d->subkeyType = type;
167}
168
169Subkey::PubkeyAlgo KeyParameters::subkeyType() const
170{
171 return d->subkeyType;
172}
173
174void KeyParameters::setSubkeyLength(unsigned int length)
175{
176 d->subkeyLength = length;
177}
178
179unsigned int KeyParameters::subkeyLength() const
180{
181 return d->subkeyLength;
182}
183
184void KeyParameters::setSubkeyCurve(const QString &curve)
185{
186 d->subkeyCurve = curve;
187}
188
189QString KeyParameters::subkeyCurve() const
190{
191 return d->subkeyCurve;
192}
193
194void KeyParameters::setSubkeyUsage(const KeyUsage &usage)
195{
196 d->subkeyUsage = usage;
197}
198
199KeyUsage KeyParameters::subkeyUsage() const
200{
201 return d->subkeyUsage;
202}
203
204void KeyParameters::setExpirationDate(const QDate &date)
205{
206 d->expirationDate = date;
207}
208
209QDate KeyParameters::expirationDate() const
210{
211 return d->expirationDate;
212}
213
214void KeyParameters::setName(const QString &name)
215{
216 d->name = name;
217}
218
219QString KeyParameters::name() const
220{
221 return d->name;
222}
223
224void KeyParameters::setComment(const QString &comment)
225{
226 d->comment = comment;
227}
228
229QString KeyParameters::comment() const
230{
231 return d->comment;
232}
233
234void KeyParameters::setDN(const QString &dn)
235{
236 d->dn = dn;
237}
238
239QString KeyParameters::dn() const
240{
241 return d->dn;
242}
243
244void KeyParameters::setEmail(const QString &email)
245{
246 d->emailAdresses = {email};
247}
248
249void KeyParameters::addEmail(const QString &email)
250{
251 d->emailAdresses.push_back(email);
252}
253
254const std::vector<QString> &KeyParameters::emails() const
255{
256 return d->emailAdresses;
257}
258
259void KeyParameters::addDomainName(const QString &domain)
260{
261 d->domainNames.push_back(domain);
262}
263
264const std::vector<QString> &KeyParameters::domainNames() const
265{
266 return d->domainNames;
267}
268
269void KeyParameters::addURI(const QString &uri)
270{
271 d->uris.push_back(uri);
272}
273
274const std::vector<QString> &KeyParameters::uris() const
275{
276 return d->uris;
277}
278
279QString KeyParameters::serial() const
280{
281 return d->serial;
282}
283
284void KeyParameters::setSerial(const QString &serial)
285{
286 d->serial = serial;
287}
288
289void KeyParameters::setUseRandomSerial()
290{
291 d->serial = u"random"_s;
292}
293
294QString KeyParameters::issuerDN() const
295{
296 return d->issuerDN;
297}
298
299void KeyParameters::setIssuerDN(const QString &issuerDN)
300{
301 d->issuerDN = issuerDN;
302}
303
304QString KeyParameters::signingKey() const
305{
306 return d->signingKey;
307}
308
309void KeyParameters::setSigningKey(const QString &signingKey)
310{
311 d->signingKey = signingKey;
312}
313
314QStringList KeyParameters::controlStatements() const
315{
316 return d->controlStatements;
317}
318
319void KeyParameters::setControlStatements(const QStringList &controlStatements)
320{
321 QStringList validControlStatements;
322 for (const auto &controlStatement : controlStatements) {
323 if (controlStatement.startsWith(u'%')) {
324 validControlStatements << controlStatements;
325 } else {
326 qCWarning(LIBKLEO_LOG).nospace() << "Invalid control statement \"" << controlStatement << "\". Control statements start with a %";
327 }
328 }
329 d->controlStatements = validControlStatements;
330}
331
332namespace
333{
334QString serialize(Subkey::PubkeyAlgo algo)
335{
336 return QString::fromLatin1(Subkey::publicKeyAlgorithmAsString(algo));
337}
338
339QString serialize(unsigned int number)
340{
341 return QString::number(number);
342}
343
344QString serialize(KeyUsage keyUsage)
345{
346 QStringList usages;
347 if (keyUsage.canSign()) {
348 usages << QStringLiteral("sign");
349 }
350 if (keyUsage.canEncrypt()) {
351 usages << QStringLiteral("encrypt");
352 }
353 if (keyUsage.canAuthenticate()) {
354 usages << QStringLiteral("auth");
355 }
356 if (keyUsage.canCertify()) {
357 usages << QStringLiteral("cert");
358 }
359 return usages.join(QLatin1Char{' '});
360}
361
362QString serialize(const QDate &date)
363{
364 return date.toString(Qt::ISODate);
365}
366
367QString serialize(const char *key, const QString &value)
368{
369 return QString::fromLatin1(key) + QLatin1Char(':') + value;
370}
371}
372
373QString KeyParameters::toString() const
374{
375 QStringList keyParameters;
376
377 keyParameters.push_back(QLatin1StringView("<GnupgKeyParms format=\"internal\">"));
378
379 if (d->protocol == OpenPGP) {
380 // for backward compatibility with GnuPG 2.0 and earlier
381 keyParameters.push_back(QStringLiteral("%ask-passphrase"));
382 }
383
384 // add Key-Type as first parameter
385 if (!d->cardKeyRef.isEmpty()) {
386 keyParameters.push_back(serialize("Key-Type", QLatin1StringView{"card:"} + d->cardKeyRef));
387 } else if (d->keyType != Subkey::AlgoUnknown) {
388 keyParameters.push_back(serialize("Key-Type", serialize(d->keyType)));
389 } else {
390 qCWarning(LIBKLEO_LOG) << "KeyParameters::toString(): Key type is unset/empty";
391 }
392 if (d->keyLength) {
393 keyParameters.push_back(serialize("Key-Length", serialize(d->keyLength)));
394 }
395 if (!d->keyCurve.isEmpty()) {
396 keyParameters.push_back(serialize("Key-Curve", d->keyCurve));
397 }
398 keyParameters.push_back(serialize("Key-Usage", serialize(d->keyUsage)));
399
400 if (d->subkeyType != Subkey::AlgoUnknown) {
401 keyParameters.push_back(serialize("Subkey-Type", serialize(d->subkeyType)));
402 if (d->subkeyUsage.value()) {
403 keyParameters.push_back(serialize("Subkey-Usage", serialize(d->subkeyUsage)));
404 }
405 if (d->subkeyLength) {
406 keyParameters.push_back(serialize("Subkey-Length", serialize(d->subkeyLength)));
407 }
408 if (!d->subkeyCurve.isEmpty()) {
409 keyParameters.push_back(serialize("Subkey-Curve", d->subkeyCurve));
410 }
411 }
412
413 if (d->expirationDate.isValid()) {
414 keyParameters.push_back(serialize("Expire-Date", serialize(d->expirationDate)));
415 }
416
417 if (!d->serial.isEmpty()) {
418 keyParameters.push_back(serialize("Serial", d->serial));
419 }
420
421 if (!d->issuerDN.isEmpty()) {
422 keyParameters.push_back(serialize("Issuer-DN", d->issuerDN));
423 }
424
425 if (!d->issuerDN.isEmpty()) {
426 keyParameters.push_back(serialize("Signing-Key", d->signingKey));
427 }
428
429 if (!d->name.isEmpty()) {
430 keyParameters.push_back(serialize("Name-Real", d->name));
431 }
432 if (!d->comment.isEmpty()) {
433 keyParameters.push_back(serialize("Name-Comment", d->comment));
434 }
435 if (!d->dn.isEmpty()) {
436 keyParameters.push_back(serialize("Name-DN", d->dn));
437 }
438 std::transform(std::cbegin(d->emailAdresses), std::cend(d->emailAdresses), std::back_inserter(keyParameters), [this](const auto &email) {
439 return serialize("Name-Email", (d->protocol == CMS) ? encodeEmail(email) : email);
440 });
441 std::transform(std::cbegin(d->domainNames), std::cend(d->domainNames), std::back_inserter(keyParameters), [](const auto &domain) {
442 return serialize("Name-DNS", encodeDomainName(domain));
443 });
444 std::transform(std::cbegin(d->uris), std::cend(d->uris), std::back_inserter(keyParameters), [](const auto &uri) {
445 return serialize("Name-URI", uri);
446 });
447
448 for (const auto &controlStatement : d->controlStatements) {
449 keyParameters.push_back(controlStatement);
450 }
451
452 keyParameters.push_back(QLatin1StringView("</GnupgKeyParms>"));
453
454 return keyParameters.join(QLatin1Char('\n'));
455}
Type type(const QSqlDatabase &db)
bool isEmpty() const const
QString toString(QStringView format, QCalendar cal) const const
void push_back(parameter_type value)
QString fromLatin1(QByteArrayView str)
qsizetype lastIndexOf(QChar ch, Qt::CaseSensitivity cs) const const
QString number(double n, char format, int precision)
QString join(QChar separator) const const
QByteArray toAce(const QString &domain, AceProcessingOptions options)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Apr 11 2025 11:53:31 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.