File indexing completed on 2024-06-23 05:14:17
0001 /* -*- mode: c++; c-basic-offset:4 -*- 0002 utils/keyparameters.cpp 0003 0004 This file is part of Kleopatra, the KDE keymanager 0005 SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB 0006 0007 SPDX-FileCopyrightText: 2020, 2022 g10 Code GmbH 0008 SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de> 0009 0010 SPDX-License-Identifier: GPL-2.0-or-later 0011 */ 0012 0013 #include "keyparameters.h" 0014 0015 #include <Libkleo/KeyUsage> 0016 0017 #include <QDate> 0018 #include <QUrl> 0019 0020 #include "kleopatra_debug.h" 0021 0022 using namespace Kleo; 0023 using namespace GpgME; 0024 0025 namespace 0026 { 0027 QString encodeDomainName(const QString &domain) 0028 { 0029 const QByteArray encodedDomain = QUrl::toAce(domain); 0030 return encodedDomain.isEmpty() ? domain : QString::fromLatin1(encodedDomain); 0031 } 0032 0033 QString encodeEmail(const QString &email) 0034 { 0035 const int at = email.lastIndexOf(QLatin1Char('@')); 0036 if (at < 0) { 0037 return email; 0038 } 0039 return email.left(at + 1) + encodeDomainName(email.mid(at + 1)); 0040 } 0041 } 0042 0043 class KeyParameters::Private 0044 { 0045 friend class ::Kleo::KeyParameters; 0046 0047 Protocol protocol; 0048 0049 Subkey::PubkeyAlgo keyType = Subkey::AlgoUnknown; 0050 QString cardKeyRef; 0051 unsigned int keyLength = 0; 0052 QString keyCurve; 0053 KeyUsage keyUsage; 0054 0055 Subkey::PubkeyAlgo subkeyType = Subkey::AlgoUnknown; 0056 unsigned int subkeyLength = 0; 0057 QString subkeyCurve; 0058 KeyUsage subkeyUsage; 0059 0060 QString name; 0061 QString comment; 0062 QString dn; 0063 std::vector<QString> emailAdresses; 0064 std::vector<QString> domainNames; 0065 std::vector<QString> uris; 0066 std::vector<QString> designatedRevokers; 0067 0068 QDate expirationDate; 0069 0070 public: 0071 explicit Private(Protocol proto) 0072 : protocol(proto) 0073 { 0074 } 0075 }; 0076 0077 KeyParameters::KeyParameters() 0078 : KeyParameters{NoProtocol} 0079 { 0080 } 0081 0082 KeyParameters::KeyParameters(Protocol protocol) 0083 : d{new Private{protocol}} 0084 { 0085 } 0086 0087 KeyParameters::~KeyParameters() = default; 0088 0089 KeyParameters::KeyParameters(const KeyParameters &other) 0090 : d{new Private{*other.d}} 0091 { 0092 } 0093 0094 KeyParameters &KeyParameters::operator=(const KeyParameters &other) 0095 { 0096 *d = *other.d; 0097 return *this; 0098 } 0099 0100 KeyParameters::KeyParameters(KeyParameters &&other) = default; 0101 0102 KeyParameters &KeyParameters::operator=(KeyParameters &&other) = default; 0103 0104 KeyParameters::Protocol KeyParameters::protocol() const 0105 { 0106 return d->protocol; 0107 } 0108 0109 void KeyParameters::setKeyType(Subkey::PubkeyAlgo type) 0110 { 0111 d->keyType = type; 0112 } 0113 0114 GpgME::Subkey::PubkeyAlgo KeyParameters::keyType() const 0115 { 0116 return d->keyType; 0117 } 0118 0119 void KeyParameters::setCardKeyRef(const QString &cardKeyRef) 0120 { 0121 d->cardKeyRef = cardKeyRef; 0122 } 0123 0124 QString KeyParameters::cardKeyRef() const 0125 { 0126 return d->cardKeyRef; 0127 } 0128 0129 void KeyParameters::setKeyLength(unsigned int length) 0130 { 0131 d->keyLength = length; 0132 } 0133 0134 unsigned int KeyParameters::keyLength() const 0135 { 0136 return d->keyLength; 0137 } 0138 0139 void KeyParameters::setKeyCurve(const QString &curve) 0140 { 0141 d->keyCurve = curve; 0142 } 0143 0144 QString KeyParameters::keyCurve() const 0145 { 0146 return d->keyCurve; 0147 } 0148 0149 void KeyParameters::setKeyUsage(const KeyUsage &usage) 0150 { 0151 d->keyUsage = usage; 0152 } 0153 0154 KeyUsage KeyParameters::keyUsage() const 0155 { 0156 return d->keyUsage; 0157 } 0158 0159 void KeyParameters::setSubkeyType(Subkey::PubkeyAlgo type) 0160 { 0161 d->subkeyType = type; 0162 } 0163 0164 Subkey::PubkeyAlgo KeyParameters::subkeyType() const 0165 { 0166 return d->subkeyType; 0167 } 0168 0169 void KeyParameters::setSubkeyLength(unsigned int length) 0170 { 0171 d->subkeyLength = length; 0172 } 0173 0174 unsigned int KeyParameters::subkeyLength() const 0175 { 0176 return d->subkeyLength; 0177 } 0178 0179 void KeyParameters::setSubkeyCurve(const QString &curve) 0180 { 0181 d->subkeyCurve = curve; 0182 } 0183 0184 QString KeyParameters::subkeyCurve() const 0185 { 0186 return d->subkeyCurve; 0187 } 0188 0189 void KeyParameters::setSubkeyUsage(const KeyUsage &usage) 0190 { 0191 d->subkeyUsage = usage; 0192 } 0193 0194 KeyUsage KeyParameters::subkeyUsage() const 0195 { 0196 return d->subkeyUsage; 0197 } 0198 0199 void KeyParameters::setExpirationDate(const QDate &date) 0200 { 0201 d->expirationDate = date; 0202 } 0203 0204 QDate KeyParameters::expirationDate() const 0205 { 0206 return d->expirationDate; 0207 } 0208 0209 void KeyParameters::setName(const QString &name) 0210 { 0211 d->name = name; 0212 } 0213 0214 QString KeyParameters::name() const 0215 { 0216 return d->name; 0217 } 0218 0219 void KeyParameters::setComment(const QString &comment) 0220 { 0221 d->comment = comment; 0222 } 0223 0224 QString KeyParameters::comment() const 0225 { 0226 return d->comment; 0227 } 0228 0229 void KeyParameters::setDN(const QString &dn) 0230 { 0231 d->dn = dn; 0232 } 0233 0234 QString KeyParameters::dn() const 0235 { 0236 return d->dn; 0237 } 0238 0239 void KeyParameters::setEmail(const QString &email) 0240 { 0241 d->emailAdresses = {email}; 0242 } 0243 0244 void KeyParameters::addEmail(const QString &email) 0245 { 0246 d->emailAdresses.push_back(email); 0247 } 0248 0249 std::vector<QString> KeyParameters::emails() const 0250 { 0251 return d->emailAdresses; 0252 } 0253 0254 void KeyParameters::addDomainName(const QString &domain) 0255 { 0256 d->domainNames.push_back(domain); 0257 } 0258 0259 std::vector<QString> KeyParameters::domainNames() const 0260 { 0261 return d->domainNames; 0262 } 0263 0264 void KeyParameters::addURI(const QString &uri) 0265 { 0266 d->uris.push_back(uri); 0267 } 0268 0269 std::vector<QString> KeyParameters::uris() const 0270 { 0271 return d->uris; 0272 } 0273 0274 void KeyParameters::addDesignatedRevoker(const QString &fpr) 0275 { 0276 d->designatedRevokers.push_back(fpr); 0277 } 0278 0279 std::vector<QString> KeyParameters::designatedRevokers() const 0280 { 0281 return d->designatedRevokers; 0282 } 0283 0284 namespace 0285 { 0286 QString serialize(Subkey::PubkeyAlgo algo) 0287 { 0288 return QString::fromLatin1(Subkey::publicKeyAlgorithmAsString(algo)); 0289 } 0290 0291 QString serialize(unsigned int number) 0292 { 0293 return QString::number(number); 0294 } 0295 0296 QString serialize(KeyUsage keyUsage) 0297 { 0298 QStringList usages; 0299 if (keyUsage.canSign()) { 0300 usages << QStringLiteral("sign"); 0301 } 0302 if (keyUsage.canEncrypt()) { 0303 usages << QStringLiteral("encrypt"); 0304 } 0305 if (keyUsage.canAuthenticate()) { 0306 usages << QStringLiteral("auth"); 0307 } 0308 if (keyUsage.canCertify()) { 0309 usages << QStringLiteral("cert"); 0310 } 0311 return usages.join(QLatin1Char{' '}); 0312 } 0313 0314 QString serialize(const QDate &date) 0315 { 0316 return date.toString(Qt::ISODate); 0317 } 0318 0319 QString serialize(const char *key, const QString &value) 0320 { 0321 return QString::fromLatin1(key) + QLatin1Char(':') + value; 0322 } 0323 } 0324 0325 QString KeyParameters::toString() const 0326 { 0327 QStringList keyParameters; 0328 0329 keyParameters.push_back(QLatin1StringView("<GnupgKeyParms format=\"internal\">")); 0330 0331 if (d->protocol == OpenPGP) { 0332 // for backward compatibility with GnuPG 2.0 and earlier 0333 keyParameters.push_back(QStringLiteral("%ask-passphrase")); 0334 } 0335 0336 // add Key-Type as first parameter 0337 if (!d->cardKeyRef.isEmpty()) { 0338 keyParameters.push_back(serialize("Key-Type", QLatin1StringView{"card:"} + d->cardKeyRef)); 0339 } else if (d->keyType != Subkey::AlgoUnknown) { 0340 keyParameters.push_back(serialize("Key-Type", serialize(d->keyType))); 0341 } else { 0342 qCWarning(KLEOPATRA_LOG) << "KeyParameters::toString(): Key type is unset/empty"; 0343 } 0344 if (d->keyLength) { 0345 keyParameters.push_back(serialize("Key-Length", serialize(d->keyLength))); 0346 } 0347 if (!d->keyCurve.isEmpty()) { 0348 keyParameters.push_back(serialize("Key-Curve", d->keyCurve)); 0349 } 0350 keyParameters.push_back(serialize("Key-Usage", serialize(d->keyUsage))); 0351 0352 if (d->subkeyType != Subkey::AlgoUnknown) { 0353 keyParameters.push_back(serialize("Subkey-Type", serialize(d->subkeyType))); 0354 if (d->subkeyUsage.value()) { 0355 keyParameters.push_back(serialize("Subkey-Usage", serialize(d->subkeyUsage))); 0356 } 0357 if (d->subkeyLength) { 0358 keyParameters.push_back(serialize("Subkey-Length", serialize(d->subkeyLength))); 0359 } 0360 if (!d->subkeyCurve.isEmpty()) { 0361 keyParameters.push_back(serialize("Subkey-Curve", d->subkeyCurve)); 0362 } 0363 } 0364 0365 if (d->expirationDate.isValid()) { 0366 keyParameters.push_back(serialize("Expire-Date", serialize(d->expirationDate))); 0367 } 0368 0369 if (!d->name.isEmpty()) { 0370 keyParameters.push_back(serialize("Name-Real", d->name)); 0371 } 0372 if (!d->comment.isEmpty()) { 0373 keyParameters.push_back(serialize("Name-Comment", d->comment)); 0374 } 0375 if (!d->dn.isEmpty()) { 0376 keyParameters.push_back(serialize("Name-DN", d->dn)); 0377 } 0378 std::transform(std::cbegin(d->emailAdresses), std::cend(d->emailAdresses), std::back_inserter(keyParameters), [this](const auto &email) { 0379 return serialize("Name-Email", (d->protocol == CMS) ? encodeEmail(email) : email); 0380 }); 0381 std::transform(std::cbegin(d->domainNames), std::cend(d->domainNames), std::back_inserter(keyParameters), [](const auto &domain) { 0382 return serialize("Name-DNS", encodeDomainName(domain)); 0383 }); 0384 std::transform(std::cbegin(d->uris), std::cend(d->uris), std::back_inserter(keyParameters), [](const auto &uri) { 0385 return serialize("Name-URI", uri); 0386 }); 0387 std::transform(std::cbegin(d->designatedRevokers), std::cend(d->designatedRevokers), std::back_inserter(keyParameters), [](const auto &designatedRevoker) { 0388 return serialize("Revoker", designatedRevoker); 0389 }); 0390 0391 keyParameters.push_back(QLatin1StringView("</GnupgKeyParms>")); 0392 0393 return keyParameters.join(QLatin1Char('\n')); 0394 }