1 /* commands/setpivcardapplicationadministrationkeycommand.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 "setpivcardapplicationadministrationkeycommand.h"
11
12 #include "cardcommand_p.h"
13
14 #include "smartcard/pivcard.h"
15 #include "smartcard/readerstatus.h"
16
17 #include "commands/authenticatepivcardapplicationcommand.h"
18
19 #include "dialogs/pivcardapplicationadministrationkeyinputdialog.h"
20
21 #include <KLocalizedString>
22
23 #include <gpgme++/error.h>
24
25 #include "kleopatra_debug.h"
26
27 using namespace Kleo;
28 using namespace Kleo::Commands;
29 using namespace Kleo::Dialogs;
30 using namespace Kleo::SmartCard;
31 using namespace GpgME;
32
33 class SetPIVCardApplicationAdministrationKeyCommand::Private : public CardCommand::Private
34 {
35 friend class ::Kleo::Commands::SetPIVCardApplicationAdministrationKeyCommand;
q_func() const36 SetPIVCardApplicationAdministrationKeyCommand *q_func() const
37 {
38 return static_cast<SetPIVCardApplicationAdministrationKeyCommand *>(q);
39 }
40 public:
41 explicit Private(SetPIVCardApplicationAdministrationKeyCommand *qq, const std::string &serialNumber, QWidget *p);
42 ~Private() override;
43
44 void init();
45
46 private:
47 void slotDialogAccepted();
48 void slotDialogRejected();
49 void slotResult(const Error &err);
50
51 private:
52 void authenticate();
53 void authenticationFinished();
54 void authenticationCanceled();
55 void setAdminKey();
56 void ensureDialogCreated();
57
58 private:
59 QByteArray newAdminKey;
60 QPointer<PIVCardApplicationAdministrationKeyInputDialog> dialog;
61 bool hasBeenCanceled = false;
62 };
63
d_func()64 SetPIVCardApplicationAdministrationKeyCommand::Private *SetPIVCardApplicationAdministrationKeyCommand::d_func()
65 {
66 return static_cast<Private *>(d.get());
67 }
d_func() const68 const SetPIVCardApplicationAdministrationKeyCommand::Private *SetPIVCardApplicationAdministrationKeyCommand::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(SetPIVCardApplicationAdministrationKeyCommand * qq,const std::string & serialNumber,QWidget * p)76 SetPIVCardApplicationAdministrationKeyCommand::Private::Private(SetPIVCardApplicationAdministrationKeyCommand *qq, const std::string &serialNumber, QWidget *p)
77 : CardCommand::Private(qq, serialNumber, p)
78 , dialog()
79 {
80 }
81
~Private()82 SetPIVCardApplicationAdministrationKeyCommand::Private::~Private()
83 {
84 qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::Private::~Private()";
85 }
86
SetPIVCardApplicationAdministrationKeyCommand(const std::string & serialNumber,QWidget * p)87 SetPIVCardApplicationAdministrationKeyCommand::SetPIVCardApplicationAdministrationKeyCommand(const std::string &serialNumber, QWidget *p)
88 : CardCommand(new Private(this, serialNumber, p))
89 {
90 d->init();
91 }
92
init()93 void SetPIVCardApplicationAdministrationKeyCommand::Private::init()
94 {
95 }
96
~SetPIVCardApplicationAdministrationKeyCommand()97 SetPIVCardApplicationAdministrationKeyCommand::~SetPIVCardApplicationAdministrationKeyCommand()
98 {
99 qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::~SetPIVCardApplicationAdministrationKeyCommand()";
100 }
101
doStart()102 void SetPIVCardApplicationAdministrationKeyCommand::doStart()
103 {
104 qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::doStart()";
105
106 d->authenticate();
107 }
108
doCancel()109 void SetPIVCardApplicationAdministrationKeyCommand::doCancel()
110 {
111 }
112
authenticate()113 void SetPIVCardApplicationAdministrationKeyCommand::Private::authenticate()
114 {
115 qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::authenticate()";
116
117 auto cmd = new AuthenticatePIVCardApplicationCommand(serialNumber(), parentWidgetOrView());
118 cmd->setPrompt(i18n("Please enter the old PIV Card Application Administration Key in hex-encoded form."));
119 connect(cmd, &AuthenticatePIVCardApplicationCommand::finished,
120 q, [this]() { authenticationFinished(); });
121 connect(cmd, &AuthenticatePIVCardApplicationCommand::canceled,
122 q, [this]() { authenticationCanceled(); });
123 cmd->start();
124 }
125
authenticationFinished()126 void SetPIVCardApplicationAdministrationKeyCommand::Private::authenticationFinished()
127 {
128 qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::authenticationFinished()";
129 if (!hasBeenCanceled) {
130 setAdminKey();
131 }
132 }
133
authenticationCanceled()134 void SetPIVCardApplicationAdministrationKeyCommand::Private::authenticationCanceled()
135 {
136 qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::authenticationCanceled()";
137 hasBeenCanceled = true;
138 canceled();
139 }
140
setAdminKey()141 void SetPIVCardApplicationAdministrationKeyCommand::Private::setAdminKey()
142 {
143 qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::setAdminKey()";
144
145 ensureDialogCreated();
146 Q_ASSERT(dialog);
147 dialog->show();
148 }
149
ensureDialogCreated()150 void SetPIVCardApplicationAdministrationKeyCommand::Private::ensureDialogCreated()
151 {
152 if (dialog) {
153 return;
154 }
155
156 dialog = new PIVCardApplicationAdministrationKeyInputDialog(parentWidgetOrView());
157 dialog->setAttribute(Qt::WA_DeleteOnClose);
158 dialog->setLabelText(newAdminKey.isEmpty() ?
159 i18n("Please enter the new PIV Card Application Administration Key in hex-encoded form. "
160 "The key needs to consist of 24 bytes, i.e. 48 hex-characters.") :
161 i18n("Please enter the new PIV Card Application Administration Key again."));
162
163 connect(dialog, SIGNAL(accepted()), q, SLOT(slotDialogAccepted()));
164 connect(dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected()));
165 }
166
slotDialogAccepted()167 void SetPIVCardApplicationAdministrationKeyCommand::Private::slotDialogAccepted()
168 {
169 if (newAdminKey.isEmpty()) {
170 newAdminKey = dialog->adminKey();
171 dialog = nullptr;
172 setAdminKey();
173 return;
174 }
175
176 const QByteArray newAdminKey2 = dialog->adminKey();
177 if (newAdminKey != newAdminKey2) {
178 error(i18nc("@info", "The two keys you have entered do not match. Please retry."),
179 i18nc("@title", "Error"));
180 newAdminKey.clear();
181 dialog = nullptr;
182 setAdminKey();
183 return;
184 }
185
186 auto pivCard = ReaderStatus::instance()->getCard<PIVCard>(serialNumber());
187 if (!pivCard) {
188 error(i18n("Failed to find the PIV card with the serial number: %1", QString::fromStdString(serialNumber())));
189 finished();
190 return;
191 }
192
193 const QByteArray plusPercentEncodedAdminKey = newAdminKey.toPercentEncoding().replace(' ', '+');
194 const QByteArray command = QByteArray("SCD SETATTR SET-ADM-KEY ") + plusPercentEncodedAdminKey;
195 ReaderStatus::mutableInstance()->startSimpleTransaction(pivCard, command, q, "slotResult");
196 }
197
slotDialogRejected()198 void SetPIVCardApplicationAdministrationKeyCommand::Private::slotDialogRejected()
199 {
200 finished();
201 }
202
slotResult(const GpgME::Error & err)203 void SetPIVCardApplicationAdministrationKeyCommand::Private::slotResult(const GpgME::Error& err)
204 {
205 qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::slotResult():"
206 << err.asString() << "(" << err.code() << ")";
207 if (err) {
208 error(i18nc("@info", "Setting the PIV Card Application Administration Key failed: %1", QString::fromLatin1(err.asString())),
209 i18nc("@title", "Error"));
210 } else if (!err.isCanceled()) {
211 information(i18nc("@info", "PIV Card Application Administration Key set successfully."), i18nc("@title", "Success"));
212 ReaderStatus::mutableInstance()->updateStatus();
213 }
214 finished();
215 }
216
217 #undef d
218 #undef q
219
220 #include "moc_setpivcardapplicationadministrationkeycommand.cpp"
221