diff --git a/src/smartcard/p15card.cpp b/src/smartcard/p15card.cpp index 5cd724e0c..027d9f558 100644 --- a/src/smartcard/p15card.cpp +++ b/src/smartcard/p15card.cpp @@ -1,82 +1,82 @@ /* smartcard/p15card.cpp This file is part of Kleopatra, the KDE keymanager - SPDX-FileCopyrightText: 2020 g10 Code GmbH - SPDX-FileContributor: Andre Heinecke + SPDX-FileCopyrightText: 2021 g10 Code GmbH + SPDX-FileContributor: Andre Heinecke SPDX-License-Identifier: GPL-2.0-or-later */ #include "p15card.h" #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::SmartCard; // static const std::string P15Card::AppName = "p15"; P15Card::P15Card(const Card &card) : Card(card) { setAppName(AppName); } std::string P15Card::appKeyFingerprint(const std::string &appKeyRef) const { return mMetaInfo.value("KLEO-FPR-" + appKeyRef); } void P15Card::setCardInfo(const std::vector< std::pair > &infos) { // XXX: This is a copy of OpenPGPCard::setCardInfo qCDebug(KLEOPATRA_LOG) << "Card" << serialNumber().c_str() << "info:"; for (const auto &pair: infos) { qCDebug(KLEOPATRA_LOG) << pair.first.c_str() << ":" << pair.second.c_str(); if (parseCardInfo(pair.first, pair.second)) { continue; } if (pair.first == "KEY-FPR") { const auto values = QString::fromStdString(pair.second).split(QLatin1Char(' ')); if (values.size() < 2) { qCWarning(KLEOPATRA_LOG) << "Invalid entry."; setStatus(Card::CardError); continue; } const auto keyNumber = values[0]; const std::string keyRef = "OPENPGP." + keyNumber.toStdString(); const auto fpr = values[1].toStdString(); if (keyNumber == QLatin1Char('1') || keyNumber == QLatin1Char('2') || keyNumber == QLatin1Char('3')) { mMetaInfo.insert("KLEO-FPR-" + keyRef, fpr); } else { // Maybe more keyslots in the future? qCDebug(KLEOPATRA_LOG) << "Unhandled keyslot"; } } else { mMetaInfo.insert(pair.first, pair.second); } } } void P15Card::setManufacturer(const std::string &manufacturer) { mManufacturer = manufacturer; } std::string P15Card::manufacturer() const { return mManufacturer; } bool P15Card::operator == (const Card& rhs) const { const P15Card *other = dynamic_cast(&rhs); if (!other) { return false; } return Card::operator ==(rhs) && mMetaInfo == other->mMetaInfo && mManufacturer == other->mManufacturer; } diff --git a/src/smartcard/p15card.h b/src/smartcard/p15card.h index 742b59a85..3d0b21cd7 100644 --- a/src/smartcard/p15card.h +++ b/src/smartcard/p15card.h @@ -1,57 +1,57 @@ -/* smartcard/pivcard.h +/* smartcard/p15card.h This file is part of Kleopatra, the KDE keymanager - SPDX-FileCopyrightText: 2020 g10 Code GmbH - SPDX-FileContributor: Ingo Klöcker + SPDX-FileCopyrightText: 2021 g10 Code GmbH + SPDX-FileContributor: Andre Heinecke SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include "card.h" #include namespace Kleo { namespace SmartCard { /** Class to work with PKCS#15 smartcards or compatible tokens. * * A PKCS#15 card is pretty generic and there is no real standard * for them. It all depends on the Apps running on the cards. This * mostly tries to leave it to GnuPG to determine if there are usable * things on the card. The generic info on all keys on the card is * accessible through keyInfo from the parent class. * * The specialization is required for specific app support. **/ class P15Card: public Card { public: explicit P15Card(const Card &card); static const std::string AppName; void setAppKeyRef(const std::string &appKeyRef, const std::string &value); std::string appKeyRef(const std::string &appKeyRef) const; /* Obtain an application specific fingerprint for a key * stored on this card. * e.g. An App Key Ref would be * OpenPGPCard::pgpSigKeyRef */ std::string appKeyFingerprint(const std::string &appKeyRef) const; void setCardInfo(const std::vector< std::pair > &infos); void setManufacturer(const std::string &manufacturer); std::string manufacturer() const; bool operator == (const Card& other) const override; private: QMap mMetaInfo; std::string mManufacturer; }; } // namespace Smartcard } // namespace Kleopatra diff --git a/src/view/p15cardwidget.cpp b/src/view/p15cardwidget.cpp index 61452ef56..0c38d4944 100644 --- a/src/view/p15cardwidget.cpp +++ b/src/view/p15cardwidget.cpp @@ -1,230 +1,230 @@ /* view/p15cardwiget.cpp This file is part of Kleopatra, the KDE keymanager - SPDX-FileCopyrightText: 2020 g10 Code GmbH + SPDX-FileCopyrightText: 2021 g10 Code GmbH SPDX-FileContributor: Andre Heinecke SPDX-License-Identifier: GPL-2.0-or-later */ #include "p15cardwidget.h" #include "smartcard/p15card.h" #include "smartcard/openpgpcard.h" #include "smartcard/readerstatus.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::SmartCard; P15CardWidget::P15CardWidget(QWidget *parent) : QWidget(parent) , mSerialNumber(new QLabel(this)) , mVersionLabel(new QLabel(this)) , mSigFprLabel(new QLabel(this)) , mEncFprLabel(new QLabel(this)) , mStatusLabel(new QLabel(this)) { // 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); areaVLay->addWidget(mStatusLabel); mStatusLabel->setVisible(false); areaVLay->addWidget(new KSeparator(Qt::Horizontal)); areaVLay->addWidget(new QLabel(QStringLiteral("%1").arg(i18n("OpenPGP keys:")))); areaVLay->addWidget(mSigFprLabel); areaVLay->addWidget(mEncFprLabel); areaVLay->addWidget(new KSeparator(Qt::Horizontal)); areaVLay->addStretch(1); } P15CardWidget::~P15CardWidget() { } 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; } static std::vector fprs; if (fpr.empty() || std::find(fprs.begin(), fprs.end(), fpr) != fprs.end()) { qCDebug(KLEOPATRA_LOG) << "Already looked for " << fpr.c_str() << "on ldap server"; return; } mStatusLabel->setText(i18n("Searching in directory service...")); mStatusLabel->setVisible(true); fprs.push_back (fpr); qCDebug(KLEOPATRA_LOG) << "Looking for:" << fpr.c_str() << "on ldap server"; QGpgME::KeyListJob *job = QGpgME::openpgp()->keyListJob(true); connect(KeyCache::instance().get(), &KeyCache::keysMayHaveChanged, this, [this, fpr] () { qCDebug(KLEOPATRA_LOG) << "Updating key info after changes"; ReaderStatus::mutableInstance()->updateStatus(); updateSigKeyWidgets(fpr); }); connect(job, &QGpgME::KeyListJob::result, job, [this](GpgME::KeyListResult, std::vector 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)); } void P15CardWidget::updateSigKeyWidgets(const std::string &fpr) { std::string keyid = fpr; if (!keyid.empty()) { QString text = i18n("Signing key:") + QStringLiteral("\t%1 (%2)") .arg(Formatting::prettyID(keyid.c_str())); text += QStringLiteral("

