Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F34252333
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
35 KB
Subscribers
None
View Options
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
Details
Attached
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
Attached To
rKLEOPATRA Kleopatra
Event Timeline
Log In to Comment