Page MenuHome GnuPG

No OneTemporary

diff --git a/src/commands/keytocardcommand.cpp b/src/commands/keytocardcommand.cpp
index fb6ea8e6f..5ebf49074 100644
--- a/src/commands/keytocardcommand.cpp
+++ b/src/commands/keytocardcommand.cpp
@@ -1,424 +1,461 @@
/* commands/keytocardcommand.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 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 "keytocardcommand.h"
-#include "kleopatra_debug.h"
#include "command_p.h"
-#include "smartcard/readerstatus.h"
+#include "commands/authenticatepivcardapplicationcommand.h"
+
+#include "dialogs/certificateselectiondialog.h"
+
#include "smartcard/openpgpcard.h"
#include "smartcard/pivcard.h"
+#include "smartcard/readerstatus.h"
-#include "commands/authenticatepivcardapplicationcommand.h"
+#include <Libkleo/Dn>
+#include <Libkleo/Formatting>
+#include <Libkleo/KeyCache>
+#include <Libkleo/KeySelectionDialog>
#include <KLocalizedString>
-#include <QInputDialog>
#include <QDateTime>
+#include <QInputDialog>
#include <QStringList>
#include "kleopatra_debug.h"
using namespace Kleo;
using namespace Kleo::Commands;
+using namespace Kleo::Dialogs;
using namespace Kleo::SmartCard;
using namespace GpgME;
class KeyToCardCommand::Private : public Command::Private
{
friend class ::Kleo::Commands::KeyToCardCommand;
KeyToCardCommand *q_func() const
{
return static_cast<KeyToCardCommand *>(q);
}
public:
- explicit Private(KeyToCardCommand *qq, const GpgME::Subkey &key, const std::string &serialno);
- explicit Private(KeyToCardCommand *qq, const std::string &cardSlot, const std::string &serialno);
+ explicit Private(KeyToCardCommand *qq, const GpgME::Subkey &subkey, const std::string &serialno);
+ explicit Private(KeyToCardCommand *qq, const std::string &slot, const std::string &serialno);
~Private();
private:
void start();
void startKeyToOpenPGPCard();
+ Subkey getSubkeyToTransferToPIVCard(const std::string &cardSlot, const std::shared_ptr<PIVCard> &card);
void startKeyToPIVCard();
void authenticate();
void authenticationFinished();
void authenticationCanceled();
private:
- std::string mSerial;
- GpgME::Subkey mSubkey;
+ std::string serialNumber;
+ GpgME::Subkey subkey;
std::string cardSlot;
bool overwriteExistingAlreadyApproved = false;
bool hasBeenCanceled = false;
};
KeyToCardCommand::Private *KeyToCardCommand::d_func()
{
return static_cast<Private *>(d.get());
}
const KeyToCardCommand::Private *KeyToCardCommand::d_func() const
{
return static_cast<const Private *>(d.get());
}
#define q q_func()
#define d d_func()
KeyToCardCommand::Private::Private(KeyToCardCommand *qq,
- const GpgME::Subkey &key,
+ const GpgME::Subkey &subkey_,
const std::string &serialno)
: Command::Private(qq, nullptr),
- mSerial(serialno),
- mSubkey(key)
+ serialNumber(serialno),
+ subkey(subkey_)
{
}
-KeyToCardCommand::Private::Private(KeyToCardCommand *qq, const std::string &cardSlot_, const std::string &serialno)
+KeyToCardCommand::Private::Private(KeyToCardCommand *qq, const std::string &slot, const std::string &serialno)
: Command::Private(qq, nullptr)
- , mSerial(serialno)
- , cardSlot(cardSlot_)
+ , serialNumber(serialno)
+ , cardSlot(slot)
{
}
KeyToCardCommand::Private::~Private()
{
}
void KeyToCardCommand::Private::start()
{
qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::Private::start()";
- const auto card = SmartCard::ReaderStatus::instance()->getCard<Card>(mSerial);
+ const auto card = SmartCard::ReaderStatus::instance()->getCard<Card>(serialNumber);
if (!card) {
- error(i18n("Failed to find the card with the serial number: %1", QString::fromStdString(mSerial)));
+ error(i18n("Failed to find the card with the serial number: %1", QString::fromStdString(serialNumber)));
finished();
return;
}
switch (card->appType()) {
case SmartCard::Card::OpenPGPApplication: {
startKeyToOpenPGPCard();
}
break;
case SmartCard::Card::PivApplication: {
startKeyToPIVCard();
}
break;
default: {
error(i18n("Sorry! Transferring keys to this card is not supported."));
finished();
return;
}
}
}
namespace {
static int getOpenPGPCardSlotForKey(const GpgME::Subkey &subKey, QWidget *parent)
{
// Check if we need to ask the user for the slot
if ((subKey.canSign() || subKey.canCertify()) && !subKey.canEncrypt() && !subKey.canAuthenticate()) {
// Signing only
return 1;
}
if (subKey.canEncrypt() && !(subKey.canSign() || subKey.canCertify()) && !subKey.canAuthenticate()) {
// Encrypt only
return 2;
}
if (subKey.canAuthenticate() && !(subKey.canSign() || subKey.canCertify()) && !subKey.canEncrypt()) {
// Auth only
return 3;
}
// Multiple uses, ask user.
QStringList options;
if (subKey.canSign() || subKey.canCertify()) {
options << i18nc("Placeholder is the number of a slot on a smart card", "Signature (%1)", 1);
}
if (subKey.canEncrypt()) {
options << i18nc("Placeholder is the number of a slot on a smart card", "Encryption (%1)", 2);
}
if (subKey.canAuthenticate()) {
options << i18nc("Placeholder is the number of a slot on a smart card", "Authentication (%1)", 3);
}
bool ok;
const QString choice = QInputDialog::getItem(parent, i18n("Select Card Slot"),
i18n("Please select the card slot the key should be written to:"), options, /* current= */ 0, /* editable= */ false, &ok);
const int slot = options.indexOf(choice) + 1;
return ok ? slot : -1;
}
}
void KeyToCardCommand::Private::startKeyToOpenPGPCard() {
qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::Private::startKeyToOpenPGPCard()";
- const auto pgpCard = SmartCard::ReaderStatus::instance()->getCard<OpenPGPCard>(mSerial);
+ const auto pgpCard = SmartCard::ReaderStatus::instance()->getCard<OpenPGPCard>(serialNumber);
if (!pgpCard) {
- error(i18n("Failed to find the OpenPGP card with the serial number: %1", QString::fromStdString(mSerial)));
+ error(i18n("Failed to find the OpenPGP card with the serial number: %1", QString::fromStdString(serialNumber)));
finished();
return;
}
- if (mSubkey.isNull()) {
+ if (subkey.isNull()) {
finished();
return;
}
- if (mSubkey.parent().protocol() != GpgME::OpenPGP) {
+ if (subkey.parent().protocol() != GpgME::OpenPGP) {
error(i18n("Sorry! This key cannot be transferred to an OpenPGP card."));
finished();
return;
}
- const auto slot = getOpenPGPCardSlotForKey(mSubkey, parentWidgetOrView());
+ const auto slot = getOpenPGPCardSlotForKey(subkey, parentWidgetOrView());
if (slot < 1) {
finished();
return;
}
// Check if we need to do the overwrite warning.
std::string existingKey;
QString encKeyWarning;
if (slot == 1) {
existingKey = pgpCard->sigFpr();
} else if (slot == 2) {
existingKey = pgpCard->encFpr();
encKeyWarning = i18n("It will no longer be possible to decrypt past communication "
"encrypted for the existing key.");
} else if (slot == 3) {
existingKey = pgpCard->authFpr();
}
if (!existingKey.empty()) {
const QString message = i18nc("@info",
"<p>This card already contains a key in this slot. Continuing will <b>overwrite</b> that key.</p>"
"<p>If there is no backup the existing key will be irrecoverably lost.</p>") +
i18n("The existing key has the fingerprint:") +
QStringLiteral("<pre>%1</pre>").arg(QString::fromStdString(existingKey)) +
encKeyWarning;
const auto choice = KMessageBox::warningContinueCancel(parentWidgetOrView(), message,
i18nc("@title:window", "Overwrite existing key"),
KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QString(), KMessageBox::Notify | KMessageBox::Dangerous);
if (choice != KMessageBox::Continue) {
finished();
return;
}
}
// Now do the deed
- const auto time = QDateTime::fromSecsSinceEpoch(mSubkey.creationTime());
+ const auto time = QDateTime::fromSecsSinceEpoch(subkey.creationTime());
const auto timestamp = time.toString(QStringLiteral("yyyyMMdd'T'HHmmss"));
const QString cmd = QStringLiteral("KEYTOCARD --force %1 %2 OPENPGP.%3 %4")
- .arg(QString::fromLatin1(mSubkey.keyGrip()), QString::fromStdString(mSerial))
+ .arg(QString::fromLatin1(subkey.keyGrip()), QString::fromStdString(serialNumber))
.arg(slot)
.arg(timestamp);
ReaderStatus::mutableInstance()->startSimpleTransaction(cmd.toUtf8(), q_func(), "keyToOpenPGPCardDone");
}
namespace {
-static GpgME::Subkey getSubkeyToTransferToPIVCard(const std::string &cardSlot, const std::shared_ptr<PIVCard> &/*card*/)
+static std::vector<Key> getEncryptionCertificates()
{
- if (!cardSlot.empty()) {
- if (cardSlot == PIVCard::keyManagementKeyRef()) {
- // get encryption certificate with secret subkey
- }
- return GpgME::Subkey();
+ std::vector<Key> encryptionCertificates = KeyCache::instance()->secretKeys();
+ const auto it = std::remove_if(encryptionCertificates.begin(), encryptionCertificates.end(),
+ [](const Key &key) {
+ return ! (key.protocol() == GpgME::CMS &&
+ !key.subkey(0).isNull() &&
+ key.subkey(0).canEncrypt() &&
+ key.subkey(0).isSecret());
+ });
+ encryptionCertificates.erase(it, encryptionCertificates.end());
+ return encryptionCertificates;
+}
+}
+
+Subkey KeyToCardCommand::Private::getSubkeyToTransferToPIVCard(const std::string &cardSlot, const std::shared_ptr<PIVCard> &/*card*/)
+{
+ if (cardSlot != PIVCard::keyManagementKeyRef()) {
+ return Subkey();
}
- return GpgME::Subkey();
-}
+ const std::vector<Key> encryptionCertificates = getEncryptionCertificates();
+ if (encryptionCertificates.empty()) {
+ error(i18n("Sorry! No suitable certificate to write to this card slot was found."));
+ return Subkey();
+ }
+
+ auto dialog = new KeySelectionDialog(parentWidgetOrView());
+ dialog->setWindowTitle(i18nc("@title:window", "Select Certificate"));
+ dialog->setText(i18n("Please select the certificate whose key pair you want to write to the card:"));
+ dialog->setKeys(encryptionCertificates);
+
+ if (dialog->exec() == QDialog::Rejected) {
+ return Subkey();
+ }
+
+ return dialog->selectedKey().subkey(0);
}
void KeyToCardCommand::Private::startKeyToPIVCard()
{
qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::Private::startKeyToPIVCard()";
- const auto pivCard = SmartCard::ReaderStatus::instance()->getCard<PIVCard>(mSerial);
+ const auto pivCard = SmartCard::ReaderStatus::instance()->getCard<PIVCard>(serialNumber);
if (!pivCard) {
- error(i18n("Failed to find the PIV card with the serial number: %1", QString::fromStdString(mSerial)));
+ error(i18n("Failed to find the PIV card with the serial number: %1", QString::fromStdString(serialNumber)));
finished();
return;
}
if (cardSlot != PIVCard::keyManagementKeyRef()) {
// key to card is only supported for encryption keys
finished();
return;
}
- if (mSubkey.isNull()) {
- mSubkey = getSubkeyToTransferToPIVCard(cardSlot, pivCard);
+ if (subkey.isNull()) {
+ subkey = getSubkeyToTransferToPIVCard(cardSlot, pivCard);
}
- if (mSubkey.isNull()) {
- error(i18n("Sorry! No suitable certificate to write to this card slot was found."));
+ if (subkey.isNull()) {
finished();
return;
}
- if (mSubkey.parent().protocol() != GpgME::CMS) {
+ if (subkey.parent().protocol() != GpgME::CMS) {
error(i18n("Sorry! This key cannot be transferred to a PIV card."));
finished();
return;
}
- if (!mSubkey.canEncrypt() && !mSubkey.canSign()) {
+ if (!subkey.canEncrypt() && !subkey.canSign()) {
error(i18n("Sorry! Only encryption keys and signing keys can be transferred to a PIV card."));
finished();
return;
}
// Check if we need to do the overwrite warning.
if (!overwriteExistingAlreadyApproved) {
const std::string existingKey = pivCard->keyGrip(cardSlot);
- if (!existingKey.empty() && (existingKey != mSubkey.keyGrip())) {
+ if (!existingKey.empty() && (existingKey != subkey.keyGrip())) {
const QString decryptionWarning = (cardSlot == PIVCard::keyManagementKeyRef()) ?
i18n("It will no longer be possible to decrypt past communication encrypted for the existing key.") :
QString();
const QString message = i18nc("@info",
"<p>This card already contains a key in this slot. Continuing will <b>overwrite</b> that key.</p>"
"<p>If there is no backup the existing key will be irrecoverably lost.</p>") +
i18n("The existing key has the key grip:") +
QStringLiteral("<pre>%1</pre>").arg(QString::fromStdString(existingKey)) +
decryptionWarning;
const auto choice = KMessageBox::warningContinueCancel(parentWidgetOrView(), message,
i18nc("@title:window", "Overwrite existing key"),
KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QString(), KMessageBox::Notify | KMessageBox::Dangerous);
if (choice != KMessageBox::Continue) {
finished();
return;
}
overwriteExistingAlreadyApproved = true;
}
}
const QString cmd = QStringLiteral("KEYTOCARD --force %1 %2 %3")
- .arg(QString::fromLatin1(mSubkey.keyGrip()), QString::fromStdString(mSerial))
+ .arg(QString::fromLatin1(subkey.keyGrip()), QString::fromStdString(serialNumber))
.arg(QString::fromStdString(cardSlot));
ReaderStatus::mutableInstance()->startSimpleTransaction(cmd.toUtf8(), q_func(), "keyToPIVCardDone");
}
void KeyToCardCommand::Private::authenticate()
{
qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::authenticate()";
- auto cmd = new AuthenticatePIVCardApplicationCommand(mSerial, parentWidgetOrView());
+ auto cmd = new AuthenticatePIVCardApplicationCommand(serialNumber, parentWidgetOrView());
connect(cmd, &AuthenticatePIVCardApplicationCommand::finished,
q, [this]() { authenticationFinished(); });
connect(cmd, &AuthenticatePIVCardApplicationCommand::canceled,
q, [this]() { authenticationCanceled(); });
cmd->start();
}
void KeyToCardCommand::Private::authenticationFinished()
{
qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::authenticationFinished()";
if (!hasBeenCanceled) {
startKeyToPIVCard();
}
}
void KeyToCardCommand::Private::authenticationCanceled()
{
qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::authenticationCanceled()";
hasBeenCanceled = true;
canceled();
}
KeyToCardCommand::KeyToCardCommand(const GpgME::Subkey &key, const std::string &serialno)
: Command(new Private(this, key, serialno))
{
}
KeyToCardCommand::KeyToCardCommand(const std::string& cardSlot, const std::string &serialno)
: Command(new Private(this, cardSlot, serialno))
{
}
KeyToCardCommand::~KeyToCardCommand()
{
qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::~KeyToCardCommand()";
}
bool KeyToCardCommand::supported()
{
return true;
}
void KeyToCardCommand::keyToOpenPGPCardDone(const GpgME::Error &err)
{
if (err) {
d->error(i18nc("@info",
"Moving the key to the card failed: %1", QString::fromUtf8(err.asString())),
i18nc("@title", "Error"));
} else if (!err.isCanceled()) {
/* TODO DELETE_KEY is too strong, because it also deletes the stub
* of the secret key. I could not find out how GnuPG does this. Question
* to GnuPG Developers is pending an answer
if (KMessageBox::questionYesNo(d->parentWidgetOrView(),
i18n("Do you want to delete the key on this computer?"),
i18nc("@title:window",
"Key transferred to card")) == KMessageBox::Yes) {
- const QString cmd = QStringLiteral("DELETE_KEY --force %1").arg(d->mSubkey.keyGrip());
+ const QString cmd = QStringLiteral("DELETE_KEY --force %1").arg(d->subkey.keyGrip());
// Using readerstatus is a bit overkill but it's an easy way to talk to the agent.
ReaderStatus::mutableInstance()->startSimpleTransaction(cmd.toUtf8(), this, "deleteDone");
}
*/
- KMessageBox::information(d->parentWidgetOrView(),
- i18n("Successfully copied the key to the card."),
- i18nc("@title", "Success"));
+ d->information(i18nc("@info", "Successfully copied the key to the card."),
+ i18nc("@title", "Success"));
+ ReaderStatus::mutableInstance()->updateStatus();
}
d->finished();
}
void KeyToCardCommand::keyToPIVCardDone(const GpgME::Error &err)
{
qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::keyToPIVCardDone():"
<< err.asString() << "(" << err.code() << ")";
if (err) {
// gpgme 1.13 reports "BAD PIN" instead of "NO AUTH"
if (err.code() == GPG_ERR_NO_AUTH || err.code() == GPG_ERR_BAD_PIN) {
d->authenticate();
return;
}
d->error(i18nc("@info",
- "Moving the key to the card failed: %1", QString::fromUtf8(err.asString())),
+ "Copying the key pair to the card failed: %1", QString::fromUtf8(err.asString())),
i18nc("@title", "Error"));
+ } else if (!err.isCanceled()) {
+ d->information(i18nc("@info", "Successfully copied the key pair to the card."),
+ i18nc("@title", "Success"));
+ ReaderStatus::mutableInstance()->updateStatus();
}
d->finished();
}
void KeyToCardCommand::deleteDone(const GpgME::Error &err)
{
if (err) {
d->error(i18nc("@info", "Failed to delete the key: %1", QString::fromUtf8(err.asString())),
i18nc("@title", "Error"));
}
d->finished();
}
void KeyToCardCommand::doStart()
{
qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::doStart()";
d->start();
}
void KeyToCardCommand::doCancel()
{
}
#undef q_func
#undef d_func
diff --git a/src/view/pivcardwidget.cpp b/src/view/pivcardwidget.cpp
index 52559ee8f..d72d14507 100644
--- a/src/view/pivcardwidget.cpp
+++ b/src/view/pivcardwidget.cpp
@@ -1,273 +1,292 @@
/* 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 "commands/certificatetopivcardcommand.h"
#include "commands/changepincommand.h"
+#include "commands/keytocardcommand.h"
#include "commands/pivgeneratecardkeycommand.h"
#include "commands/setpivcardapplicationadministrationkeycommand.h"
#include "smartcard/pivcard.h"
#include "smartcard/readerstatus.h"
#include <QFrame>
#include <QGridLayout>
#include <QLabel>
#include <QPushButton>
#include <QScrollArea>
#include <QVBoxLayout>
#include <KLocalizedString>
#include <KMessageBox>
using namespace Kleo;
using namespace Kleo::Commands;
using namespace Kleo::SmartCard;
namespace {
static QString formatVersion(int value)
{
if (value < 0) {
return QLatin1String("n/a");
}
const unsigned int a = ((value >> 24) & 0xff);
const unsigned int b = ((value >> 16) & 0xff);
const unsigned int c = ((value >> 8) & 0xff);
const unsigned int d = ((value ) & 0xff);
if (a) {
return QStringLiteral("%1.%2.%3.%4").arg(QString::number(a), QString::number(b), QString::number(c), QString::number(d));
} else if (b) {
return QStringLiteral("%1.%2.%3").arg(QString::number(b), QString::number(c), QString::number(d));
} else if (c) {
return QStringLiteral("%1.%2").arg(QString::number(c), QString::number(d));
}
return QString::number(d);
}
} // Namespace
PIVCardWidget::PIVCardWidget(QWidget *parent):
QWidget(parent),
mSerialNumber(new QLabel(this)),
mVersionLabel(new QLabel(this)),
mPIVAuthenticationKey(new QLabel(this)),
mCardAuthenticationKey(new QLabel(this)),
mDigitalSignatureKey(new QLabel(this)),
mKeyManagementKey(new QLabel(this)),
mGeneratePIVAuthenticationKeyBtn(new QPushButton(this)),
mWritePIVAuthenticationCertificateBtn(new QPushButton(this)),
mGenerateCardAuthenticationKeyBtn(new QPushButton(this)),
mWriteCardAuthenticationCertificateBtn(new QPushButton(this)),
mGenerateDigitalSignatureKeyBtn(new QPushButton(this)),
mWriteDigitalSignatureCertificateBtn(new QPushButton(this)),
mGenerateKeyManagementKeyBtn(new QPushButton(this)),
- mWriteKeyManagementCertificateBtn(new QPushButton(this))
+ mWriteKeyManagementCertificateBtn(new QPushButton(this)),
+ mWriteKeyManagementKeyBtn(new QPushButton(this))
{
auto grid = new QGridLayout;
int row = 0;
// Set up the scroll are
auto area = new QScrollArea;
area->setFrameShape(QFrame::NoFrame);
area->setWidgetResizable(true);
auto areaWidget = new QWidget;
auto areaVLay = new QVBoxLayout(areaWidget);
areaVLay->addLayout(grid);
areaVLay->addStretch(1);
area->setWidget(areaWidget);
auto myLayout = new QVBoxLayout(this);
myLayout->addWidget(area);
// Version and Serialnumber
grid->addWidget(mVersionLabel, row++, 0, 1, 2);
mVersionLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
grid->addWidget(new QLabel(i18n("Serial number:")), row, 0);
grid->addWidget(mSerialNumber, row++, 1);
mSerialNumber->setTextInteractionFlags(Qt::TextBrowserInteraction);
// The keys
auto line1 = new QFrame();
line1->setFrameShape(QFrame::HLine);
- grid->addWidget(line1, row++, 0, 1, 4);
+ grid->addWidget(line1, row++, 0, 1, 5);
grid->addWidget(new QLabel(QStringLiteral("<b>%1</b>").arg(i18n("Keys:"))), row++, 0);
grid->addWidget(new QLabel(i18n("PIV authentication:")), row, 0);
grid->addWidget(mPIVAuthenticationKey, row, 1);
mPIVAuthenticationKey->setTextInteractionFlags(Qt::TextBrowserInteraction);
mGeneratePIVAuthenticationKeyBtn->setText(i18nc("@action:button", "Generate"));
mGeneratePIVAuthenticationKeyBtn->setEnabled(false);
grid->addWidget(mGeneratePIVAuthenticationKeyBtn, row, 2);
connect(mGeneratePIVAuthenticationKeyBtn, &QPushButton::clicked, this, [this] () { generateKey(PIVCard::pivAuthenticationKeyRef()); });
mWritePIVAuthenticationCertificateBtn->setText(i18nc("@action:button", "Write Certificate"));
mWritePIVAuthenticationCertificateBtn->setToolTip(i18nc("@info:tooltip", "Write the certificate corresponding to this key to the card"));
mWritePIVAuthenticationCertificateBtn->setEnabled(false);
grid->addWidget(mWritePIVAuthenticationCertificateBtn, row, 3);
connect(mWritePIVAuthenticationCertificateBtn, &QPushButton::clicked, this, [this] () { writeCertificateToCard(PIVCard::pivAuthenticationKeyRef()); });
row++;
grid->addWidget(new QLabel(i18n("Card authentication:")), row, 0);
grid->addWidget(mCardAuthenticationKey, row, 1);
mCardAuthenticationKey->setTextInteractionFlags(Qt::TextBrowserInteraction);
mGenerateCardAuthenticationKeyBtn->setText(i18nc("@action:button", "Generate"));
mGenerateCardAuthenticationKeyBtn->setEnabled(false);
grid->addWidget(mGenerateCardAuthenticationKeyBtn, row, 2);
connect(mGenerateCardAuthenticationKeyBtn, &QPushButton::clicked, this, [this] () { generateKey(PIVCard::cardAuthenticationKeyRef()); });
mWriteCardAuthenticationCertificateBtn->setText(i18nc("@action:button", "Write Certificate"));
mWriteCardAuthenticationCertificateBtn->setToolTip(i18nc("@info:tooltip", "Write the certificate corresponding to this key to the card"));
mWriteCardAuthenticationCertificateBtn->setEnabled(false);
grid->addWidget(mWriteCardAuthenticationCertificateBtn, row, 3);
connect(mWriteCardAuthenticationCertificateBtn, &QPushButton::clicked, this, [this] () { writeCertificateToCard(PIVCard::cardAuthenticationKeyRef()); });
row++;
grid->addWidget(new QLabel(i18n("Digital signature:")), row, 0);
grid->addWidget(mDigitalSignatureKey, row, 1);
mDigitalSignatureKey->setTextInteractionFlags(Qt::TextBrowserInteraction);
mGenerateDigitalSignatureKeyBtn->setText(i18nc("@action:button", "Generate"));
mGenerateDigitalSignatureKeyBtn->setEnabled(false);
grid->addWidget(mGenerateDigitalSignatureKeyBtn, row, 2);
connect(mGenerateDigitalSignatureKeyBtn, &QPushButton::clicked, this, [this] () { generateKey(PIVCard::digitalSignatureKeyRef()); });
mWriteDigitalSignatureCertificateBtn->setText(i18nc("@action:button", "Write Certificate"));
mWriteDigitalSignatureCertificateBtn->setToolTip(i18nc("@info:tooltip", "Write the certificate corresponding to this key to the card"));
mWriteDigitalSignatureCertificateBtn->setEnabled(false);
grid->addWidget(mWriteDigitalSignatureCertificateBtn, row, 3);
connect(mWriteDigitalSignatureCertificateBtn, &QPushButton::clicked, this, [this] () { writeCertificateToCard(PIVCard::digitalSignatureKeyRef()); });
row++;
grid->addWidget(new QLabel(i18n("Key management:")), row, 0);
grid->addWidget(mKeyManagementKey, row, 1);
mKeyManagementKey->setTextInteractionFlags(Qt::TextBrowserInteraction);
mGenerateKeyManagementKeyBtn->setText(i18nc("@action:button", "Generate"));
mGenerateKeyManagementKeyBtn->setEnabled(false);
grid->addWidget(mGenerateKeyManagementKeyBtn, row, 2);
connect(mGenerateKeyManagementKeyBtn, &QPushButton::clicked, this, [this] () { generateKey(PIVCard::keyManagementKeyRef()); });
mWriteKeyManagementCertificateBtn->setText(i18nc("@action:button", "Write Certificate"));
mWriteKeyManagementCertificateBtn->setToolTip(i18nc("@info:tooltip", "Write the certificate corresponding to this key to the card"));
mWriteKeyManagementCertificateBtn->setEnabled(false);
grid->addWidget(mWriteKeyManagementCertificateBtn, row, 3);
connect(mWriteKeyManagementCertificateBtn, &QPushButton::clicked, this, [this] () { writeCertificateToCard(PIVCard::keyManagementKeyRef()); });
+ mWriteKeyManagementKeyBtn->setText(i18nc("@action:button", "Write Key"));
+ mWriteKeyManagementKeyBtn->setToolTip(i18nc("@info:tooltip", "Write the key pair of a certificate to the card"));
+ mWriteKeyManagementKeyBtn->setEnabled(true);
+ grid->addWidget(mWriteKeyManagementKeyBtn, row, 4);
+ connect(mWriteKeyManagementKeyBtn, &QPushButton::clicked, this, [this] () { writeKeyToCard(PIVCard::keyManagementKeyRef()); });
row++;
auto line2 = new QFrame();
line2->setFrameShape(QFrame::HLine);
- grid->addWidget(line2, row++, 0, 1, 4);
+ grid->addWidget(line2, row++, 0, 1, 5);
auto actionLayout = new QHBoxLayout;
{
auto button = new QPushButton(i18nc("@action:button", "Change PIN"));
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"));
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"));
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);
grid->addLayout(actionLayout, row++, 0, 1, 4);
grid->setColumnStretch(4, -1);
}
PIVCardWidget::~PIVCardWidget()
{
}
void PIVCardWidget::setCard(const PIVCard *card)
{
mCardSerialNumber = card->serialNumber();
mVersionLabel->setText(i18nc("%1 version number", "PIV v%1 card", formatVersion(card->appVersion())));
if (card->displaySerialNumber() != card->serialNumber()) {
mSerialNumber->setText(QStringLiteral("%1 (%2)").arg(QString::fromStdString(card->displaySerialNumber()),
QString::fromStdString(card->serialNumber())));
} else {
mSerialNumber->setText(QString::fromStdString(card->serialNumber()));
}
updateKey(PIVCard::pivAuthenticationKeyRef(), card, mPIVAuthenticationKey, mGeneratePIVAuthenticationKeyBtn, mWritePIVAuthenticationCertificateBtn);
updateKey(PIVCard::cardAuthenticationKeyRef(), card, mCardAuthenticationKey, mGenerateCardAuthenticationKeyBtn, mWriteCardAuthenticationCertificateBtn);
updateKey(PIVCard::digitalSignatureKeyRef(), card, mDigitalSignatureKey, mGenerateDigitalSignatureKeyBtn, mWriteDigitalSignatureCertificateBtn);
updateKey(PIVCard::keyManagementKeyRef(), card, mKeyManagementKey, mGenerateKeyManagementKeyBtn, mWriteKeyManagementCertificateBtn);
}
void PIVCardWidget::updateKey(const std::string &keyRef, const PIVCard *card, QLabel *label, QPushButton *generateButton, QPushButton *writeButton)
{
const std::string grip = card->keyGrip(keyRef);
label->setText(grip.empty() ? i18nc("@info", "Slot empty") : QString::fromStdString(grip));
generateButton->setText(grip.empty() ? i18nc("@action:button", "Generate") : i18nc("@action:button", "Replace"));
generateButton->setToolTip(grip.empty() ?
i18nc("@info:tooltip %1 display name of a key", "Generate %1", PIVCard::keyDisplayName(keyRef)) :
i18nc("@info:tooltip %1 display name of a key", "Replace %1 with new key", PIVCard::keyDisplayName(keyRef)));
generateButton->setEnabled(true);
if (writeButton) {
writeButton->setEnabled(!grip.empty());
}
}
void PIVCardWidget::generateKey(const std::string &keyref)
{
auto cmd = new PIVGenerateCardKeyCommand(mCardSerialNumber, this);
this->setEnabled(false);
connect(cmd, &PIVGenerateCardKeyCommand::finished,
this, [this]() {
this->setEnabled(true);
});
cmd->setKeyRef(keyref);
cmd->start();
}
void PIVCardWidget::writeCertificateToCard(const std::string &keyref)
{
auto cmd = new CertificateToPIVCardCommand(keyref, mCardSerialNumber);
this->setEnabled(false);
connect(cmd, &CertificateToPIVCardCommand::finished,
this, [this]() {
this->setEnabled(true);
});
cmd->setParentWidget(this);
cmd->start();
}
+void PIVCardWidget::writeKeyToCard(const std::string &keyref)
+{
+ auto cmd = new KeyToCardCommand(keyref, mCardSerialNumber);
+ this->setEnabled(false);
+ connect(cmd, &KeyToCardCommand::finished,
+ this, [this]() {
+ this->setEnabled(true);
+ });
+ cmd->setParentWidget(this);
+ cmd->start();
+}
+
void PIVCardWidget::changePin(const std::string &keyRef)
{
auto cmd = new ChangePinCommand(mCardSerialNumber, 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(mCardSerialNumber, this);
this->setEnabled(false);
connect(cmd, &SetPIVCardApplicationAdministrationKeyCommand::finished,
this, [this]() {
this->setEnabled(true);
});
cmd->start();
}
diff --git a/src/view/pivcardwidget.h b/src/view/pivcardwidget.h
index 771b181cf..9162f0f2f 100644
--- a/src/view/pivcardwidget.h
+++ b/src/view/pivcardwidget.h
@@ -1,62 +1,64 @@
/* view/pivcardwiget.h
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
*/
#ifndef VIEW_PIVCARDWIDGET_H
#define VIEW_PIVCARDWIDGET_H
#include <QWidget>
#include <gpgme++/error.h>
class QLabel;
class QPushButton;
namespace Kleo
{
namespace SmartCard
{
class PIVCard;
} // namespace SmartCard
class PIVCardWidget: public QWidget
{
Q_OBJECT
public:
explicit PIVCardWidget(QWidget *parent = nullptr);
~PIVCardWidget();
void setCard(const SmartCard::PIVCard* card);
private:
void updateKey(const std::string &keyRef, const SmartCard::PIVCard *card, QLabel *label, QPushButton *generateButton, QPushButton *writeButton);
void generateKey(const std::string &keyref);
void writeCertificateToCard(const std::string &keyref);
+ void writeKeyToCard(const std::string &keyref);
void changePin(const std::string &keyRef);
void setAdminKey();
private:
std::string mCardSerialNumber;
QLabel *mSerialNumber = nullptr,
*mVersionLabel = nullptr,
*mPIVAuthenticationKey = nullptr,
*mCardAuthenticationKey = nullptr,
*mDigitalSignatureKey = nullptr,
*mKeyManagementKey = nullptr;
QPushButton *mGeneratePIVAuthenticationKeyBtn = nullptr,
*mWritePIVAuthenticationCertificateBtn = nullptr,
*mGenerateCardAuthenticationKeyBtn = nullptr,
*mWriteCardAuthenticationCertificateBtn = nullptr,
*mGenerateDigitalSignatureKeyBtn = nullptr,
*mWriteDigitalSignatureCertificateBtn = nullptr,
*mGenerateKeyManagementKeyBtn = nullptr,
- *mWriteKeyManagementCertificateBtn = nullptr;
+ *mWriteKeyManagementCertificateBtn = nullptr,
+ *mWriteKeyManagementKeyBtn = nullptr;
};
} // namespace Kleo
#endif // VIEW_PIVCARDWIDGET_H

File Metadata

Mime Type
text/x-diff
Expires
Wed, Dec 24, 10:47 PM (1 d, 16 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
56/65/18b1eb25ecb48c9276f59f81d361

Event Timeline