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