pivcardwidget.cpp 11.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
/*  view/pivcardwiget.cpp

    This file is part of Kleopatra, the KDE keymanager
    SPDX-FileCopyrightText: 2020 g10 Code GmbH
    SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>

    SPDX-License-Identifier: GPL-2.0-or-later
*/

#include "pivcardwidget.h"

12
#include "commands/certificatetopivcardcommand.h"
13
#include "commands/changepincommand.h"
14
#include "commands/keytocardcommand.h"
15
#include "commands/pivgeneratecardkeycommand.h"
16
#include "commands/setpivcardapplicationadministrationkeycommand.h"
17

18
#include "smartcard/pivcard.h"
19
#include "smartcard/readerstatus.h"
20
21
22
23

#include <QFrame>
#include <QGridLayout>
#include <QLabel>
24
#include <QPushButton>
25
26
27
28
#include <QScrollArea>
#include <QVBoxLayout>

#include <KLocalizedString>
29
#include <KMessageBox>
30
31

using namespace Kleo;
32
using namespace Kleo::Commands;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
using namespace Kleo::SmartCard;

namespace {
static QString formatVersion(int value)
{
    if (value < 0) {
        return QLatin1String("n/a");
    }

    const unsigned int a = ((value >> 24) & 0xff);
    const unsigned int b = ((value >> 16) & 0xff);
    const unsigned int c = ((value >>  8) & 0xff);
    const unsigned int d = ((value      ) & 0xff);
    if (a) {
        return QStringLiteral("%1.%2.%3.%4").arg(QString::number(a), QString::number(b), QString::number(c), QString::number(d));
    } else if (b) {
        return QStringLiteral("%1.%2.%3").arg(QString::number(b), QString::number(c), QString::number(d));
    } else if (c) {
        return QStringLiteral("%1.%2").arg(QString::number(c), QString::number(d));
    }
    return QString::number(d);
}
55
}
56
57
58
59

PIVCardWidget::PIVCardWidget(QWidget *parent):
    QWidget(parent),
    mSerialNumber(new QLabel(this)),
