p15cardwidget.cpp 6.24 KB
Newer Older
1
2
3
/*  view/p15cardwiget.cpp

    This file is part of Kleopatra, the KDE keymanager
4
    SPDX-FileCopyrightText: 2021 g10 Code GmbH
5
    SPDX-FileContributor: Andre Heinecke <aheinecke@g10code.com>
6
    SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
7
8
9
10
11
12

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

#include "p15cardwidget.h"

13
14
#include "openpgpkeycardwidget.h"

15
16
#include "smartcard/p15card.h"
#include "smartcard/openpgpcard.h"
17
#include "smartcard/readerstatus.h"
18
19
20

#include <QVBoxLayout>
#include <QGridLayout>
21
#include <QLabel>
22
23
24
25
26
27
28
29
#include <QScrollArea>
#include <QStringList>

#include <KLocalizedString>
#include <KSeparator>

#include <Libkleo/KeyCache>
#include <Libkleo/Formatting>
30
#include <Libkleo/GnuPG>
31

32
33
34
35
36
37
38
39
40
#include <QGpgME/Protocol>
#include <QGpgME/KeyListJob>
#include <QGpgME/ImportFromKeyserverJob>
#include <QGpgME/CryptoConfig>
#include <gpgme++/keylistresult.h>
#include <gpgme++/importresult.h>

#include "kleopatra_debug.h"

41
42
43
44
using namespace Kleo;
using namespace Kleo::SmartCard;

P15CardWidget::P15CardWidget(QWidget *parent)
45
46
47
48
    : QWidget{parent}
    , mSerialNumber{new QLabel{this}}
    , mVersionLabel{new QLabel{this}}
    , mStatusLabel{new QLabel{this}}
49
    , mOpenPGPKeysSection{new QWidget{this}}
50
    , mOpenPGPKeysWidget{new OpenPGPKeyCardWidget{this}}
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
{
    // Set up the scroll area
    auto myLayout = new QVBoxLayout(this);
    myLayout->setContentsMargins(0, 0, 0, 0);

    auto area = new QScrollArea;
    area->setFrameShape(QFrame::NoFrame);
    area->setWidgetResizable(true);
    myLayout->addWidget(area);

    auto areaWidget = new QWidget;
    area->setWidget(areaWidget);

    auto areaVLay = new QVBoxLayout(areaWidget);

    auto cardInfoGrid = new QGridLayout;
    {
        int row = 0;

        // Version and Serialnumber
        cardInfoGrid->addWidget(mVersionLabel, row++, 0, 1, 2);
        mVersionLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);

        cardInfoGrid->addWidget(new QLabel(i18n("Serial number:")), row, 0);
        cardInfoGrid->addWidget(mSerialNumber, row++, 1);
        mSerialNumber->setTextInteractionFlags(Qt::TextBrowserInteraction);

        cardInfoGrid->setColumnStretch(cardInfoGrid->columnCount(), 1);
    }
    areaVLay->addLayout(cardInfoGrid);
81
82
    areaVLay->addWidget(mStatusLabel);
    mStatusLabel->setVisible(false);
83
84
85

    areaVLay->addWidget(new KSeparator(Qt::Horizontal));

86
87
88
89
90
91
92
93
94
95
    {
        auto l = new QVBoxLayout{mOpenPGPKeysSection};
        l->setContentsMargins(0, 0, 0, 0);
        l->addWidget(new QLabel(QStringLiteral("<b>%1</b>").arg(i18n("OpenPGP keys:"))));
        mOpenPGPKeysWidget->setAllowedActions(OpenPGPKeyCardWidget::NoAction);
        l->addWidget(mOpenPGPKeysWidget);
        l->addWidget(new KSeparator(Qt::Horizontal));
    }
    mOpenPGPKeysSection->setVisible(false);
    areaVLay->addWidget(mOpenPGPKeysSection);
96
97
98
99

    areaVLay->addStretch(1);
}

100
P15CardWidget::~P15CardWidget() = default;
101

102
103
104
105
106
107
108
109
110
111
112
113
114
115
void P15CardWidget::searchPGPFpr(const std::string &fpr)
{
    /* Only do auto import from LDAP */
    auto conf = QGpgME::cryptoConfig();
    Q_ASSERT (conf);
    const QString cmp = engineIsVersion(2, 3, 0) ? QStringLiteral("dirmngr") : QStringLiteral("gpg");
    const auto entry = conf->entry(cmp, QStringLiteral("Keyserver"), QStringLiteral("keyserver"));
    if (!entry || !entry->stringValue().startsWith(QStringLiteral("ldap"))) {
        return;
    }
    mStatusLabel->setText(i18n("Searching in directory service..."));
    mStatusLabel->setVisible(true);
    qCDebug(KLEOPATRA_LOG) << "Looking for:" << fpr.c_str() << "on ldap server";
    QGpgME::KeyListJob *job = QGpgME::openpgp()->keyListJob(true);
