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

0001 /*  commands/authenticatepivcardapplicationcommand.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 "authenticatepivcardapplicationcommand.h"
0011 
0012 #include "cardcommand_p.h"
0013 
0014 #include "smartcard/pivcard.h"
0015 #include "smartcard/readerstatus.h"
0016 
0017 #include "dialogs/pivcardapplicationadministrationkeyinputdialog.h"
0018 
0019 #include <Libkleo/Formatting>
0020 
0021 #include <KLocalizedString>
0022 
0023 #include <gpgme++/error.h>
0024 
0025 #include <gpg-error.h>
0026 #if GPG_ERROR_VERSION_NUMBER >= 0x12400 // 1.36
0027 #define GPG_ERROR_HAS_BAD_AUTH
0028 #endif
0029 
0030 #include "kleopatra_debug.h"
0031 
0032 using namespace Kleo;
0033 using namespace Kleo::Commands;
0034 using namespace Kleo::Dialogs;
0035 using namespace Kleo::SmartCard;
0036 using namespace GpgME;
0037 
0038 class AuthenticatePIVCardApplicationCommand::Private : public CardCommand::Private
0039 {
0040     friend class ::Kleo::Commands::AuthenticatePIVCardApplicationCommand;
0041     AuthenticatePIVCardApplicationCommand *q_func() const
0042     {
0043         return static_cast<AuthenticatePIVCardApplicationCommand *>(q);
0044     }
0045 
0046 public:
0047     explicit Private(AuthenticatePIVCardApplicationCommand *qq, const std::string &serialNumber, QWidget *p);
0048     ~Private() override;
0049 
0050     void init();
0051 
0052 private:
0053     void slotResult(const Error &err);
0054     void slotDialogAccepted();
0055     void slotDialogRejected();
0056 
0057 private:
0058     void authenticate(const QByteArray &adminKey);
0059     void retryAskingForKey();
0060     void ensureDialogCreated();
0061 
0062 private:
0063     QString prompt;
0064     QPointer<PIVCardApplicationAdministrationKeyInputDialog> dialog;
0065 };
0066 
0067 AuthenticatePIVCardApplicationCommand::Private *AuthenticatePIVCardApplicationCommand::d_func()
0068 {
0069     return static_cast<Private *>(d.get());
0070 }
0071 const AuthenticatePIVCardApplicationCommand::Private *AuthenticatePIVCardApplicationCommand::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 AuthenticatePIVCardApplicationCommand::Private::Private(AuthenticatePIVCardApplicationCommand *qq, const std::string &serialNumber, QWidget *p)
0080     : CardCommand::Private(qq, serialNumber, p)
0081     , dialog()
0082 {
0083 }
0084 
0085 AuthenticatePIVCardApplicationCommand::Private::~Private()
0086 {
0087     qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::Private::~Private()";
0088 }
0089 
0090 AuthenticatePIVCardApplicationCommand::AuthenticatePIVCardApplicationCommand(const std::string &serialNumber, QWidget *p)
0091     : CardCommand(new Private(this, serialNumber, p))
0092 {
0093     d->init();
0094 }
0095 
0096 void AuthenticatePIVCardApplicationCommand::Private::init()
0097 {
0098 }
0099 
0100 AuthenticatePIVCardApplicationCommand::~AuthenticatePIVCardApplicationCommand()
0101 {
0102     qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::~AuthenticatePIVCardApplicationCommand()";
0103 }
0104 
0105 void AuthenticatePIVCardApplicationCommand::setPrompt(const QString &prompt)
0106 {
0107     d->prompt = prompt;
0108 }
0109 
0110 void AuthenticatePIVCardApplicationCommand::doStart()
0111 {
0112     qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::doStart()";
0113 
0114     // at first, try to authenticate using the default application administration key
0115     d->authenticate(QByteArray::fromHex("010203040506070801020304050607080102030405060708"));
0116 }
0117 
0118 void AuthenticatePIVCardApplicationCommand::doCancel()
0119 {
0120 }
0121 
0122 void AuthenticatePIVCardApplicationCommand::Private::authenticate(const QByteArray &adminKey)
0123 {
0124     qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::authenticate()";
0125 
0126     const auto pivCard = SmartCard::ReaderStatus::instance()->getCard<PIVCard>(serialNumber());
0127     if (!pivCard) {
0128         error(i18n("Failed to find the PIV card with the serial number: %1", QString::fromStdString(serialNumber())));
0129         finished();
0130         return;
0131     }
0132 
0133     const QByteArray plusPercentEncodedAdminKey = adminKey.toPercentEncoding().replace(' ', '+');
0134     const QByteArray command = QByteArray("SCD SETATTR AUTH-ADM-KEY ") + plusPercentEncodedAdminKey;
0135     ReaderStatus::mutableInstance()->startSimpleTransaction(pivCard, command, q, [this](const GpgME::Error &err) {
0136         slotResult(err);
0137     });
0138 }
0139 
0140 void AuthenticatePIVCardApplicationCommand::Private::slotResult(const Error &err)
0141 {
0142     qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::slotResult():" << Formatting::errorAsString(err) << "(" << err.code() << ")";
0143     if (err.isCanceled()) {
0144         canceled();
0145         return;
0146     }
0147     if (err) {
0148 #ifdef GPG_ERROR_HAS_BAD_AUTH
0149         if (err.code() == GPG_ERR_BAD_AUTH) {
0150             retryAskingForKey();
0151             return;
0152         }
0153 #endif
0154         error(i18nc("@info", "Authenticating to the card failed: %1", Formatting::errorAsString(err)));
0155     }
0156     finished();
0157 }
0158 
0159 void AuthenticatePIVCardApplicationCommand::Private::retryAskingForKey()
0160 {
0161     ensureDialogCreated();
0162     Q_ASSERT(dialog);
0163     dialog->show();
0164 }
0165 
0166 void AuthenticatePIVCardApplicationCommand::Private::ensureDialogCreated()
0167 {
0168     if (dialog) {
0169         return;
0170     }
0171 
0172     dialog = new PIVCardApplicationAdministrationKeyInputDialog(parentWidgetOrView());
0173     dialog->setAttribute(Qt::WA_DeleteOnClose);
0174     dialog->setLabelText(prompt.isEmpty() ? i18n("Please enter the PIV Card Application Administration Key in hex-encoded form.") : prompt);
0175 
0176     connect(dialog, &QDialog::accepted, q, [this]() {
0177         slotDialogAccepted();
0178     });
0179     connect(dialog, &QDialog::rejected, q, [this]() {
0180         slotDialogRejected();
0181     });
0182 }
0183 
0184 void AuthenticatePIVCardApplicationCommand::Private::slotDialogAccepted()
0185 {
0186     authenticate(dialog->adminKey());
0187 }
0188 
0189 void AuthenticatePIVCardApplicationCommand::Private::slotDialogRejected()
0190 {
0191     canceled();
0192 }
0193 
0194 #undef d
0195 #undef q
0196 
0197 #include "moc_authenticatepivcardapplicationcommand.cpp"