pivcardwidget.cpp 10.6 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/pivgeneratecardkeycommand.h"
15
#include "commands/setpivcardapplicationadministrationkeycommand.h"
16

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

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

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

using namespace Kleo;
31
using namespace Kleo::Commands;
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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);
}
} // Namespace

PIVCardWidget::PIVCardWidget(QWidget *parent):
    QWidget(parent),
    mSerialNumber(new QLabel(this)),
    mVersionLabel(new QLabel(this)),
60
    mPIVAuthenticationKey(new QLabel(this)),
61
    mCardAuthenticationKey(new QLabel(this)),
62
63
64
65
66
    mDigitalSignatureKey(new QLabel(this)),
    mKeyManagementKey(new QLabel(this)),
    mGeneratePIVAuthenticationKeyBtn(new QPushButton(this)),
    mGenerateCardAuthenticationKeyBtn(new QPushButton(this)),
    mGenerateDigitalSignatureKeyBtn(new QPushButton(this)),
67
    mWriteDigitalSignatureKeyBtn(new QPushButton(this)),
68
    mGenerateKeyManagementKeyBtn(new QPushButton(this))
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
{
    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);
    grid->addWidget(line1, row++, 0, 1, 4);
    grid->addWidget(new QLabel(QStringLiteral("<b>%1</b>").arg(i18n("Keys:"))), row++, 0);

    grid->addWidget(new QLabel(i18n("PIV authentication:")), row, 0);
100
101
102
    grid->addWidget(mPIVAuthenticationKey, row, 1);
    mPIVAuthenticationKey->setTextInteractionFlags(Qt::TextBrowserInteraction);
    mGeneratePIVAuthenticationKeyBtn->setText(i18n("Generate"));
103
    mGeneratePIVAuthenticationKeyBtn->setEnabled(false);
104
105
106
    grid->addWidget(mGeneratePIVAuthenticationKeyBtn, row, 2);
    connect(mGeneratePIVAuthenticationKeyBtn, &QPushButton::clicked, this, &PIVCardWidget::generatePIVAuthenticationKey);
    row++;
107
108

    grid->addWidget(new QLabel(i18n("Card authentication:")), row, 0);
109
    grid->addWidget(mCardAuthenticationKey, row, 1);
110
    mCardAuthenticationKey->setTextInteractionFlags(Qt::TextBrowserInteraction);
111
    mGenerateCardAuthenticationKeyBtn->setText(i18n("Generate"));
112
    mGenerateCardAuthenticationKeyBtn->setEnabled(false);
113
114
115
    grid->addWidget(mGenerateCardAuthenticationKeyBtn, row, 2);
    connect(mGenerateCardAuthenticationKeyBtn, &QPushButton::clicked, this, &PIVCardWidget::generateCardAuthenticationKey);
    row++;
116
117

    grid->addWidget(new QLabel(i18n("Digital signature:")), row, 0);
118
119
120
    grid->addWidget(mDigitalSignatureKey, row, 1);
    mDigitalSignatureKey->setTextInteractionFlags(Qt::TextBrowserInteraction);
    mGenerateDigitalSignatureKeyBtn->setText(i18n("Generate"));
121
    mGenerateDigitalSignatureKeyBtn->setEnabled(false);
122
123
    grid->addWidget(mGenerateDigitalSignatureKeyBtn, row, 2);
    connect(mGenerateDigitalSignatureKeyBtn, &QPushButton::clicked, this, &PIVCardWidget::generateDigitalSignatureKey);
124
125
126
127
    mWriteDigitalSignatureKeyBtn->setText(i18n("Write Certificate"));
    mWriteDigitalSignatureKeyBtn->setToolTip(i18n("Write the certificate corresponding to this key to the card"));
    mWriteDigitalSignatureKeyBtn->setEnabled(false);
    grid->addWidget(mWriteDigitalSignatureKeyBtn, row, 3);
128
    connect(mWriteDigitalSignatureKeyBtn, &QPushButton::clicked, this, [this] () { writeCertificateToCard(PIVCard::digitalSignatureKeyRef()); });
129
    row++;
130
131

    grid->addWidget(new QLabel(i18n("Key management:")), row, 0);
132
133
134
    grid->addWidget(mKeyManagementKey, row, 1);
    mKeyManagementKey->setTextInteractionFlags(Qt::TextBrowserInteraction);
    mGenerateKeyManagementKeyBtn->setText(i18n("Generate"));
135
    mGenerateKeyManagementKeyBtn->setEnabled(false);
136
137
138
    grid->addWidget(mGenerateKeyManagementKeyBtn, row, 2);
    connect(mGenerateKeyManagementKeyBtn, &QPushButton::clicked, this, &PIVCardWidget::generateKeyManagementKey);
    row++;
139
140
141
142
143

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

144
145
    auto actionLayout = new QHBoxLayout;