60
    mVersionLabel(new QLabel(this))
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
{
    auto grid = new QGridLayout;
    int row = 0;

    // Set up the scroll are
    auto area = new QScrollArea;
    area->setFrameShape(QFrame::NoFrame);
    area->setWidgetResizable(true);
    auto areaWidget = new QWidget;
    auto areaVLay = new QVBoxLayout(areaWidget);
    areaVLay->addLayout(grid);
    areaVLay->addStretch(1);
    area->setWidget(areaWidget);
    auto myLayout = new QVBoxLayout(this);
    myLayout->addWidget(area);

    // Version and Serialnumber
    grid->addWidget(mVersionLabel, row++, 0, 1, 2);
    mVersionLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
    grid->addWidget(new QLabel(i18n("Serial number:")), row, 0);

    grid->addWidget(mSerialNumber, row++, 1);
    mSerialNumber->setTextInteractionFlags(Qt::TextBrowserInteraction);

    // The keys
    auto line1 = new QFrame();
    line1->setFrameShape(QFrame::HLine);
88
    grid->addWidget(line1, row++, 0, 1, 6);
89
90
    grid->addWidget(new QLabel(QStringLiteral("<b>%1</b>").arg(i18n("Keys:"))), row++, 0);

91
    mPIVAuthenticationKey = createKeyWidgets(PIVCard::pivAuthenticationKeyRef());
92
    grid->addWidget(new QLabel(i18n("PIV authentication:")), row, 0);
93
    grid->addWidget(mPIVAuthenticationKey.keyGrip, row, 1);
94
95
96
    grid->addWidget(mPIVAuthenticationKey.keyAlgorithm, row, 2);
    grid->addWidget(mPIVAuthenticationKey.generateButton, row, 3);
    grid->addWidget(mPIVAuthenticationKey.writeCertificateButton, row, 4);
97
    row++;
98

99
    mCardAuthenticationKey = createKeyWidgets(PIVCard::cardAuthenticationKeyRef());
100
    grid->addWidget(new QLabel(i18n("Card authentication:")), row, 0);
101
    grid->addWidget(mCardAuthenticationKey.keyGrip, row, 1);
102
103
104
    grid->addWidget(mCardAuthenticationKey.keyAlgorithm, row, 2);
    grid->addWidget(mCardAuthenticationKey.generateButton, row, 3);
    grid->addWidget(mCardAuthenticationKey.writeCertificateButton, row, 4);
105
    row++;
106

107
    mDigitalSignatureKey = createKeyWidgets(PIVCard::digitalSignatureKeyRef());
108
    grid->addWidget(new QLabel(i18n("Digital signature:")), row, 0);
109
    grid->addWidget(mDigitalSignatureKey.keyGrip, row, 1);
110
111
112
    grid->addWidget(mDigitalSignatureKey.keyAlgorithm, row, 2);
    grid->addWidget(mDigitalSignatureKey.generateButton, row, 3);
    grid->addWidget(mDigitalSignatureKey.writeCertificateButton, row, 4);
113
    row++;
114

115
    mKeyManagementKey = createKeyWidgets(PIVCard::keyManagementKeyRef());
116
    grid->addWidget(new QLabel(i18n("Key management:")), row, 0);
117
    grid->addWidget(mKeyManagementKey.keyGrip, row, 1);
118
119
120
121
    grid->addWidget(mKeyManagementKey.keyAlgorithm, row, 2);
    grid->addWidget(mKeyManagementKey.generateButton, row, 3);
    grid->addWidget(mKeyManagementKey.writeCertificateButton, row, 4);
    grid->addWidget(mKeyManagementKey.writeKeyButton, row, 5);
122
    row++;
123
124
125

    auto line2 = new QFrame();
    line2->setFrameShape(QFrame::HLine);
126
    grid->addWidget(line2, row++, 0, 1, 6);
127

128
129
    auto actionLayout = new QHBoxLayout;

130
    {
131
132
133
        auto button = new QPushButton(i18nc("@action:button", "Change PIN"));
        button->setToolTip(i18nc("@info:tooltip", "Change the PIV Card Application PIN that activates the PIV Card "
                                 "and enables private key operations using the stored keys."));
134
135
136
137
        actionLayout->addWidget(button);
        connect(button, &QPushButton::clicked, this, [this] () { changePin(PIVCard::pinKeyRef()); });
    }
    {
138
139
        auto button = new QPushButton(i18nc("@action:button", "Change PUK"));
        button->setToolTip(i18nc("@info:tooltip", "Change the PIN Unblocking Key that enables a reset of the PIN."));
140
141
142
143
        actionLayout->addWidget(button);
        connect(button, &QPushButton::clicked, this, [this] () { changePin(PIVCard::pukKeyRef()); });
    }
    {
144
145
146
147
        auto button = new QPushButton(i18nc("@action:button", "Change Admin Key"));
        button->setToolTip(i18nc("@info:tooltip", "Change the PIV Card Application Administration Key that is used by the "
                                 "PIV Card Application to authenticate the PIV Card Application Administrator and by the "
                                 "administrator (resp. Kleopatra) to authenticate the PIV Card Application."));
148
149
150
        actionLayout->addWidget(button);
        connect(button, &QPushButton::clicked, this, [this] () { setAdminKey(); });
    }
151
152

    actionLayout->addStretch(-1);
153
    grid->addLayout(actionLayout, row++, 0, 1, 6);
154

155
156
157
    grid->setColumnStretch(4, -1);
}

158
159
160
161
162
PIVCardWidget::KeyWidgets PIVCardWidget::createKeyWidgets(const std::string &keyRef)
{
    KeyWidgets keyWidgets;
    keyWidgets.keyGrip = new QLabel(this);
    keyWidgets.keyGrip->setTextInteractionFlags(Qt::TextBrowserInteraction);
163
    keyWidgets.keyAlgorithm = new QLabel(this);
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
    keyWidgets.generateButton = new QPushButton(i18nc("@action:button", "Generate"), this);
    keyWidgets.generateButton->setEnabled(false);
    connect(keyWidgets.generateButton, &QPushButton::clicked, this, [this, keyRef] () { generateKey(keyRef); });
    keyWidgets.writeCertificateButton = new QPushButton(i18nc("@action:button", "Write Certificate"));
    keyWidgets.writeCertificateButton->setToolTip(i18nc("@info:tooltip", "Write the certificate corresponding to this key to the card"));
    keyWidgets.writeCertificateButton->setEnabled(false);
    connect(keyWidgets.writeCertificateButton, &QPushButton::clicked, this, [this, keyRef] () { writeCertificateToCard(keyRef); });
    if (keyRef == PIVCard::keyManagementKeyRef()) {
        keyWidgets.writeKeyButton = new QPushButton(i18nc("@action:button", "Write Key"));
        keyWidgets.writeKeyButton->setToolTip(i18nc("@info:tooltip", "Write the key pair of a certificate to the card"));
        keyWidgets.writeKeyButton->setEnabled(true);
        connect(keyWidgets.writeKeyButton, &QPushButton::clicked, this, [this, keyRef] () { writeKeyToCard(keyRef); });
    }
    return keyWidgets;
}

180
181
182
183
PIVCardWidget::~PIVCardWidget()
{
}

