File indexing completed on 2024-06-23 05:14:09
0001 /* -*- mode: c++; c-basic-offset:4 -*- 0002 newcertificatewizard/keycreationpage.cpp 0003 0004 This file is part of Kleopatra, the KDE keymanager 0005 SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB 0006 SPDX-FileCopyrightText: 2016, 2017 Bundesamt für Sicherheit in der Informationstechnik 0007 SPDX-FileContributor: Intevation GmbH 0008 SPDX-FileCopyrightText: 2022 g10 Code GmbH 0009 SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de> 0010 0011 SPDX-License-Identifier: GPL-2.0-or-later 0012 */ 0013 0014 #include <config-kleopatra.h> 0015 0016 #include "keycreationpage_p.h" 0017 0018 #include "keyalgo_p.h" 0019 0020 #include "kleopatraapplication.h" 0021 0022 #include "utils/keyparameters.h" 0023 0024 #include <Libkleo/Formatting> 0025 #include <Libkleo/KeyCache> 0026 #include <Libkleo/KeyUsage> 0027 0028 #include <KConfigGroup> 0029 #include <KLocalizedString> 0030 #include <KSharedConfig> 0031 0032 #include <QGpgME/KeyGenerationJob> 0033 #include <QGpgME/Protocol> 0034 0035 #include <QLabel> 0036 #include <QUrl> 0037 #include <QVBoxLayout> 0038 0039 #include <gpgme++/context.h> 0040 #include <gpgme++/keygenerationresult.h> 0041 0042 #include "kleopatra_debug.h" 0043 0044 using namespace Kleo; 0045 using namespace Kleo::NewCertificateUi; 0046 using namespace GpgME; 0047 0048 struct KeyCreationPage::UI { 0049 UI(QWizardPage *parent) 0050 { 0051 parent->setTitle(i18nc("@title", "Creating Key Pair...")); 0052 0053 auto mainLayout = new QVBoxLayout{parent}; 0054 0055 auto label = new QLabel{i18n("The process of creating a key requires large amounts of random numbers. This may require several minutes..."), parent}; 0056 label->setWordWrap(true); 0057 mainLayout->addWidget(label); 0058 } 0059 }; 0060 0061 KeyCreationPage::KeyCreationPage(QWidget *p) 0062 : WizardPage{p} 0063 , ui{new UI{this}} 0064 { 0065 setObjectName(QString::fromUtf8("Kleo__NewCertificateUi__KeyCreationPage")); 0066 } 0067 0068 KeyCreationPage::~KeyCreationPage() = default; 0069 0070 bool KeyCreationPage::isComplete() const 0071 { 0072 return !job; 0073 } 0074 0075 void KeyCreationPage::initializePage() 0076 { 0077 startJob(); 0078 } 0079 0080 void KeyCreationPage::startJob() 0081 { 0082 const auto proto = pgp() ? QGpgME::openpgp() : QGpgME::smime(); 0083 if (!proto) { 0084 return; 0085 } 0086 QGpgME::KeyGenerationJob *const j = proto->keyGenerationJob(); 0087 if (!j) { 0088 return; 0089 } 0090 if (!protectedKey() && pgp()) { 0091 auto ctx = QGpgME::Job::context(j); 0092 ctx->setPassphraseProvider(&mEmptyPassphraseProvider); 0093 ctx->setPinentryMode(Context::PinentryLoopback); 0094 } 0095 connect(j, &QGpgME::KeyGenerationJob::result, this, &KeyCreationPage::slotResult); 0096 if (const Error err = j->start(createGnupgKeyParms())) 0097 setField(QStringLiteral("error"), i18n("Could not start key pair creation: %1", Formatting::errorAsString(err))); 0098 else { 0099 job = j; 0100 } 0101 } 0102 0103 KeyUsage KeyCreationPage::keyUsage() const 0104 { 0105 KeyUsage usage; 0106 if (signingAllowed()) { 0107 usage.setCanSign(true); 0108 } 0109 if (encryptionAllowed() && !is_ecdh(subkeyType()) && !is_dsa(keyType()) && !is_rsa(subkeyType())) { 0110 usage.setCanEncrypt(true); 0111 } 0112 if (authenticationAllowed()) { 0113 usage.setCanAuthenticate(true); 0114 } 0115 if (!usage.value() && certificationAllowed()) { 0116 /* Empty usages cause an error so we need to 0117 * add at least certify if nothing else is selected */ 0118 usage.setCanCertify(true); 0119 } 0120 return usage; 0121 } 0122 0123 KeyUsage KeyCreationPage::subkeyUsage() const 0124 { 0125 KeyUsage usage; 0126 if (encryptionAllowed() && (is_dsa(keyType()) || is_rsa(subkeyType()) || is_ecdh(subkeyType()))) { 0127 Q_ASSERT(subkeyType()); 0128 usage.setCanEncrypt(true); 0129 } 0130 return usage; 0131 } 0132 0133 QString KeyCreationPage::createGnupgKeyParms() const 0134 { 0135 KeyParameters keyParameters(pgp() ? KeyParameters::OpenPGP : KeyParameters::CMS); 0136 0137 keyParameters.setKeyType(keyType()); 0138 if (is_ecdsa(keyType()) || is_eddsa(keyType())) { 0139 keyParameters.setKeyCurve(keyCurve()); 0140 } else if (const unsigned int strength = keyStrength()) { 0141 keyParameters.setKeyLength(strength); 0142 } 0143 keyParameters.setKeyUsage(keyUsage()); 0144 0145 if (subkeyType()) { 0146 keyParameters.setSubkeyType(subkeyType()); 0147 if (is_ecdh(subkeyType())) { 0148 keyParameters.setSubkeyCurve(subkeyCurve()); 0149 } else if (const unsigned int strength = subkeyStrength()) { 0150 keyParameters.setSubkeyLength(strength); 0151 } 0152 keyParameters.setSubkeyUsage(subkeyUsage()); 0153 } 0154 0155 if (pgp()) { 0156 if (expiryDate().isValid()) { 0157 keyParameters.setExpirationDate(expiryDate()); 0158 } 0159 if (!name().isEmpty()) { 0160 keyParameters.setName(name()); 0161 } 0162 if (!email().isEmpty()) { 0163 keyParameters.setEmail(email()); 0164 } 0165 } else { 0166 keyParameters.setDN(dn()); 0167 keyParameters.setEmail(email()); 0168 const auto addesses{additionalEMailAddresses()}; 0169 for (const QString &email : addesses) { 0170 keyParameters.addEmail(email); 0171 } 0172 const auto dnsN{dnsNames()}; 0173 for (const QString &dns : dnsN) { 0174 keyParameters.addDomainName(dns); 0175 } 0176 const auto urisList{uris()}; 0177 for (const QString &uri : urisList) { 0178 keyParameters.addURI(uri); 0179 } 0180 } 0181 0182 const QString result = keyParameters.toString(); 0183 qCDebug(KLEOPATRA_LOG) << '\n' << result; 0184 return result; 0185 } 0186 0187 void KeyCreationPage::slotResult(const GpgME::KeyGenerationResult &result, const QByteArray &request, const QString &auditLog) 0188 { 0189 Q_UNUSED(auditLog) 0190 if (result.error().code() || (pgp() && !result.fingerprint())) { 0191 setField(QStringLiteral("error"), 0192 result.error().isCanceled() ? i18n("Operation canceled.") : i18n("Could not create key pair: %1", Formatting::errorAsString(result.error()))); 0193 setField(QStringLiteral("url"), QString()); 0194 setField(QStringLiteral("result"), QString()); 0195 } else if (pgp()) { 0196 setField(QStringLiteral("error"), QString()); 0197 setField(QStringLiteral("url"), QString()); 0198 setField(QStringLiteral("result"), 0199 i18n("Key pair created successfully.\n" 0200 "Fingerprint: %1", 0201 Formatting::prettyID(result.fingerprint()))); 0202 } else { 0203 QFile file(tmpDir().absoluteFilePath(QStringLiteral("request.p10"))); 0204 0205 if (!file.open(QIODevice::WriteOnly)) { 0206 setField(QStringLiteral("error"), i18n("Could not write output file %1: %2", file.fileName(), file.errorString())); 0207 setField(QStringLiteral("url"), QString()); 0208 setField(QStringLiteral("result"), QString()); 0209 } else { 0210 file.write(request); 0211 setField(QStringLiteral("error"), QString()); 0212 setField(QStringLiteral("url"), QUrl::fromLocalFile(file.fileName()).toString()); 0213 setField(QStringLiteral("result"), i18n("Key pair created successfully.")); 0214 } 0215 } 0216 // Ensure that we have the key in the keycache 0217 if (pgp() && !result.error().code() && result.fingerprint()) { 0218 auto ctx = Context::createForProtocol(OpenPGP); 0219 if (ctx) { 0220 // Check is pretty useless something very buggy in that case. 0221 Error e; 0222 const auto key = ctx->key(result.fingerprint(), e, true); 0223 if (!key.isNull()) { 0224 KeyCache::mutableInstance()->insert(key); 0225 } else { 0226 qCDebug(KLEOPATRA_LOG) << "Failed to find newly generated key."; 0227 } 0228 delete ctx; 0229 } 0230 } 0231 setField(QStringLiteral("fingerprint"), result.fingerprint() ? QString::fromLatin1(result.fingerprint()) : QString()); 0232 job = nullptr; 0233 Q_EMIT completeChanged(); 0234 const KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("CertificateCreationWizard")); 0235 if (config.readEntry("SkipResultPage", false)) { 0236 if (result.fingerprint()) { 0237 KleopatraApplication::instance()->slotActivateRequested(QStringList() << QStringLiteral("kleopatra") << QStringLiteral("--query") 0238 << QLatin1StringView(result.fingerprint()), 0239 QString()); 0240 QMetaObject::invokeMethod(wizard(), "close", Qt::QueuedConnection); 0241 } else { 0242 QMetaObject::invokeMethod(wizard(), "next", Qt::QueuedConnection); 0243 } 0244 } else { 0245 QMetaObject::invokeMethod(wizard(), "next", Qt::QueuedConnection); 0246 } 0247 } 0248 0249 #include "moc_keycreationpage_p.cpp"