116
117
118
    connect(KeyCache::instance().get(), &KeyCache::keysMayHaveChanged, this, [this, fpr] () {
            qCDebug(KLEOPATRA_LOG) << "Updating key info after changes";
            ReaderStatus::mutableInstance()->updateStatus();
119
            mOpenPGPKeysWidget->update(nullptr);
120
    });
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
    connect(job, &QGpgME::KeyListJob::result, job, [this](GpgME::KeyListResult, std::vector<GpgME::Key> keys, QString, GpgME::Error) {
        if (keys.size() == 1) {
            auto importJob = QGpgME::openpgp()->importFromKeyserverJob();
            qCDebug(KLEOPATRA_LOG) << "Importing: " << keys[0].primaryFingerprint();
            connect(importJob, &QGpgME::ImportFromKeyserverJob::result, importJob, [this](GpgME::ImportResult, QString, GpgME::Error) {
                qCDebug(KLEOPATRA_LOG) << "import job done";
                mStatusLabel->setText(i18n("Automatic import finished."));
            });
            importJob->start(keys);
        } else if (keys.size() > 1) {
            qCDebug(KLEOPATRA_LOG) << "Multiple keys found on server";
            mStatusLabel->setText(i18n("Error multiple keys found on server."));
        } else {
            qCDebug(KLEOPATRA_LOG) << "No key found";
            mStatusLabel->setText(i18n("Key not found in directory service."));
        }
    });
    job->start(QStringList() << QString::fromStdString(fpr));
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
}

void P15CardWidget::setCard(const P15Card *card)
{
    mCardSerialNumber = card->serialNumber();
    mVersionLabel->setText(i18nc("%1 is a smartcard manufacturer", "%1 PKCS#15 card",
                           QString::fromStdString(card->manufacturer())));
    mSerialNumber->setText(card->displaySerialNumber());
    mSerialNumber->setToolTip(QString::fromStdString(card->serialNumber()));

    const auto sigInfo = card->keyInfo(card->signingKeyRef());
    if (!sigInfo.grip.empty()) {
        const auto key = KeyCache::instance()->findSubkeyByKeyGrip(sigInfo.grip, GpgME::OpenPGP).parent();
        if (key.isNull()) {
            qCDebug(KLEOPATRA_LOG) << "Failed to find key for grip:" << sigInfo.grip.c_str();
154
            const auto pgpSigFpr = card->keyFingerprint(OpenPGPCard::pgpSigKeyRef());
155
156
157
158
159
160
161
162
163
            if (!pgpSigFpr.empty()) {
                qCDebug(KLEOPATRA_LOG) << "Should be pgp key:" << pgpSigFpr.c_str();
                searchPGPFpr(pgpSigFpr);
            }
        } else {
            mStatusLabel->setVisible(false);
        }
    }

164
165
166
167
168
169
    const bool cardHasOpenPGPKeys = !card->keyFingerprint(OpenPGPCard::pgpSigKeyRef()).empty()
                                 || !card->keyFingerprint(OpenPGPCard::pgpEncKeyRef()).empty();
    mOpenPGPKeysSection->setVisible(cardHasOpenPGPKeys);
    if (cardHasOpenPGPKeys) {
        mOpenPGPKeysWidget->update(card);
    }
170
}