Commit 662d68fa authored by Ingo Klöcker's avatar Ingo Klöcker
Browse files

Ask for PIV Card Application Administration Key if necessary

Ask the user for the admin key, if the default admin key doesn't work,
i.e. if the admin key has been changed/set.

AuthenticatePIVCardApplicationCommand:
* New command handling the authentication to/of the PIV Card Application

CardCommand:
* Add possibility to cancel a card command

PIVGenerateCardKeyCommand:
* Use new AuthenticatePIVCardApplicationCommand for performing the
  authentication to/of the PIV Card Application

PIVCardApplicationAdministrationKeyInputDialog:
* New simple dialog for asking the user for the hex-encoded PIV Card
  Application Administration Key

GnuPG-bug-id: 4794
parent ec107441
......@@ -132,6 +132,7 @@ set(_kleopatra_SRCS
dialogs/subkeyswidget.cpp
dialogs/gencardkeydialog.cpp
dialogs/updatenotification.cpp
dialogs/pivcardapplicationadministrationkeyinputdialog.cpp
crypto/controller.cpp
crypto/certificateresolver.cpp
......@@ -229,6 +230,7 @@ set(_kleopatra_SRCS
commands/cardcommand.cpp
commands/pivgeneratecardkeycommand.cpp
commands/changepincommand.cpp
commands/authenticatepivcardapplicationcommand.cpp
${_kleopatra_uiserver_files}
......
/* commands/authenticatepivcardapplicationcommand.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 "authenticatepivcardapplicationcommand.h"
#include "cardcommand_p.h"
#include "smartcard/readerstatus.h"
#include "dialogs/pivcardapplicationadministrationkeyinputdialog.h"
#include <KLocalizedString>
#include <gpgme++/error.h>
#include "kleopatra_debug.h"
using namespace Kleo;
using namespace Kleo::Commands;
using namespace Kleo::Dialogs;
using namespace Kleo::SmartCard;
using namespace GpgME;
class AuthenticatePIVCardApplicationCommand::Private : public CardCommand::Private
{
friend class ::Kleo::Commands::AuthenticatePIVCardApplicationCommand;
AuthenticatePIVCardApplicationCommand *q_func() const
{
return static_cast<AuthenticatePIVCardApplicationCommand *>(q);
}
public:
explicit Private(AuthenticatePIVCardApplicationCommand *qq, const std::string &serialNumber, QWidget *p);
~Private();
void init();
private:
void slotResult(const Error &err);
void slotDialogAccepted();
void slotDialogRejected();
private:
void authenticate(const QByteArray& adminKey);
void retryAskingForKey();
void ensureDialogCreated();
private:
QPointer<PIVCardApplicationAdministrationKeyInputDialog> dialog;
};
AuthenticatePIVCardApplicationCommand::Private *AuthenticatePIVCardApplicationCommand::d_func()
{
return static_cast<Private *>(d.get());
}
const AuthenticatePIVCardApplicationCommand::Private *AuthenticatePIVCardApplicationCommand::d_func() const
{
return static_cast<const Private *>(d.get());
}
#define d d_func()
#define q q_func()
AuthenticatePIVCardApplicationCommand::Private::Private(AuthenticatePIVCardApplicationCommand *qq, const std::string &serialNumber, QWidget *p)
: CardCommand::Private(qq, serialNumber, p)
, dialog()
{
}
AuthenticatePIVCardApplicationCommand::Private::~Private()
{
qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::Private::~Private()";
}
AuthenticatePIVCardApplicationCommand::AuthenticatePIVCardApplicationCommand(const std::string &serialNumber, QWidget *p)
: CardCommand(new Private(this, serialNumber, p))
{
d->init();
}
void AuthenticatePIVCardApplicationCommand::Private::init()
{
}
AuthenticatePIVCardApplicationCommand::~AuthenticatePIVCardApplicationCommand()
{
qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::~AuthenticatePIVCardApplicationCommand()";
}
void AuthenticatePIVCardApplicationCommand::doStart()
{
qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::doStart()";
// at first, try to authenticate using the default application administration key
d->authenticate(QByteArray::fromHex("010203040506070801020304050607080102030405060708"));
}
void AuthenticatePIVCardApplicationCommand::Private::authenticate(const QByteArray& adminKey)
{
qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::authenticate()";
const QByteArray plusPercentEncodedAdminKey = adminKey.toPercentEncoding().replace(' ', '+');
const QByteArray command = QByteArray("SCD SETATTR AUTH-ADM-KEY ") + plusPercentEncodedAdminKey;
ReaderStatus::mutableInstance()->startSimpleTransaction(command, q, "slotResult");
}
void AuthenticatePIVCardApplicationCommand::Private::slotResult(const Error &err)
{
qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::slotResult():"
<< err.asString() << "(" << err.code() << ")";
if (err.isCanceled()) {
canceled();
return;
}
if (err) {
if (err.code() == GPG_ERR_BAD_AUTH) {
retryAskingForKey();
return;
}
error(i18nc("@info", "Authenticating to the card failed: %1", QString::fromLatin1(err.asString())),
i18nc("@title", "Error"));
}
finished();
}
void AuthenticatePIVCardApplicationCommand::Private::retryAskingForKey()
{
ensureDialogCreated();
Q_ASSERT(dialog);
dialog->show();
}
void AuthenticatePIVCardApplicationCommand::Private::ensureDialogCreated()
{
if (dialog) {
return;
}
dialog = new PIVCardApplicationAdministrationKeyInputDialog(parentWidget());
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->setLabelText(i18n("Please enter the PIV Card Application Administration Key in hex-encoded form."));
connect(dialog, SIGNAL(accepted()), q, SLOT(slotDialogAccepted()));
connect(dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected()));
}
void AuthenticatePIVCardApplicationCommand::Private::slotDialogAccepted()
{
authenticate(dialog->adminKey());
}
void AuthenticatePIVCardApplicationCommand::Private::slotDialogRejected()
{
canceled();
}
#undef d
#undef q
#include "moc_authenticatepivcardapplicationcommand.cpp"
/* commands/authenticatepivcardapplicationcommand.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_AUTHENTICATEPIVCARDAPPLICATIONCOMMAND_H__
#define __KLEOPATRA_COMMMANDS_AUTHENTICATEPIVCARDAPPLICATIONCOMMAND_H__
#include "cardcommand.h"
namespace GpgME
{
class Error;
}
namespace Kleo
{
namespace Commands
{
class AuthenticatePIVCardApplicationCommand : public CardCommand
{
Q_OBJECT
public:
explicit AuthenticatePIVCardApplicationCommand(const std::string &serialNumber, QWidget *parent);
~AuthenticatePIVCardApplicationCommand() override;
private:
void doStart() override;
private:
class Private;
inline Private *d_func();
inline const Private *d_func() const;
Q_PRIVATE_SLOT(d_func(), void slotDialogAccepted())
Q_PRIVATE_SLOT(d_func(), void slotDialogRejected())
Q_PRIVATE_SLOT(d_func(), void slotResult(GpgME::Error))
};
} // namespace Commands
} // namespace Kleo
#endif // __KLEOPATRA_COMMMANDS_AUTHENTICATEPIVCARDAPPLICATIONCOMMAND_H__
......@@ -55,3 +55,13 @@ void CardCommand::start()
{
doStart();
}
void CardCommand::cancel()
{
doCancel();
Q_EMIT canceled();
}
void CardCommand::doCancel()
{
}
......@@ -32,12 +32,15 @@ public:
public Q_SLOTS:
void start();
void cancel();
Q_SIGNALS:
void finished();
void canceled();
private:
virtual void doStart() = 0;
virtual void doCancel();
protected:
class Private;
......
......@@ -44,6 +44,12 @@ public:
}
}
void canceled()
{
Q_EMIT q->canceled();
finished();
}
void error(const QString &text, const QString &caption = QString(), KMessageBox::Options options = KMessageBox::Notify) const
{
KMessageBox::error(parentWidget(), text, caption, options);
......
......@@ -14,6 +14,8 @@
#include "smartcard/pivcard.h"
#include "smartcard/readerstatus.h"
#include "commands/authenticatepivcardapplicationcommand.h"
#include "dialogs/gencardkeydialog.h"
#include <KLocalizedString>
......@@ -43,11 +45,12 @@ public:
private:
void slotDialogAccepted();
void slotDialogRejected();
void slotAuthenticateResult(const Error &err);
void slotGenerateKeyResult(const Error &err);
void slotResult(const Error &err);
private:
void authenticate();
void authenticationFinished();
void authenticationCanceled();
void generateKey();
void ensureDialogCreated();
......@@ -56,6 +59,7 @@ private:
bool overwriteExistingKey = false;
std::string algorithm;
QPointer<GenCardKeyDialog> dialog;
bool hasBeenCanceled = false;
};
PIVGenerateCardKeyCommand::Private *PIVGenerateCardKeyCommand::d_func()
......@@ -141,27 +145,27 @@ 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");
auto cmd = new AuthenticatePIVCardApplicationCommand(serialNumber(), parentWidget());
connect(cmd, &AuthenticatePIVCardApplicationCommand::finished,
q, [this]() { authenticationFinished(); });
connect(cmd, &AuthenticatePIVCardApplicationCommand::canceled,
q, [this]() { authenticationCanceled(); });
cmd->start();
}
void PIVGenerateCardKeyCommand::Private::slotAuthenticateResult(const Error &err)
void PIVGenerateCardKeyCommand::Private::authenticationFinished()
{
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();
return;
qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::authenticationFinished()";
if (!hasBeenCanceled) {
generateKey();
}
if (err.isCanceled()) {
finished();
return;
}
generateKey();
}
void PIVGenerateCardKeyCommand::Private::authenticationCanceled()
{
qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::authenticationCanceled()";
hasBeenCanceled = true;
canceled();
}
void PIVGenerateCardKeyCommand::Private::generateKey()
......@@ -177,12 +181,12 @@ void PIVGenerateCardKeyCommand::Private::generateKey()
command << "--algo=" + QByteArray::fromStdString(algorithm);
}
command << "--" << QByteArray::fromStdString(keyRef);
ReaderStatus::mutableInstance()->startSimpleTransaction(command.join(' '), q, "slotGenerateKeyResult");
ReaderStatus::mutableInstance()->startSimpleTransaction(command.join(' '), q, "slotResult");
}
void PIVGenerateCardKeyCommand::Private::slotGenerateKeyResult(const GpgME::Error& err)
void PIVGenerateCardKeyCommand::Private::slotResult(const GpgME::Error& err)
{
qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::slotGenerateKeyResult():"
qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::slotResult():"
<< err.asString() << "(" << err.code() << ")";
if (err) {
if (err.code() == GPG_ERR_NO_AUTH) {
......
......@@ -39,8 +39,7 @@ private:
inline const Private *d_func() const;
Q_PRIVATE_SLOT(d_func(), void slotDialogAccepted())
Q_PRIVATE_SLOT(d_func(), void slotDialogRejected())
Q_PRIVATE_SLOT(d_func(), void slotGenerateKeyResult(GpgME::Error))
Q_PRIVATE_SLOT(d_func(), void slotAuthenticateResult(GpgME::Error))
Q_PRIVATE_SLOT(d_func(), void slotResult(GpgME::Error))
};
} // namespace Commands
......
/* dialogs/pivcardapplicationadministrationkeyinputdialog.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 "pivcardapplicationadministrationkeyinputdialog.h"
#include <QDialogButtonBox>
#include <QFontDatabase>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include <KLocalizedString>
#include "kleopatra_debug.h"
using namespace Kleo;
using namespace Kleo::Dialogs;
class PIVCardApplicationAdministrationKeyInputDialog::Private
{
friend class ::Kleo::Dialogs::PIVCardApplicationAdministrationKeyInputDialog;
public:
explicit Private(PIVCardApplicationAdministrationKeyInputDialog *qq);
void checkAcceptable();
PIVCardApplicationAdministrationKeyInputDialog *const q;
QLabel *mLabel;
QLineEdit *mHexEncodedAdminKeyEdit;
QPushButton *mOkButton;
QByteArray adminKey;
};
PIVCardApplicationAdministrationKeyInputDialog::Private::Private(PIVCardApplicationAdministrationKeyInputDialog *qq): q(qq),
mLabel(new QLabel(qq)),
mHexEncodedAdminKeyEdit(new QLineEdit(qq)),
mOkButton(nullptr)
{
auto *vBox = new QVBoxLayout(q);
{
mLabel->setWordWrap(true);
vBox->addWidget(mLabel);
}
{
const QFont fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont);
mHexEncodedAdminKeyEdit->setInputMask(QStringLiteral("HH:HH:HH:HH:HH:HH:HH:HH:HH:HH:HH:HH:HH:HH:HH:HH:HH:HH:HH:HH:HH:HH:HH:HH;_"));
mHexEncodedAdminKeyEdit->setFont(fixedFont);
mHexEncodedAdminKeyEdit->setMinimumWidth(QFontMetrics(fixedFont).horizontalAdvance(QStringLiteral("HH:")) * 24);
connect(mHexEncodedAdminKeyEdit, &QLineEdit::textChanged, q, [this] () { checkAcceptable(); });
vBox->addWidget(mHexEncodedAdminKeyEdit);
}
auto bbox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, qq);
mOkButton = bbox->button(QDialogButtonBox::Ok);
mOkButton->setDefault(true);
mOkButton->setShortcut(Qt::CTRL | Qt::Key_Return);
connect(bbox, &QDialogButtonBox::rejected, q, [this]() {q->reject();});
connect(bbox, &QDialogButtonBox::accepted, q, [this]() {q->accept();});
vBox->addWidget(bbox);
q->setMinimumWidth(400);
checkAcceptable();
}
void PIVCardApplicationAdministrationKeyInputDialog::Private::checkAcceptable()
{
mOkButton->setEnabled(mHexEncodedAdminKeyEdit->hasAcceptableInput());
}
PIVCardApplicationAdministrationKeyInputDialog::PIVCardApplicationAdministrationKeyInputDialog(QWidget *parent) : QDialog(parent),
d(new Private(this))
{
}
void PIVCardApplicationAdministrationKeyInputDialog::setLabelText(const QString& text)
{
d->mLabel->setText(text);
}
QString PIVCardApplicationAdministrationKeyInputDialog::labelText() const
{
return d->mLabel->text();
}
QByteArray PIVCardApplicationAdministrationKeyInputDialog::adminKey() const
{
return QByteArray::fromHex(d->mHexEncodedAdminKeyEdit->text().toUtf8());
}
/* dialogs/pivcardapplicationadministrationkeyinputdialog.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 DIALOGS_PIVCARDAPPLICATIONADMINISTRATIONKEYINPUTDIALOG_H
#define DIALOGS_PIVCARDAPPLICATIONADMINISTRATIONKEYINPUTDIALOG_H
#include <QDialog>
namespace Kleo
{
namespace Dialogs
{
class PIVCardApplicationAdministrationKeyInputDialog: public QDialog
{
Q_OBJECT
Q_PROPERTY(QString labelText READ labelText WRITE setLabelText)
public:
explicit PIVCardApplicationAdministrationKeyInputDialog(QWidget *parent = nullptr);
void setLabelText(const QString& text);
QString labelText() const;
QByteArray adminKey() const;
private:
class Private;
std::shared_ptr<Private> d;
};
} // namespace Dialogs
} // namespace Kleo
#endif // DIALOGS_PIVCARDAPPLICATIONADMINISTRATIONKEYINPUTDIALOG_H
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