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"