146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
    {
        auto button = new QPushButton(i18n("Change PIN"));
        button->setToolTip(i18n("Change the PIV Card Application PIN that activates the PIV Card and enables private key operations using the stored keys."));
        actionLayout->addWidget(button);
        connect(button, &QPushButton::clicked, this, [this] () { changePin(PIVCard::pinKeyRef()); });
    }
    {
        auto button = new QPushButton(i18n("Change PUK"));
        button->setToolTip(i18n("Change the PIN Unblocking Key that enables a reset of the PIN."));
        actionLayout->addWidget(button);
        connect(button, &QPushButton::clicked, this, [this] () { changePin(PIVCard::pukKeyRef()); });
    }
    {
        auto button = new QPushButton(i18n("Change Admin Key"));
        button->setToolTip(i18n("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."));
        actionLayout->addWidget(button);
        connect(button, &QPushButton::clicked, this, [this] () { setAdminKey(); });
    }
166
167
168
169

    actionLayout->addStretch(-1);
    grid->addLayout(actionLayout, row++, 0, 1, 4);

170
171
172
    grid->setColumnStretch(4, -1);
}

173
174
175
176
PIVCardWidget::~PIVCardWidget()
{
}

177
178
void PIVCardWidget::setCard(const PIVCard *card)
{
179
    mCardSerialNumber = card->serialNumber();
180
181
182
183
184
185
186
187
188
    mVersionLabel->setText(i18nc("Placeholder is a version number", "PIV v%1 card", formatVersion(card->appVersion())));

    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()));
    }

189
190
191
192
    updateKey(PIVCard::pivAuthenticationKeyRef(), card, mPIVAuthenticationKey, mGeneratePIVAuthenticationKeyBtn, nullptr);
    updateKey(PIVCard::cardAuthenticationKeyRef(), card, mCardAuthenticationKey, mGenerateCardAuthenticationKeyBtn, nullptr);
    updateKey(PIVCard::digitalSignatureKeyRef(), card, mDigitalSignatureKey, mGenerateDigitalSignatureKeyBtn, mWriteDigitalSignatureKeyBtn);
    updateKey(PIVCard::keyManagementKeyRef(), card, mKeyManagementKey, mGenerateKeyManagementKeyBtn, nullptr);
193
194
}

195
void PIVCardWidget::updateKey(const std::string &keyRef, const PIVCard *card, QLabel *label, QPushButton *generateButton, QPushButton *writeButton)
196
{
197
    const std::string grip = card->keyGrip(keyRef);
198
    label->setText(grip.empty() ? i18n("Slot empty") : QString::fromStdString(grip));
199
200
    generateButton->setText(grip.empty() ? i18n("Generate") : i18n("Replace"));
    generateButton->setToolTip(grip.empty() ?
201
202
        i18nc("Placeholder is the display name of a key", "Generate %1", PIVCard::keyDisplayName(keyRef)) :
        i18nc("Placeholder is the display name of a key", "Replace %1 with new key", PIVCard::keyDisplayName(keyRef)));
203
204
205
206
    generateButton->setEnabled(true);
    if (writeButton) {
        writeButton->setEnabled(!grip.empty());
    }
207
208
}

209
void PIVCardWidget::generateKey(const std::string &keyref)
210
{
211
    auto cmd = new PIVGenerateCardKeyCommand(mCardSerialNumber, this);
212
213
214
215
216
217
218
219
    this->setEnabled(false);
    connect(cmd, &PIVGenerateCardKeyCommand::finished,
            this, [this]() {
                this->setEnabled(true);
            });
    cmd->setKeyRef(keyref);
    cmd->start();
}
220

221
void PIVCardWidget::writeCertificateToCard(const std::string &keyref)
222
{
223
    auto cmd = new CertificateToPIVCardCommand(keyref, mCardSerialNumber);
224
    this->setEnabled(false);
225
    connect(cmd, &CertificateToPIVCardCommand::finished,
226
227
228
229
230
231
232
            this, [this]() {
                this->setEnabled(true);
            });
    cmd->setParentWidget(this);
    cmd->start();
}

233
234
void PIVCardWidget::generatePIVAuthenticationKey()
{
235
    generateKey(PIVCard::pivAuthenticationKeyRef());
236
237
238
239
}

void PIVCardWidget::generateCardAuthenticationKey()
{
240
    generateKey(PIVCard::cardAuthenticationKeyRef());
241
242
243
244
}

void PIVCardWidget::generateDigitalSignatureKey()
{
245
    generateKey(PIVCard::digitalSignatureKeyRef());
246
247
248
249
}

void PIVCardWidget::generateKeyManagementKey()
{
250
    generateKey(PIVCard::keyManagementKeyRef());
251
}
252
253
254
255
256
257
258
259
260
261
262
263

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();
}
264
265
266
267
268
269
270
271
272
273
274

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