diff --git a/src/utils/keyparameters.cpp b/src/utils/keyparameters.cpp index 7069ce1be..0604032fe 100644 --- a/src/utils/keyparameters.cpp +++ b/src/utils/keyparameters.cpp @@ -1,263 +1,362 @@ /* -*- mode: c++; c-basic-offset:4 -*- utils/keyparameters.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB - SPDX-FileCopyrightText: 2020 g10 Code GmbH + SPDX-FileCopyrightText: 2020, 2022 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include "keyparameters.h" #include "keyusage.h" #include #include #include #include "kleopatra_debug.h" using namespace Kleo; using namespace GpgME; namespace { QString encodeDomainName(const QString &domain) { const QByteArray encodedDomain = QUrl::toAce(domain); return encodedDomain.isEmpty() ? domain : QString::fromLatin1(encodedDomain); } QString encodeEmail(const QString &email) { const int at = email.lastIndexOf(QLatin1Char('@')); if (at < 0) { return email; } return email.left(at + 1) + encodeDomainName(email.mid(at + 1)); } } class KeyParameters::Private { friend class ::Kleo::KeyParameters; Protocol protocol; Subkey::PubkeyAlgo keyType = Subkey::AlgoUnknown; QString cardKeyRef; + unsigned int keyLength = 0; + QString keyCurve; KeyUsage keyUsage; Subkey::PubkeyAlgo subkeyType = Subkey::AlgoUnknown; + unsigned int subkeyLength = 0; + QString subkeyCurve; KeyUsage subkeyUsage; - QMap parameters; + QString name; + QString dn; + std::vector emailAdresses; + std::vector domainNames; + std::vector uris; + + QDate expirationDate; public: explicit Private(Protocol proto) : protocol(proto) { } - - void setValue(const QString &key, const QString &value) - { - parameters[key] = QStringList() << value; - } - - void addValue(const QString &key, const QString &value) - { - parameters[key].push_back(value); - } }; KeyParameters::KeyParameters(Protocol protocol) : d{new Private{protocol}} { } KeyParameters::~KeyParameters() = default; KeyParameters::KeyParameters(const KeyParameters &other) : d{new Private{*other.d}} { } KeyParameters &KeyParameters::operator=(const KeyParameters &other) { *d = *other.d; return *this; } KeyParameters::KeyParameters(KeyParameters &&other) = default; KeyParameters &KeyParameters::operator=(KeyParameters &&other) = default; +KeyParameters::Protocol KeyParameters::protocol() const +{ + return d->protocol; +} + void KeyParameters::setKeyType(Subkey::PubkeyAlgo type) { d->keyType = type; } GpgME::Subkey::PubkeyAlgo KeyParameters::keyType() const { return d->keyType; } void KeyParameters::setCardKeyRef(const QString &cardKeyRef) { d->cardKeyRef = cardKeyRef; } QString KeyParameters::cardKeyRef() const { return d->cardKeyRef; } void KeyParameters::setKeyLength(unsigned int length) { - d->setValue(QStringLiteral("Key-Length"), QString::number(length)); + d->keyLength = length; +} + +unsigned int KeyParameters::keyLength() const +{ + return d->keyLength; } void KeyParameters::setKeyCurve(const QString &curve) { - d->setValue(QStringLiteral("Key-Curve"), curve); + d->keyCurve = curve; +} + +QString KeyParameters::keyCurve() const +{ + return d->keyCurve; } void KeyParameters::setKeyUsage(const KeyUsage &usage) { d->keyUsage = usage; } KeyUsage KeyParameters::keyUsage() const { return d->keyUsage; } void KeyParameters::setSubkeyType(Subkey::PubkeyAlgo type) { d->subkeyType = type; } Subkey::PubkeyAlgo KeyParameters::subkeyType() const { return d->subkeyType; } void KeyParameters::setSubkeyLength(unsigned int length) { - d->setValue(QStringLiteral("Subkey-Length"), QString::number(length)); + d->subkeyLength = length; +} + +unsigned int KeyParameters::subkeyLength() const +{ + return d->subkeyLength; } void KeyParameters::setSubkeyCurve(const QString &curve) { - d->setValue(QStringLiteral("Subkey-Curve"), curve); + d->subkeyCurve = curve; +} + +QString KeyParameters::subkeyCurve() const +{ + return d->subkeyCurve; } void KeyParameters::setSubkeyUsage(const KeyUsage &usage) { d->subkeyUsage = usage; } KeyUsage KeyParameters::subkeyUsage() const { return d->subkeyUsage; } void KeyParameters::setExpirationDate(const QDate &date) { - d->setValue(QStringLiteral("Expire-Date"), date.toString(Qt::ISODate)); + d->expirationDate = date; +} + +QDate KeyParameters::expirationDate() const +{ + return d->expirationDate; } void KeyParameters::setName(const QString &name) { - d->setValue(QStringLiteral("Name-Real"), name); + d->name = name; +} + +QString KeyParameters::name() const +{ + return d->name; } void KeyParameters::setDN(const QString &dn) { - d->setValue(QStringLiteral("Name-DN"), dn); + d->dn = dn; +} + +QString KeyParameters::dn() const +{ + return d->dn; } void KeyParameters::setEmail(const QString &email) { - d->setValue(QStringLiteral("Name-Email"), - (d->protocol == CMS) ? encodeEmail(email) : email); + d->emailAdresses = {email}; } void KeyParameters::addEmail(const QString& email) { - d->addValue(QStringLiteral("Name-Email"), - (d->protocol == CMS) ? encodeEmail(email) : email); + d->emailAdresses.push_back(email); +} + +std::vector KeyParameters::emails() const +{ + return d->emailAdresses; } void KeyParameters::addDomainName(const QString& domain) { - d->addValue(QStringLiteral("Name-DNS"), encodeDomainName(domain)); + d->domainNames.push_back(domain); +} + +std::vector KeyParameters::domainNames() const +{ + return d->domainNames; } void KeyParameters::addURI(const QString& uri) { - d->addValue(QStringLiteral("Name-URI"), uri); + d->uris.push_back(uri); +} + +std::vector KeyParameters::uris() const +{ + return d->uris; } namespace { +QString serialize(Subkey::PubkeyAlgo algo) +{ + return QString::fromLatin1(Subkey::publicKeyAlgorithmAsString(algo)); +} + +QString serialize(unsigned int number) +{ + return QString::number(number); +} + QString serialize(KeyUsage keyUsage) { QStringList usages; if (keyUsage.canSign()) { usages << QStringLiteral("sign"); } if (keyUsage.canEncrypt()) { usages << QStringLiteral("encrypt"); } if (keyUsage.canAuthenticate()) { usages << QStringLiteral("auth"); } if (keyUsage.canCertify()) { usages << QStringLiteral("cert"); } return usages.join(QLatin1Char{' '}); } + +QString serialize(const QDate &date) +{ + return date.toString(Qt::ISODate); +} + +QString serialize(const char *key, const QString &value) +{ + return QString::fromLatin1(key) + QLatin1Char(':') + value; +} } QString KeyParameters::toString() const { QStringList keyParameters; keyParameters.push_back(QLatin1String("")); if (d->protocol == OpenPGP) { // for backward compatibility with GnuPG 2.0 and earlier keyParameters.push_back(QStringLiteral("%ask-passphrase")); } // add Key-Type as first parameter if (!d->cardKeyRef.isEmpty()) { - keyParameters.push_back(QLatin1String{"Key-Type:card:"} + d->cardKeyRef); + keyParameters.push_back(serialize("Key-Type", QLatin1String{"card:"} + d->cardKeyRef)); } else if (d->keyType != Subkey::AlgoUnknown) { - keyParameters.push_back(QLatin1String{"Key-Type:"} + QString::fromLatin1(Subkey::publicKeyAlgorithmAsString(d->keyType))); + keyParameters.push_back(serialize("Key-Type", serialize(d->keyType))); } else { qCWarning(KLEOPATRA_LOG) << "KeyParameters::toString(): Key type is unset/empty"; } - keyParameters.push_back(QLatin1String{"Key-Usage:"} + serialize(d->keyUsage)); + if (d->keyLength) { + keyParameters.push_back(serialize("Key-Length", serialize(d->keyLength))); + } + if (!d->keyCurve.isEmpty()) { + keyParameters.push_back(serialize("Key-Curve", d->keyCurve)); + } + keyParameters.push_back(serialize("Key-Usage", serialize(d->keyUsage))); if (d->subkeyType != Subkey::AlgoUnknown) { - keyParameters.push_back(QLatin1String{"Subkey-Type:"} + QString::fromLatin1(Subkey::publicKeyAlgorithmAsString(d->subkeyType))); + keyParameters.push_back(serialize("Subkey-Type", serialize(d->subkeyType))); if (d->subkeyUsage.value()) { - keyParameters.push_back(QLatin1String{"Subkey-Usage:"} + serialize(d->subkeyUsage)); + keyParameters.push_back(serialize("Subkey-Usage", serialize(d->subkeyUsage))); + } + if (d->subkeyLength) { + keyParameters.push_back(serialize("Subkey-Length", serialize(d->subkeyLength))); + } + if (!d->subkeyCurve.isEmpty()) { + keyParameters.push_back(serialize("Subkey-Curve", d->subkeyCurve)); } } - for (auto it = d->parameters.constBegin(); it != d->parameters.constEnd(); ++it) { - for (const auto &v : it.value()) { - keyParameters.push_back(it.key() + QLatin1Char(':') + v); - } + if (d->expirationDate.isValid()) { + keyParameters.push_back(serialize("Expire-Date", serialize(d->expirationDate))); + } + + if (!d->name.isEmpty()) { + keyParameters.push_back(serialize("Name-Real", d->name)); + } + if (!d->dn.isEmpty()) { + keyParameters.push_back(serialize("Name-DN", d->dn)); } + std::transform(std::cbegin(d->emailAdresses), std::cend(d->emailAdresses), std::back_inserter(keyParameters), [this](const auto &email) { + return serialize("Name-Email", (d->protocol == CMS) ? encodeEmail(email) : email); + }); + std::transform(std::cbegin(d->domainNames), std::cend(d->domainNames), std::back_inserter(keyParameters), [](const auto &domain) { + return serialize("Name-DNS", encodeDomainName(domain)); + }); + std::transform(std::cbegin(d->uris), std::cend(d->uris), std::back_inserter(keyParameters), [](const auto &uri) { + return serialize("Name-URI", uri); + }); keyParameters.push_back(QLatin1String("")); return keyParameters.join(QLatin1Char('\n')); } diff --git a/src/utils/keyparameters.h b/src/utils/keyparameters.h index b76d1fb5e..3264dbef7 100644 --- a/src/utils/keyparameters.h +++ b/src/utils/keyparameters.h @@ -1,73 +1,85 @@ /* -*- mode: c++; c-basic-offset:4 -*- utils/keyparameters.h This file is part of Kleopatra, the KDE keymanager - SPDX-FileCopyrightText: 2020 g10 Code GmbH + SPDX-FileCopyrightText: 2020, 2022 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include class QDate; class QString; namespace Kleo { class KeyUsage; class KeyParameters { public: enum Protocol { OpenPGP, - CMS + CMS, }; explicit KeyParameters(Protocol protocol); ~KeyParameters(); KeyParameters(const KeyParameters &other); KeyParameters &operator=(const KeyParameters &other); KeyParameters(KeyParameters &&other); KeyParameters &operator=(KeyParameters &&other); + Protocol protocol() const; + void setKeyType(GpgME::Subkey::PubkeyAlgo type); GpgME::Subkey::PubkeyAlgo keyType() const; void setCardKeyRef(const QString &cardKeyRef); QString cardKeyRef() const; void setKeyLength(unsigned int length); + unsigned int keyLength() const; void setKeyCurve(const QString &curve); + QString keyCurve() const; void setKeyUsage(const KeyUsage &usage); KeyUsage keyUsage() const; void setSubkeyType(GpgME::Subkey::PubkeyAlgo type); GpgME::Subkey::PubkeyAlgo subkeyType() const; void setSubkeyLength(unsigned int length); + unsigned int subkeyLength() const; void setSubkeyCurve(const QString &curve); + QString subkeyCurve() const; void setSubkeyUsage(const KeyUsage &usage); KeyUsage subkeyUsage() const; void setExpirationDate(const QDate &date); + QDate expirationDate() const; void setName(const QString &name); + QString name() const; void setDN(const QString &dn); + QString dn() const; void setEmail(const QString &email); void addEmail(const QString &email); + std::vector emails() const; void addDomainName(const QString &domain); + std::vector domainNames() const; void addURI(const QString &uri); + std::vector uris() const; QString toString() const; private: class Private; std::unique_ptr d; }; }