diff --git a/src/commands/authenticatepivcardapplicationcommand.cpp b/src/commands/authenticatepivcardapplicationcommand.cpp index e51cf80aa..def549790 100644 --- a/src/commands/authenticatepivcardapplicationcommand.cpp +++ b/src/commands/authenticatepivcardapplicationcommand.cpp @@ -1,173 +1,177 @@ /* commands/authenticatepivcardapplicationcommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include "authenticatepivcardapplicationcommand.h" #include "cardcommand_p.h" #include "smartcard/readerstatus.h" #include "dialogs/pivcardapplicationadministrationkeyinputdialog.h" #include #include #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(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: QString prompt; QPointer dialog; }; AuthenticatePIVCardApplicationCommand::Private *AuthenticatePIVCardApplicationCommand::d_func() { return static_cast(d.get()); } const AuthenticatePIVCardApplicationCommand::Private *AuthenticatePIVCardApplicationCommand::d_func() const { return static_cast(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::setPrompt(const QString& prompt) { d->prompt = prompt; } 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::doCancel() +{ +} + 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 = new PIVCardApplicationAdministrationKeyInputDialog(parentWidgetOrView()); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setLabelText(prompt.isEmpty() ? i18n("Please enter the PIV Card Application Administration Key in hex-encoded form.") : prompt); 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" diff --git a/src/commands/authenticatepivcardapplicationcommand.h b/src/commands/authenticatepivcardapplicationcommand.h index 87e1740ef..c5ae1e124 100644 --- a/src/commands/authenticatepivcardapplicationcommand.h +++ b/src/commands/authenticatepivcardapplicationcommand.h @@ -1,48 +1,49 @@ /* commands/authenticatepivcardapplicationcommand.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker 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; void setPrompt(const QString& prompt); private: void doStart() override; + void doCancel() 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__ diff --git a/src/commands/cardcommand.cpp b/src/commands/cardcommand.cpp index 10d8ea0d2..3f4219d8b 100644 --- a/src/commands/cardcommand.cpp +++ b/src/commands/cardcommand.cpp @@ -1,67 +1,55 @@ /* 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 SPDX-License-Identifier: GPL-2.0-or-later */ #include "cardcommand.h" #include "cardcommand_p.h" #include using namespace Kleo; -CardCommand::Private::Private(CardCommand *qq, const std::string &serialNumber, QWidget *parent) - : q(qq), - autoDelete(true), - serialNumber_(serialNumber), - parentWidget_(parent) +CardCommand::Private *CardCommand::d_func() { + return static_cast(d.get()); } - -CardCommand::Private::~Private() +const CardCommand::Private *CardCommand::d_func() const { + return static_cast(d.get()); } -CardCommand::CardCommand(const std::string &serialNumber, QWidget *parent) - : QObject(parent), d(new Private(this, serialNumber, parent)) -{ -} - -CardCommand::CardCommand(Private *pp) - : QObject(pp->parentWidget_), d(pp) -{ -} +#define d d_func() +#define q q_func() -CardCommand::~CardCommand() +CardCommand::Private::Private(CardCommand *qq, const std::string &serialNumber, QWidget *parent) + : Command::Private(qq, parent) + , serialNumber_(serialNumber) { } -void CardCommand::setAutoDelete(bool on) +CardCommand::Private::~Private() { - d->autoDelete = on; } -bool CardCommand::autoDelete() const +CardCommand::CardCommand(const std::string &serialNumber, QWidget *parent) + : Command(new Private(this, serialNumber, parent)) { - return d->autoDelete; } -void CardCommand::start() +CardCommand::CardCommand(Private *pp) + : Command(pp) { - doStart(); } -void CardCommand::cancel() +CardCommand::~CardCommand() { - doCancel(); - Q_EMIT canceled(); } -void CardCommand::doCancel() -{ -} +#undef q_func +#undef d_func diff --git a/src/commands/cardcommand.h b/src/commands/cardcommand.h index 7ad9713db..475554d52 100644 --- a/src/commands/cardcommand.h +++ b/src/commands/cardcommand.h @@ -1,54 +1,37 @@ /* 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 SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef __KLEOPATRA_COMMANDS_CARDCOMMAND_H__ #define __KLEOPATRA_COMMANDS_CARDCOMMAND_H__ -#include - -class QWidget; - -#include +#include "command.h" namespace Kleo { -class CardCommand : public QObject +class CardCommand : public Command { Q_OBJECT public: explicit CardCommand(const std::string &serialNumber, QWidget *parent); ~CardCommand() override; - void setAutoDelete(bool on); - bool autoDelete() const; - -public Q_SLOTS: - void start(); - void cancel(); - -Q_SIGNALS: - void finished(); - void canceled(); - -private: - virtual void doStart() = 0; - virtual void doCancel(); - protected: class Private; - kdtools::pimpl_ptr d; + inline Private *d_func(); + inline const Private *d_func() const; + protected: explicit CardCommand(Private *pp); }; } // namespace Kleo #endif /* __KLEOPATRA_COMMANDS_CARDCOMMAND_H__ */ diff --git a/src/commands/cardcommand_p.h b/src/commands/cardcommand_p.h index 276931c52..d52b24ecf 100644 --- a/src/commands/cardcommand_p.h +++ b/src/commands/cardcommand_p.h @@ -1,69 +1,37 @@ /* 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 SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef __KLEOPATRA_COMMANDS_CARDCOMMAND_P_H__ #define __KLEOPATRA_COMMANDS_CARDCOMMAND_P_H__ #include "cardcommand.h" +#include "command_p.h" -#include - -#include - -class Kleo::CardCommand::Private +class Kleo::CardCommand::Private : public Command::Private { friend class ::Kleo::CardCommand; -protected: - CardCommand *const q; + Kleo::CardCommand *q_func() const + { + return static_cast(q); + } public: explicit Private(CardCommand *qq, const std::string &serialNumber, QWidget *parent); - virtual ~Private(); + ~Private(); std::string serialNumber() const { return serialNumber_; } - QWidget *parentWidget() const - { - return parentWidget_; - } - - void finished() - { - Q_EMIT q->finished(); - if (autoDelete) { - q->deleteLater(); - } - } - - 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); - } - - 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; std::string serialNumber_; - QPointer parentWidget_; }; #endif /* __KLEOPATRA_COMMANDS_CARDCOMMAND_P_H__ */ diff --git a/src/commands/certificatetopivcardcommand.cpp b/src/commands/certificatetopivcardcommand.cpp index f97fa64b8..b66548abf 100644 --- a/src/commands/certificatetopivcardcommand.cpp +++ b/src/commands/certificatetopivcardcommand.cpp @@ -1,246 +1,244 @@ /* commands/certificatetopivcardcommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "certificatetopivcardcommand.h" -#include "command_p.h" +#include "cardcommand_p.h" #include "commands/authenticatepivcardapplicationcommand.h" #include "smartcard/pivcard.h" #include "smartcard/readerstatus.h" #include "utils/writecertassuantransaction.h" #include #include #include #include #include #include #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::SmartCard; using namespace GpgME; -class CertificateToPIVCardCommand::Private : public Command::Private +class CertificateToPIVCardCommand::Private : public CardCommand::Private { friend class ::Kleo::Commands::CertificateToPIVCardCommand; CertificateToPIVCardCommand *q_func() const { return static_cast(q); } public: explicit Private(CertificateToPIVCardCommand *qq, const std::string &slot, const std::string &serialno); ~Private(); private: void start(); void startCertificateToPIVCard(); void authenticate(); void authenticationFinished(); void authenticationCanceled(); private: - std::string serialNumber; std::string cardSlot; Key certificate; bool hasBeenCanceled = false; }; CertificateToPIVCardCommand::Private *CertificateToPIVCardCommand::d_func() { return static_cast(d.get()); } const CertificateToPIVCardCommand::Private *CertificateToPIVCardCommand::d_func() const { return static_cast(d.get()); } #define q q_func() #define d d_func() CertificateToPIVCardCommand::Private::Private(CertificateToPIVCardCommand *qq, const std::string &slot, const std::string &serialno) - : Command::Private(qq, nullptr) - , serialNumber(serialno) + : CardCommand::Private(qq, serialno, nullptr) , cardSlot(slot) { } CertificateToPIVCardCommand::Private::~Private() { } namespace { static Key getCertificateToWriteToPIVCard(const std::string &cardSlot, const std::shared_ptr &card) { if (!cardSlot.empty()) { const std::string cardKeygrip = card->keyGrip(cardSlot); const auto certificate = KeyCache::instance()->findSubkeyByKeyGrip(cardKeygrip).parent(); if (certificate.isNull() || certificate.protocol() != GpgME::CMS) { return Key(); } if ((cardSlot == PIVCard::pivAuthenticationKeyRef() && certificate.canSign()) || (cardSlot == PIVCard::cardAuthenticationKeyRef() && certificate.canSign()) || (cardSlot == PIVCard::digitalSignatureKeyRef() && certificate.canSign()) || (cardSlot == PIVCard::keyManagementKeyRef() && certificate.canEncrypt())) { return certificate; } } return Key(); } } void CertificateToPIVCardCommand::Private::start() { qCDebug(KLEOPATRA_LOG) << "CertificateToPIVCardCommand::Private::start()"; - const auto pivCard = SmartCard::ReaderStatus::instance()->getCard(serialNumber); + const auto pivCard = SmartCard::ReaderStatus::instance()->getCard(serialNumber()); if (!pivCard) { - error(i18n("Failed to find the PIV card with the serial number: %1", QString::fromStdString(serialNumber))); + error(i18n("Failed to find the PIV card with the serial number: %1", QString::fromStdString(serialNumber()))); finished(); return; } certificate = getCertificateToWriteToPIVCard(cardSlot, pivCard); if (certificate.isNull()) { error(i18n("Sorry! No suitable certificate to write to this card slot was found.")); finished(); return; } const QString certificateInfo = i18nc("X.509 certificate DN (validity, created: date)", "%1 (%2, created: %3)", DN(certificate.userID(0).id()).prettyDN(), Formatting::complianceStringShort(certificate), Formatting::creationDateString(certificate)); const QString message = i18nc( "@info %1 name of card slot, %2 serial number of card", "

