Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F25703567
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
51 KB
Subscribers
None
View Options
diff --git a/src/view/netkeywidget.cpp b/src/view/netkeywidget.cpp
index ed0600e57..736144499 100644
--- a/src/view/netkeywidget.cpp
+++ b/src/view/netkeywidget.cpp
@@ -1,240 +1,240 @@
/* view/netkeywidget.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2017 Intevation GmbH
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "netkeywidget.h"
#include "cardkeysview.h"
#include "kleopatraapplication.h"
#include "nullpinwidget.h"
#include "systrayicon.h"
#include "kleopatra_debug.h"
#include "smartcard/netkeycard.h"
#include "smartcard/readerstatus.h"
#include "commands/changepincommand.h"
#include "commands/createcsrforcardkeycommand.h"
#include "commands/createopenpgpkeyfromcardkeyscommand.h"
#include <Libkleo/Algorithm>
#include <Libkleo/Compliance>
#include <Libkleo/Debug>
#include <Libkleo/KeyCache>
#include <Libkleo/KeyHelpers>
#include <Libkleo/KeyListModel>
#include <KLocalizedString>
#include <KMessageBox>
#include <KSeparator>
#include <QHBoxLayout>
#include <QInputDialog>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include <gpgme++/engineinfo.h>
using namespace Kleo;
using namespace Kleo::SmartCard;
using namespace Kleo::Commands;
NetKeyWidget::NetKeyWidget(QWidget *parent)
: SmartCardWidget(parent)
{
mNullPinWidget = new NullPinWidget{this};
mContentLayout->addWidget(mNullPinWidget);
mErrorLabel = new QLabel{this};
mErrorLabel->setVisible(false);
mContentLayout->addWidget(mErrorLabel);
mCardKeysView = new CardKeysView{this, CardKeysView::NoCreated};
mContentLayout->addWidget(mCardKeysView, 1);
// The action area
auto actionLayout = new QHBoxLayout();
if (CreateOpenPGPKeyFromCardKeysCommand::isSupported()) {
mKeyForCardKeysButton = new QPushButton(this);
mKeyForCardKeysButton->setText(i18nc("@action:button", "Create OpenPGP Key"));
mKeyForCardKeysButton->setToolTip(i18nc("@info:tooltip", "Create an OpenPGP key for the keys stored on the card."));
actionLayout->addWidget(mKeyForCardKeysButton);
connect(mKeyForCardKeysButton, &QPushButton::clicked, this, &NetKeyWidget::createKeyFromCardKeys);
}
if (!(engineInfo(GpgME::GpgSMEngine).engineVersion() < "2.2.26")) { // see https://dev.gnupg.org/T5184
mCreateCSRButton = new QPushButton(this);
mCreateCSRButton->setText(i18nc("@action:button", "Create CSR"));
mCreateCSRButton->setToolTip(i18nc("@info:tooltip", "Create a certificate signing request for a key stored on the card."));
mCreateCSRButton->setEnabled(false);
actionLayout->addWidget(mCreateCSRButton);
connect(mCreateCSRButton, &QPushButton::clicked, this, [this]() {
createCSR();
});
}
mChangeNKSPINBtn = new QPushButton{this};
mChangeNKSPINBtn->setText(i18nc("@action:button NKS is an identifier for a type of keys on a NetKey card", "Change NKS PIN"));
mChangeSigGPINBtn = new QPushButton{this};
mChangeSigGPINBtn->setText(i18nc("@action:button SigG is an identifier for a type of keys on a NetKey card", "Change SigG PIN"));
connect(mChangeNKSPINBtn, &QPushButton::clicked, this, [this]() {
doChangePin(NetKeyCard::nksPinKeyRef());
});
connect(mChangeSigGPINBtn, &QPushButton::clicked, this, [this]() {
doChangePin(NetKeyCard::sigGPinKeyRef());
});
actionLayout->addWidget(mChangeNKSPINBtn);
actionLayout->addWidget(mChangeSigGPINBtn);
actionLayout->addStretch(1);
mContentLayout->addLayout(actionLayout);
}
NetKeyWidget::~NetKeyWidget() = default;
namespace
{
std::vector<KeyPairInfo> getKeysSuitableForCSRCreation(const NetKeyCard *netKeyCard)
{
if (netKeyCard->hasNKSNullPin()) {
return {};
}
std::vector<KeyPairInfo> keys;
Kleo::copy_if(netKeyCard->keyInfos(), std::back_inserter(keys), [](const auto &keyInfo) {
if (keyInfo.keyRef.substr(0, 9) == "NKS-SIGG.") {
// SigG certificates for qualified signatures are issued with the physical cards;
// it's not possible to request a certificate for them
return false;
}
return keyInfo.canSign() //
&& (keyInfo.keyRef.substr(0, 9) == "NKS-NKS3.") //
&& DeVSCompliance::algorithmIsCompliant(keyInfo.algorithm);
});
return keys;
}
}
void NetKeyWidget::setCard(const NetKeyCard *card)
{
SmartCardWidget::setCard(card);
- mNullPinWidget->setSerialNumber(mSerialNumber);
+ mNullPinWidget->setSerialNumber(serialNumber());
/* According to users of NetKey Cards it is fairly uncommon
* to use SigG Certificates at all. So it should be optional to set the pins. */
mNullPinWidget->setVisible(card->hasNKSNullPin() /*|| card->hasSigGNullPin()*/);
mNullPinWidget->setSigGVisible(false /*card->hasSigGNullPin()*/);
mNullPinWidget->setNKSVisible(card->hasNKSNullPin());
mChangeNKSPINBtn->setEnabled(!card->hasNKSNullPin());
if (card->hasSigGNullPin()) {
mChangeSigGPINBtn->setText(i18nc("SigG is an identifier for a type of keys on a NetKey card", "Set SigG PIN"));
} else {
mChangeSigGPINBtn->setText(i18nc("SigG is an identifier for a type of keys on a NetKey card", "Change SigG PIN"));
}
const auto errMsg = card->errorMsg();
if (!errMsg.isEmpty()) {
mErrorLabel->setText(QStringLiteral("<b>%1:</b> %2").arg(i18n("Error"), errMsg));
mErrorLabel->setVisible(true);
} else {
mErrorLabel->setVisible(false);
}
if (mKeyForCardKeysButton) {
mKeyForCardKeysButton->setEnabled(!card->hasNKSNullPin() && card->hasSigningKey() && card->hasEncryptionKey()
&& DeVSCompliance::algorithmIsCompliant(card->keyInfo(card->signingKeyRef()).algorithm)
&& DeVSCompliance::algorithmIsCompliant(card->keyInfo(card->encryptionKeyRef()).algorithm));
}
if (mCreateCSRButton) {
mCreateCSRButton->setEnabled(!getKeysSuitableForCSRCreation(card).empty());
}
mCardKeysView->setCard(card);
}
void NetKeyWidget::doChangePin(const std::string &keyRef)
{
- const auto netKeyCard = ReaderStatus::instance()->getCard<NetKeyCard>(mSerialNumber);
+ const auto netKeyCard = ReaderStatus::instance()->getCard<NetKeyCard>(serialNumber());
if (!netKeyCard) {
- KMessageBox::error(this, i18n("Failed to find the smartcard with the serial number: %1", QString::fromStdString(mSerialNumber)));
+ KMessageBox::error(this, i18n("Failed to find the smartcard with the serial number: %1", QString::fromStdString(serialNumber())));
return;
}
- auto cmd = new ChangePinCommand(mSerialNumber, NetKeyCard::AppName, this);
+ auto cmd = new ChangePinCommand(serialNumber(), NetKeyCard::AppName, this);
this->setEnabled(false);
connect(cmd, &ChangePinCommand::finished, this, [this]() {
this->setEnabled(true);
});
cmd->setKeyRef(keyRef);
if ((keyRef == NetKeyCard::nksPinKeyRef() && netKeyCard->hasNKSNullPin()) //
|| (keyRef == NetKeyCard::sigGPinKeyRef() && netKeyCard->hasSigGNullPin())) {
cmd->setMode(ChangePinCommand::NullPinMode);
}
cmd->start();
}
void NetKeyWidget::createKeyFromCardKeys()
{
- auto cmd = new CreateOpenPGPKeyFromCardKeysCommand(mSerialNumber, NetKeyCard::AppName, this);
+ auto cmd = new CreateOpenPGPKeyFromCardKeysCommand(serialNumber(), NetKeyCard::AppName, this);
this->setEnabled(false);
connect(cmd, &CreateOpenPGPKeyFromCardKeysCommand::finished, this, [this]() {
this->setEnabled(true);
});
cmd->start();
}
namespace
{
std::string getKeyRef(const std::vector<KeyPairInfo> &keys, QWidget *parent)
{
QStringList options;
for (const auto &key : keys) {
options << QStringLiteral("%1 - %2").arg(QString::fromStdString(key.keyRef), QString::fromStdString(key.grip));
}
bool ok;
const QString choice = QInputDialog::getItem(parent,
i18n("Select Key"),
i18n("Please select the key you want to create a certificate signing request for:"),
options,
/* current= */ 0,
/* editable= */ false,
&ok);
return ok ? keys[options.indexOf(choice)].keyRef : std::string();
}
}
void NetKeyWidget::createCSR()
{
- const auto netKeyCard = ReaderStatus::instance()->getCard<NetKeyCard>(mSerialNumber);
+ const auto netKeyCard = ReaderStatus::instance()->getCard<NetKeyCard>(serialNumber());
if (!netKeyCard) {
- KMessageBox::error(this, i18n("Failed to find the smartcard with the serial number: %1", QString::fromStdString(mSerialNumber)));
+ KMessageBox::error(this, i18n("Failed to find the smartcard with the serial number: %1", QString::fromStdString(serialNumber())));
return;
}
const auto suitableKeys = getKeysSuitableForCSRCreation(netKeyCard.get());
if (suitableKeys.empty()) {
KMessageBox::error(this, i18n("Sorry! No keys suitable for creating a certificate signing request found on the smartcard."));
return;
}
const auto keyRef = getKeyRef(suitableKeys, this);
if (keyRef.empty()) {
return;
}
- auto cmd = new CreateCSRForCardKeyCommand(keyRef, mSerialNumber, NetKeyCard::AppName, this);
+ auto cmd = new CreateCSRForCardKeyCommand(keyRef, serialNumber(), NetKeyCard::AppName, this);
this->setEnabled(false);
connect(cmd, &CreateCSRForCardKeyCommand::finished, this, [this]() {
this->setEnabled(true);
});
cmd->start();
}
diff --git a/src/view/pgpcardwidget.cpp b/src/view/pgpcardwidget.cpp
index f023f0f91..6c0ba2b1b 100644
--- a/src/view/pgpcardwidget.cpp
+++ b/src/view/pgpcardwidget.cpp
@@ -1,501 +1,501 @@
/* view/pgpcardwiget.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2017 Bundesamt für Sicherheit in der Informationstechnik
SPDX-FileContributor: Intevation GmbH
SPDX-FileCopyrightText: 2020, 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 "pgpcardwidget.h"
#include "openpgpkeycardwidget.h"
#include "kleopatra_debug.h"
#include "commands/createcsrforcardkeycommand.h"
#include "commands/openpgpgeneratecardkeycommand.h"
#include "smartcard/algorithminfo.h"
#include "smartcard/openpgpcard.h"
#include "smartcard/readerstatus.h"
#include "smartcard/utils.h"
#include "dialogs/gencardkeydialog.h"
#include <utils/qt-cxx20-compat.h>
#include <Libkleo/Compliance>
#include <Libkleo/GnuPG>
#include <QFileDialog>
#include <QFileInfo>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QInputDialog>
#include <QLabel>
#include <QProgressDialog>
#include <QPushButton>
#include <QThread>
#include <QVBoxLayout>
#include <KLocalizedString>
#include <KMessageBox>
#include <KSeparator>
#include <Libkleo/Formatting>
#include <Libkleo/KeyCache>
#include <gpgme++/context.h>
#include <gpgme++/data.h>
#include <QGpgME/DataProvider>
#include <gpgme++/gpggencardkeyinteractor.h>
using namespace Kleo;
using namespace Kleo::Commands;
using namespace Kleo::SmartCard;
namespace
{
class GenKeyThread : public QThread
{
Q_OBJECT
public:
explicit GenKeyThread(const GenCardKeyDialog::KeyParams ¶ms, const std::string &serial)
: mSerial(serial)
, mParams(params)
{
}
GpgME::Error error()
{
return mErr;
}
std::string bkpFile()
{
return mBkpFile;
}
protected:
void run() override
{
// the index of the curves in this list has to match the enum values
// minus 1 of GpgGenCardKeyInteractor::Curve
static const std::vector<std::string> curves = {
"curve25519",
"curve448",
"nistp256",
"nistp384",
"nistp521",
"brainpoolP256r1",
"brainpoolP384r1",
"brainpoolP512r1",
"secp256k1", // keep it, even if we don't support it in Kleopatra
};
auto ei = std::make_unique<GpgME::GpgGenCardKeyInteractor>(mSerial);
if (mParams.algorithm.starts_with("rsa")) {
ei->setAlgo(GpgME::GpgGenCardKeyInteractor::RSA);
ei->setKeySize(QByteArray::fromStdString(mParams.algorithm.substr(3)).toInt());
} else {
ei->setAlgo(GpgME::GpgGenCardKeyInteractor::ECC);
const auto curveIt = std::find(curves.cbegin(), curves.cend(), mParams.algorithm);
if (curveIt != curves.end()) {
ei->setCurve(static_cast<GpgME::GpgGenCardKeyInteractor::Curve>(curveIt - curves.cbegin() + 1));
} else {
qCWarning(KLEOPATRA_LOG) << this << __func__ << "Invalid curve name:" << mParams.algorithm;
mErr = GpgME::Error::fromCode(GPG_ERR_INV_VALUE);
return;
}
}
ei->setNameUtf8(mParams.name.toStdString());
ei->setEmailUtf8(mParams.email.toStdString());
ei->setDoBackup(mParams.backup);
const auto ctx = std::shared_ptr<GpgME::Context>(GpgME::Context::createForProtocol(GpgME::OpenPGP));
ctx->setFlag("extended-edit", "1"); // we want to be able to select all curves
QGpgME::QByteArrayDataProvider dp;
GpgME::Data data(&dp);
mErr = ctx->cardEdit(GpgME::Key(), std::move(ei), data);
mBkpFile = static_cast<GpgME::GpgGenCardKeyInteractor *>(ctx->lastCardEditInteractor())->backupFileName();
}
private:
GpgME::Error mErr;
std::string mSerial;
GenCardKeyDialog::KeyParams mParams;
std::string mBkpFile;
};
} // Namespace
PGPCardWidget::PGPCardWidget(QWidget *parent)
: SmartCardWidget(parent)
{
{
mInfoGridLayout->setColumnStretch(mInfoGridLayout->columnCount() - 1, 0); // undo stretch set by base widget
int row = mInfoGridLayout->rowCount();
// Cardholder Row
mInfoGridLayout->addWidget(new QLabel(i18nc("The owner of a smartcard. GnuPG refers to this as cardholder.", "Cardholder:")), row, 0);
mCardHolderLabel = new QLabel{this};
mCardHolderLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
mInfoGridLayout->addWidget(mCardHolderLabel, row, 1);
{
auto button = new QPushButton{this};
button->setIcon(QIcon::fromTheme(QStringLiteral("cell_edit")));
button->setAccessibleName(i18nc("@action:button", "Edit"));
button->setToolTip(i18n("Change"));
mInfoGridLayout->addWidget(button, row, 2);
connect(button, &QPushButton::clicked, this, &PGPCardWidget::changeNameRequested);
}
row++;
// URL Row
mInfoGridLayout->addWidget(new QLabel(i18nc("The URL under which a public key that "
"corresponds to a smartcard can be downloaded",
"Pubkey URL:")),
row,
0);
mUrlLabel = new QLabel{this};
mUrlLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
mInfoGridLayout->addWidget(mUrlLabel, row, 1);
{
auto button = new QPushButton{this};
button->setIcon(QIcon::fromTheme(QStringLiteral("cell_edit")));
button->setAccessibleName(i18nc("@action:button", "Edit"));
button->setToolTip(i18n("Change"));
mInfoGridLayout->addWidget(button, row, 2);
connect(button, &QPushButton::clicked, this, &PGPCardWidget::changeUrlRequested);
}
mInfoGridLayout->setColumnStretch(mInfoGridLayout->columnCount(), 1);
}
mContentLayout->addWidget(new KSeparator(Qt::Horizontal));
// The keys
mContentLayout->addWidget(new QLabel(QStringLiteral("<b>%1</b>").arg(i18n("Keys:"))));
mKeysWidget = new OpenPGPKeyCardWidget{this};
mContentLayout->addWidget(mKeysWidget);
connect(mKeysWidget, &OpenPGPKeyCardWidget::createCSRRequested, this, &PGPCardWidget::createCSR);
connect(mKeysWidget, &OpenPGPKeyCardWidget::generateKeyRequested, this, &PGPCardWidget::generateKey);
mContentLayout->addWidget(new KSeparator(Qt::Horizontal));
mContentLayout->addWidget(new QLabel(QStringLiteral("<b>%1</b>").arg(i18n("Actions:"))));
auto actionLayout = new QHBoxLayout;
{
auto generateButton = new QPushButton(i18n("Generate New Keys"), this);
generateButton->setToolTip(xi18nc("@info:tooltip",
"<para>Generate three new keys on the smart card and create a new OpenPGP "
"certificate with those keys. Optionally, the encryption key is generated "
"off-card and a backup is created so that you can still access data encrypted "
"with this key in case the card is lost or damaged.</para>"
"<para><emphasis strong='true'>"
"Existing keys on the smart card will be overwritten."
"</emphasis></para>"));
actionLayout->addWidget(generateButton);
connect(generateButton, &QPushButton::clicked, this, &PGPCardWidget::genkeyRequested);
}
{
auto pinButton = new QPushButton(i18n("Change PIN"), this);
pinButton->setToolTip(i18nc("@info:tooltip",
"Change the PIN required for using the keys on the smart card. "
"The PIN must contain at least six characters."));
actionLayout->addWidget(pinButton);
connect(pinButton, &QPushButton::clicked, this, [this]() {
doChangePin(OpenPGPCard::pinKeyRef());
});
}
{
auto unblockButton = new QPushButton(i18n("Unblock Card"), this);
unblockButton->setToolTip(i18nc("@info:tooltip", "Unblock the smart card with the PUK."));
actionLayout->addWidget(unblockButton);
connect(unblockButton, &QPushButton::clicked, this, [this]() {
doChangePin(OpenPGPCard::resetCodeKeyRef());
});
}
{
auto pukButton = new QPushButton(i18n("Change Admin PIN"), this);
pukButton->setToolTip(i18nc("@info:tooltip", "Change the PIN required for administrative operations."));
actionLayout->addWidget(pukButton);
connect(pukButton, &QPushButton::clicked, this, [this]() {
doChangePin(OpenPGPCard::adminPinKeyRef());
});
}
{
auto resetCodeButton = new QPushButton(i18n("Change PUK"), this);
resetCodeButton->setToolTip(i18nc("@info:tooltip",
"Set or change the PUK required to unblock the smart card. "
"The PUK must contain at least eight characters."));
actionLayout->addWidget(resetCodeButton);
connect(resetCodeButton, &QPushButton::clicked, this, [this]() {
doChangePin(OpenPGPCard::resetCodeKeyRef(), ChangePinCommand::ResetMode);
});
}
actionLayout->addStretch(-1);
mContentLayout->addLayout(actionLayout);
mContentLayout->addStretch(1);
}
void PGPCardWidget::setCard(const OpenPGPCard *card)
{
SmartCardWidget::setCard(card);
mIs21 = card->appVersion() >= 0x0201;
const auto holder = card->cardHolder();
const auto url = QString::fromStdString(card->pubkeyUrl());
mCardHolderLabel->setText(holder.isEmpty() ? i18n("not set") : holder);
mUrl = url;
mUrlLabel->setText(url.isEmpty() ? i18n("not set") : QStringLiteral("<a href=\"%1\">%1</a>").arg(url.toHtmlEscaped()));
mUrlLabel->setOpenExternalLinks(true);
mKeysWidget->update(card);
mCardIsEmpty = card->keyFingerprint(OpenPGPCard::pgpSigKeyRef()).empty() && card->keyFingerprint(OpenPGPCard::pgpEncKeyRef()).empty()
&& card->keyFingerprint(OpenPGPCard::pgpAuthKeyRef()).empty();
}
void PGPCardWidget::doChangePin(const std::string &keyRef, ChangePinCommand::ChangePinMode mode)
{
- auto cmd = new ChangePinCommand(mSerialNumber, OpenPGPCard::AppName, this);
+ auto cmd = new ChangePinCommand(serialNumber(), OpenPGPCard::AppName, this);
this->setEnabled(false);
connect(cmd, &ChangePinCommand::finished, this, [this]() {
this->setEnabled(true);
});
cmd->setKeyRef(keyRef);
cmd->setMode(mode);
cmd->start();
}
void PGPCardWidget::doGenKey(GenCardKeyDialog *dlg)
{
- const GpgME::Error err = ReaderStatus::switchCardAndApp(mSerialNumber, OpenPGPCard::AppName);
+ const GpgME::Error err = ReaderStatus::switchCardAndApp(serialNumber(), OpenPGPCard::AppName);
if (err) {
return;
}
const auto params = dlg->getKeyParams();
auto progress = new QProgressDialog(this, Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::Dialog);
progress->setAutoClose(true);
progress->setMinimumDuration(0);
progress->setMaximum(0);
progress->setMinimum(0);
progress->setModal(true);
progress->setCancelButton(nullptr);
progress->setWindowTitle(i18nc("@title:window", "Generating Keys"));
progress->setLabel(new QLabel(i18n("This may take several minutes...")));
- auto workerThread = new GenKeyThread(params, mSerialNumber);
+ auto workerThread = new GenKeyThread(params, serialNumber());
connect(workerThread, &QThread::finished, this, [this, workerThread, progress] {
progress->accept();
progress->deleteLater();
genKeyDone(workerThread->error(), workerThread->bkpFile());
delete workerThread;
});
workerThread->start();
progress->exec();
}
void PGPCardWidget::genKeyDone(const GpgME::Error &err, const std::string &backup)
{
if (err) {
KMessageBox::error(this, i18nc("@info", "Failed to generate new key: %1", Formatting::errorAsString(err)));
return;
}
if (err.isCanceled()) {
return;
}
if (!backup.empty()) {
const auto bkpFile = QString::fromStdString(backup);
QFileInfo fi(bkpFile);
const auto target =
QFileDialog::getSaveFileName(this, i18n("Save backup of encryption key"), fi.fileName(), QStringLiteral("%1 (*.gpg)").arg(i18n("Backup Key")));
if (!target.isEmpty() && !QFile::copy(bkpFile, target)) {
KMessageBox::error(this, i18nc("@info", "Failed to move backup. The backup key is still stored under: %1", bkpFile));
} else if (!target.isEmpty()) {
QFile::remove(bkpFile);
}
}
KMessageBox::information(this, i18nc("@info", "Successfully generated a new key for this card."), i18nc("@title", "Success"));
ReaderStatus::mutableInstance()->updateStatus();
}
void PGPCardWidget::genkeyRequested()
{
- const auto pgpCard = ReaderStatus::instance()->getCard<OpenPGPCard>(mSerialNumber);
+ const auto pgpCard = ReaderStatus::instance()->getCard<OpenPGPCard>(serialNumber());
if (!pgpCard) {
- KMessageBox::error(this, i18n("Failed to find the OpenPGP card with the serial number: %1", QString::fromStdString(mSerialNumber)));
+ KMessageBox::error(this, i18n("Failed to find the OpenPGP card with the serial number: %1", QString::fromStdString(serialNumber())));
return;
}
if (!mCardIsEmpty) {
auto ret = KMessageBox::warningContinueCancel(this,
i18n("The existing keys on this card will be <b>deleted</b> "
"and replaced by new keys.")
+ QStringLiteral("<br/><br/>")
+ i18n("It will no longer be possible to decrypt past communication "
"encrypted for the existing key."),
i18n("Secret Key Deletion"),
KStandardGuiItem::guiItem(KStandardGuiItem::Delete),
KStandardGuiItem::cancel(),
QString(),
KMessageBox::Notify | KMessageBox::Dangerous);
if (ret != KMessageBox::Continue) {
return;
}
}
auto dlg = new GenCardKeyDialog(GenCardKeyDialog::AllKeyAttributes, this);
const auto allowedAlgos = getAllowedAlgorithms(pgpCard->supportedAlgorithms());
if (allowedAlgos.empty()) {
KMessageBox::error(this, i18nc("@info", "You cannot generate keys on this smart card because it doesn't support any of the compliant algorithms."));
return;
}
dlg->setSupportedAlgorithms(allowedAlgos, getPreferredAlgorithm(allowedAlgos));
connect(dlg, &QDialog::accepted, this, [this, dlg]() {
doGenKey(dlg);
dlg->deleteLater();
});
dlg->setModal(true);
dlg->show();
}
void PGPCardWidget::changeNameRequested()
{
QString text = mCardHolderLabel->text();
while (true) {
bool ok = false;
text = QInputDialog::getText(this, i18n("Change cardholder"), i18n("New name:"), QLineEdit::Normal, text, &ok, Qt::WindowFlags(), Qt::ImhLatinOnly);
if (!ok) {
return;
}
// Some additional restrictions imposed by gnupg
if (text.contains(QLatin1Char('<'))) {
KMessageBox::error(this, i18nc("@info", "The \"<\" character may not be used."));
continue;
}
if (text.contains(QLatin1String(" "))) {
KMessageBox::error(this, i18nc("@info", "Double spaces are not allowed"));
continue;
}
if (text.size() > 38) {
KMessageBox::error(this, i18nc("@info", "The size of the name may not exceed 38 characters."));
}
break;
}
auto parts = text.split(QLatin1Char(' '));
const auto lastName = parts.takeLast();
const QString formatted = lastName + QStringLiteral("<<") + parts.join(QLatin1Char('<'));
- const auto pgpCard = ReaderStatus::instance()->getCard<OpenPGPCard>(mSerialNumber);
+ const auto pgpCard = ReaderStatus::instance()->getCard<OpenPGPCard>(serialNumber());
if (!pgpCard) {
- KMessageBox::error(this, i18n("Failed to find the OpenPGP card with the serial number: %1", QString::fromStdString(mSerialNumber)));
+ KMessageBox::error(this, i18n("Failed to find the OpenPGP card with the serial number: %1", QString::fromStdString(serialNumber())));
return;
}
const QByteArray command = QByteArrayLiteral("SCD SETATTR DISP-NAME ") + formatted.toUtf8();
ReaderStatus::mutableInstance()->startSimpleTransaction(pgpCard, command, this, [this](const GpgME::Error &err) {
changeNameResult(err);
});
}
void PGPCardWidget::changeNameResult(const GpgME::Error &err)
{
if (err) {
KMessageBox::error(this, i18nc("@info", "Name change failed: %1", Formatting::errorAsString(err)));
return;
}
if (!err.isCanceled()) {
KMessageBox::information(this, i18nc("@info", "Name successfully changed."), i18nc("@title", "Success"));
ReaderStatus::mutableInstance()->updateStatus();
}
}
void PGPCardWidget::changeUrlRequested()
{
QString text = mUrl;
while (true) {
bool ok = false;
text = QInputDialog::getText(this,
i18n("Change the URL where the pubkey can be found"),
i18n("New pubkey URL:"),
QLineEdit::Normal,
text,
&ok,
Qt::WindowFlags(),
Qt::ImhLatinOnly);
if (!ok) {
return;
}
// Some additional restrictions imposed by gnupg
if (text.size() > 254) {
KMessageBox::error(this, i18nc("@info", "The size of the URL may not exceed 254 characters."));
}
break;
}
- const auto pgpCard = ReaderStatus::instance()->getCard<OpenPGPCard>(mSerialNumber);
+ const auto pgpCard = ReaderStatus::instance()->getCard<OpenPGPCard>(serialNumber());
if (!pgpCard) {
- KMessageBox::error(this, i18n("Failed to find the OpenPGP card with the serial number: %1", QString::fromStdString(mSerialNumber)));
+ KMessageBox::error(this, i18n("Failed to find the OpenPGP card with the serial number: %1", QString::fromStdString(serialNumber())));
return;
}
const QByteArray command = QByteArrayLiteral("SCD SETATTR PUBKEY-URL ") + text.toUtf8();
ReaderStatus::mutableInstance()->startSimpleTransaction(pgpCard, command, this, [this](const GpgME::Error &err) {
changeUrlResult(err);
});
}
void PGPCardWidget::changeUrlResult(const GpgME::Error &err)
{
if (err) {
KMessageBox::error(this, i18nc("@info", "URL change failed: %1", Formatting::errorAsString(err)));
return;
}
if (!err.isCanceled()) {
KMessageBox::information(this, i18nc("@info", "URL successfully changed."), i18nc("@title", "Success"));
ReaderStatus::mutableInstance()->updateStatus();
}
}
void PGPCardWidget::createCSR(const std::string &keyref)
{
- auto cmd = new CreateCSRForCardKeyCommand(keyref, mSerialNumber, OpenPGPCard::AppName, this);
+ auto cmd = new CreateCSRForCardKeyCommand(keyref, serialNumber(), OpenPGPCard::AppName, this);
this->setEnabled(false);
connect(cmd, &CreateCSRForCardKeyCommand::finished, this, [this]() {
this->setEnabled(true);
});
cmd->start();
}
void PGPCardWidget::generateKey(const std::string &keyref)
{
- auto cmd = new OpenPGPGenerateCardKeyCommand(keyref, mSerialNumber, this);
+ auto cmd = new OpenPGPGenerateCardKeyCommand(keyref, serialNumber(), this);
this->setEnabled(false);
connect(cmd, &OpenPGPGenerateCardKeyCommand::finished, this, [this]() {
this->setEnabled(true);
});
cmd->start();
}
#include "pgpcardwidget.moc"
diff --git a/src/view/pivcardwidget.cpp b/src/view/pivcardwidget.cpp
index 254768263..643e52da9 100644
--- a/src/view/pivcardwidget.cpp
+++ b/src/view/pivcardwidget.cpp
@@ -1,356 +1,356 @@
/* view/pivcardwiget.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2020 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "pivcardwidget.h"
#include "tooltippreferences.h"
#include "commands/certificatetopivcardcommand.h"
#include "commands/changepincommand.h"
#include "commands/createcsrforcardkeycommand.h"
#include "commands/createopenpgpkeyfromcardkeyscommand.h"
#include "commands/importcertificatefrompivcardcommand.h"
#include "commands/keytocardcommand.h"
#include "commands/pivgeneratecardkeycommand.h"
#include "commands/setpivcardapplicationadministrationkeycommand.h"
#include "smartcard/pivcard.h"
#include "smartcard/readerstatus.h"
#include <Libkleo/Compliance>
#include <Libkleo/Dn>
#include <Libkleo/Formatting>
#include <Libkleo/KeyCache>
#include <KLocalizedString>
#include <KSeparator>
#include <QGridLayout>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
using namespace GpgME;
using namespace Kleo;
using namespace Kleo::Commands;
using namespace Kleo::SmartCard;
namespace
{
static void layoutKeyWidgets(QGridLayout *grid, const QString &keyName, const PIVCardWidget::KeyWidgets &keyWidgets)
{
int row = grid->rowCount();
grid->addWidget(new QLabel(keyName), row, 0);
grid->addWidget(keyWidgets.keyGrip, row, 1);
grid->addWidget(keyWidgets.keyAlgorithm, row, 2);
grid->addWidget(keyWidgets.generateButton, row, 3);
if (keyWidgets.writeKeyButton) {
grid->addWidget(keyWidgets.writeKeyButton, row, 4);
}
row++;
grid->addWidget(keyWidgets.certificateInfo, row, 1, 1, 2);
grid->addWidget(keyWidgets.writeCertificateButton, row, 3);
grid->addWidget(keyWidgets.importCertificateButton, row, 4);
if (keyWidgets.createCSRButton) {
grid->addWidget(keyWidgets.createCSRButton, row, 5);
}
}
static int toolTipOptions()
{
using namespace Kleo::Formatting;
static const int validityFlags = Validity | Issuer | ExpiryDates | CertificateUsage;
static const int ownerFlags = Subject | UserIDs | OwnerTrust;
static const int detailsFlags = StorageLocation | CertificateType | SerialNumber | Fingerprint;
const TooltipPreferences prefs;
int flags = KeyID;
flags |= prefs.showValidity() ? validityFlags : 0;
flags |= prefs.showOwnerInformation() ? ownerFlags : 0;
flags |= prefs.showCertificateDetails() ? detailsFlags : 0;
return flags;
}
}
PIVCardWidget::PIVCardWidget(QWidget *parent)
: SmartCardWidget(parent)
{
mContentLayout->addWidget(new KSeparator(Qt::Horizontal));
mContentLayout->addWidget(new QLabel(QStringLiteral("<b>%1</b>").arg(i18n("Keys:")), this));
auto keysGrid = new QGridLayout;
for (const auto &keyInfo : PIVCard::supportedKeys()) {
KeyWidgets keyWidgets = createKeyWidgets(keyInfo);
layoutKeyWidgets(keysGrid, PIVCard::keyDisplayName(keyInfo.keyRef), keyWidgets);
}
mContentLayout->addLayout(keysGrid);
mContentLayout->addWidget(new KSeparator(Qt::Horizontal));
auto actionLayout = new QHBoxLayout;
if (CreateOpenPGPKeyFromCardKeysCommand::isSupported()) {
mKeyForCardKeysButton = new QPushButton(this);
mKeyForCardKeysButton->setText(i18nc("@action:button", "Create OpenPGP Key"));
mKeyForCardKeysButton->setToolTip(i18nc("@info:tooltip", "Create an OpenPGP key for the keys stored on the card."));
actionLayout->addWidget(mKeyForCardKeysButton);
connect(mKeyForCardKeysButton, &QPushButton::clicked, this, &PIVCardWidget::createKeyFromCardKeys);
}
{
auto button = new QPushButton(i18nc("@action:button", "Change PIN"), this);
button->setToolTip(i18nc("@info:tooltip",
"Change the PIV Card Application PIN that activates the PIV Card "
"and enables private key operations using the stored keys."));
actionLayout->addWidget(button);
connect(button, &QPushButton::clicked, this, [this]() {
changePin(PIVCard::pinKeyRef());
});
}
{
auto button = new QPushButton(i18nc("@action:button", "Change PUK"), this);
button->setToolTip(i18nc("@info:tooltip", "Change the PIN Unblocking Key that enables a reset of the PIN."));
actionLayout->addWidget(button);
connect(button, &QPushButton::clicked, this, [this]() {
changePin(PIVCard::pukKeyRef());
});
}
{
auto button = new QPushButton(i18nc("@action:button", "Change Admin Key"), this);
button->setToolTip(i18nc("@info:tooltip",
"Change the PIV Card Application Administration Key that is used by the "
"PIV Card Application to authenticate the PIV Card Application Administrator and by the "
"administrator (resp. Kleopatra) to authenticate the PIV Card Application."));
actionLayout->addWidget(button);
connect(button, &QPushButton::clicked, this, [this]() {
setAdminKey();
});
}
actionLayout->addStretch(-1);
mContentLayout->addLayout(actionLayout);
mContentLayout->addStretch(1);
}
PIVCardWidget::KeyWidgets PIVCardWidget::createKeyWidgets(const KeyPairInfo &keyInfo)
{
const std::string keyRef = keyInfo.keyRef;
KeyWidgets keyWidgets;
keyWidgets.keyGrip = new QLabel(this);
keyWidgets.keyGrip->setTextInteractionFlags(Qt::TextBrowserInteraction);
keyWidgets.keyAlgorithm = new QLabel(this);
keyWidgets.keyAlgorithm->setTextInteractionFlags(Qt::TextSelectableByMouse);
keyWidgets.generateButton = new QPushButton(i18nc("@action:button", "Generate"), this);
keyWidgets.generateButton->setEnabled(false);
connect(keyWidgets.generateButton, &QPushButton::clicked, this, [this, keyRef]() {
generateKey(keyRef);
});
if (keyRef == PIVCard::cardAuthenticationKeyRef() || keyRef == PIVCard::keyManagementKeyRef()) {
keyWidgets.writeKeyButton = new QPushButton(i18nc("@action:button", "Write Key"), this);
keyWidgets.writeKeyButton->setToolTip(i18nc("@info:tooltip", "Write the key pair of a certificate to the card"));
keyWidgets.writeKeyButton->setEnabled(true);
connect(keyWidgets.writeKeyButton, &QPushButton::clicked, this, [this, keyRef]() {
writeKeyToCard(keyRef);
});
}
keyWidgets.certificateInfo = new QLabel(this);
keyWidgets.certificateInfo->setTextInteractionFlags(Qt::TextBrowserInteraction);
keyWidgets.writeCertificateButton = new QPushButton(i18nc("@action:button", "Write Certificate"), this);
keyWidgets.writeCertificateButton->setToolTip(i18nc("@info:tooltip", "Write the certificate corresponding to this key to the card"));
keyWidgets.writeCertificateButton->setEnabled(false);
connect(keyWidgets.writeCertificateButton, &QPushButton::clicked, this, [this, keyRef]() {
writeCertificateToCard(keyRef);
});
keyWidgets.importCertificateButton = new QPushButton(i18nc("@action:button", "Import Certificate"), this);
keyWidgets.importCertificateButton->setToolTip(i18nc("@info:tooltip", "Import the certificate stored on the card"));
keyWidgets.importCertificateButton->setEnabled(false);
connect(keyWidgets.importCertificateButton, &QPushButton::clicked, this, [this, keyRef]() {
importCertificateFromCard(keyRef);
});
if (keyInfo.canSign() || keyInfo.canEncrypt()) {
keyWidgets.createCSRButton = new QPushButton(i18nc("@action:button", "Create CSR"), this);
keyWidgets.createCSRButton->setToolTip(i18nc("@info:tooltip", "Create a certificate signing request for this key"));
keyWidgets.createCSRButton->setEnabled(false);
connect(keyWidgets.createCSRButton, &QPushButton::clicked, this, [this, keyRef]() {
createCSR(keyRef);
});
}
mKeyWidgets.insert({keyRef, keyWidgets});
return keyWidgets;
}
PIVCardWidget::~PIVCardWidget()
{
}
void PIVCardWidget::setCard(const PIVCard *card)
{
SmartCardWidget::setCard(card);
if (card) {
updateCachedValues(PIVCard::pivAuthenticationKeyRef(), card);
updateCachedValues(PIVCard::cardAuthenticationKeyRef(), card);
updateCachedValues(PIVCard::digitalSignatureKeyRef(), card);
updateCachedValues(PIVCard::keyManagementKeyRef(), card);
}
updateKeyWidgets(PIVCard::pivAuthenticationKeyRef());
updateKeyWidgets(PIVCard::cardAuthenticationKeyRef());
updateKeyWidgets(PIVCard::digitalSignatureKeyRef());
updateKeyWidgets(PIVCard::keyManagementKeyRef());
if (mKeyForCardKeysButton) {
mKeyForCardKeysButton->setEnabled(card->hasSigningKey() //
&& card->hasEncryptionKey() //
&& DeVSCompliance::algorithmIsCompliant(card->keyInfo(card->signingKeyRef()).algorithm)
&& DeVSCompliance::algorithmIsCompliant(card->keyInfo(card->encryptionKeyRef()).algorithm));
}
}
void PIVCardWidget::updateCachedValues(const std::string &keyRef, const SmartCard::PIVCard *card)
{
KeyWidgets &widgets = mKeyWidgets.at(keyRef);
widgets.keyInfo = card->keyInfo(keyRef);
widgets.certificateData = card->certificateData(keyRef);
}
void PIVCardWidget::updateKeyWidgets(const std::string &keyRef)
{
const KeyWidgets &widgets = mKeyWidgets.at(keyRef);
const std::string grip = widgets.keyInfo.grip;
if (grip.empty()) {
widgets.certificateInfo->setText(i18nc("@info", "<em>slot empty</em>"));
widgets.certificateInfo->setToolTip(QString());
widgets.keyGrip->setText(QString());
widgets.keyAlgorithm->setText(QString());
widgets.generateButton->setText(i18nc("@action:button", "Generate"));
widgets.generateButton->setToolTip(i18nc("@info:tooltip %1 display name of a key", "Generate %1", PIVCard::keyDisplayName(keyRef)));
if (widgets.createCSRButton) {
widgets.createCSRButton->setEnabled(false);
}
widgets.writeCertificateButton->setEnabled(false);
widgets.importCertificateButton->setEnabled(false);
} else {
const Key certificate = KeyCache::instance()->findSubkeyByKeyGrip(grip, GpgME::CMS).parent();
if (!certificate.isNull()) {
widgets.certificateInfo->setText(i18nc("X.509 certificate DN (validity, created: date)",
"%1 (%2, created: %3)",
DN(certificate.userID(0).id()).prettyDN(),
Formatting::complianceStringShort(certificate),
Formatting::creationDateString(certificate)));
widgets.certificateInfo->setToolTip(Formatting::toolTip(certificate, toolTipOptions()));
widgets.writeCertificateButton->setEnabled(true);
} else {
widgets.certificateInfo->setText(i18nc("@info", "<em>no matching certificate</em>"));
widgets.certificateInfo->setToolTip(QString());
widgets.writeCertificateButton->setEnabled(false);
}
widgets.keyGrip->setText(QString::fromStdString(grip));
const std::string algo = widgets.keyInfo.algorithm;
widgets.keyAlgorithm->setText(algo.empty() ? i18nc("@info unknown key algorithm", "unknown") : QString::fromStdString(algo));
widgets.importCertificateButton->setEnabled(!widgets.certificateData.empty());
widgets.generateButton->setText(i18nc("@action:button", "Replace"));
widgets.generateButton->setToolTip(i18nc("@info:tooltip %1 display name of a key", "Replace %1 with new key", PIVCard::keyDisplayName(keyRef)));
if (widgets.createCSRButton) {
widgets.createCSRButton->setEnabled(DeVSCompliance::algorithmIsCompliant(algo));
}
}
widgets.generateButton->setEnabled(true);
}
void PIVCardWidget::generateKey(const std::string &keyref)
{
- auto cmd = new PIVGenerateCardKeyCommand(mSerialNumber, this);
+ auto cmd = new PIVGenerateCardKeyCommand(serialNumber(), this);
this->setEnabled(false);
connect(cmd, &PIVGenerateCardKeyCommand::finished, this, [this]() {
this->setEnabled(true);
});
cmd->setKeyRef(keyref);
cmd->start();
}
void PIVCardWidget::createCSR(const std::string &keyref)
{
- auto cmd = new CreateCSRForCardKeyCommand(keyref, mSerialNumber, PIVCard::AppName, this);
+ auto cmd = new CreateCSRForCardKeyCommand(keyref, serialNumber(), PIVCard::AppName, this);
this->setEnabled(false);
connect(cmd, &CreateCSRForCardKeyCommand::finished, this, [this]() {
this->setEnabled(true);
});
cmd->start();
}
void PIVCardWidget::writeCertificateToCard(const std::string &keyref)
{
- auto cmd = new CertificateToPIVCardCommand(keyref, mSerialNumber);
+ auto cmd = new CertificateToPIVCardCommand(keyref, serialNumber());
this->setEnabled(false);
connect(cmd, &CertificateToPIVCardCommand::finished, this, [this]() {
this->setEnabled(true);
});
cmd->setParentWidget(this);
cmd->start();
}
void PIVCardWidget::importCertificateFromCard(const std::string &keyref)
{
- auto cmd = new ImportCertificateFromPIVCardCommand(keyref, mSerialNumber);
+ auto cmd = new ImportCertificateFromPIVCardCommand(keyref, serialNumber());
this->setEnabled(false);
connect(cmd, &ImportCertificateFromPIVCardCommand::finished, this, [this, keyref]() {
this->updateKeyWidgets(keyref);
this->setEnabled(true);
});
cmd->setParentWidget(this);
cmd->start();
}
void PIVCardWidget::writeKeyToCard(const std::string &keyref)
{
- auto cmd = new KeyToCardCommand(keyref, mSerialNumber, PIVCard::AppName);
+ auto cmd = new KeyToCardCommand(keyref, serialNumber(), PIVCard::AppName);
this->setEnabled(false);
connect(cmd, &KeyToCardCommand::finished, this, [this]() {
this->setEnabled(true);
});
cmd->setParentWidget(this);
cmd->start();
}
void PIVCardWidget::createKeyFromCardKeys()
{
- auto cmd = new CreateOpenPGPKeyFromCardKeysCommand(mSerialNumber, PIVCard::AppName, this);
+ auto cmd = new CreateOpenPGPKeyFromCardKeysCommand(serialNumber(), PIVCard::AppName, this);
this->setEnabled(false);
connect(cmd, &CreateOpenPGPKeyFromCardKeysCommand::finished, this, [this]() {
this->setEnabled(true);
});
cmd->start();
}
void PIVCardWidget::changePin(const std::string &keyRef)
{
- auto cmd = new ChangePinCommand(mSerialNumber, PIVCard::AppName, this);
+ auto cmd = new ChangePinCommand(serialNumber(), PIVCard::AppName, this);
this->setEnabled(false);
connect(cmd, &ChangePinCommand::finished, this, [this]() {
this->setEnabled(true);
});
cmd->setKeyRef(keyRef);
cmd->start();
}
void PIVCardWidget::setAdminKey()
{
- auto cmd = new SetPIVCardApplicationAdministrationKeyCommand(mSerialNumber, this);
+ auto cmd = new SetPIVCardApplicationAdministrationKeyCommand(serialNumber(), this);
this->setEnabled(false);
connect(cmd, &SetPIVCardApplicationAdministrationKeyCommand::finished, this, [this]() {
this->setEnabled(true);
});
cmd->start();
}
diff --git a/src/view/smartcardwidget.cpp b/src/view/smartcardwidget.cpp
index 2a5d34aeb..6f842d7dc 100644
--- a/src/view/smartcardwidget.cpp
+++ b/src/view/smartcardwidget.cpp
@@ -1,118 +1,126 @@
/* view/smartcardwidget.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2024 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "smartcardwidget.h"
#include "infofield.h"
#include <smartcard/card.h>
#include <view/cardkeysview.h>
#include <KLocalizedString>
#include <QGridLayout>
#include <QLabel>
#include <QScrollArea>
#include <QVBoxLayout>
using namespace Kleo;
using namespace Kleo::SmartCard;
-QString cardType(const Card *card)
+static QString cardTypeForDisplay(const Card *card)
{
switch (card->appType()) {
case AppType::NetKeyApp:
return i18nc("1 is a Version number", "NetKey v%1 Card", card->appVersion());
case AppType::OpenPGPApp: {
const std::string manufacturer = card->manufacturer();
const bool manufacturerIsUnknown = manufacturer.empty() || manufacturer == "unknown";
return (manufacturerIsUnknown //
? i18nc("Placeholder is a version number", "Unknown OpenPGP v%1 card", card->displayAppVersion())
: i18nc("First placeholder is manufacturer, second placeholder is a version number",
"%1 OpenPGP v%2 card",
QString::fromStdString(manufacturer),
card->displayAppVersion()));
}
case AppType::P15App:
return i18nc("%1 is a smartcard manufacturer", "%1 PKCS#15 card", QString::fromStdString(card->manufacturer()));
case AppType::PIVApp:
return i18nc("%1 version number", "PIV v%1 card", card->displayAppVersion());
default:
return {};
};
}
SmartCardWidget::SmartCardWidget(QWidget *parent)
: QWidget{parent}
{
auto mainLayout = new QVBoxLayout{this};
mainLayout->setContentsMargins({});
auto area = new QScrollArea{this};
area->setFocusPolicy(Qt::NoFocus);
area->setFrameShape(QFrame::NoFrame);
area->setWidgetResizable(true);
mainLayout->addWidget(area);
auto areaWidget = new QWidget{this};
area->setWidget(areaWidget);
mContentLayout = new QVBoxLayout{areaWidget};
auto contentLayout = mContentLayout;
{
// auto gridLayout = new QGridLayout;
mInfoGridLayout = new QGridLayout;
auto gridLayout = mInfoGridLayout;
// gridLayout->setColumnStretch(1, 1);
int row = -1;
row++;
mCardTypeField = std::make_unique<InfoField>(i18nc("@label", "Card type:"), parent);
gridLayout->addWidget(mCardTypeField->label(), row, 0);
gridLayout->addLayout(mCardTypeField->layout(), row, 1);
row++;
mSerialNumberField = std::make_unique<InfoField>(i18nc("@label", "Serial number:"), parent);
gridLayout->addWidget(mSerialNumberField->label(), row, 0);
gridLayout->addLayout(mSerialNumberField->layout(), row, 1);
gridLayout->setColumnStretch(gridLayout->columnCount(), 1);
contentLayout->addLayout(gridLayout);
}
}
SmartCardWidget::~SmartCardWidget() = default;
void SmartCardWidget::setCard(const Card *card)
{
- mSerialNumber = card->serialNumber();
- mAppName = card->appName();
- mAppType = card->appType();
+ mCard.reset(card->clone());
- mCardTypeField->setValue(cardType(card));
+ mCardTypeField->setValue(cardTypeForDisplay(card));
mSerialNumberField->setValue(card->displaySerialNumber());
}
+Kleo::SmartCard::AppType SmartCardWidget::cardType() const
+{
+ return mCard ? mCard->appType() : AppType::NoApp;
+}
+
+std::string SmartCardWidget::serialNumber() const
+{
+ return mCard ? mCard->serialNumber() : std::string{};
+}
+
std::string SmartCardWidget::currentCardSlot() const
{
if (mCardKeysView) {
return mCardKeysView->currentCardSlot();
}
return {};
}
GpgME::Key SmartCardWidget::currentCertificate() const
{
if (mCardKeysView) {
return mCardKeysView->currentCertificate();
}
return {};
}
diff --git a/src/view/smartcardwidget.h b/src/view/smartcardwidget.h
index 635a8e382..03f8fdcea 100644
--- a/src/view/smartcardwidget.h
+++ b/src/view/smartcardwidget.h
@@ -1,62 +1,61 @@
/* view/smartcardwidget.h
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2024 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QWidget>
#include <memory>
#include <string>
class QGridLayout;
class QVBoxLayout;
namespace GpgME
{
class Key;
}
namespace Kleo
{
class CardKeysView;
class InfoField;
}
namespace Kleo::SmartCard
{
enum class AppType;
class Card;
}
class SmartCardWidget : public QWidget
{
Q_OBJECT
public:
SmartCardWidget(QWidget *parent = nullptr);
~SmartCardWidget() override;
void setCard(const Kleo::SmartCard::Card *card);
+ Kleo::SmartCard::AppType cardType() const;
+ std::string serialNumber() const;
std::string currentCardSlot() const;
GpgME::Key currentCertificate() const;
protected:
- std::string mSerialNumber;
-
QVBoxLayout *mContentLayout = nullptr;
QGridLayout *mInfoGridLayout = nullptr;
private:
- std::string mAppName;
- Kleo::SmartCard::AppType mAppType;
+ std::unique_ptr<const Kleo::SmartCard::Card> mCard;
std::unique_ptr<Kleo::InfoField> mCardTypeField;
std::unique_ptr<Kleo::InfoField> mSerialNumberField;
protected:
Kleo::CardKeysView *mCardKeysView = nullptr;
};
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Jul 8, 12:24 PM (11 h, 32 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
d0/06/5fd5303db975a3f7678ad4e147e3
Attached To
rKLEOPATRA Kleopatra
Event Timeline
Log In to Comment