Commit 3fa1d8bb authored by Ingo Klöcker's avatar Ingo Klöcker

Add basic generation of keys for PIV smartcards

Allows generation of keys for empty slots of PIV smartcards. Uses
the default key algorithm. Assumes a default authentication key.

CardCommand is a heavily stripped-down variant of Command. (Command is
too tightly coupled to KeyListController.)

GnuPG-bug-id: 4794
parent 611581bc
Pipeline #31132 passed with stage
in 29 minutes and 44 seconds
......@@ -226,6 +226,8 @@ set(_kleopatra_SRCS
commands/importpaperkeycommand.cpp
commands/genrevokecommand.cpp
commands/keytocardcommand.cpp
commands/cardcommand.cpp
commands/pivgeneratecardkeycommand.cpp
${_kleopatra_uiserver_files}
......
/* commands/cardcommand.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2020 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "cardcommand.h"
#include "cardcommand_p.h"
#include <QWidget>
using namespace Kleo;
CardCommand::Private::Private(CardCommand *qq, QWidget *parent)
: q(qq),
autoDelete(true),
parentWidget_(parent)
{
}
CardCommand::Private::~Private()
{
}
CardCommand::CardCommand(QWidget *parent)
: QObject(parent), d(new Private(this, parent))
{
}
CardCommand::CardCommand(Private *pp)
: QObject(pp->parentWidget_), d(pp)
{
}
CardCommand::~CardCommand()
{
}
void CardCommand::setAutoDelete(bool on)
{
d->autoDelete = on;
}
bool CardCommand::autoDelete() const
{
return d->autoDelete;
}
void CardCommand::start()
{
doStart();
}
/* commands/cardcommand.h
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2020 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef __KLEOPATRA_COMMANDS_CARDCOMMAND_H__
#define __KLEOPATRA_COMMANDS_CARDCOMMAND_H__
#include <QObject>
class QWidget;
#include <utils/pimpl_ptr.h>
namespace Kleo
{
class CardCommand : public QObject
{
Q_OBJECT
public:
explicit CardCommand(QWidget *parent);
~CardCommand() override;
void setAutoDelete(bool on);
bool autoDelete() const;
public Q_SLOTS:
void start();
Q_SIGNALS:
void finished();
private:
virtual void doStart() = 0;
protected:
class Private;
kdtools::pimpl_ptr<Private> d;
protected:
explicit CardCommand(Private *pp);
};
} // namespace Kleo
#endif /* __KLEOPATRA_COMMANDS_CARDCOMMAND_H__ */
/* commands/cardcommand_p.h
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2020 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef __KLEOPATRA_COMMANDS_CARDCOMMAND_P_H__
#define __KLEOPATRA_COMMANDS_CARDCOMMAND_P_H__
#include "cardcommand.h"
#include <QPointer>
#include <KMessageBox>
class Kleo::CardCommand::Private
{
friend class ::Kleo::CardCommand;
protected:
CardCommand *const q;
public:
explicit Private(CardCommand *qq, QWidget *parent);
virtual ~Private();
QWidget *parentWidget() const
{
return parentWidget_;
}
void finished()
{
Q_EMIT q->finished();
if (autoDelete) {
q->deleteLater();
}
}
void error(const QString &text, const QString &caption = QString(), KMessageBox::Options options = KMessageBox::Notify) const
{
KMessageBox::error(parentWidget(), text, caption, options);
}
void information(const QString &text, const QString &caption = QString(), const QString &dontShowAgainName = QString(), KMessageBox::Options options = KMessageBox::Notify) const
{
KMessageBox::information(parentWidget(), text, caption, dontShowAgainName, options);
}
private:
bool autoDelete : 1;
QPointer<QWidget> parentWidget_;
};
#endif /* __KLEOPATRA_COMMANDS_CARDCOMMAND_P_H__ */
/* commands/pivgeneratecardkeycommand.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
*/
#include "pivgeneratecardkeycommand.h"
#include "cardcommand_p.h"
#include "smartcard/readerstatus.h"
#include <gpgme++/error.h>
#include <KLocalizedString>
#include "kleopatra_debug.h"
using namespace Kleo;
using namespace Kleo::Commands;
using namespace Kleo::SmartCard;
using namespace GpgME;
class PIVGenerateCardKeyCommand::Private : public CardCommand::Private
{
friend class ::Kleo::Commands::PIVGenerateCardKeyCommand;
PIVGenerateCardKeyCommand *q_func() const
{
return static_cast<PIVGenerateCardKeyCommand *>(q);
}
public:
explicit Private(PIVGenerateCardKeyCommand *qq, QWidget *p);
~Private();
void init();
private:
void slotAuthenticateResult(const Error &err);
void slotGenerateKeyResult(const Error &err);
private:
void authenticate();
void generateKey();
private:
QByteArray keyref;
};
PIVGenerateCardKeyCommand::Private *PIVGenerateCardKeyCommand::d_func()
{
return static_cast<Private *>(d.get());
}
const PIVGenerateCardKeyCommand::Private *PIVGenerateCardKeyCommand::d_func() const
{
return static_cast<const Private *>(d.get());
}
#define d d_func()
#define q q_func()
PIVGenerateCardKeyCommand::Private::Private(PIVGenerateCardKeyCommand *qq, QWidget *p)
: CardCommand::Private(qq, p)
{
}
PIVGenerateCardKeyCommand::Private::~Private()
{
qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::Private::~Private()";
}
PIVGenerateCardKeyCommand::PIVGenerateCardKeyCommand(QWidget *p)
: CardCommand(new Private(this, p))
{
d->init();
}
void PIVGenerateCardKeyCommand::Private::init()
{
}
PIVGenerateCardKeyCommand::~PIVGenerateCardKeyCommand()
{
qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::~PIVGenerateCardKeyCommand()";
}
void PIVGenerateCardKeyCommand::setKeyRef(const QByteArray &keyref)
{
d->keyref = keyref;
}
void PIVGenerateCardKeyCommand::doStart()
{
qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::doStart()";
d->generateKey();
}
void PIVGenerateCardKeyCommand::Private::authenticate()
{
qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::authenticate()";
const QByteArray defaultAuthenticationKey = QByteArray::fromHex("010203040506070801020304050607080102030405060708");
const QByteArray plusPercentEncodedAuthenticationKey = defaultAuthenticationKey.toPercentEncoding().replace(' ', '+');
const QByteArray command = QByteArray("SCD SETATTR AUTH-ADM-KEY ") + plusPercentEncodedAuthenticationKey;
ReaderStatus::mutableInstance()->startSimpleTransaction(command, q, "slotAuthenticateResult");
}
void PIVGenerateCardKeyCommand::Private::slotAuthenticateResult(const Error &err)
{
qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::slotAuthenticateResult():"
<< err.asString() << "(" << err.code() << ")";
if (err) {
error(i18nc("@info", "Authenticating to the card failed: %1", QString::fromLatin1(err.asString())),
i18nc("@title", "Error"));
finished();
} else if (err.isCanceled()) {
finished();
} else {
generateKey();
}
}
void PIVGenerateCardKeyCommand::Private::generateKey()
{
qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::generateKey()";
ReaderStatus::mutableInstance()->startSimpleTransaction("SCD GENKEY -- " + keyref, q, "slotGenerateKeyResult");
}
void PIVGenerateCardKeyCommand::Private::slotGenerateKeyResult(const GpgME::Error& err)
{
qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::slotGenerateKeyResult():"
<< err.asString() << "(" << err.code() << ")";
if (err) {
if (err.code() == GPG_ERR_NO_AUTH) {
authenticate();
return;
}
error(i18nc("@info", "Generating key failed: %1", QString::fromLatin1(err.asString())),
i18nc("@title", "Error"));
} else if (!err.isCanceled()) {
information(i18nc("@info", "Key successfully generated."), i18nc("@title", "Success"));
ReaderStatus::mutableInstance()->updateStatus();
}
finished();
}
#undef d
#undef q
#include "moc_pivgeneratecardkeycommand.cpp"
/* commands/pivgeneratecardkeycommand.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 __KLEOPATRA_COMMMANDS_PIVGENERATECARDKEYCOMMAND_H__
#define __KLEOPATRA_COMMMANDS_PIVGENERATECARDKEYCOMMAND_H__
#include "cardcommand.h"
namespace GpgME
{
class Error;
}
namespace Kleo
{
namespace Commands
{
class PIVGenerateCardKeyCommand : public CardCommand
{
Q_OBJECT
public:
explicit PIVGenerateCardKeyCommand(QWidget *parent);
~PIVGenerateCardKeyCommand() override;
void setKeyRef(const QByteArray &keyref);
private:
void doStart() override;
private:
class Private;
inline Private *d_func();
inline const Private *d_func() const;
Q_PRIVATE_SLOT(d_func(), void slotGenerateKeyResult(GpgME::Error))
Q_PRIVATE_SLOT(d_func(), void slotAuthenticateResult(GpgME::Error))
};
} // namespace Commands
} // namespace Kleo
#endif // __KLEOPATRA_COMMMANDS_PIVGENERATECARDKEYCOMMAND_H__
......@@ -9,17 +9,23 @@
#include "pivcardwidget.h"
#include "commands/pivgeneratecardkeycommand.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 {
......@@ -48,10 +54,14 @@ PIVCardWidget::PIVCardWidget(QWidget *parent):
QWidget(parent),
mSerialNumber(new QLabel(this)),
mVersionLabel(new QLabel(this)),
mPivAuthenticationKey(new QLabel(this)),
mPIVAuthenticationKey(new QLabel(this)),
mCardAuthenticationKey(new QLabel(this)),
mSigningKey(new QLabel(this)),
mEncryptionKey(new QLabel(this)),
mDigitalSignatureKey(new QLabel(this)),
mKeyManagementKey(new QLabel(this)),
mGeneratePIVAuthenticationKeyBtn(new QPushButton(this)),
mGenerateCardAuthenticationKeyBtn(new QPushButton(this)),
mGenerateDigitalSignatureKeyBtn(new QPushButton(this)),
mGenerateKeyManagementKeyBtn(new QPushButton(this)),
mCardIsEmpty(false)
{
auto grid = new QGridLayout;
......@@ -84,20 +94,40 @@ PIVCardWidget::PIVCardWidget(QWidget *parent):
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);
grid->addWidget(mPIVAuthenticationKey, row, 1);
mPIVAuthenticationKey->setTextInteractionFlags(Qt::TextBrowserInteraction);
mGeneratePIVAuthenticationKeyBtn->setText(i18n("Generate"));
mGeneratePIVAuthenticationKeyBtn->setToolTip(i18n("Generate PIV Authentication Key"));
grid->addWidget(mGeneratePIVAuthenticationKeyBtn, row, 2);
connect(mGeneratePIVAuthenticationKeyBtn, &QPushButton::clicked, this, &PIVCardWidget::generatePIVAuthenticationKey);
row++;
grid->addWidget(new QLabel(i18n("Card authentication:")), row, 0);
grid->addWidget(mCardAuthenticationKey, row++, 1);
grid->addWidget(mCardAuthenticationKey, row, 1);
mCardAuthenticationKey->setTextInteractionFlags(Qt::TextBrowserInteraction);
mGenerateCardAuthenticationKeyBtn->setText(i18n("Generate"));
mGenerateCardAuthenticationKeyBtn->setToolTip(i18n("Generate Card Authentication Key"));
grid->addWidget(mGenerateCardAuthenticationKeyBtn, row, 2);
connect(mGenerateCardAuthenticationKeyBtn, &QPushButton::clicked, this, &PIVCardWidget::generateCardAuthenticationKey);
row++;
grid->addWidget(new QLabel(i18n("Digital signature:")), row, 0);
grid->addWidget(mSigningKey, row++, 1);
mSigningKey->setTextInteractionFlags(Qt::TextBrowserInteraction);
grid->addWidget(mDigitalSignatureKey, row, 1);
mDigitalSignatureKey->setTextInteractionFlags(Qt::TextBrowserInteraction);
mGenerateDigitalSignatureKeyBtn->setText(i18n("Generate"));
mGenerateDigitalSignatureKeyBtn->setToolTip(i18n("Generate Digital Signature Key"));
grid->addWidget(mGenerateDigitalSignatureKeyBtn, row, 2);
connect(mGenerateDigitalSignatureKeyBtn, &QPushButton::clicked, this, &PIVCardWidget::generateDigitalSignatureKey);
row++;
grid->addWidget(new QLabel(i18n("Key management:")), row, 0);
grid->addWidget(mEncryptionKey, row++, 1);
mEncryptionKey->setTextInteractionFlags(Qt::TextBrowserInteraction);
grid->addWidget(mKeyManagementKey, row, 1);
mKeyManagementKey->setTextInteractionFlags(Qt::TextBrowserInteraction);
mGenerateKeyManagementKeyBtn->setText(i18n("Generate"));
mGenerateKeyManagementKeyBtn->setToolTip(i18n("Generate Key Management Key"));
grid->addWidget(mGenerateKeyManagementKeyBtn, row, 2);
connect(mGenerateKeyManagementKeyBtn, &QPushButton::clicked, this, &PIVCardWidget::generateKeyManagementKey);
row++;
auto line2 = new QFrame();
line2->setFrameShape(QFrame::HLine);
......@@ -106,6 +136,10 @@ PIVCardWidget::PIVCardWidget(QWidget *parent):
grid->setColumnStretch(4, -1);
}
PIVCardWidget::~PIVCardWidget()
{
}
void PIVCardWidget::setCard(const PIVCard *card)
{
mVersionLabel->setText(i18nc("Placeholder is a version number", "PIV v%1 card", formatVersion(card->appVersion())));
......@@ -117,22 +151,50 @@ void PIVCardWidget::setCard(const PIVCard *card)
mSerialNumber->setText(QString::fromStdString(card->serialNumber()));
}
updateKey(mPivAuthenticationKey, card->pivAuthenticationKeyGrip());
updateKey(mCardAuthenticationKey, card->cardAuthenticationKeyGrip());
updateKey(mSigningKey, card->digitalSignatureKeyGrip());
updateKey(mEncryptionKey, card->keyManagementKeyGrip());
updateKey(mPIVAuthenticationKey, mGeneratePIVAuthenticationKeyBtn, card->pivAuthenticationKeyGrip());
updateKey(mCardAuthenticationKey, mGenerateCardAuthenticationKeyBtn, card->cardAuthenticationKeyGrip());
updateKey(mDigitalSignatureKey, mGenerateDigitalSignatureKeyBtn, card->digitalSignatureKeyGrip());
updateKey(mKeyManagementKey, mGenerateKeyManagementKeyBtn, card->keyManagementKeyGrip());
mCardIsEmpty = card->pivAuthenticationKeyGrip().empty()
&& card->cardAuthenticationKeyGrip().empty()
&& card->digitalSignatureKeyGrip().empty()
&& card->keyManagementKeyGrip().empty();
}
void PIVCardWidget::updateKey(QLabel *label, const std::string &grip)
void PIVCardWidget::updateKey(QLabel *label, QPushButton *button, const std::string &grip)
{
label->setText(grip.empty() ? i18n("Slot empty") : QString::fromStdString(grip));
button->setEnabled(grip.empty());
}
void PIVCardWidget::generateKey(const QByteArray &keyref)
{
label->setText(QString::fromStdString(grip));
auto cmd = new PIVGenerateCardKeyCommand(this);
this->setEnabled(false);
connect(cmd, &PIVGenerateCardKeyCommand::finished,
this, [this]() {
this->setEnabled(true);
});
cmd->setKeyRef(keyref);
cmd->start();
}
if (grip.empty()) {
label->setText(i18n("Slot empty"));
return;
}
void PIVCardWidget::generatePIVAuthenticationKey()
{
generateKey("PIV.9A");
}
void PIVCardWidget::generateCardAuthenticationKey()
{
generateKey("PIV.9E");
}
void PIVCardWidget::generateDigitalSignatureKey()
{
generateKey("PIV.9C");
}
void PIVCardWidget::generateKeyManagementKey()
{
generateKey("PIV.9D");
}
......@@ -11,11 +11,13 @@
#include <QWidget>
#include <gpgme++/error.h>
class QLabel;
class QPushButton;
namespace Kleo
{
class GenCardKeyDialog;
namespace SmartCard
{
......@@ -27,18 +29,31 @@ class PIVCardWidget: public QWidget
Q_OBJECT
public:
explicit PIVCardWidget(QWidget *parent = nullptr);
~PIVCardWidget();
void setCard(const SmartCard::PIVCard* card);
private:
void updateKey(QLabel *label, const std::string &fpr);
void updateKey(QLabel *label, QPushButton *button, const std::string &fpr);
void generateKey(const QByteArray &keyref);
private Q_SLOTS:
void generatePIVAuthenticationKey();
void generateCardAuthenticationKey();
void generateDigitalSignatureKey();
void generateKeyManagementKey();
private:
QLabel *mSerialNumber = nullptr,
*mVersionLabel = nullptr,
*mPivAuthenticationKey = nullptr,
*mPIVAuthenticationKey = nullptr,
*mCardAuthenticationKey = nullptr,
*mSigningKey = nullptr,
*mEncryptionKey = nullptr;
*mDigitalSignatureKey = nullptr,
*mKeyManagementKey = nullptr;
QPushButton *mGeneratePIVAuthenticationKeyBtn = nullptr,
*mGenerateCardAuthenticationKeyBtn = nullptr,
*mGenerateDigitalSignatureKeyBtn = nullptr,
*mGenerateKeyManagementKeyBtn = nullptr;
bool mCardIsEmpty = false;
};
} // namespace Kleo
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment