1 /* commands/authenticatepivcardapplicationcommand.cpp
2
3 This file is part of Kleopatra, the KDE keymanager
4 SPDX-FileCopyrightText: 2020 g10 Code GmbH
5 SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "authenticatepivcardapplicationcommand.h"
11
12 #include "cardcommand_p.h"
13
14 #include "smartcard/pivcard.h"
15 #include "smartcard/readerstatus.h"
16
17 #include "dialogs/pivcardapplicationadministrationkeyinputdialog.h"
18
19 #include <KLocalizedString>
20
21 #include <gpgme++/error.h>
22
23 #include <gpg-error.h>
24 #if GPG_ERROR_VERSION_NUMBER >= 0x12400 // 1.36
25 # define GPG_ERROR_HAS_BAD_AUTH
26 #endif
27
28 #include "kleopatra_debug.h"
29
30 using namespace Kleo;
31 using namespace Kleo::Commands;
32 using namespace Kleo::Dialogs;
33 using namespace Kleo::SmartCard;
34 using namespace GpgME;
35
36 class AuthenticatePIVCardApplicationCommand::Private : public CardCommand::Private
37 {
38 friend class ::Kleo::Commands::AuthenticatePIVCardApplicationCommand;
q_func() const39 AuthenticatePIVCardApplicationCommand *q_func() const
40 {
41 return static_cast<AuthenticatePIVCardApplicationCommand *>(q);
42 }
43 public:
44 explicit Private(AuthenticatePIVCardApplicationCommand *qq, const std::string &serialNumber, QWidget *p);
45 ~Private() override;
46
47 void init();
48
49 private:
50 void slotResult(const Error &err);
51 void slotDialogAccepted();
52 void slotDialogRejected();
53
54 private:
55 void authenticate(const QByteArray& adminKey);
56 void retryAskingForKey();
57 void ensureDialogCreated();
58
59 private:
60 QString prompt;
61 QPointer<PIVCardApplicationAdministrationKeyInputDialog> dialog;
62 };
63
d_func()64 AuthenticatePIVCardApplicationCommand::Private *AuthenticatePIVCardApplicationCommand::d_func()
65 {
66 return static_cast<Private *>(d.get());
67 }
d_func() const68 const AuthenticatePIVCardApplicationCommand::Private *AuthenticatePIVCardApplicationCommand::d_func() const
69 {
70 return static_cast<const Private *>(d.get());
71 }
72
73 #define d d_func()
74 #define q q_func()
75
Private(AuthenticatePIVCardApplicationCommand * qq,const std::string & serialNumber,QWidget * p)76 AuthenticatePIVCardApplicationCommand::Private::Private(AuthenticatePIVCardApplicationCommand *qq, const std::string &serialNumber, QWidget *p)
77 : CardCommand::Private(qq, serialNumber, p)
78 , dialog()
79 {
80 }
81
~Private()82 AuthenticatePIVCardApplicationCommand::Private::~Private()
83 {
84 qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::Private::~Private()";
85 }
86
AuthenticatePIVCardApplicationCommand(const std::string & serialNumber,QWidget * p)87 AuthenticatePIVCardApplicationCommand::AuthenticatePIVCardApplicationCommand(const std::string &serialNumber, QWidget *p)
88 : CardCommand(new Private(this, serialNumber, p))
89 {
90 d->init();
91 }
92
init()93 void AuthenticatePIVCardApplicationCommand::Private::init()
94 {
95 }
96
~AuthenticatePIVCardApplicationCommand()97 AuthenticatePIVCardApplicationCommand::~AuthenticatePIVCardApplicationCommand()
98 {
99 qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::~AuthenticatePIVCardApplicationCommand()";
100 }
101
setPrompt(const QString & prompt)102 void AuthenticatePIVCardApplicationCommand::setPrompt(const QString& prompt)
103 {
104 d->prompt = prompt;
105 }
106
doStart()107 void AuthenticatePIVCardApplicationCommand::doStart()
108 {
109 qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::doStart()";
110
111 // at first, try to authenticate using the default application administration key
112 d->authenticate(QByteArray::fromHex("010203040506070801020304050607080102030405060708"));
113 }
114
doCancel()115 void AuthenticatePIVCardApplicationCommand::doCancel()
116 {
117 }
118
authenticate(const QByteArray & adminKey)119 void AuthenticatePIVCardApplicationCommand::Private::authenticate(const QByteArray& adminKey)
120 {
121 qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::authenticate()";
122
123 const auto pivCard = SmartCard::ReaderStatus::instance()->getCard<PIVCard>(serialNumber());
124 if (!pivCard) {
125 error(i18n("Failed to find the PIV card with the serial number: %1", QString::fromStdString(serialNumber())));
126 finished();
127 return;
128 }
129
130 const QByteArray plusPercentEncodedAdminKey = adminKey.toPercentEncoding().replace(' ', '+');
131 const QByteArray command = QByteArray("SCD SETATTR AUTH-ADM-KEY ") + plusPercentEncodedAdminKey;
132 ReaderStatus::mutableInstance()->startSimpleTransaction(pivCard, command, q, "slotResult");
133 }
134
slotResult(const Error & err)135 void AuthenticatePIVCardApplicationCommand::Private::slotResult(const Error &err)
136 {
137 qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::slotResult():"
138 << err.asString() << "(" << err.code() << ")";
139 if (err.isCanceled()) {
140 canceled();
141 return;
142 }
143 if (err) {
144 #ifdef GPG_ERROR_HAS_BAD_AUTH
145 if (err.code() == GPG_ERR_BAD_AUTH) {
146 retryAskingForKey();
147 return;
148 }
149 #endif
150 error(i18nc("@info", "Authenticating to the card failed: %1", QString::fromLatin1(err.asString())),
151 i18nc("@title", "Error"));
152 }
153 finished();
154 }
155
retryAskingForKey()156 void AuthenticatePIVCardApplicationCommand::Private::retryAskingForKey()
157 {
158 ensureDialogCreated();
159 Q_ASSERT(dialog);
160 dialog->show();
161 }
162
ensureDialogCreated()163 void AuthenticatePIVCardApplicationCommand::Private::ensureDialogCreated()
164 {
165 if (dialog) {
166 return;
167 }
168
169 dialog = new PIVCardApplicationAdministrationKeyInputDialog(parentWidgetOrView());
170 dialog->setAttribute(Qt::WA_DeleteOnClose);
171 dialog->setLabelText(prompt.isEmpty() ?
172 i18n("Please enter the PIV Card Application Administration Key in hex-encoded form.") :
173 prompt);
174
175 connect(dialog, SIGNAL(accepted()), q, SLOT(slotDialogAccepted()));
176 connect(dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected()));
177 }
178
slotDialogAccepted()179 void AuthenticatePIVCardApplicationCommand::Private::slotDialogAccepted()
180 {
181 authenticate(dialog->adminKey());
182 }
183
slotDialogRejected()184 void AuthenticatePIVCardApplicationCommand::Private::slotDialogRejected()
185 {
186 canceled();
187 }
188
189 #undef d
190 #undef q
191
192 #include "moc_authenticatepivcardapplicationcommand.cpp"
193