Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F34132176
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
42 KB
Subscribers
None
View Options
diff --git a/src/dialogs/expirydialog.cpp b/src/dialogs/expirydialog.cpp
index cf3a09b62..b9915832c 100644
--- a/src/dialogs/expirydialog.cpp
+++ b/src/dialogs/expirydialog.cpp
@@ -1,228 +1,228 @@
/* -*- mode: c++; c-basic-offset:4 -*-
dialogs/expirydialog.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2021 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "expirydialog.h"
#include "utils/expiration.h"
#include "utils/gui-helper.h"
#include "utils/qt-cxx20-compat.h"
#include <Libkleo/Formatting>
#include <KDateComboBox>
#include <KLocalizedString>
#include <KMessageBox>
#include <KStandardGuiItem>
#include <QCheckBox>
#include <QDate>
#include <QDialogButtonBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QRadioButton>
#include <QVBoxLayout>
using namespace Kleo;
using namespace Kleo::Dialogs;
class ExpiryDialog::Private
{
friend class ::Kleo::Dialogs::ExpiryDialog;
ExpiryDialog *const q;
public:
Private(Mode mode, ExpiryDialog *qq)
: q{qq}
, ui{mode, qq}
{
ui.neverRB->setEnabled(unlimitedValidityAllowed());
ui.onRB->setEnabled(!fixedExpirationDate());
connect(ui.onCB, &KDateComboBox::dateChanged,
q, [this] () { slotOnDateChanged(); });
}
private:
void slotOnDateChanged();
private:
bool unlimitedValidityAllowed() const;
bool fixedExpirationDate() const;
void setInitialFocus();
private:
bool initialFocusWasSet = false;
struct UI {
QRadioButton *neverRB;
QRadioButton *onRB;
KDateComboBox *onCB;
QCheckBox *updateSubkeysCheckBox;
explicit UI(Mode mode, Dialogs::ExpiryDialog *qq)
{
auto mainLayout = new QVBoxLayout{qq};
auto mainWidget = new QWidget{qq};
auto vboxLayout = new QVBoxLayout{mainWidget};
vboxLayout->setContentsMargins(0, 0, 0, 0);
{
auto label = new QLabel{qq};
label->setText(mode == Mode::UpdateIndividualSubkey ?
i18n("Please select until when the subkey should be valid:") :
i18n("Please select until when the certificate should be valid:"));
vboxLayout->addWidget(label);
}
neverRB = new QRadioButton(i18n("Unlimited validity"), mainWidget);
neverRB->setChecked(false);
vboxLayout->addWidget(neverRB);
{
auto hboxLayout = new QHBoxLayout;
onRB = new QRadioButton{i18n("Valid until:"), mainWidget};
onRB->setChecked(true);
hboxLayout->addWidget(onRB);
onCB = new KDateComboBox{mainWidget};
setUpExpirationDateComboBox(onCB);
hboxLayout->addWidget(onCB);
hboxLayout->addStretch(1);
vboxLayout->addLayout(hboxLayout);
}
{
updateSubkeysCheckBox = new QCheckBox{i18n("Also update the validity period of the subkeys"), qq};
#if QGPGME_SUPPORTS_CHANGING_EXPIRATION_OF_COMPLETE_KEY
updateSubkeysCheckBox->setVisible(mode == Mode::UpdateCertificateWithSubkeys);
#else
updateSubkeysCheckBox->setVisible(false);
#endif
vboxLayout->addWidget(updateSubkeysCheckBox);
}
vboxLayout->addStretch(1);
mainLayout->addWidget(mainWidget);
auto buttonBox = new QDialogButtonBox{QDialogButtonBox::Ok | QDialogButtonBox::Cancel, qq};
auto okButton = buttonBox->button(QDialogButtonBox::Ok);
KGuiItem::assign(okButton, KStandardGuiItem::ok());
okButton->setDefault(true);
okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
KGuiItem::assign(buttonBox->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel());
qq->connect(buttonBox, &QDialogButtonBox::accepted, qq, &ExpiryDialog::accept);
qq->connect(buttonBox, &QDialogButtonBox::rejected, qq, &QDialog::reject);
mainLayout->addWidget(buttonBox);
connect(onRB, &QRadioButton::toggled, onCB, &QWidget::setEnabled);
}
} ui;
};
void ExpiryDialog::Private::slotOnDateChanged()
{
ui.onRB->setAccessibleName(i18nc("Valid until DATE", "Valid until %1", Formatting::accessibleDate(ui.onCB->date())));
}
bool Kleo::Dialogs::ExpiryDialog::Private::unlimitedValidityAllowed() const
{
- return !ui.onCB->maximumDate().isValid();
+ return !Kleo::maximumExpirationDate().isValid();
}
bool Kleo::Dialogs::ExpiryDialog::Private::fixedExpirationDate() const
{
return ui.onCB->minimumDate() == ui.onCB->maximumDate();
}
void ExpiryDialog::Private::setInitialFocus()
{
if (initialFocusWasSet) {
return;
}
// give focus to the checked radio button
(void) focusFirstCheckedButton({ui.neverRB, ui.onRB});
initialFocusWasSet = true;
}
ExpiryDialog::ExpiryDialog(Mode mode, QWidget *p)
: QDialog{p}
, d{new Private{mode, this}}
{
setWindowTitle(i18nc("@title:window", "Change Validity Period"));
}
ExpiryDialog::~ExpiryDialog() = default;
void ExpiryDialog::setDateOfExpiry(const QDate &date)
{
const QDate current = QDate::currentDate();
if (date.isValid()) {
d->ui.onRB->setChecked(true);
if (date <= current) {
d->ui.onCB->setDate(defaultExpirationDate(ExpirationOnUnlimitedValidity::InternalDefaultExpiration));
} else {
d->ui.onCB->setDate(date);
}
} else {
if (d->unlimitedValidityAllowed()) {
d->ui.neverRB->setChecked(true);
} else {
d->ui.onRB->setChecked(true);
}
d->ui.onCB->setDate(defaultExpirationDate(ExpirationOnUnlimitedValidity::InternalDefaultExpiration));
}
}
QDate ExpiryDialog::dateOfExpiry() const
{
return d->ui.onRB->isChecked() ? d->ui.onCB->date() : QDate{};
}
void ExpiryDialog::setUpdateExpirationOfAllSubkeys(bool update)
{
d->ui.updateSubkeysCheckBox->setChecked(update);
}
bool ExpiryDialog::updateExpirationOfAllSubkeys() const
{
return d->ui.updateSubkeysCheckBox->isChecked();
}
void ExpiryDialog::accept()
{
const auto date = dateOfExpiry();
if (!Kleo::isValidExpirationDate(date)) {
KMessageBox::error(this, i18nc("@info", "Error: %1", Kleo::validityPeriodHint()));
return;
}
QDialog::accept();
}
void ExpiryDialog::showEvent(QShowEvent *event)
{
d->setInitialFocus();
QDialog::showEvent(event);
}
#include "moc_expirydialog.cpp"
diff --git a/src/newcertificatewizard/advancedsettingsdialog.cpp b/src/newcertificatewizard/advancedsettingsdialog.cpp
index 7e9a0e26a..398e56ae1 100644
--- a/src/newcertificatewizard/advancedsettingsdialog.cpp
+++ b/src/newcertificatewizard/advancedsettingsdialog.cpp
@@ -1,1021 +1,1021 @@
/* -*- mode: c++; c-basic-offset:4 -*-
newcertificatewizard/advancedsettingsdialog.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2016, 2017 Bundesamt für Sicherheit in der Informationstechnik
SPDX-FileContributor: Intevation GmbH
SPDX-FileCopyrightText: 2022 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "advancedsettingsdialog_p.h"
#include "keyalgo_p.h"
#include "listwidget.h"
#include "utils/expiration.h"
#include "utils/gui-helper.h"
#include "utils/scrollarea.h"
#include <settings.h>
#include <Libkleo/Compat>
#include <Libkleo/Compliance>
#include <Libkleo/GnuPG>
#include <KDateComboBox>
#include <KLocalizedString>
#include <QGpgME/CryptoConfig>
#include <QGpgME/Protocol>
#include <QCheckBox>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QPushButton>
#include <QRadioButton>
#include <QTabWidget>
#include <QVBoxLayout>
#include "kleopatra_debug.h"
using namespace Kleo;
using namespace Kleo::NewCertificateUi;
using namespace GpgME;
static const char RSA_KEYSIZES_ENTRY[] = "RSAKeySizes";
static const char DSA_KEYSIZES_ENTRY[] = "DSAKeySizes";
static const char ELG_KEYSIZES_ENTRY[] = "ELGKeySizes";
static const char RSA_KEYSIZE_LABELS_ENTRY[] = "RSAKeySizeLabels";
static const char DSA_KEYSIZE_LABELS_ENTRY[] = "DSAKeySizeLabels";
static const char ELG_KEYSIZE_LABELS_ENTRY[] = "ELGKeySizeLabels";
static const char PGP_KEY_TYPE_ENTRY[] = "PGPKeyType";
static const char CMS_KEY_TYPE_ENTRY[] = "CMSKeyType";
// This should come from gpgme in the future
// For now we only support the basic 2.1 curves and check
// for GnuPG 2.1. The whole subkey / usage generation needs
// new api and a reworked dialog. (ah 10.3.16)
// EDDSA should be supported, too.
static const QStringList curveNames {
{ QStringLiteral("brainpoolP256r1") },
{ QStringLiteral("brainpoolP384r1") },
{ QStringLiteral("brainpoolP512r1") },
{ QStringLiteral("NIST P-256") },
{ QStringLiteral("NIST P-384") },
{ QStringLiteral("NIST P-521") },
};
namespace
{
static void set_keysize(QComboBox *cb, unsigned int strength)
{
if (!cb) {
return;
}
const int idx = cb->findData(static_cast<int>(strength));
if (idx >= 0) {
cb->setCurrentIndex(idx);
}
}
static unsigned int get_keysize(const QComboBox *cb)
{
if (!cb) {
return 0;
}
const int idx = cb->currentIndex();
if (idx < 0) {
return 0;
}
return cb->itemData(idx).toInt();
}
static void set_curve(QComboBox *cb, const QString &curve)
{
if (!cb) {
return;
}
const int idx = cb->findText(curve, Qt::MatchFixedString);
if (idx >= 0) {
cb->setCurrentIndex(idx);
}
}
static QString get_curve(const QComboBox *cb)
{
if (!cb) {
return QString();
}
return cb->currentText();
}
// Extract the algo information from default_pubkey_algo format
//
// and put it into the return values size, algo and curve.
//
// Values look like:
// RSA-2048
// rsa2048/cert,sign+rsa2048/enc
// brainpoolP256r1+brainpoolP256r1
static void parseAlgoString(const QString &algoString, int *size, Subkey::PubkeyAlgo *algo, QString &curve)
{
const auto split = algoString.split(QLatin1Char('/'));
bool isEncrypt = split.size() == 2 && split[1].contains(QLatin1String("enc"));
// Normalize
const auto lowered = split[0].toLower().remove(QLatin1Char('-'));
if (!algo || !size) {
return;
}
*algo = Subkey::AlgoUnknown;
if (lowered.startsWith(QLatin1String("rsa"))) {
*algo = Subkey::AlgoRSA;
} else if (lowered.startsWith(QLatin1String("dsa"))) {
*algo = Subkey::AlgoDSA;
} else if (lowered.startsWith(QLatin1String("elg"))) {
*algo = Subkey::AlgoELG;
}
if (*algo != Subkey::AlgoUnknown) {
bool ok;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
*size = lowered.rightRef(lowered.size() - 3).toInt(&ok);
#else
*size = QStringView(lowered).right(lowered.size() - 3).toInt(&ok);
#endif
if (!ok) {
qCWarning(KLEOPATRA_LOG) << "Could not extract size from: " << lowered;
*size = 3072;
}
return;
}
// Now the ECC Algorithms
if (lowered.startsWith(QLatin1String("ed25519"))) {
// Special handling for this as technically
// this is a cv25519 curve used for EDDSA
if (isEncrypt) {
curve = QLatin1String("cv25519");
*algo = Subkey::AlgoECDH;
} else {
curve = split[0];
*algo = Subkey::AlgoEDDSA;
}
return;
}
if (lowered.startsWith(QLatin1String("cv25519")) ||
lowered.startsWith(QLatin1String("nist")) ||
lowered.startsWith(QLatin1String("brainpool")) ||
lowered.startsWith(QLatin1String("secp"))) {
curve = split[0];
*algo = isEncrypt ? Subkey::AlgoECDH : Subkey::AlgoECDSA;
return;
}
qCWarning(KLEOPATRA_LOG) << "Failed to parse default_pubkey_algo:" << algoString;
}
}
struct AdvancedSettingsDialog::UI
{
QTabWidget *tabWidget = nullptr;
QRadioButton *rsaRB = nullptr;
QComboBox *rsaKeyStrengthCB = nullptr;
QCheckBox *rsaSubCB = nullptr;
QComboBox *rsaKeyStrengthSubCB = nullptr;
QRadioButton *dsaRB = nullptr;
QComboBox *dsaKeyStrengthCB = nullptr;
QCheckBox *elgCB = nullptr;
QComboBox *elgKeyStrengthCB = nullptr;
QRadioButton *ecdsaRB = nullptr;
QComboBox *ecdsaKeyCurvesCB = nullptr;
QCheckBox *ecdhCB = nullptr;
QComboBox *ecdhKeyCurvesCB = nullptr;
QCheckBox *certificationCB = nullptr;
QCheckBox *signingCB = nullptr;
QCheckBox *encryptionCB = nullptr;
QCheckBox *authenticationCB = nullptr;
QCheckBox *expiryCB = nullptr;
KDateComboBox *expiryDE = nullptr;
ScrollArea *personalTab = nullptr;
QGroupBox *uidGB = nullptr;
Kleo::NewCertificateUi::ListWidget *uidLW = nullptr;
QGroupBox *emailGB = nullptr;
Kleo::NewCertificateUi::ListWidget *emailLW = nullptr;
QGroupBox *dnsGB = nullptr;
Kleo::NewCertificateUi::ListWidget *dnsLW = nullptr;
QGroupBox *uriGB = nullptr;
Kleo::NewCertificateUi::ListWidget *uriLW = nullptr;
QDialogButtonBox *buttonBox = nullptr;
UI(QDialog *parent)
{
parent->setWindowTitle(i18nc("@title:window", "Advanced Settings"));
auto mainLayout = new QVBoxLayout{parent};
tabWidget = new QTabWidget{parent};
{
auto technicalTab = new ScrollArea{tabWidget};
technicalTab->setFocusPolicy(Qt::NoFocus);
technicalTab->setFrameStyle(QFrame::NoFrame);
technicalTab->setBackgroundRole(parent->backgroundRole());
technicalTab->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
technicalTab->setSizeAdjustPolicy(QScrollArea::AdjustToContents);
auto tabLayout = qobject_cast<QVBoxLayout *>(technicalTab->widget()->layout());
{
auto groupBox = new QGroupBox{i18nc("@title:group", "Key Material"), technicalTab};
auto groupBoxGrid = new QGridLayout{groupBox};
int row = 0;
rsaRB = new QRadioButton{i18nc("@option:radio", "RSA"), groupBox};
rsaRB->setChecked(false);
groupBoxGrid->addWidget(rsaRB, row, 0, 1, 2);
rsaKeyStrengthCB = new QComboBox{groupBox};
rsaKeyStrengthCB->setEnabled(false);
groupBoxGrid->addWidget(rsaKeyStrengthCB, row, 2, 1, 1);
row++;
auto subKeyIndentation = new QSpacerItem(13, 13, QSizePolicy::Fixed, QSizePolicy::Minimum);
groupBoxGrid->addItem(subKeyIndentation, row, 0, 1, 1);
rsaSubCB = new QCheckBox{i18nc("@option:check", "+ RSA"), groupBox};
rsaSubCB->setEnabled(true);
groupBoxGrid->addWidget(rsaSubCB, row, 1, 1, 1);
rsaKeyStrengthSubCB = new QComboBox{groupBox};
rsaKeyStrengthSubCB->setEnabled(false);
groupBoxGrid->addWidget(rsaKeyStrengthSubCB, row, 2, 1, 1);
row++;
dsaRB = new QRadioButton{i18nc("@option:radio", "DSA"), groupBox};
groupBoxGrid->addWidget(dsaRB, row, 0, 1, 2);
dsaKeyStrengthCB = new QComboBox{groupBox};
dsaKeyStrengthCB->setEnabled(false);
groupBoxGrid->addWidget(dsaKeyStrengthCB, row, 2, 1, 1);
row++;
elgCB = new QCheckBox{i18nc("@option:check", "+ Elgamal"), groupBox};
elgCB->setToolTip(i18nc("@info:tooltip", "This subkey is required for encryption."));
elgCB->setEnabled(true);
groupBoxGrid->addWidget(elgCB, row, 1, 1, 1);
elgKeyStrengthCB = new QComboBox{groupBox};
elgKeyStrengthCB->setEnabled(false);
groupBoxGrid->addWidget(elgKeyStrengthCB, row, 2, 1, 1);
row++;
ecdsaRB = new QRadioButton{i18nc("@option:radio", "ECDSA"), groupBox};
groupBoxGrid->addWidget(ecdsaRB, row, 0, 1, 2);
ecdsaKeyCurvesCB = new QComboBox{groupBox};
ecdsaKeyCurvesCB->setEnabled(false);
groupBoxGrid->addWidget(ecdsaKeyCurvesCB, row, 2, 1, 1);
row++;
ecdhCB = new QCheckBox{i18nc("@option:check", "+ ECDH"), groupBox};
ecdhCB->setToolTip(i18nc("@info:tooltip", "This subkey is required for encryption."));
ecdhCB->setEnabled(true);
groupBoxGrid->addWidget(ecdhCB, row, 1, 1, 1);
ecdhKeyCurvesCB = new QComboBox{groupBox};
ecdhKeyCurvesCB->setEnabled(false);
groupBoxGrid->addWidget(ecdhKeyCurvesCB, row, 2, 1, 1);
groupBoxGrid->setColumnStretch(3, 1);
tabLayout->addWidget(groupBox);
}
{
auto groupBox = new QGroupBox{i18nc("@title:group", "Certificate Usage"), technicalTab};
auto groupBoxGrid = new QGridLayout{groupBox};
int row = 0;
signingCB = new QCheckBox{i18nc("@option:check", "Signing"), groupBox};
signingCB->setChecked(true);
groupBoxGrid->addWidget(signingCB, row, 0, 1, 1);
certificationCB = new QCheckBox{i18nc("@option:check", "Certification"), groupBox};
groupBoxGrid->addWidget(certificationCB, row, 1, 1, 1);
row++;
encryptionCB = new QCheckBox{i18nc("@option:check", "Encryption"), groupBox};
encryptionCB->setChecked(true);
groupBoxGrid->addWidget(encryptionCB, row, 0, 1, 1);
authenticationCB = new QCheckBox{i18nc("@option:check", "Authentication"), groupBox};
groupBoxGrid->addWidget(authenticationCB, row, 1, 1, 1);
row++;
{
auto hbox = new QHBoxLayout;
expiryCB = new QCheckBox{i18nc("@option:check", "Valid until:"), groupBox};
hbox->addWidget(expiryCB);
expiryDE = new KDateComboBox(groupBox);
hbox->addWidget(expiryDE, 1);
groupBoxGrid->addLayout(hbox, row, 0, 1, 2);
}
tabLayout->addWidget(groupBox);
}
tabLayout->addStretch(1);
tabWidget->addTab(technicalTab, i18nc("@title:tab", "Technical Details"));
}
{
personalTab = new ScrollArea{tabWidget};
personalTab->setFocusPolicy(Qt::NoFocus);
personalTab->setFrameStyle(QFrame::NoFrame);
personalTab->setBackgroundRole(parent->backgroundRole());
personalTab->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
personalTab->setSizeAdjustPolicy(QScrollArea::AdjustToContents);
auto scrollAreaLayout = qobject_cast<QVBoxLayout *>(personalTab->widget()->layout());
auto tabGrid = new QGridLayout;
uidGB = new QGroupBox{i18nc("@title:group", "Additional User IDs"), personalTab};
{
auto layout = new QVBoxLayout{uidGB};
uidLW = new Kleo::NewCertificateUi::ListWidget{uidGB};
layout->addWidget(uidLW);
}
tabGrid->addWidget(uidGB, 0, 0, 1, 2);
emailGB = new QGroupBox{i18nc("@title:group", "EMail Addresses"), personalTab};
{
auto layout = new QVBoxLayout{emailGB};
emailLW = new Kleo::NewCertificateUi::ListWidget{emailGB};
layout->addWidget(emailLW);
}
tabGrid->addWidget(emailGB, 2, 0, 2, 1);
dnsGB = new QGroupBox{i18nc("@title:group", "DNS Names"), personalTab};
{
auto layout = new QVBoxLayout{dnsGB};
dnsLW = new Kleo::NewCertificateUi::ListWidget{dnsGB};
layout->addWidget(dnsLW);
}
tabGrid->addWidget(dnsGB, 2, 1, 1, 1);
uriGB = new QGroupBox{i18nc("@title:group", "URIs"), personalTab};
{
auto layout = new QVBoxLayout{uriGB};
uriLW = new Kleo::NewCertificateUi::ListWidget{uriGB};
layout->addWidget(uriLW);
}
tabGrid->addWidget(uriGB, 3, 1, 1, 1);
scrollAreaLayout->addLayout(tabGrid);
tabWidget->addTab(personalTab, i18nc("@title:tab", "Personal Details"));
}
mainLayout->addWidget(tabWidget);
buttonBox = new QDialogButtonBox{parent};
buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
mainLayout->addWidget(buttonBox);
}
};
AdvancedSettingsDialog::AdvancedSettingsDialog(QWidget *parent)
: QDialog{parent}
, ui{new UI{this}}
, mECCSupported{engineIsVersion(2, 1, 0)}
, mEdDSASupported{engineIsVersion(2, 1, 15)}
{
qRegisterMetaType<Subkey::PubkeyAlgo>("Subkey::PubkeyAlgo");
Kleo::setUpExpirationDateComboBox(ui->expiryDE);
if (unlimitedValidityIsAllowed()) {
ui->expiryDE->setEnabled(ui->expiryCB->isChecked());
} else {
ui->expiryCB->setEnabled(false);
ui->expiryCB->setChecked(true);
}
ui->emailLW->setDefaultValue(i18n("new email"));
ui->dnsLW->setDefaultValue(i18n("new dns name"));
ui->uriLW->setDefaultValue(i18n("new uri"));
fillKeySizeComboBoxen();
connect(ui->rsaRB, &QAbstractButton::toggled, ui->rsaKeyStrengthCB, &QWidget::setEnabled);
connect(ui->rsaRB, &QAbstractButton::toggled, this, &AdvancedSettingsDialog::slotKeyMaterialSelectionChanged);
connect(ui->rsaSubCB, &QAbstractButton::toggled, ui->rsaKeyStrengthSubCB, &QWidget::setEnabled);
connect(ui->rsaSubCB, &QAbstractButton::toggled, this, &AdvancedSettingsDialog::slotKeyMaterialSelectionChanged);
connect(ui->dsaRB, &QAbstractButton::toggled, ui->dsaKeyStrengthCB, &QWidget::setEnabled);
connect(ui->dsaRB, &QAbstractButton::toggled, this, &AdvancedSettingsDialog::slotKeyMaterialSelectionChanged);
connect(ui->elgCB, &QAbstractButton::toggled, ui->elgKeyStrengthCB, &QWidget::setEnabled);
connect(ui->elgCB, &QAbstractButton::toggled, this, &AdvancedSettingsDialog::slotKeyMaterialSelectionChanged);
connect(ui->ecdsaRB, &QAbstractButton::toggled, ui->ecdsaKeyCurvesCB, &QWidget::setEnabled);
connect(ui->ecdsaRB, &QAbstractButton::toggled, this, &AdvancedSettingsDialog::slotKeyMaterialSelectionChanged);
connect(ui->ecdhCB, &QAbstractButton::toggled, ui->ecdhKeyCurvesCB, &QWidget::setEnabled);
connect(ui->ecdhCB, &QAbstractButton::toggled, this, &AdvancedSettingsDialog::slotKeyMaterialSelectionChanged);
connect(ui->signingCB, &QAbstractButton::toggled, this, &AdvancedSettingsDialog::slotSigningAllowedToggled);
connect(ui->encryptionCB, &QAbstractButton::toggled, this, &AdvancedSettingsDialog::slotEncryptionAllowedToggled);
connect(ui->expiryCB, &QAbstractButton::toggled,
this, [this](bool checked) {
ui->expiryDE->setEnabled(checked);
if (checked && !ui->expiryDE->isValid()) {
setExpiryDate(defaultExpirationDate(ExpirationOnUnlimitedValidity::InternalDefaultExpiration));
}
});
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
}
AdvancedSettingsDialog::~AdvancedSettingsDialog() = default;
bool AdvancedSettingsDialog::unlimitedValidityIsAllowed() const
{
- return !ui->expiryDE->maximumDate().isValid();
+ return !Kleo::maximumExpirationDate().isValid();
}
void AdvancedSettingsDialog::setProtocol(GpgME::Protocol proto)
{
if (protocol == proto) {
return;
}
protocol = proto;
loadDefaults();
}
void AdvancedSettingsDialog::setAdditionalUserIDs(const QStringList &items)
{
ui->uidLW->setItems(items);
}
QStringList AdvancedSettingsDialog::additionalUserIDs() const
{
return ui->uidLW->items();
}
void AdvancedSettingsDialog::setAdditionalEMailAddresses(const QStringList &items)
{
ui->emailLW->setItems(items);
}
QStringList AdvancedSettingsDialog::additionalEMailAddresses() const
{
return ui->emailLW->items();
}
void AdvancedSettingsDialog::setDnsNames(const QStringList &items)
{
ui->dnsLW->setItems(items);
}
QStringList AdvancedSettingsDialog::dnsNames() const
{
return ui->dnsLW->items();
}
void AdvancedSettingsDialog::setUris(const QStringList &items)
{
ui->uriLW->setItems(items);
}
QStringList AdvancedSettingsDialog::uris() const
{
return ui->uriLW->items();
}
void AdvancedSettingsDialog::setKeyStrength(unsigned int strength)
{
set_keysize(ui->rsaKeyStrengthCB, strength);
set_keysize(ui->dsaKeyStrengthCB, strength);
}
unsigned int AdvancedSettingsDialog::keyStrength() const
{
return
ui->dsaRB->isChecked() ? get_keysize(ui->dsaKeyStrengthCB) :
ui->rsaRB->isChecked() ? get_keysize(ui->rsaKeyStrengthCB) : 0;
}
void AdvancedSettingsDialog::setKeyType(Subkey::PubkeyAlgo algo)
{
QRadioButton *const rb =
is_rsa(algo) ? ui->rsaRB :
is_dsa(algo) ? ui->dsaRB :
is_ecdsa(algo) || is_eddsa(algo) ? ui->ecdsaRB : nullptr;
if (rb) {
rb->setChecked(true);
}
}
Subkey::PubkeyAlgo AdvancedSettingsDialog::keyType() const
{
return
ui->dsaRB->isChecked() ? Subkey::AlgoDSA :
ui->rsaRB->isChecked() ? Subkey::AlgoRSA :
ui->ecdsaRB->isChecked() ?
ui->ecdsaKeyCurvesCB->currentText() == QLatin1String("ed25519") ? Subkey::AlgoEDDSA :
Subkey::AlgoECDSA :
Subkey::AlgoUnknown;
}
void AdvancedSettingsDialog::setKeyCurve(const QString &curve)
{
set_curve(ui->ecdsaKeyCurvesCB, curve);
}
QString AdvancedSettingsDialog::keyCurve() const
{
return get_curve(ui->ecdsaKeyCurvesCB);
}
void AdvancedSettingsDialog::setSubkeyType(Subkey::PubkeyAlgo algo)
{
ui->elgCB->setChecked(is_elg(algo));
ui->rsaSubCB->setChecked(is_rsa(algo));
ui->ecdhCB->setChecked(is_ecdh(algo));
}
Subkey::PubkeyAlgo AdvancedSettingsDialog::subkeyType() const
{
if (ui->elgCB->isChecked()) {
return Subkey::AlgoELG_E;
} else if (ui->rsaSubCB->isChecked()) {
return Subkey::AlgoRSA;
} else if (ui->ecdhCB->isChecked()) {
return Subkey::AlgoECDH;
}
return Subkey::AlgoUnknown;
}
void AdvancedSettingsDialog::setSubkeyCurve(const QString &curve)
{
set_curve(ui->ecdhKeyCurvesCB, curve);
}
QString AdvancedSettingsDialog::subkeyCurve() const
{
return get_curve(ui->ecdhKeyCurvesCB);
}
void AdvancedSettingsDialog::setSubkeyStrength(unsigned int strength)
{
if (subkeyType() == Subkey::AlgoRSA) {
set_keysize(ui->rsaKeyStrengthSubCB, strength);
} else {
set_keysize(ui->elgKeyStrengthCB, strength);
}
}
unsigned int AdvancedSettingsDialog::subkeyStrength() const
{
if (subkeyType() == Subkey::AlgoRSA) {
return get_keysize(ui->rsaKeyStrengthSubCB);
}
return get_keysize(ui->elgKeyStrengthCB);
}
void AdvancedSettingsDialog::setSigningAllowed(bool on)
{
ui->signingCB->setChecked(on);
}
bool AdvancedSettingsDialog::signingAllowed() const
{
return ui->signingCB->isChecked();
}
void AdvancedSettingsDialog::setEncryptionAllowed(bool on)
{
ui->encryptionCB->setChecked(on);
}
bool AdvancedSettingsDialog::encryptionAllowed() const
{
return ui->encryptionCB->isChecked();
}
void AdvancedSettingsDialog::setCertificationAllowed(bool on)
{
ui->certificationCB->setChecked(on);
}
bool AdvancedSettingsDialog::certificationAllowed() const
{
return ui->certificationCB->isChecked();
}
void AdvancedSettingsDialog::setAuthenticationAllowed(bool on)
{
ui->authenticationCB->setChecked(on);
}
bool AdvancedSettingsDialog::authenticationAllowed() const
{
return ui->authenticationCB->isChecked();
}
QDate AdvancedSettingsDialog::forceDateIntoAllowedRange(QDate date) const
{
const auto minDate = ui->expiryDE->minimumDate();
if (minDate.isValid() && date < minDate) {
date = minDate;
}
const auto maxDate = ui->expiryDE->maximumDate();
if (maxDate.isValid() && date > maxDate) {
date = maxDate;
}
return date;
}
void AdvancedSettingsDialog::setExpiryDate(QDate date)
{
if (date.isValid()) {
ui->expiryDE->setDate(forceDateIntoAllowedRange(date));
} else {
// check if unlimited validity is allowed
if (unlimitedValidityIsAllowed()) {
ui->expiryDE->setDate(date);
}
}
if (ui->expiryCB->isEnabled()) {
ui->expiryCB->setChecked(ui->expiryDE->isValid());
}
}
QDate AdvancedSettingsDialog::expiryDate() const
{
return ui->expiryCB->isChecked() ? forceDateIntoAllowedRange(ui->expiryDE->date()) : QDate();
}
void AdvancedSettingsDialog::slotKeyMaterialSelectionChanged()
{
const unsigned int algo = keyType();
const unsigned int sk_algo = subkeyType();
if (protocol == OpenPGP) {
// first update the enabled state, but only if key type is not forced
if (!keyTypeImmutable) {
ui->elgCB->setEnabled(is_dsa(algo));
ui->rsaSubCB->setEnabled(is_rsa(algo));
ui->ecdhCB->setEnabled(is_ecdsa(algo) || is_eddsa(algo));
if (is_rsa(algo)) {
ui->encryptionCB->setEnabled(true);
ui->signingCB->setEnabled(true);
ui->authenticationCB->setEnabled(true);
if (is_rsa(sk_algo)) {
ui->encryptionCB->setEnabled(false);
} else {
ui->encryptionCB->setEnabled(true);
}
} else if (is_dsa(algo)) {
ui->encryptionCB->setEnabled(false);
} else if (is_ecdsa(algo) || is_eddsa(algo)) {
ui->signingCB->setEnabled(true);
ui->authenticationCB->setEnabled(true);
ui->encryptionCB->setEnabled(false);
}
}
// then update the checked state
if (sender() == ui->dsaRB || sender() == ui->rsaRB || sender() == ui->ecdsaRB) {
ui->elgCB->setChecked(is_dsa(algo));
ui->ecdhCB->setChecked(is_ecdsa(algo) || is_eddsa(algo));
ui->rsaSubCB->setChecked(is_rsa(algo));
}
if (is_rsa(algo)) {
ui->encryptionCB->setChecked(true);
ui->signingCB->setChecked(true);
if (is_rsa(sk_algo)) {
ui->encryptionCB->setChecked(true);
}
} else if (is_dsa(algo)) {
if (is_elg(sk_algo)) {
ui->encryptionCB->setChecked(true);
} else {
ui->encryptionCB->setChecked(false);
}
} else if (is_ecdsa(algo) || is_eddsa(algo)) {
ui->signingCB->setChecked(true);
ui->encryptionCB->setChecked(is_ecdh(sk_algo));
}
} else {
//assert( is_rsa( keyType() ) ); // it can happen through misconfiguration by the admin that no key type is selectable at all
}
}
void AdvancedSettingsDialog::slotSigningAllowedToggled(bool on)
{
if (!on && protocol == CMS && !encryptionAllowed()) {
setEncryptionAllowed(true);
}
}
void AdvancedSettingsDialog::slotEncryptionAllowedToggled(bool on)
{
if (!on && protocol == CMS && !signingAllowed()) {
setSigningAllowed(true);
}
}
static void fill_combobox(QComboBox &cb, const QList<int> &sizes, const QStringList &labels)
{
cb.clear();
for (int i = 0, end = sizes.size(); i != end; ++i) {
const int size = std::abs(sizes[i]);
/* As we respect the defaults configurable in GnuPG, and we also have configurable
* defaults in Kleopatra its difficult to print out "default" here. To avoid confusion
* about that its better not to show any default indication. */
cb.addItem(i < labels.size() && !labels[i].trimmed().isEmpty()
? i18ncp("%2: some admin-supplied text, %1: key size in bits", "%2 (1 bit)", "%2 (%1 bits)", size, labels[i].trimmed())
: i18ncp("%1: key size in bits", "1 bit", "%1 bits", size),
size);
if (sizes[i] < 0) {
cb.setCurrentIndex(cb.count() - 1);
}
}
}
void AdvancedSettingsDialog::fillKeySizeComboBoxen()
{
const KConfigGroup config(KSharedConfig::openConfig(), "CertificateCreationWizard");
QList<int> rsaKeySizes = config.readEntry(RSA_KEYSIZES_ENTRY, QList<int>() << 2048 << -3072 << 4096);
if (DeVSCompliance::isActive()) {
rsaKeySizes = config.readEntry(RSA_KEYSIZES_ENTRY, QList<int>() << -3072 << 4096);
}
const QList<int> dsaKeySizes = config.readEntry(DSA_KEYSIZES_ENTRY, QList<int>() << -2048);
const QList<int> elgKeySizes = config.readEntry(ELG_KEYSIZES_ENTRY, QList<int>() << -2048 << 3072 << 4096);
const QStringList rsaKeySizeLabels = config.readEntry(RSA_KEYSIZE_LABELS_ENTRY, QStringList());
const QStringList dsaKeySizeLabels = config.readEntry(DSA_KEYSIZE_LABELS_ENTRY, QStringList());
const QStringList elgKeySizeLabels = config.readEntry(ELG_KEYSIZE_LABELS_ENTRY, QStringList());
fill_combobox(*ui->rsaKeyStrengthCB, rsaKeySizes, rsaKeySizeLabels);
fill_combobox(*ui->rsaKeyStrengthSubCB, rsaKeySizes, rsaKeySizeLabels);
fill_combobox(*ui->dsaKeyStrengthCB, dsaKeySizes, dsaKeySizeLabels);
fill_combobox(*ui->elgKeyStrengthCB, elgKeySizes, elgKeySizeLabels);
if (mEdDSASupported) {
// If supported we recommend cv25519
ui->ecdsaKeyCurvesCB->addItem(QStringLiteral("ed25519"));
ui->ecdhKeyCurvesCB->addItem(QStringLiteral("cv25519"));
}
ui->ecdhKeyCurvesCB->addItems(curveNames);
ui->ecdsaKeyCurvesCB->addItems(curveNames);
}
// Try to load the default key type from GnuPG
void AdvancedSettingsDialog::loadDefaultGnuPGKeyType()
{
const auto conf = QGpgME::cryptoConfig();
if (!conf) {
qCWarning(KLEOPATRA_LOG) << "Failed to obtain cryptoConfig.";
return;
}
const auto entry = getCryptoConfigEntry(conf, protocol == CMS ? "gpgsm" : "gpg", "default_pubkey_algo");
if (!entry) {
qCDebug(KLEOPATRA_LOG) << "GnuPG does not have default key type. Fallback to RSA";
setKeyType(Subkey::AlgoRSA);
setSubkeyType(Subkey::AlgoRSA);
return;
}
qCDebug(KLEOPATRA_LOG) << "Have default key type: " << entry->stringValue();
// Format is <primarytype>[/usage]+<subkeytype>[/usage]
const auto split = entry->stringValue().split(QLatin1Char('+'));
int size = 0;
Subkey::PubkeyAlgo algo = Subkey::AlgoUnknown;
QString curve;
parseAlgoString(split[0], &size, &algo, curve);
if (algo == Subkey::AlgoUnknown) {
setSubkeyType(Subkey::AlgoRSA);
return;
}
setKeyType(algo);
if (is_rsa(algo) || is_elg(algo) || is_dsa(algo)) {
setKeyStrength(size);
} else {
setKeyCurve(curve);
}
{
auto algoString = (split.size() == 2) ? split[1] : split[0];
// If it has no usage we assume encrypt subkey
if (!algoString.contains(QLatin1Char('/'))) {
algoString += QStringLiteral("/enc");
}
parseAlgoString(algoString, &size, &algo, curve);
if (algo == Subkey::AlgoUnknown) {
setSubkeyType(Subkey::AlgoRSA);
return;
}
setSubkeyType(algo);
if (is_rsa(algo) || is_elg(algo)) {
setSubkeyStrength(size);
} else {
setSubkeyCurve(curve);
}
}
}
void AdvancedSettingsDialog::loadDefaultKeyType()
{
if (protocol != CMS && protocol != OpenPGP) {
return;
}
const KConfigGroup config(KSharedConfig::openConfig(), "CertificateCreationWizard");
const QString entry = protocol == CMS ? QLatin1String(CMS_KEY_TYPE_ENTRY) : QLatin1String(PGP_KEY_TYPE_ENTRY);
const QString keyType = config.readEntry(entry).trimmed().toUpper();
if (protocol == OpenPGP && keyType == QLatin1String("DSA")) {
setKeyType(Subkey::AlgoDSA);
setSubkeyType(Subkey::AlgoUnknown);
} else if (protocol == OpenPGP && keyType == QLatin1String("DSA+ELG")) {
setKeyType(Subkey::AlgoDSA);
setSubkeyType(Subkey::AlgoELG_E);
} else if (keyType.isEmpty() && engineIsVersion(2, 1, 17)) {
loadDefaultGnuPGKeyType();
} else {
if (!keyType.isEmpty() && keyType != QLatin1String("RSA"))
qCWarning(KLEOPATRA_LOG) << "invalid value \"" << qPrintable(keyType)
<< "\" for entry \"[CertificateCreationWizard]"
<< qPrintable(entry) << "\"";
setKeyType(Subkey::AlgoRSA);
setSubkeyType(Subkey::AlgoRSA);
}
keyTypeImmutable = config.isEntryImmutable(entry);
}
void AdvancedSettingsDialog::loadDefaultExpiration()
{
if (protocol != OpenPGP) {
return;
}
if (unlimitedValidityIsAllowed()) {
setExpiryDate(defaultExpirationDate(ExpirationOnUnlimitedValidity::NoExpiration));
} else {
setExpiryDate(defaultExpirationDate(ExpirationOnUnlimitedValidity::InternalDefaultExpiration));
}
}
void AdvancedSettingsDialog::loadDefaults()
{
loadDefaultKeyType();
loadDefaultExpiration();
updateWidgetVisibility();
}
void AdvancedSettingsDialog::updateWidgetVisibility()
{
// Personal Details Page
if (protocol == OpenPGP) { // ### hide until multi-uid is implemented
if (ui->tabWidget->indexOf(ui->personalTab) != -1) {
ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->personalTab));
}
} else {
if (ui->tabWidget->indexOf(ui->personalTab) == -1) {
ui->tabWidget->addTab(ui->personalTab, i18nc("@title:tab", "Personal Details"));
}
}
ui->uidGB->setVisible(protocol == OpenPGP);
ui->uidGB->setEnabled(false);
ui->uidGB->setToolTip(i18nc("@info:tooltip", "Adding more than one user ID is not yet implemented."));
ui->emailGB->setVisible(protocol == CMS);
ui->dnsGB->setVisible(protocol == CMS);
ui->uriGB->setVisible(protocol == CMS);
// Technical Details Page
ui->ecdhCB->setVisible(mECCSupported);
ui->ecdhKeyCurvesCB->setVisible(mECCSupported);
ui->ecdsaKeyCurvesCB->setVisible(mECCSupported);
ui->ecdsaRB->setVisible(mECCSupported);
if (mEdDSASupported) {
// We use the same radio button for EdDSA as we use for
// ECDSA GnuPG does the same and this is really super technical
// land.
ui->ecdsaRB->setText(QStringLiteral("ECDSA/EdDSA"));
}
const bool deVsHack = DeVSCompliance::isActive();
if (deVsHack) {
// GnuPG Provides no API to query which keys are compliant for
// a mode. If we request a different one it will error out so
// we have to remove the options.
//
// Does anyone want to use NIST anyway?
int i;
while ((i = ui->ecdsaKeyCurvesCB->findText(QStringLiteral("NIST"), Qt::MatchStartsWith)) != -1 ||
(i = ui->ecdsaKeyCurvesCB->findText(QStringLiteral("25519"), Qt::MatchEndsWith)) != -1) {
ui->ecdsaKeyCurvesCB->removeItem(i);
}
while ((i = ui->ecdhKeyCurvesCB->findText(QStringLiteral("NIST"), Qt::MatchStartsWith)) != -1 ||
(i = ui->ecdhKeyCurvesCB->findText(QStringLiteral("25519"), Qt::MatchEndsWith)) != -1) {
ui->ecdhKeyCurvesCB->removeItem(i);
}
}
ui->certificationCB->setVisible(protocol == OpenPGP); // gpgsm limitation?
ui->authenticationCB->setVisible(protocol == OpenPGP);
if (keyTypeImmutable) {
ui->rsaRB->setEnabled(false);
ui->rsaSubCB->setEnabled(false);
ui->dsaRB->setEnabled(false);
ui->elgCB->setEnabled(false);
ui->ecdsaRB->setEnabled(false);
ui->ecdhCB->setEnabled(false);
// force usage if key type is forced
ui->certificationCB->setEnabled(false);
ui->signingCB->setEnabled(false);
ui->encryptionCB->setEnabled(false);
ui->authenticationCB->setEnabled(false);
} else {
ui->rsaRB->setEnabled(true);
ui->rsaSubCB->setEnabled(protocol == OpenPGP);
ui->dsaRB->setEnabled(protocol == OpenPGP && !deVsHack);
ui->elgCB->setEnabled(protocol == OpenPGP && !deVsHack);
ui->ecdsaRB->setEnabled(protocol == OpenPGP);
ui->ecdhCB->setEnabled(protocol == OpenPGP);
if (protocol == OpenPGP) {
// OpenPGP keys must have certify capability
ui->certificationCB->setEnabled(false);
}
if (protocol == CMS) {
ui->encryptionCB->setEnabled(true);
ui->rsaKeyStrengthSubCB->setEnabled(false);
}
}
if (protocol == OpenPGP) {
// OpenPGP keys must have certify capability
ui->certificationCB->setChecked(true);
}
if (protocol == CMS) {
ui->rsaSubCB->setChecked(false);
}
ui->expiryDE->setVisible(protocol == OpenPGP);
ui->expiryCB->setVisible(protocol == OpenPGP);
slotKeyMaterialSelectionChanged();
}
void AdvancedSettingsDialog::setInitialFocus()
{
// first try the key type radio buttons
if (focusFirstCheckedButton({ui->rsaRB, ui->dsaRB, ui->ecdsaRB})) {
return;
}
// then try the usage check boxes and the expiration check box
if (focusFirstEnabledButton({ui->signingCB, ui->certificationCB, ui->encryptionCB, ui->authenticationCB, ui->expiryCB})) {
return;
}
// finally, focus the OK button
ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus();
}
void AdvancedSettingsDialog::showEvent(QShowEvent *event)
{
if (isFirstShowEvent) {
setInitialFocus();
isFirstShowEvent = false;
}
QDialog::showEvent(event);
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Dec 8, 3:27 AM (1 h, 58 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
2f/94/849a76fd7f6daac54e1dae97a49f
Attached To
rKLEOPATRA Kleopatra
Event Timeline
Log In to Comment