184
185
void PIVCardWidget::setCard(const PIVCard *card)
{
186
    mCardSerialNumber = card->serialNumber();
187
    mVersionLabel->setText(i18nc("%1 version number", "PIV v%1 card", formatVersion(card->appVersion())));
188
189
190
191
192
193
194
195

    if (card->displaySerialNumber() != card->serialNumber()) {
        mSerialNumber->setText(QStringLiteral("%1 (%2)").arg(QString::fromStdString(card->displaySerialNumber()),
                                                             QString::fromStdString(card->serialNumber())));
    } else {
        mSerialNumber->setText(QString::fromStdString(card->serialNumber()));
    }

196
197
198
199
    updateKey(PIVCard::pivAuthenticationKeyRef(), card, mPIVAuthenticationKey);
    updateKey(PIVCard::cardAuthenticationKeyRef(), card, mCardAuthenticationKey);
    updateKey(PIVCard::digitalSignatureKeyRef(), card, mDigitalSignatureKey);
    updateKey(PIVCard::keyManagementKeyRef(), card, mKeyManagementKey);
200
201
}

202
void PIVCardWidget::updateKey(const std::string &keyRef, const PIVCard *card, const KeyWidgets &widgets)
203
{
204
    const std::string grip = card->keyGrip(keyRef);
205
206
207
208
209
210
211
212
213
214
215
216
217
218
    if (grip.empty()) {
        widgets.keyGrip->setText(i18nc("@info", "Slot empty"));
        widgets.keyAlgorithm->setText(QString());
        widgets.generateButton->setText(i18nc("@action:button", "Generate"));
        widgets.generateButton->setToolTip(
            i18nc("@info:tooltip %1 display name of a key", "Generate %1", PIVCard::keyDisplayName(keyRef)));
    } else {
        widgets.keyGrip->setText(QString::fromStdString(grip));
        const std::string algo = card->keyAlgorithm(keyRef);
        widgets.keyAlgorithm->setText(algo.empty() ? i18nc("@info unknown key algorithm", "unknown") : QString::fromStdString(algo));
        widgets.generateButton->setText(i18nc("@action:button", "Replace"));
        widgets.generateButton->setToolTip(
            i18nc("@info:tooltip %1 display name of a key", "Replace %1 with new key", PIVCard::keyDisplayName(keyRef)));
    }
219
220
221
    widgets.generateButton->setEnabled(true);
    if (widgets.writeCertificateButton) {
        widgets.writeCertificateButton->setEnabled(!grip.empty());
222
    }
223
224
}

225
void PIVCardWidget::generateKey(const std::string &keyref)
226
{
227
    auto cmd = new PIVGenerateCardKeyCommand(mCardSerialNumber, this);
228
229
230
231
232
233
234
235
    this->setEnabled(false);
    connect(cmd, &PIVGenerateCardKeyCommand::finished,
            this, [this]() {
                this->setEnabled(true);
            });
    cmd->setKeyRef(keyref);
    cmd->start();
}
236

237
void PIVCardWidget::writeCertificateToCard(const std::string &keyref)
238
{
239
    auto cmd = new CertificateToPIVCardCommand(keyref, mCardSerialNumber);
240
    this->setEnabled(false);
241
    connect(cmd, &CertificateToPIVCardCommand::finished,
242
243
244
245
246
247
248
            this, [this]() {
                this->setEnabled(true);
            });
    cmd->setParentWidget(this);
    cmd->start();
}

249
250
251
252
253
254
255
256
257
258
259
260
void PIVCardWidget::writeKeyToCard(const std::string &keyref)
{
    auto cmd = new KeyToCardCommand(keyref, mCardSerialNumber);
    this->setEnabled(false);
    connect(cmd, &KeyToCardCommand::finished,
            this, [this]() {
                this->setEnabled(true);
            });
    cmd->setParentWidget(this);
    cmd->start();
}

261
262
263
264
265
266
267
268
269
270
271
void PIVCardWidget::changePin(const std::string &keyRef)
{
    auto cmd = new ChangePinCommand(mCardSerialNumber, this);
    this->setEnabled(false);
    connect(cmd, &ChangePinCommand::finished,
            this, [this]() {
                this->setEnabled(true);
            });
    cmd->setKeyRef(keyRef);
    cmd->start();
}
272
273
274
275
276
277
278
279
280
281
282

void PIVCardWidget::setAdminKey()
{
    auto cmd = new SetPIVCardApplicationAdministrationKeyCommand(mCardSerialNumber, this);
    this->setEnabled(false);
    connect(cmd, &SetPIVCardApplicationAdministrationKeyCommand::finished,
            this, [this]() {
                this->setEnabled(true);
            });
    cmd->start();
}