"); keyid.erase(0, keyid.size() - 16); const auto subkeys = KeyCache::instance()->findSubkeysByKeyID({keyid}); if (subkeys.empty() || subkeys[0].isNull()) { text += i18n("Public key not found."); } else { QStringList toolTips; toolTips.reserve(subkeys.size()); for (const auto &sub: subkeys) { // Yep you can have one subkey associated with multiple // primary keys. toolTips << Formatting::toolTip(sub.parent(), Formatting::Validity | Formatting::ExpiryDates | Formatting::UserIDs | Formatting::Fingerprint); } text += toolTips.join(QLatin1String("
")); } mSigFprLabel->setText(text); } else { mSigFprLabel->setVisible(false); } } 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(); const auto pgpSigFpr = card->appKeyFingerprint(OpenPGPCard::pgpSigKeyRef()); if (!pgpSigFpr.empty()) { qCDebug(KLEOPATRA_LOG) << "Should be pgp key:" << pgpSigFpr.c_str(); searchPGPFpr(pgpSigFpr); } } else { mStatusLabel->setVisible(false); } } std::string keyid = card->appKeyFingerprint(OpenPGPCard::pgpSigKeyRef()); updateSigKeyWidgets(keyid); keyid = card->appKeyFingerprint(OpenPGPCard::pgpEncKeyRef()); if (!keyid.empty()) { mEncFprLabel->setText(i18n("Encryption key:") + QStringLiteral(" %1 (%2)") .arg(Formatting::prettyID(keyid.c_str())) .arg(QString::fromStdString(card->encryptionKeyRef()))); keyid.erase(0, keyid.size() - 16); const auto subkeys = KeyCache::instance()->findSubkeysByKeyID({keyid}); if (subkeys.empty() || subkeys[0].isNull()) { mEncFprLabel->setToolTip(i18n("Public key not found.")); } else { QStringList toolTips; toolTips.reserve(subkeys.size()); for (const auto &sub: subkeys) { // Yep you can have one subkey associated with multiple // primary keys. toolTips << Formatting::toolTip(sub.parent(), Formatting::Validity | Formatting::StorageLocation | Formatting::ExpiryDates | Formatting::UserIDs | Formatting::Fingerprint); } mEncFprLabel->setToolTip(toolTips.join(QLatin1String("
"))); } } else { mEncFprLabel->setVisible(false); } // updateKeyWidgets(OpenPGPCard::pgpSigKeyRef(), card); // updateKeyWidgets(OpenPGPCard::pgpEncKeyRef(), card); } diff --git a/src/view/p15cardwidget.h b/src/view/p15cardwidget.h index cf5c7c099..9f596359c 100644 --- a/src/view/p15cardwidget.h +++ b/src/view/p15cardwidget.h @@ -1,43 +1,44 @@ /* view/p15cardwiget.h This file is part of Kleopatra, the KDE keymanager - SPDX-FileCopyrightText: 2020 g10 Code GmbH + SPDX-FileCopyrightText: 2021 g10 Code GmbH SPDX-FileContributor: Andre Heinecke + SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include class QLabel; namespace Kleo { namespace SmartCard { struct KeyPairInfo; class P15Card; } // namespace SmartCard class P15CardWidget: public QWidget { Q_OBJECT public: explicit P15CardWidget(QWidget *parent = nullptr); ~P15CardWidget(); void setCard(const SmartCard::P15Card* card); private: void searchPGPFpr(const std::string &fpr); void updateSigKeyWidgets(const std::string &keyid); std::string mCardSerialNumber; QLabel *mSerialNumber = nullptr; QLabel *mVersionLabel = nullptr; QLabel *mSigFprLabel = nullptr; QLabel *mEncFprLabel = nullptr; QLabel *mStatusLabel = nullptr; }; }