File indexing completed on 2024-06-23 05:13:45

0001 /*  commands/setpivcardapplicationadministrationkeycommand.cpp
0002 
0003     This file is part of Kleopatra, the KDE keymanager
0004     SPDX-FileCopyrightText: 2020 g10 Code GmbH
0005     SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include "setpivcardapplicationadministrationkeycommand.h"
0011 
0012 #include "cardcommand_p.h"
0013 
0014 #include "smartcard/pivcard.h"
0015 #include "smartcard/readerstatus.h"
0016 
0017 #include "commands/authenticatepivcardapplicationcommand.h"
0018 
0019 #include "dialogs/pivcardapplicationadministrationkeyinputdialog.h"
0020 
0021 #include <Libkleo/Formatting>
0022 
0023 #include <KLocalizedString>
0024 
0025 #include <gpgme++/error.h>
0026 
0027 #include "kleopatra_debug.h"
0028 
0029 using namespace Kleo;
0030 using namespace Kleo::Commands;
0031 using namespace Kleo::Dialogs;
0032 using namespace Kleo::SmartCard;
0033 using namespace GpgME;
0034 
0035 class SetPIVCardApplicationAdministrationKeyCommand::Private : public CardCommand::Private
0036 {
0037     friend class ::Kleo::Commands::SetPIVCardApplicationAdministrationKeyCommand;
0038     SetPIVCardApplicationAdministrationKeyCommand *q_func() const
0039     {
0040         return static_cast<SetPIVCardApplicationAdministrationKeyCommand *>(q);
0041     }
0042 
0043 public:
0044     explicit Private(SetPIVCardApplicationAdministrationKeyCommand *qq, const std::string &serialNumber, QWidget *p);
0045     ~Private() override;
0046 
0047     void init();
0048 
0049 private:
0050     void slotDialogAccepted();
0051     void slotDialogRejected();
0052     void slotResult(const Error &err);
0053 
0054 private:
0055     void authenticate();
0056     void authenticationFinished();
0057     void authenticationCanceled();
0058     void setAdminKey();
0059     void ensureDialogCreated();
0060 
0061 private:
0062     QByteArray newAdminKey;
0063     QPointer<PIVCardApplicationAdministrationKeyInputDialog> dialog;
0064     bool hasBeenCanceled = false;
0065 };
0066 
0067 SetPIVCardApplicationAdministrationKeyCommand::Private *SetPIVCardApplicationAdministrationKeyCommand::d_func()
0068 {
0069     return static_cast<Private *>(d.get());
0070 }
0071 const SetPIVCardApplicationAdministrationKeyCommand::Private *SetPIVCardApplicationAdministrationKeyCommand::d_func() const
0072 {
0073     return static_cast<const Private *>(d.get());
0074 }
0075 
0076 #define d d_func()
0077 #define q q_func()
0078 
0079 SetPIVCardApplicationAdministrationKeyCommand::Private::Private(SetPIVCardApplicationAdministrationKeyCommand *qq, const std::string &serialNumber, QWidget *p)
0080     : CardCommand::Private(qq, serialNumber, p)
0081     , dialog()
0082 {
0083 }
0084 
0085 SetPIVCardApplicationAdministrationKeyCommand::Private::~Private()
0086 {
0087     qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::Private::~Private()";
0088 }
0089 
0090 SetPIVCardApplicationAdministrationKeyCommand::SetPIVCardApplicationAdministrationKeyCommand(const std::string &serialNumber, QWidget *p)
0091     : CardCommand(new Private(this, serialNumber, p))
0092 {
0093     d->init();
0094 }
0095 
0096 void SetPIVCardApplicationAdministrationKeyCommand::Private::init()
0097 {
0098 }
0099 
0100 SetPIVCardApplicationAdministrationKeyCommand::~SetPIVCardApplicationAdministrationKeyCommand()
0101 {
0102     qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::~SetPIVCardApplicationAdministrationKeyCommand()";
0103 }
0104 
0105 void SetPIVCardApplicationAdministrationKeyCommand::doStart()
0106 {
0107     qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::doStart()";
0108 
0109     d->authenticate();
0110 }
0111 
0112 void SetPIVCardApplicationAdministrationKeyCommand::doCancel()
0113 {
0114 }
0115 
0116 void SetPIVCardApplicationAdministrationKeyCommand::Private::authenticate()
0117 {
0118     qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::authenticate()";
0119 
0120     auto cmd = new AuthenticatePIVCardApplicationCommand(serialNumber(), parentWidgetOrView());
0121     cmd->setAutoResetCardToOpenPGP(false);
0122     cmd->setPrompt(i18n("Please enter the old PIV Card Application Administration Key in hex-encoded form."));
0123     connect(cmd, &AuthenticatePIVCardApplicationCommand::finished, q, [this]() {
0124         authenticationFinished();
0125     });
0126     connect(cmd, &AuthenticatePIVCardApplicationCommand::canceled, q, [this]() {
0127         authenticationCanceled();
0128     });
0129     cmd->start();
0130 }
0131 
0132 void SetPIVCardApplicationAdministrationKeyCommand::Private::authenticationFinished()
0133 {
0134     qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::authenticationFinished()";
0135     if (!hasBeenCanceled) {
0136         setAdminKey();
0137     }
0138 }
0139 
0140 void SetPIVCardApplicationAdministrationKeyCommand::Private::authenticationCanceled()
0141 {
0142     qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::authenticationCanceled()";
0143     hasBeenCanceled = true;
0144     canceled();
0145 }
0146 
0147 void SetPIVCardApplicationAdministrationKeyCommand::Private::setAdminKey()
0148 {
0149     qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::setAdminKey()";
0150 
0151     ensureDialogCreated();
0152     Q_ASSERT(dialog);
0153     dialog->show();
0154 }
0155 
0156 void SetPIVCardApplicationAdministrationKeyCommand::Private::ensureDialogCreated()
0157 {
0158     if (dialog) {
0159         return;
0160     }
0161 
0162     dialog = new PIVCardApplicationAdministrationKeyInputDialog(parentWidgetOrView());
0163     dialog->setAttribute(Qt::WA_DeleteOnClose);
0164     dialog->setLabelText(newAdminKey.isEmpty() ? i18n("Please enter the new PIV Card Application Administration Key in hex-encoded form. "
0165                                                       "The key needs to consist of 24 bytes, i.e. 48 hex-characters.")
0166                                                : i18n("Please enter the new PIV Card Application Administration Key again."));
0167 
0168     connect(dialog, &QDialog::accepted, q, [this]() {
0169         slotDialogAccepted();
0170     });
0171     connect(dialog, &QDialog::rejected, q, [this]() {
0172         slotDialogRejected();
0173     });
0174 }
0175 
0176 void SetPIVCardApplicationAdministrationKeyCommand::Private::slotDialogAccepted()
0177 {
0178     if (newAdminKey.isEmpty()) {
0179         newAdminKey = dialog->adminKey();
0180         dialog = nullptr;
0181         setAdminKey();
0182         return;
0183     }
0184 
0185     const QByteArray newAdminKey2 = dialog->adminKey();
0186     if (newAdminKey != newAdminKey2) {
0187         error(i18nc("@info", "The two keys you have entered do not match. Please retry."));
0188         newAdminKey.clear();
0189         dialog = nullptr;
0190         setAdminKey();
0191         return;
0192     }
0193 
0194     auto pivCard = ReaderStatus::instance()->getCard<PIVCard>(serialNumber());
0195     if (!pivCard) {
0196         error(i18n("Failed to find the PIV card with the serial number: %1", QString::fromStdString(serialNumber())));
0197         finished();
0198         return;
0199     }
0200 
0201     const QByteArray plusPercentEncodedAdminKey = newAdminKey.toPercentEncoding().replace(' ', '+');
0202     const QByteArray command = QByteArray("SCD SETATTR SET-ADM-KEY ") + plusPercentEncodedAdminKey;
0203     ReaderStatus::mutableInstance()->startSimpleTransaction(pivCard, command, q, [this](const GpgME::Error &err) {
0204         slotResult(err);
0205     });
0206 }
0207 
0208 void SetPIVCardApplicationAdministrationKeyCommand::Private::slotDialogRejected()
0209 {
0210     finished();
0211 }
0212 
0213 void SetPIVCardApplicationAdministrationKeyCommand::Private::slotResult(const GpgME::Error &err)
0214 {
0215     qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::slotResult():" << Formatting::errorAsString(err) << "(" << err.code() << ")";
0216     if (err) {
0217         error(i18nc("@info", "Setting the PIV Card Application Administration Key failed: %1", Formatting::errorAsString(err)));
0218     } else if (!err.isCanceled()) {
0219         success(i18nc("@info", "PIV Card Application Administration Key set successfully."));
0220         ReaderStatus::mutableInstance()->updateStatus();
0221     }
0222     finished();
0223 }
0224 
0225 #undef d
0226 #undef q
0227 
0228 #include "moc_setpivcardapplicationadministrationkeycommand.cpp"