10#include <config-libkleo.h>
12#include "openpgpcertificatecreationdialog.h"
14#include "adjustingscrollarea.h"
15#include "animatedexpander_p.h"
16#include "nameandemailwidget.h"
17#include "openpgpcertificatecreationconfig.h"
18#include "utils/compat.h"
19#include "utils/compliance.h"
20#include "utils/expiration.h"
21#include "utils/gnupg.h"
22#include "utils/keyparameters.h"
23#include "utils/keyusage.h"
25#include <KConfigGroup>
26#include <KDateComboBox>
27#include <KLocalizedString>
30#include <KSharedConfig>
33#include <QDialogButtonBox>
38#include <QGpgME/CryptoConfig>
39#include <QGpgME/Protocol>
41#include "libkleo_debug.h"
46static bool unlimitedValidityIsAllowed()
48 return !Kleo::Expiration::maximumExpirationDate().
isValid();
51class OpenPGPCertificateCreationDialog::Private
53 friend class ::Kleo::OpenPGPCertificateCreationDialog;
67 AnimatedExpander *expander;
73 infoLabel =
new QLabel{dialog};
75 mainLayout->addWidget(infoLabel);
86 scrollAreaLayout->setContentsMargins(0, 0, 0, 0);
90 scrollAreaLayout->addWidget(nameAndEmail);
92 withPassCheckBox =
new QCheckBox{
i18n(
"Protect the generated key with a passphrase."), dialog};
94 i18n(
"Encrypts the secret key with an unrecoverable passphrase. You will be asked for the passphrase during key generation."));
95 scrollAreaLayout->addWidget(withPassCheckBox);
97 expander =
new AnimatedExpander(
i18n(
"Advanced options"), {}, dialog);
98 scrollAreaLayout->addWidget(expander);
101 expander->setContentLayout(advancedLayout);
103 keyAlgoLabel =
new QLabel(dialog);
104 keyAlgoLabel->
setText(
i18nc(
"The algorithm and strength of encryption key",
"Key Material"));
108 advancedLayout->addWidget(keyAlgoLabel);
112 advancedLayout->addWidget(keyAlgoCB);
119 hbox->addWidget(expiryCB);
121 expiryLabel =
new QLabel{Expiration::validUntilLabel(), dialog};
122 hbox->addWidget(expiryLabel);
125 hbox->addWidget(expiryDE, 1);
127 advancedLayout->addLayout(hbox);
130 scrollAreaLayout->addStretch(1);
132 mainLayout->addWidget(scrollArea);
138 mainLayout->addWidget(buttonBox);
146 , technicalParameters{KeyParameters::OpenPGP}
150 OpenPGPCertificateCreationConfig settings;
151 const auto requiredFields = settings.requiredFields();
155 ui.infoLabel->
setText(nameIsRequired || emailIsRequired
156 ?
i18n(
"Enter a name and an email address to use for the certificate.")
157 :
i18n(
"Enter a name and/or an email address to use for the certificate."));
159 ui.nameAndEmail->setNameIsRequired(nameIsRequired);
160 ui.nameAndEmail->setNameLabel(settings.nameLabel());
161 const auto nameHint = settings.nameHint();
162 ui.nameAndEmail->setNameHint(nameHint.isEmpty() ? settings.namePlaceholder() : nameHint);
163 ui.nameAndEmail->setNamePattern(settings.nameRegex());
164 ui.nameAndEmail->setEmailIsRequired(emailIsRequired);
165 ui.nameAndEmail->setEmailLabel(settings.emailLabel());
166 const auto emailHint = settings.emailHint();
167 ui.nameAndEmail->setEmailHint(emailHint.isEmpty() ? settings.emailPlaceholder() : emailHint);
168 ui.nameAndEmail->setEmailPattern(settings.emailRegex());
170 ui.expander->setVisible(!settings.hideAdvanced());
172 const auto conf = QGpgME::cryptoConfig();
173 const auto entry = getCryptoConfigEntry(conf,
"gpg-agent",
"enforce-passphrase-constraints");
174 if (entry && entry->boolValue()) {
175 qCDebug(LIBKLEO_LOG) <<
"Disabling passphrase check box because of agent config.";
179 ui.withPassCheckBox->
setChecked(settings.withPassphrase());
180 ui.withPassCheckBox->
setEnabled(!settings.isWithPassphraseImmutable());
188 for (
const auto &algorithm : DeVSCompliance::isActive() ? DeVSCompliance::compliantAlgorithms() : availableAlgorithms()) {
191 auto cryptoConfig = QGpgME::cryptoConfig();
193 auto pubkeyEntry = getCryptoConfigEntry(QGpgME::cryptoConfig(),
"gpg",
"default_pubkey_algo");
195 auto algo = pubkeyEntry->stringValue().split(
QLatin1Char(
'/'))[0];
197 algo = QStringLiteral(
"curve25519");
199 algo = QStringLiteral(
"curve448");
201 auto index = ui.keyAlgoCB->
findData(algo);
214 Kleo::Expiration::setUpExpirationDateComboBox(ui.expiryDE);
216 setExpiryDate(defaultExpirationDate(Kleo::Expiration::ExpirationOnUnlimitedValidity::InternalDefaultExpiration));
217 if (unlimitedValidityIsAllowed()) {
225 ui.expiryLabel->setEnabled(checked);
226 ui.expiryDE->setEnabled(checked);
227 if (checked && !ui.expiryDE->isValid()) {
228 setExpiryDate(defaultExpirationDate(Kleo::Expiration::ExpirationOnUnlimitedValidity::InternalDefaultExpiration));
230 updateTechnicalParameters();
233 updateTechnicalParameters();
236 updateTechnicalParameters();
238 updateTechnicalParameters();
239 connect(ui.expander, &AnimatedExpander::startExpanding, q, [
this]() {
240 q->resize(std::max(q->sizeHint().width(), ui.expander->contentWidth()) + 20, q->sizeHint().height() + ui.expander->contentHeight() + 20);
245 void updateTechnicalParameters()
247 technicalParameters = KeyParameters{KeyParameters::OpenPGP};
248 auto keyType = GpgME::Subkey::AlgoUnknown;
249 auto subkeyType = GpgME::Subkey::AlgoUnknown;
250 auto algoString = ui.keyAlgoCB->currentData().toString();
251 if (algoString.startsWith(QStringLiteral(
"rsa"))) {
252 keyType = GpgME::Subkey::AlgoRSA;
253 subkeyType = GpgME::Subkey::AlgoRSA;
254 const auto strength = algoString.mid(3).toInt();
255 technicalParameters.setKeyLength(strength);
256 technicalParameters.setSubkeyLength(strength);
258 keyType = GpgME::Subkey::AlgoEDDSA;
259 subkeyType = GpgME::Subkey::AlgoECDH;
260 if (algoString.endsWith(QStringLiteral(
"25519"))) {
261 technicalParameters.setKeyCurve(QStringLiteral(
"ed25519"));
262 technicalParameters.setSubkeyCurve(QStringLiteral(
"cv25519"));
264 technicalParameters.setKeyCurve(QStringLiteral(
"ed448"));
265 technicalParameters.setSubkeyCurve(QStringLiteral(
"cv448"));
267#if GPGMEPP_SUPPORTS_KYBER
268 }
else if (algoString ==
"ky768_bp256"_L1) {
269 keyType = GpgME::Subkey::AlgoECDSA;
270 subkeyType = GpgME::Subkey::AlgoKyber;
271 technicalParameters.setKeyCurve(u
"brainpoolP256r1"_s);
272 technicalParameters.setSubkeyCurve(u
"brainpoolP256r1"_s);
273 technicalParameters.setSubkeyLength(768);
274 }
else if (algoString ==
"ky1024_bp384"_L1) {
275 keyType = GpgME::Subkey::AlgoECDSA;
276 subkeyType = GpgME::Subkey::AlgoKyber;
277 technicalParameters.setKeyCurve(u
"brainpoolP384r1"_s);
278 technicalParameters.setSubkeyCurve(u
"brainpoolP384r1"_s);
279 technicalParameters.setSubkeyLength(1024);
282 keyType = GpgME::Subkey::AlgoECDSA;
283 subkeyType = GpgME::Subkey::AlgoECDH;
284 technicalParameters.setKeyCurve(algoString);
285 technicalParameters.setSubkeyCurve(algoString);
287 technicalParameters.setKeyType(keyType);
288 technicalParameters.setSubkeyType(subkeyType);
290 technicalParameters.setKeyUsage(KeyUsage(KeyUsage::Certify | KeyUsage::Sign));
291 technicalParameters.setSubkeyUsage(KeyUsage(KeyUsage::Encrypt));
293 technicalParameters.setExpirationDate(expiryDate());
297 QDate expiryDate()
const
299 return ui.expiryCB->isChecked() ? ui.expiryDE->date() :
QDate{};
302 void setTechnicalParameters(
const KeyParameters ¶meters)
305 if (parameters.keyType() == GpgME::Subkey::AlgoRSA_S) {
306 index = ui.keyAlgoCB->findData(QStringLiteral(
"rsa%1").arg(parameters.keyLength()));
308 index = ui.keyAlgoCB->findData(QStringLiteral(
"curve25519"));
310 index = ui.keyAlgoCB->findData(QStringLiteral(
"curve448"));
311#if GPGMEPP_SUPPORTS_KYBER
312 }
else if (parameters.subkeyType() == GpgME::Subkey::AlgoKyber) {
313 if (parameters.subkeyLength() == 768 && parameters.keyCurve() ==
"brainpoolP256r1"_L1) {
314 index = ui.keyAlgoCB->findData(
"ky768_bp256"_L1);
315 }
else if (parameters.subkeyLength() == 1024 && parameters.keyCurve() ==
"brainpoolP384r1"_L1) {
316 index = ui.keyAlgoCB->findData(
"ky1024_bp384"_L1);
318 qCDebug(LIBKLEO_LOG) << __func__ <<
"Unsupported Kyber parameters" << parameters.subkeyLength() << parameters.keyCurve();
322 index = ui.keyAlgoCB->findData(parameters.keyCurve());
325 ui.keyAlgoCB->setCurrentIndex(index);
327 setExpiryDate(parameters.expirationDate());
333 if (ui.nameAndEmail->userID().isEmpty() && !ui.nameAndEmail->nameIsRequired() && !ui.nameAndEmail->emailIsRequired()) {
336 const auto nameError = ui.nameAndEmail->nameError();
337 if (!nameError.isEmpty()) {
340 const auto emailError = ui.nameAndEmail->emailError();
341 if (!emailError.isEmpty()) {
344 if (!Expiration::isValidExpirationDate(expiryDate())) {
345 errors.
push_back(Expiration::validityPeriodHint());
347 if (errors.
size() > 1) {
349 }
else if (!errors.
empty()) {
356 QDate forceDateIntoAllowedRange(
QDate date)
const
358 const auto minDate = ui.expiryDE->minimumDate();
359 if (minDate.isValid() && date < minDate) {
362 const auto maxDate = ui.expiryDE->maximumDate();
363 if (maxDate.isValid() && date > maxDate) {
369 void setExpiryDate(
QDate date)
372 ui.expiryDE->setDate(forceDateIntoAllowedRange(date));
375 if (unlimitedValidityIsAllowed()) {
376 ui.expiryDE->setDate(date);
379 if (ui.expiryCB->isEnabled()) {
380 ui.expiryCB->setChecked(ui.expiryDE->isValid());
385 KeyParameters technicalParameters;
390 , d(new Private{this})
392 resize(std::max(sizeHint().width(), d->ui.expander->contentWidth()) + 20, sizeHint().height() + 20);
395OpenPGPCertificateCreationDialog::~OpenPGPCertificateCreationDialog() =
default;
397void OpenPGPCertificateCreationDialog::setName(
const QString &name)
399 d->ui.nameAndEmail->setName(name);
402QString OpenPGPCertificateCreationDialog::name()
const
404 return d->ui.nameAndEmail->name();
407void OpenPGPCertificateCreationDialog::setEmail(
const QString &email)
409 d->ui.nameAndEmail->setEmail(email);
412QString OpenPGPCertificateCreationDialog::email()
const
414 return d->ui.nameAndEmail->email();
417void Kleo::OpenPGPCertificateCreationDialog::setKeyParameters(
const Kleo::KeyParameters ¶meters)
419 setName(parameters.name());
420 const auto emails = parameters.emails();
421 if (!emails.empty()) {
422 setEmail(emails.front());
424 d->setTechnicalParameters(parameters);
427KeyParameters OpenPGPCertificateCreationDialog::keyParameters()
const
430 auto parameters = d->technicalParameters;
431 if (!name().isEmpty()) {
432 parameters.setName(name());
434 if (!email().isEmpty()) {
435 parameters.setEmail(email());
440void Kleo::OpenPGPCertificateCreationDialog::setProtectKeyWithPassword(
bool protectKey)
442 d->ui.withPassCheckBox->setChecked(protectKey);
445bool OpenPGPCertificateCreationDialog::protectKeyWithPassword()
const
447 return d->ui.withPassCheckBox->isChecked();
450#include "moc_openpgpcertificatecreationdialog.cpp"
void dateChanged(const QDate &date)
Dialog to create a new OpenPGP key.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
void errorList(QWidget *parent, const QString &text, const QStringList &strlist, const QString &title=QString(), Options options=Notify)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
void addItem(const QIcon &icon, const QString &text, const QVariant &userData)
void setCurrentIndex(int index)
void currentIndexChanged(int index)
int findData(const QVariant &data, int role, Qt::MatchFlags flags) const const
bool isValid(int year, int month, int day)
void setFrameStyle(int style)
void setBuddy(QWidget *buddy)
void setText(const QString &)
void setWordWrap(bool on)
void setContentsMargins(const QMargins &margins)
void push_back(parameter_type value)
qsizetype size() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T qobject_cast(QObject *object)
QString fromStdString(const std::string &str)