Please confirm that you want to write the following certificate to the %1 slot of card %2:

" "
%3
", - PIVCard::keyDisplayName(cardSlot), QString::fromStdString(serialNumber), certificateInfo); + PIVCard::keyDisplayName(cardSlot), QString::fromStdString(serialNumber()), certificateInfo); auto confirmButton = KStandardGuiItem::yes(); confirmButton.setText(i18nc("@action:button", "Write certificate")); confirmButton.setToolTip(QString()); const auto choice = KMessageBox::questionYesNo( parentWidgetOrView(), message, i18nc("@title:window", "Write certificate to card"), confirmButton, KStandardGuiItem::cancel(), QString(), KMessageBox::Notify | KMessageBox::WindowModal); if (choice != KMessageBox::Yes) { finished(); return; } startCertificateToPIVCard(); } void CertificateToPIVCardCommand::Private::startCertificateToPIVCard() { qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::Private::startCertificateToPIVCard()"; auto ctx = Context::createForProtocol(GpgME::CMS); QGpgME::QByteArrayDataProvider dp; Data data(&dp); const Error err = ctx->exportPublicKeys(certificate.primaryFingerprint(), data); if (err) { error(i18nc("@info", "Exporting the certificate failed: %1", QString::fromUtf8(err.asString())), i18nc("@title", "Error")); finished(); return; } const QByteArray certificateData = dp.data(); const QString cmd = QStringLiteral("SCD WRITECERT %1") .arg(QString::fromStdString(cardSlot)); auto transaction = std::unique_ptr(new WriteCertAssuanTransaction(certificateData)); ReaderStatus::mutableInstance()->startTransaction(cmd.toUtf8(), q_func(), "certificateToPIVCardDone", std::move(transaction)); } void CertificateToPIVCardCommand::Private::authenticate() { qCDebug(KLEOPATRA_LOG) << "CertificateToPIVCardCommand::authenticate()"; - auto cmd = new AuthenticatePIVCardApplicationCommand(serialNumber, parentWidgetOrView()); + auto cmd = new AuthenticatePIVCardApplicationCommand(serialNumber(), parentWidgetOrView()); connect(cmd, &AuthenticatePIVCardApplicationCommand::finished, q, [this]() { authenticationFinished(); }); connect(cmd, &AuthenticatePIVCardApplicationCommand::canceled, q, [this]() { authenticationCanceled(); }); cmd->start(); } void CertificateToPIVCardCommand::Private::authenticationFinished() { qCDebug(KLEOPATRA_LOG) << "CertificateToPIVCardCommand::authenticationFinished()"; if (!hasBeenCanceled) { startCertificateToPIVCard(); } } void CertificateToPIVCardCommand::Private::authenticationCanceled() { qCDebug(KLEOPATRA_LOG) << "CertificateToPIVCardCommand::authenticationCanceled()"; hasBeenCanceled = true; canceled(); } CertificateToPIVCardCommand::CertificateToPIVCardCommand(const std::string& cardSlot, const std::string &serialno) - : Command(new Private(this, cardSlot, serialno)) + : CardCommand(new Private(this, cardSlot, serialno)) { } CertificateToPIVCardCommand::~CertificateToPIVCardCommand() { qCDebug(KLEOPATRA_LOG) << "CertificateToPIVCardCommand::~CertificateToPIVCardCommand()"; } void CertificateToPIVCardCommand::certificateToPIVCardDone(const Error &err) { qCDebug(KLEOPATRA_LOG) << "CertificateToPIVCardCommand::certificateToPIVCardDone():" << 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", "Writing the certificate to the card failed: %1", QString::fromUtf8(err.asString())), i18nc("@title", "Error")); } else if (!err.isCanceled()) { KMessageBox::information(d->parentWidgetOrView(), i18nc("@info", "Writing the certificate to the card succeeded."), i18nc("@title", "Success")); ReaderStatus::mutableInstance()->updateStatus(); } d->finished(); } void CertificateToPIVCardCommand::doStart() { qCDebug(KLEOPATRA_LOG) << "CertificateToPIVCardCommand::doStart()"; d->start(); } void CertificateToPIVCardCommand::doCancel() { } #undef q_func #undef d_func diff --git a/src/commands/certificatetopivcardcommand.h b/src/commands/certificatetopivcardcommand.h index eb4f820d8..6240746f4 100644 --- a/src/commands/certificatetopivcardcommand.h +++ b/src/commands/certificatetopivcardcommand.h @@ -1,48 +1,48 @@ /* commands/certificatetopivcardcommand.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef __KLEOPATRA_COMMANDS_CERTIFICATETOPIVCARDCOMMAND_H__ #define __KLEOPATRA_COMMANDS_CERTIFICATETOPIVCARDCOMMAND_H__ -#include +#include namespace GpgME { class Error; } namespace Kleo { namespace Commands { -class CertificateToPIVCardCommand : public Command +class CertificateToPIVCardCommand : public CardCommand { Q_OBJECT public: CertificateToPIVCardCommand(const std::string& cardSlot, const std::string &serialno); ~CertificateToPIVCardCommand() override; public Q_SLOTS: void certificateToPIVCardDone(const GpgME::Error &err); private: void doStart() override; void doCancel() override; private: class Private; inline Private *d_func(); inline const Private *d_func() const; }; } } #endif /* __KLEOPATRA_COMMANDS_CERTIFICATETOPIVCARDCOMMAND_H__ */ diff --git a/src/commands/changepincommand.cpp b/src/commands/changepincommand.cpp index 6468c633b..98ed08373 100644 --- a/src/commands/changepincommand.cpp +++ b/src/commands/changepincommand.cpp @@ -1,168 +1,172 @@ /* commands/changepincommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include "changepincommand.h" #include "cardcommand_p.h" #include "smartcard/openpgpcard.h" #include "smartcard/pivcard.h" #include "smartcard/readerstatus.h" #include #include #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::SmartCard; using namespace GpgME; class ChangePinCommand::Private : public CardCommand::Private { friend class ::Kleo::Commands::ChangePinCommand; ChangePinCommand *q_func() const { return static_cast(q); } public: explicit Private(ChangePinCommand *qq, const std::string &serialNumber, QWidget *p); ~Private(); void init(); private: void slotResult(const Error &err); private: void changePin(); private: std::string keyRef; }; ChangePinCommand::Private *ChangePinCommand::d_func() { return static_cast(d.get()); } const ChangePinCommand::Private *ChangePinCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() ChangePinCommand::Private::Private(ChangePinCommand *qq, const std::string &serialNumber, QWidget *p) : CardCommand::Private(qq, serialNumber, p) { } ChangePinCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG) << "ChangePinCommand::Private::~Private()"; } ChangePinCommand::ChangePinCommand(const std::string &serialNumber, QWidget *p) : CardCommand(new Private(this, serialNumber, p)) { d->init(); } void ChangePinCommand::Private::init() { } ChangePinCommand::~ChangePinCommand() { qCDebug(KLEOPATRA_LOG) << "ChangePinCommand::~ChangePinCommand()"; } void ChangePinCommand::setKeyRef(const std::string &keyRef) { d->keyRef = keyRef; } void ChangePinCommand::doStart() { qCDebug(KLEOPATRA_LOG) << "ChangePinCommand::doStart()"; d->changePin(); } +void ChangePinCommand::doCancel() +{ +} + void ChangePinCommand::Private::changePin() { qCDebug(KLEOPATRA_LOG) << "ChangePinCommand::changePin()"; QByteArrayList command; command << "SCD PASSWD"; if (keyRef == OpenPGPCard::resetCodeKeyRef()) { // special handling for setting/changing the Reset Code of OpenPGP v2 cards const auto card = ReaderStatus::instance()->getCard(serialNumber()); const std::string firstTwoVersionChars = card->cardVersion().substr(0, 2); const bool isVersion2 = !(firstTwoVersionChars == "1." || firstTwoVersionChars == "0."); if (isVersion2) { command << "--reset"; } } command << QByteArray::fromStdString(keyRef); ReaderStatus::mutableInstance()->startSimpleTransaction(command.join(' '), q, "slotResult"); } namespace { static QString errorMessage(const std::string &keyRef, const QString &errorText) { // see cmd_passwd() in gpg-card.c if (keyRef == PIVCard::pukKeyRef()) { return i18nc("@info", "Changing the PUK failed: %1", errorText); } if (keyRef == OpenPGPCard::adminPinKeyRef()) { return i18nc("@info", "Changing the Admin PIN failed: %1", errorText); } if (keyRef == OpenPGPCard::resetCodeKeyRef()) { return i18nc("@info", "Changing the Reset Code failed: %1", errorText); } return i18nc("@info", "Changing the PIN failed: %1", errorText); } static QString successMessage(const std::string &keyRef) { // see cmd_passwd() in gpg-card.c if (keyRef == PIVCard::pukKeyRef()) { return i18nc("@info", "PUK successfully changed."); } if (keyRef == OpenPGPCard::adminPinKeyRef()) { return i18nc("@info", "Admin PIN changed successfully."); } if (keyRef == OpenPGPCard::resetCodeKeyRef()) { return i18nc("@info", "Reset Code changed successfully."); } return i18nc("@info", "PIN changed successfully."); } } void ChangePinCommand::Private::slotResult(const GpgME::Error& err) { qCDebug(KLEOPATRA_LOG) << "ChangePinCommand::slotResult():" << err.asString() << "(" << err.code() << ")"; if (err) { error(errorMessage(keyRef, QString::fromLatin1(err.asString())), i18nc("@title", "Error")); } else if (!err.isCanceled()) { information(successMessage(keyRef), i18nc("@title", "Success")); ReaderStatus::mutableInstance()->updateStatus(); } finished(); } #undef d #undef q #include "moc_changepincommand.cpp" diff --git a/src/commands/changepincommand.h b/src/commands/changepincommand.h index 104e95477..164c56a9e 100644 --- a/src/commands/changepincommand.h +++ b/src/commands/changepincommand.h @@ -1,47 +1,48 @@ /* commands/changepincommand.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef __KLEOPATRA_COMMMANDS_CHANGEPINCOMMAND_H__ #define __KLEOPATRA_COMMMANDS_CHANGEPINCOMMAND_H__ #include "cardcommand.h" namespace GpgME { class Error; } namespace Kleo { namespace Commands { class ChangePinCommand : public CardCommand { Q_OBJECT public: explicit ChangePinCommand(const std::string &serialNumber, QWidget *parent); ~ChangePinCommand() override; void setKeyRef(const std::string &keyRef); private: void doStart() override; + void doCancel() override; private: class Private; inline Private *d_func(); inline const Private *d_func() const; Q_PRIVATE_SLOT(d_func(), void slotResult(GpgME::Error)) }; } // namespace Commands } // namespace Kleo #endif // __KLEOPATRA_COMMMANDS_CHANGEPINCOMMAND_H__ diff --git a/src/commands/command.cpp b/src/commands/command.cpp index d4529c0d4..2216b3761 100644 --- a/src/commands/command.cpp +++ b/src/commands/command.cpp @@ -1,292 +1,303 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/command.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "command.h" #include "command_p.h" #include "signencryptfilescommand.h" #include "importcertificatefromfilecommand.h" #include "decryptverifyfilescommand.h" #include "detailscommand.h" #include "lookupcertificatescommand.h" #include "checksumverifyfilescommand.h" #include #include #include #include "kleopatra_debug.h" #include #include #include using namespace Kleo; using namespace Kleo::Commands; using namespace GpgME; +Command::Private::Private(Command *qq) + : q(qq), + autoDelete(true), + warnWhenRunningAtShutdown(true) +{ +} + Command::Private::Private(Command *qq, KeyListController *controller) : q(qq), autoDelete(true), warnWhenRunningAtShutdown(true), - indexes_(), - view_(), - parentWId(0), controller_(controller) { +} +Command::Private::Private(Command *qq, QWidget *parent) + : q(qq), + autoDelete(true), + warnWhenRunningAtShutdown(true), + parentWidget_(parent) +{ } Command::Private::~Private() { qCDebug(KLEOPATRA_LOG); } Command::Command(KeyListController *p) : QObject(p), d(new Private(this, p)) { if (p) { p->registerCommand(this); } } Command::Command(QAbstractItemView *v, KeyListController *p) : QObject(p), d(new Private(this, p)) { if (p) { p->registerCommand(this); } if (v) { setView(v); } } Command::Command(Private *pp) : QObject(pp->controller_), d(pp) { if (pp->controller_) { pp->controller_->registerCommand(this); } } Command::Command(QAbstractItemView *v, Private *pp) : QObject(pp->controller_), d(pp) { if (pp->controller_) { pp->controller_->registerCommand(this); } if (v) { setView(v); } } Command::Command(const GpgME::Key &key) - : QObject(nullptr), d(new Private(this, nullptr)) + : QObject(nullptr), d(new Private(this)) { d->keys_ = std::vector(1, key); } Command::Command(const std::vector &keys) - : QObject(nullptr), d(new Private(this, nullptr)) + : QObject(nullptr), d(new Private(this)) { d->keys_ = keys; } Command::Command(const Key &key, Private *pp) : QObject(nullptr), d(pp) { d->keys_ = std::vector(1, key); } Command::Command(const std::vector &keys, Private *pp) : QObject(nullptr), d(pp) { d->keys_ = keys; } Command::~Command() { qCDebug(KLEOPATRA_LOG); } void Command::setAutoDelete(bool on) { d->autoDelete = on; } bool Command::autoDelete() const { return d->autoDelete; } void Command::setWarnWhenRunningAtShutdown(bool on) { d->warnWhenRunningAtShutdown = on; } bool Command::warnWhenRunningAtShutdown() const { return d->warnWhenRunningAtShutdown; } void Command::setParentWidget(QWidget *widget) { d->parentWidget_ = widget; } void Command::setParentWId(WId wid) { d->parentWId = wid; } void Command::setView(QAbstractItemView *view) { if (view == d->view_) { return; } d->view_ = view; if (!view || !d->indexes_.empty()) { return; } const QItemSelectionModel *const sm = view->selectionModel(); if (!sm) { qCWarning(KLEOPATRA_LOG) << "view " << (void *)view << " has no selectionModel!"; return; } const QList selected = sm->selectedRows(); if (!selected.empty()) { std::copy(selected.begin(), selected.end(), std::back_inserter(d->indexes_)); return; } } void Command::setIndex(const QModelIndex &idx) { d->indexes_.clear(); d->indexes_.push_back(idx); } void Command::setIndexes(const QList &idx) { d->indexes_.clear(); std::copy(idx.begin(), idx.end(), std::back_inserter(d->indexes_)); } void Command::setKey(const Key &key) { d->keys_.clear(); if (!key.isNull()) { d->keys_.push_back(key); } } void Command::setKeys(const std::vector &keys) { d->keys_ = keys; } void Command::start() { doStart(); } void Command::cancel() { qCDebug(KLEOPATRA_LOG) << metaObject()->className(); doCancel(); Q_EMIT canceled(); } void Command::addTemporaryView(const QString &title, AbstractKeyListSortFilterProxyModel *proxy, const QString &tabToolTip) { if (TabWidget *const tw = d->controller_ ? d->controller_->tabWidget() : nullptr) if (QAbstractItemView *const v = tw->addTemporaryView(title, proxy, tabToolTip)) { setView(v); } } void Command::applyWindowID(QWidget *w) const { if (w) { if (d->parentWId) { if (QWidget *pw = QWidget::find(d->parentWId)) { w->setParent(pw, w->windowFlags()); } else { w->setAttribute(Qt::WA_NativeWindow, true); KWindowSystem::setMainWindow(w->windowHandle(), d->parentWId); } } else { w->setParent(d->parentWidgetOrView(), w->windowFlags()); } } } // static QVector Command::commandsForFiles(const QStringList &files) { QStringList importFiles, decryptFiles, encryptFiles, checksumFiles; QVector cmds; for (const QString &fileName : files) { const unsigned int classification = classify(fileName); if (classification & Class::AnyCertStoreType) { importFiles << fileName; } else if (classification & Class::AnyMessageType) { // For any message we decrypt / verify. This includes // the class CipherText decryptFiles << fileName; } else if (isChecksumFile(fileName)) { checksumFiles << fileName; } else { QFileInfo fi(fileName); if (fi.isReadable()) { encryptFiles << fileName; } } } if (!importFiles.isEmpty()) { cmds << new ImportCertificateFromFileCommand(importFiles, nullptr); } if (!decryptFiles.isEmpty()) { cmds << new DecryptVerifyFilesCommand(decryptFiles, nullptr); } if (!encryptFiles.isEmpty()) { cmds << new SignEncryptFilesCommand(encryptFiles, nullptr); } if (!checksumFiles.isEmpty()) { cmds << new ChecksumVerifyFilesCommand(checksumFiles, nullptr); } return cmds; } // static Command *Command::commandForQuery(const QString &query) { const auto cache = Kleo::KeyCache::instance(); GpgME::Key key = cache->findByKeyIDOrFingerprint(query.toLocal8Bit().data()); if (key.isNull() && query.size() > 16) { // Try to find by subkeyid std::vector id; id.push_back(query.right(16).toStdString()); auto keys = cache->findSubkeysByKeyID(id); if (keys.size()) { key = keys[0].parent(); } } if (key.isNull()) { return new LookupCertificatesCommand(query, nullptr); } else { return new DetailsCommand(key, nullptr); } } diff --git a/src/commands/command_p.h b/src/commands/command_p.h index e4f46aab4..d3e807010 100644 --- a/src/commands/command_p.h +++ b/src/commands/command_p.h @@ -1,121 +1,123 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/command_p.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef __KLEOPATRA_COMMANDS_COMMAND_P_H__ #define __KLEOPATRA_COMMANDS_COMMAND_P_H__ #include "command.h" #include "view/keylistcontroller.h" #include #include #include #include #include #include #include #include #include class Kleo::Command::Private { friend class ::Kleo::Command; protected: Command *const q; public: + explicit Private(Command *qq); explicit Private(Command *qq, KeyListController *controller); + explicit Private(Command *qq, QWidget *parent); virtual ~Private(); QAbstractItemView *view() const { return view_; } QWidget *parentWidgetOrView() const { if (parentWidget_) { return parentWidget_; } else { return view_; } } KeyListModelInterface *model() const { return view_ ? dynamic_cast(view_->model()) : nullptr; } KeyListController *controller() const { return controller_; } QList indexes() const { QList result; std::copy(indexes_.begin(), indexes_.end(), std::back_inserter(result)); return result; } GpgME::Key key() const { return keys_.empty() ? model() && !indexes_.empty() ? model()->key(indexes_.front()) : GpgME::Key::null : keys_.front(); } std::vector keys() const { return keys_.empty() ? model() ? model()->keys(indexes()) : std::vector() : keys_; } void finished() { Q_EMIT q->finished(); if (autoDelete) { q->deleteLater(); } } void canceled() { Q_EMIT q->canceled(); finished(); } void error(const QString &text, const QString &caption = QString(), KMessageBox::Options options = KMessageBox::Notify) const { if (parentWId) { KMessageBox::errorWId(parentWId, text, caption, options); } else { KMessageBox::error(parentWidgetOrView(), text, caption, options); } } void information(const QString &text, const QString &caption = QString(), const QString &dontShowAgainName = QString(), KMessageBox::Options options = KMessageBox::Notify) const { if (parentWId) { KMessageBox::informationWId(parentWId, text, caption, dontShowAgainName, options); } else { KMessageBox::information(parentWidgetOrView(), text, caption, dontShowAgainName, options); } } void applyWindowID(QWidget *w) const { q->applyWindowID(w); } private: bool autoDelete : 1; bool warnWhenRunningAtShutdown : 1; std::vector keys_; QList indexes_; QPointer view_; QPointer parentWidget_; - WId parentWId; + WId parentWId = 0; QPointer controller_; }; #endif /* __KLEOPATRA_COMMANDS_COMMAND_P_H__ */ diff --git a/src/commands/importcertificatefromdatacommand.cpp b/src/commands/importcertificatefromdatacommand.cpp index 3f658fc0e..08c494dbb 100644 --- a/src/commands/importcertificatefromdatacommand.cpp +++ b/src/commands/importcertificatefromdatacommand.cpp @@ -1,75 +1,78 @@ /* -*- mode: c++; c-basic-offset:4 -*- importcertificatefromdatacommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "importcertificatefromdatacommand.h" #include "importcertificatescommand_p.h" #include #include using namespace GpgME; using namespace Kleo; using namespace QGpgME; class ImportCertificateFromDataCommand::Private : public ImportCertificatesCommand::Private { friend class ::ImportCertificateFromDataCommand; ImportCertificateFromDataCommand *q_func() const { return static_cast(q); } public: explicit Private(ImportCertificateFromDataCommand *qq, - const QByteArray &data, GpgME::Protocol proto); + const QByteArray &data, GpgME::Protocol proto, const QString &id); ~Private(); private: QByteArray mData; GpgME::Protocol mProto; + QString mId; }; ImportCertificateFromDataCommand::Private *ImportCertificateFromDataCommand::d_func() { return static_cast(d.get()); } const ImportCertificateFromDataCommand::Private *ImportCertificateFromDataCommand::d_func() const { return static_cast(d.get()); } ImportCertificateFromDataCommand::Private::Private(ImportCertificateFromDataCommand *qq, const QByteArray &data, - GpgME::Protocol proto) - : ImportCertificatesCommand::Private(qq, nullptr), mData(data), mProto(proto) + GpgME::Protocol proto, + const QString &id) + : ImportCertificatesCommand::Private(qq, nullptr), mData(data), mProto(proto), mId(id) { } ImportCertificateFromDataCommand::Private::~Private() {} #define d d_func() #define q q_func() ImportCertificateFromDataCommand::ImportCertificateFromDataCommand(const QByteArray &data, - GpgME::Protocol proto) - : ImportCertificatesCommand(new Private(this, data, proto)) + GpgME::Protocol proto, + const QString &id) + : ImportCertificatesCommand(new Private(this, data, proto, id)) { } ImportCertificateFromDataCommand::~ImportCertificateFromDataCommand() {} void ImportCertificateFromDataCommand::doStart() { - d->startImport(d->mProto, d->mData, i18n("Notepad")); + d->startImport(d->mProto, d->mData, d->mId.isEmpty() ? i18n("Notepad") : d->mId); } #undef d #undef q diff --git a/src/commands/importcertificatefromdatacommand.h b/src/commands/importcertificatefromdatacommand.h index c84e31b79..849e98107 100644 --- a/src/commands/importcertificatefromdatacommand.h +++ b/src/commands/importcertificatefromdatacommand.h @@ -1,40 +1,41 @@ /* -*- mode: c++; c-basic-offset:4 -*- importcertificatefromdatacommand.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2018 Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef __KLEOPATRA_IMPORTCERTIFICATEFROMDATACOMMAND_H__ #define __KLEOPATRA_IMPORTCERTIFICATEFROMDATACOMMAND_H__ #include "importcertificatescommand.h" #include namespace Kleo { class ImportCertificateFromDataCommand : public ImportCertificatesCommand { Q_OBJECT public: explicit ImportCertificateFromDataCommand(const QByteArray &data, - GpgME::Protocol proto); + GpgME::Protocol proto, + const QString &id = QString()); ~ImportCertificateFromDataCommand() override; private: void doStart() override; private: class Private; inline Private *d_func(); inline const Private *d_func() const; }; } #endif // __KLEOPATRA_IMPORTCERTIFICATEFROMDATACOMMAND_H__ diff --git a/src/commands/importcertificatefrompivcardcommand.cpp b/src/commands/importcertificatefrompivcardcommand.cpp index 571bfc3e8..994eb191f 100644 --- a/src/commands/importcertificatefrompivcardcommand.cpp +++ b/src/commands/importcertificatefrompivcardcommand.cpp @@ -1,109 +1,136 @@ /* commands/importcertificatefrompivcardcommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include "importcertificatefrompivcardcommand.h" -#include "importcertificatescommand_p.h" +#include "cardcommand_p.h" #include "smartcard/pivcard.h" #include "smartcard/readerstatus.h" +#include "commands/importcertificatefromdatacommand.h" + #include #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::SmartCard; -class ImportCertificateFromPIVCardCommand::Private : public ImportCertificatesCommand::Private +class ImportCertificateFromPIVCardCommand::Private : public CardCommand::Private { friend class ::Kleo::Commands::ImportCertificateFromPIVCardCommand; ImportCertificateFromPIVCardCommand *q_func() const { return static_cast(q); } public: explicit Private(ImportCertificateFromPIVCardCommand *qq, const std::string &slot, const std::string &serialno); ~Private(); private: void start(); + void importFinished(); + void importCanceled(); private: - std::string serialNumber; std::string cardSlot; + bool hasBeenCanceled = false; }; ImportCertificateFromPIVCardCommand::Private *ImportCertificateFromPIVCardCommand::d_func() { return static_cast(d.get()); } const ImportCertificateFromPIVCardCommand::Private *ImportCertificateFromPIVCardCommand::d_func() const { return static_cast(d.get()); } #define q q_func() #define d d_func() ImportCertificateFromPIVCardCommand::Private::Private(ImportCertificateFromPIVCardCommand *qq, const std::string &slot, const std::string &serialno) - : ImportCertificatesCommand::Private(qq, nullptr) - , serialNumber(serialno) + : CardCommand::Private(qq, serialno, nullptr) , cardSlot(slot) { } ImportCertificateFromPIVCardCommand::Private::~Private() { } void ImportCertificateFromPIVCardCommand::Private::start() { qCDebug(KLEOPATRA_LOG) << "ImportCertificateFromPIVCardCommand::Private::start()"; - const auto pivCard = ReaderStatus::instance()->getCard(serialNumber); + const auto pivCard = ReaderStatus::instance()->getCard(serialNumber()); if (!pivCard) { - error(i18n("Failed to find the PIV card with the serial number: %1", QString::fromStdString(serialNumber))); + error(i18n("Failed to find the PIV card with the serial number: %1", QString::fromStdString(serialNumber()))); finished(); return; } const std::string certificateData = pivCard->certificateData(cardSlot); if (certificateData.empty()) { error(i18n("Sorry! No certificate to import from this card slot was found.")); finished(); return; } - startImport(GpgME::CMS, QByteArray::fromStdString(certificateData), i18n("Card Certificate")); + auto cmd = new ImportCertificateFromDataCommand(QByteArray::fromStdString(certificateData), GpgME::CMS, i18n("Card Certificate")); + connect(cmd, &ImportCertificateFromDataCommand::finished, + q, [this]() { importFinished(); }); + connect(cmd, &ImportCertificateFromDataCommand::canceled, + q, [this]() { importCanceled(); }); + cmd->start(); +} + +void ImportCertificateFromPIVCardCommand::Private::importFinished() +{ + qCDebug(KLEOPATRA_LOG) << "ImportCertificateFromPIVCardCommand::importFinished()"; + if (!hasBeenCanceled) { + finished(); + } +} + +void ImportCertificateFromPIVCardCommand::Private::importCanceled() +{ + qCDebug(KLEOPATRA_LOG) << "ImportCertificateFromPIVCardCommand::importCanceled()"; + hasBeenCanceled = true; + canceled(); } ImportCertificateFromPIVCardCommand::ImportCertificateFromPIVCardCommand(const std::string& cardSlot, const std::string &serialno) - : ImportCertificatesCommand(new Private(this, cardSlot, serialno)) + : CardCommand(new Private(this, cardSlot, serialno)) { } ImportCertificateFromPIVCardCommand::~ImportCertificateFromPIVCardCommand() { qCDebug(KLEOPATRA_LOG) << "ImportCertificateFromPIVCardCommand::~ImportCertificateFromPIVCardCommand()"; } void ImportCertificateFromPIVCardCommand::doStart() { qCDebug(KLEOPATRA_LOG) << "ImportCertificateFromPIVCardCommand::doStart()"; d->start(); } +void ImportCertificateFromPIVCardCommand::doCancel() +{ +} + #undef q_func #undef d_func diff --git a/src/commands/importcertificatefrompivcardcommand.h b/src/commands/importcertificatefrompivcardcommand.h index 6dac47dc8..e7566d263 100644 --- a/src/commands/importcertificatefrompivcardcommand.h +++ b/src/commands/importcertificatefrompivcardcommand.h @@ -1,39 +1,40 @@ /* commands/importcertificatefrompivcardcommand.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef KLEOPATRA_COMMANDS_IMPORTCERTIFICATEFROMPIVCARDCOMMAND_H #define KLEOPATRA_COMMANDS_IMPORTCERTIFICATEFROMPIVCARDCOMMAND_H -#include "importcertificatescommand.h" +#include "cardcommand.h" namespace Kleo { namespace Commands { -class ImportCertificateFromPIVCardCommand : public ImportCertificatesCommand +class ImportCertificateFromPIVCardCommand : public CardCommand { Q_OBJECT public: ImportCertificateFromPIVCardCommand(const std::string& cardSlot, const std::string &serialno); ~ImportCertificateFromPIVCardCommand() override; private: void doStart() override; + void doCancel() override; private: class Private; inline Private *d_func(); inline const Private *d_func() const; }; } } #endif /* KLEOPATRA_COMMANDS_IMPORTCERTIFICATEFROMPIVCARDCOMMAND_H */ diff --git a/src/commands/keytocardcommand.cpp b/src/commands/keytocardcommand.cpp index 5ebf49074..8093d0af4 100644 --- a/src/commands/keytocardcommand.cpp +++ b/src/commands/keytocardcommand.cpp @@ -1,461 +1,458 @@ /* 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 SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "keytocardcommand.h" -#include "command_p.h" +#include "cardcommand_p.h" #include "commands/authenticatepivcardapplicationcommand.h" #include "dialogs/certificateselectiondialog.h" #include "smartcard/openpgpcard.h" #include "smartcard/pivcard.h" #include "smartcard/readerstatus.h" #include #include #include #include #include #include #include #include #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 +class KeyToCardCommand::Private : public CardCommand::Private { friend class ::Kleo::Commands::KeyToCardCommand; KeyToCardCommand *q_func() const { return static_cast(q); } public: 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 &card); void startKeyToPIVCard(); void authenticate(); void authenticationFinished(); void authenticationCanceled(); private: - std::string serialNumber; GpgME::Subkey subkey; std::string cardSlot; bool overwriteExistingAlreadyApproved = false; bool hasBeenCanceled = false; }; KeyToCardCommand::Private *KeyToCardCommand::d_func() { return static_cast(d.get()); } const KeyToCardCommand::Private *KeyToCardCommand::d_func() const { return static_cast(d.get()); } #define q q_func() #define d d_func() KeyToCardCommand::Private::Private(KeyToCardCommand *qq, const GpgME::Subkey &subkey_, const std::string &serialno) - : Command::Private(qq, nullptr), - serialNumber(serialno), + : CardCommand::Private(qq, serialno, nullptr), subkey(subkey_) { } KeyToCardCommand::Private::Private(KeyToCardCommand *qq, const std::string &slot, const std::string &serialno) - : Command::Private(qq, nullptr) - , serialNumber(serialno) + : CardCommand::Private(qq, serialno, nullptr) , cardSlot(slot) { } KeyToCardCommand::Private::~Private() { } void KeyToCardCommand::Private::start() { qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::Private::start()"; - const auto card = SmartCard::ReaderStatus::instance()->getCard(serialNumber); + const auto card = SmartCard::ReaderStatus::instance()->getCard(serialNumber()); if (!card) { - error(i18n("Failed to find the card with the serial number: %1", QString::fromStdString(serialNumber))); + 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(serialNumber); + const auto pgpCard = SmartCard::ReaderStatus::instance()->getCard(serialNumber()); if (!pgpCard) { - error(i18n("Failed to find the OpenPGP card with the serial number: %1", QString::fromStdString(serialNumber))); + error(i18n("Failed to find the OpenPGP card with the serial number: %1", QString::fromStdString(serialNumber()))); finished(); return; } if (subkey.isNull()) { finished(); return; } if (subkey.parent().protocol() != GpgME::OpenPGP) { error(i18n("Sorry! This key cannot be transferred to an OpenPGP card.")); finished(); return; } 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", "

This card already contains a key in this slot. Continuing will overwrite that key.

" "

If there is no backup the existing key will be irrecoverably lost.

") + i18n("The existing key has the fingerprint:") + QStringLiteral("
%1
").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(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(subkey.keyGrip()), QString::fromStdString(serialNumber)) + .arg(QString::fromLatin1(subkey.keyGrip()), QString::fromStdString(serialNumber())) .arg(slot) .arg(timestamp); ReaderStatus::mutableInstance()->startSimpleTransaction(cmd.toUtf8(), q_func(), "keyToOpenPGPCardDone"); } namespace { static std::vector getEncryptionCertificates() { std::vector 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 &/*card*/) { if (cardSlot != PIVCard::keyManagementKeyRef()) { return Subkey(); } const std::vector 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(serialNumber); + const auto pivCard = SmartCard::ReaderStatus::instance()->getCard(serialNumber()); if (!pivCard) { - error(i18n("Failed to find the PIV card with the serial number: %1", QString::fromStdString(serialNumber))); + 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 (subkey.isNull()) { subkey = getSubkeyToTransferToPIVCard(cardSlot, pivCard); } if (subkey.isNull()) { finished(); return; } if (subkey.parent().protocol() != GpgME::CMS) { error(i18n("Sorry! This key cannot be transferred to a PIV card.")); finished(); return; } 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 != 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", "

This card already contains a key in this slot. Continuing will overwrite that key.

" "

If there is no backup the existing key will be irrecoverably lost.

") + i18n("The existing key has the key grip:") + QStringLiteral("
%1
").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(subkey.keyGrip()), QString::fromStdString(serialNumber)) + .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(serialNumber, 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)) + : CardCommand(new Private(this, key, serialno)) { } KeyToCardCommand::KeyToCardCommand(const std::string& cardSlot, const std::string &serialno) - : Command(new Private(this, cardSlot, serialno)) + : CardCommand(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->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"); } */ 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", "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/commands/keytocardcommand.h b/src/commands/keytocardcommand.h index 6bcb7c1eb..e1898634f 100644 --- a/src/commands/keytocardcommand.h +++ b/src/commands/keytocardcommand.h @@ -1,52 +1,52 @@ /* commands/keytocardcommand.h 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 SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef __KLEOPATRA_COMMANDS_KEYTOCARDCOMMAND_H__ #define __KLEOPATRA_COMMANDS_KEYTOCARDCOMMAND_H__ -#include +#include #include namespace Kleo { namespace Commands { -class KeyToCardCommand : public Command +class KeyToCardCommand : public CardCommand { Q_OBJECT public: KeyToCardCommand(const GpgME::Subkey &key, const std::string &serialno); KeyToCardCommand(const std::string& cardSlot, const std::string &serialno); ~KeyToCardCommand() override; static bool supported(); public Q_SLOTS: void keyToOpenPGPCardDone(const GpgME::Error &err); void keyToPIVCardDone(const GpgME::Error &err); void deleteDone(const GpgME::Error &err); private: void doStart() override; void doCancel() override; private: class Private; inline Private *d_func(); inline const Private *d_func() const; }; } } #endif /* __KLEOPATRA_COMMANDS_KEYTOCARDCOMMAND_H__ */ diff --git a/src/commands/pivgeneratecardkeycommand.cpp b/src/commands/pivgeneratecardkeycommand.cpp index b9aba8a81..aaad782f0 100644 --- a/src/commands/pivgeneratecardkeycommand.cpp +++ b/src/commands/pivgeneratecardkeycommand.cpp @@ -1,236 +1,240 @@ /* commands/pivgeneratecardkeycommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include "pivgeneratecardkeycommand.h" #include "cardcommand_p.h" #include "smartcard/pivcard.h" #include "smartcard/readerstatus.h" #include "commands/authenticatepivcardapplicationcommand.h" #include "dialogs/gencardkeydialog.h" #include #include #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(q); } public: explicit Private(PIVGenerateCardKeyCommand *qq, const std::string &serialNumber, QWidget *p); ~Private(); void init(); private: void slotDialogAccepted(); void slotDialogRejected(); void slotResult(const Error &err); private: void authenticate(); void authenticationFinished(); void authenticationCanceled(); void generateKey(); void ensureDialogCreated(); private: std::string keyRef; bool overwriteExistingKey = false; std::string algorithm; QPointer dialog; bool hasBeenCanceled = false; }; PIVGenerateCardKeyCommand::Private *PIVGenerateCardKeyCommand::d_func() { return static_cast(d.get()); } const PIVGenerateCardKeyCommand::Private *PIVGenerateCardKeyCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() PIVGenerateCardKeyCommand::Private::Private(PIVGenerateCardKeyCommand *qq, const std::string &serialNumber, QWidget *p) : CardCommand::Private(qq, serialNumber, p) , dialog() { } PIVGenerateCardKeyCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::Private::~Private()"; } PIVGenerateCardKeyCommand::PIVGenerateCardKeyCommand(const std::string &serialNumber, QWidget *p) : CardCommand(new Private(this, serialNumber, p)) { d->init(); } void PIVGenerateCardKeyCommand::Private::init() { } PIVGenerateCardKeyCommand::~PIVGenerateCardKeyCommand() { qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::~PIVGenerateCardKeyCommand()"; } void PIVGenerateCardKeyCommand::setKeyRef(const std::string &keyRef) { d->keyRef = keyRef; } void PIVGenerateCardKeyCommand::doStart() { qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::doStart()"; // check if key exists auto pivCard = ReaderStatus::instance()->getCard(d->serialNumber()); if (!pivCard) { d->error(i18n("Failed to find the card with the serial number: %1", QString::fromStdString(d->serialNumber()))); d->finished(); return; } auto existingKey = pivCard->keyGrip(d->keyRef); if (!existingKey.empty()) { const QString warningText = i18nc("@info", "

This card already contains a key in this slot. Continuing will overwrite that key.

" "

If there is no backup the existing key will be irrecoverably lost.

") + i18n("The existing key has the ID:") + QStringLiteral("
%1
").arg(QString::fromStdString(existingKey)) + (d->keyRef == PIVCard::keyManagementKeyRef() ? i18n("It will no longer be possible to decrypt past communication encrypted for the existing key.") : QString()); - const auto choice = KMessageBox::warningContinueCancel(d->parentWidget(), warningText, + const auto choice = KMessageBox::warningContinueCancel(d->parentWidgetOrView(), warningText, i18nc("@title:window", "Overwrite existing key"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QString(), KMessageBox::Notify | KMessageBox::Dangerous); if (choice != KMessageBox::Continue) { d->finished(); return; } d->overwriteExistingKey = true; } d->ensureDialogCreated(); Q_ASSERT(d->dialog); d->dialog->show(); } +void PIVGenerateCardKeyCommand::doCancel() +{ +} + void PIVGenerateCardKeyCommand::Private::authenticate() { qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::authenticate()"; - auto cmd = new AuthenticatePIVCardApplicationCommand(serialNumber(), parentWidget()); + auto cmd = new AuthenticatePIVCardApplicationCommand(serialNumber(), parentWidgetOrView()); connect(cmd, &AuthenticatePIVCardApplicationCommand::finished, q, [this]() { authenticationFinished(); }); connect(cmd, &AuthenticatePIVCardApplicationCommand::canceled, q, [this]() { authenticationCanceled(); }); cmd->start(); } void PIVGenerateCardKeyCommand::Private::authenticationFinished() { qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::authenticationFinished()"; if (!hasBeenCanceled) { generateKey(); } } void PIVGenerateCardKeyCommand::Private::authenticationCanceled() { qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::authenticationCanceled()"; hasBeenCanceled = true; canceled(); } void PIVGenerateCardKeyCommand::Private::generateKey() { qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::generateKey()"; QByteArrayList command; command << "SCD GENKEY"; if (overwriteExistingKey) { command << "--force"; } if (!algorithm.empty()) { command << "--algo=" + QByteArray::fromStdString(algorithm); } command << "--" << QByteArray::fromStdString(keyRef); ReaderStatus::mutableInstance()->startSimpleTransaction(command.join(' '), q, "slotResult"); } void PIVGenerateCardKeyCommand::Private::slotResult(const GpgME::Error& err) { qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::slotResult():" << 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(); } void PIVGenerateCardKeyCommand::Private::slotDialogAccepted() { algorithm = dialog->getKeyParams().algorithm; // assume that we are already authenticated to the card generateKey(); } void PIVGenerateCardKeyCommand::Private::slotDialogRejected() { finished(); } void PIVGenerateCardKeyCommand::Private::ensureDialogCreated() { if (dialog) { return; } - dialog = new GenCardKeyDialog(GenCardKeyDialog::KeyAlgorithm, parentWidget()); + dialog = new GenCardKeyDialog(GenCardKeyDialog::KeyAlgorithm, parentWidgetOrView()); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setSupportedAlgorithms(PIVCard::supportedAlgorithms(keyRef), "rsa2048"); connect(dialog, SIGNAL(accepted()), q, SLOT(slotDialogAccepted())); connect(dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected())); } #undef d #undef q #include "moc_pivgeneratecardkeycommand.cpp" diff --git a/src/commands/pivgeneratecardkeycommand.h b/src/commands/pivgeneratecardkeycommand.h index f4e8e3c1a..11b3d58d0 100644 --- a/src/commands/pivgeneratecardkeycommand.h +++ b/src/commands/pivgeneratecardkeycommand.h @@ -1,48 +1,49 @@ /* commands/pivgeneratecardkeycommand.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker 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(const std::string &serialNumber, QWidget *parent); ~PIVGenerateCardKeyCommand() override; void setKeyRef(const std::string &keyref); private: void doStart() override; + void doCancel() 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_PIVGENERATECARDKEYCOMMAND_H__ diff --git a/src/commands/setinitialpincommand.cpp b/src/commands/setinitialpincommand.cpp index 3c00a7c07..6a23b4e44 100644 --- a/src/commands/setinitialpincommand.cpp +++ b/src/commands/setinitialpincommand.cpp @@ -1,162 +1,162 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/setinitialpincommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "setinitialpincommand.h" #include "command_p.h" #include #include #include using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Dialogs; using namespace Kleo::SmartCard; using namespace GpgME; class SetInitialPinCommand::Private : public Command::Private { friend class ::Kleo::Commands::SetInitialPinCommand; SetInitialPinCommand *q_func() const { return static_cast(q); } public: explicit Private(SetInitialPinCommand *qq); ~Private(); private: void init() { } void ensureDialogCreated() const { if (dialog) { return; } SetInitialPinDialog *dlg = new SetInitialPinDialog; applyWindowID(dlg); dlg->setAttribute(Qt::WA_DeleteOnClose); dlg->setWindowTitle(i18nc("@title:window", "Set Initial Pin")); const std::vector pinStates = ReaderStatus::instance()->pinStates(0); dlg->setNksPinPresent(pinStates.size() >= 1 && pinStates[0] != Card::NullPin); dlg->setSigGPinPresent(pinStates.size() >= 3 && pinStates[2] != Card::NullPin); connect(dlg, SIGNAL(nksPinRequested()), q_func(), SLOT(slotNksPinRequested())); connect(dlg, SIGNAL(sigGPinRequested()), q_func(), SLOT(slotSigGPinRequested())); connect(dlg, SIGNAL(rejected()), q_func(), SLOT(slotDialogRejected())); connect(dlg, SIGNAL(accepted()), q_func(), SLOT(slotDialogAccepted())); dialog = dlg; } void ensureDialogVisible() { ensureDialogCreated(); if (dialog->isVisible()) { dialog->raise(); } else { dialog->show(); } } private: void slotNksPinRequested() { ReaderStatus::mutableInstance() ->startSimpleTransaction("SCD PASSWD --nullpin PW1.CH", dialog, "setNksPinSettingResult"); } void slotSigGPinRequested() { ReaderStatus::mutableInstance() ->startSimpleTransaction("SCD PASSWD --nullpin PW1.CH.SIG", dialog, "setSigGPinSettingResult"); } void slotDialogRejected() { if (dialog->isComplete()) { slotDialogAccepted(); } else { canceled(); } } void slotDialogAccepted() { ReaderStatus::mutableInstance()->updateStatus(); finished(); } private: mutable QPointer dialog; }; SetInitialPinCommand::Private *SetInitialPinCommand::d_func() { return static_cast(d.get()); } const SetInitialPinCommand::Private *SetInitialPinCommand::d_func() const { return static_cast(d.get()); } #define q q_func() #define d d_func() SetInitialPinCommand::Private::Private(SetInitialPinCommand *qq) - : Command::Private(qq, nullptr), + : Command::Private(qq), dialog() { } SetInitialPinCommand::Private::~Private() {} SetInitialPinCommand::SetInitialPinCommand() : Command(new Private(this)) { d->init(); } SetInitialPinCommand::~SetInitialPinCommand() {} QDialog *SetInitialPinCommand::dialog() const { d->ensureDialogCreated(); return d->dialog; } void SetInitialPinCommand::doStart() { d->ensureDialogVisible(); } void SetInitialPinCommand::doCancel() { if (d->dialog) { d->dialog->close(); } } #undef q_func #undef d_func #include "moc_setinitialpincommand.cpp" diff --git a/src/commands/setpivcardapplicationadministrationkeycommand.cpp b/src/commands/setpivcardapplicationadministrationkeycommand.cpp index df37df891..0256857cc 100644 --- a/src/commands/setpivcardapplicationadministrationkeycommand.cpp +++ b/src/commands/setpivcardapplicationadministrationkeycommand.cpp @@ -1,208 +1,212 @@ /* commands/setpivcardapplicationadministrationkeycommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include "setpivcardapplicationadministrationkeycommand.h" #include "cardcommand_p.h" #include "smartcard/readerstatus.h" #include "commands/authenticatepivcardapplicationcommand.h" #include "dialogs/pivcardapplicationadministrationkeyinputdialog.h" #include #include #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Dialogs; using namespace Kleo::SmartCard; using namespace GpgME; class SetPIVCardApplicationAdministrationKeyCommand::Private : public CardCommand::Private { friend class ::Kleo::Commands::SetPIVCardApplicationAdministrationKeyCommand; SetPIVCardApplicationAdministrationKeyCommand *q_func() const { return static_cast(q); } public: explicit Private(SetPIVCardApplicationAdministrationKeyCommand *qq, const std::string &serialNumber, QWidget *p); ~Private(); void init(); private: void slotDialogAccepted(); void slotDialogRejected(); void slotResult(const Error &err); private: void authenticate(); void authenticationFinished(); void authenticationCanceled(); void setAdminKey(); void ensureDialogCreated(); private: QByteArray newAdminKey; QPointer dialog; bool hasBeenCanceled = false; }; SetPIVCardApplicationAdministrationKeyCommand::Private *SetPIVCardApplicationAdministrationKeyCommand::d_func() { return static_cast(d.get()); } const SetPIVCardApplicationAdministrationKeyCommand::Private *SetPIVCardApplicationAdministrationKeyCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() SetPIVCardApplicationAdministrationKeyCommand::Private::Private(SetPIVCardApplicationAdministrationKeyCommand *qq, const std::string &serialNumber, QWidget *p) : CardCommand::Private(qq, serialNumber, p) , dialog() { } SetPIVCardApplicationAdministrationKeyCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::Private::~Private()"; } SetPIVCardApplicationAdministrationKeyCommand::SetPIVCardApplicationAdministrationKeyCommand(const std::string &serialNumber, QWidget *p) : CardCommand(new Private(this, serialNumber, p)) { d->init(); } void SetPIVCardApplicationAdministrationKeyCommand::Private::init() { } SetPIVCardApplicationAdministrationKeyCommand::~SetPIVCardApplicationAdministrationKeyCommand() { qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::~SetPIVCardApplicationAdministrationKeyCommand()"; } void SetPIVCardApplicationAdministrationKeyCommand::doStart() { qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::doStart()"; d->authenticate(); } +void SetPIVCardApplicationAdministrationKeyCommand::doCancel() +{ +} + void SetPIVCardApplicationAdministrationKeyCommand::Private::authenticate() { qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::authenticate()"; - auto cmd = new AuthenticatePIVCardApplicationCommand(serialNumber(), parentWidget()); + auto cmd = new AuthenticatePIVCardApplicationCommand(serialNumber(), parentWidgetOrView()); cmd->setPrompt(i18n("Please enter the old PIV Card Application Administration Key in hex-encoded form.")); connect(cmd, &AuthenticatePIVCardApplicationCommand::finished, q, [this]() { authenticationFinished(); }); connect(cmd, &AuthenticatePIVCardApplicationCommand::canceled, q, [this]() { authenticationCanceled(); }); cmd->start(); } void SetPIVCardApplicationAdministrationKeyCommand::Private::authenticationFinished() { qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::authenticationFinished()"; if (!hasBeenCanceled) { setAdminKey(); } } void SetPIVCardApplicationAdministrationKeyCommand::Private::authenticationCanceled() { qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::authenticationCanceled()"; hasBeenCanceled = true; canceled(); } void SetPIVCardApplicationAdministrationKeyCommand::Private::setAdminKey() { qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::setAdminKey()"; ensureDialogCreated(); Q_ASSERT(dialog); dialog->show(); } void SetPIVCardApplicationAdministrationKeyCommand::Private::ensureDialogCreated() { if (dialog) { return; } - dialog = new PIVCardApplicationAdministrationKeyInputDialog(parentWidget()); + dialog = new PIVCardApplicationAdministrationKeyInputDialog(parentWidgetOrView()); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setLabelText(newAdminKey.isEmpty() ? i18n("Please enter the new PIV Card Application Administration Key in hex-encoded form. " "The key needs to consist of 24 bytes, i.e. 48 hex-characters.") : i18n("Please enter the new PIV Card Application Administration Key again.")); connect(dialog, SIGNAL(accepted()), q, SLOT(slotDialogAccepted())); connect(dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected())); } void SetPIVCardApplicationAdministrationKeyCommand::Private::slotDialogAccepted() { if (newAdminKey.isEmpty()) { newAdminKey = dialog->adminKey(); dialog = nullptr; setAdminKey(); return; } const QByteArray newAdminKey2 = dialog->adminKey(); if (newAdminKey != newAdminKey2) { error(i18nc("@info", "The two keys you have entered do not match. Please retry."), i18nc("@title", "Error")); newAdminKey.clear(); dialog = nullptr; setAdminKey(); return; } const QByteArray plusPercentEncodedAdminKey = newAdminKey.toPercentEncoding().replace(' ', '+'); const QByteArray command = QByteArray("SCD SETATTR SET-ADM-KEY ") + plusPercentEncodedAdminKey; ReaderStatus::mutableInstance()->startSimpleTransaction(command, q, "slotResult"); } void SetPIVCardApplicationAdministrationKeyCommand::Private::slotDialogRejected() { finished(); } void SetPIVCardApplicationAdministrationKeyCommand::Private::slotResult(const GpgME::Error& err) { qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::slotResult():" << err.asString() << "(" << err.code() << ")"; if (err) { error(i18nc("@info", "Setting the PIV Card Application Administration Key failed: %1", QString::fromLatin1(err.asString())), i18nc("@title", "Error")); } else if (!err.isCanceled()) { information(i18nc("@info", "PIV Card Application Administration Key set successfully."), i18nc("@title", "Success")); ReaderStatus::mutableInstance()->updateStatus(); } finished(); } #undef d #undef q #include "moc_setpivcardapplicationadministrationkeycommand.cpp" diff --git a/src/commands/setpivcardapplicationadministrationkeycommand.h b/src/commands/setpivcardapplicationadministrationkeycommand.h index bb929de32..f5c9d4a08 100644 --- a/src/commands/setpivcardapplicationadministrationkeycommand.h +++ b/src/commands/setpivcardapplicationadministrationkeycommand.h @@ -1,46 +1,47 @@ /* commands/setpivcardapplicationadministrationkeycommand.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef __KLEOPATRA_COMMMANDS_SETPIVCARDAPPLICATIONADMINISTRATIONKEYCOMMAND_H__ #define __KLEOPATRA_COMMMANDS_SETPIVCARDAPPLICATIONADMINISTRATIONKEYCOMMAND_H__ #include "cardcommand.h" namespace GpgME { class Error; } namespace Kleo { namespace Commands { class SetPIVCardApplicationAdministrationKeyCommand : public CardCommand { Q_OBJECT public: explicit SetPIVCardApplicationAdministrationKeyCommand(const std::string &serialNumber, QWidget *parent); ~SetPIVCardApplicationAdministrationKeyCommand() override; private: void doStart() override; + void doCancel() 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_SETPIVCARDAPPLICATIONADMINISTRATIONKEYCOMMAND_H__