diff --git a/src/smartcard/netkeycard.cpp b/src/smartcard/netkeycard.cpp index d9e807629..1cff2d51d 100644 --- a/src/smartcard/netkeycard.cpp +++ b/src/smartcard/netkeycard.cpp @@ -1,116 +1,128 @@ /* smartcard/netkeycard.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2017 Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #include "netkeycard.h" #include "keypairinfo.h" #include "kleopatra_debug.h" #include #include #include #include #include using namespace Kleo; using namespace Kleo::SmartCard; // static const std::string NetKeyCard::AppName = "nks"; namespace { static GpgME::Key lookup_key(GpgME::Context *ctx, const std::string &keyGrip) { if (!ctx || keyGrip.empty()) { return GpgME::Key(); } const std::string pattern = '&' + keyGrip; qCDebug(KLEOPATRA_LOG) << "parse_keypairinfo_and_lookup_key: pattern=" << pattern.c_str(); if (const auto err = ctx->startKeyListing(pattern.c_str())) { qCDebug(KLEOPATRA_LOG) << "parse_keypairinfo_and_lookup_key: startKeyListing failed:" << err.asString(); return GpgME::Key(); } GpgME::Error e; const auto key = ctx->nextKey(e); ctx->endKeyListing(); qCDebug(KLEOPATRA_LOG) << "parse_keypairinfo_and_lookup_key: e=" << e.code() << "; key.isNull()" << key.isNull(); return key; } } // namespace NetKeyCard::NetKeyCard(const Card &card) : Card(card) { setAppName(AppName); } +// static +std::string NetKeyCard::nksPinKeyRef() +{ + return std::string("PW1.CH"); +} + +// static +std::string NetKeyCard::sigGPinKeyRef() +{ + return std::string("PW1.CH.SIG"); +} + void NetKeyCard::setCardInfo(const std::vector< std::pair > &infos) { qCDebug(KLEOPATRA_LOG) << "Card" << serialNumber().c_str() << "info:"; for (const auto &pair: infos) { qCDebug(KLEOPATRA_LOG) << pair.first.c_str() << ":" << pair.second.c_str(); parseCardInfo(pair.first, pair.second); } setKeyPairInfo(keyInfos()); } void NetKeyCard::setKeyPairInfo(const std::vector &infos) { // check that any of the keys are new const std::unique_ptr klc(GpgME::Context::createForProtocol(GpgME::CMS)); if (!klc.get()) { return; } klc->setKeyListMode(GpgME::Ephemeral); klc->addKeyListMode(GpgME::Validate); setCanLearnKeys(false); mKeys.clear(); for (const auto &info: infos) { const auto key = lookup_key(klc.get(), info.grip); if (key.isNull()) { setCanLearnKeys(true); } mKeys.push_back(key); } } // State 0 -> NKS PIN Retry counter // State 1 -> NKS PUK Retry counter // State 2 -> SigG PIN Retry counter // State 3 -> SigG PUK Retry counter bool NetKeyCard::hasNKSNullPin() const { const auto states = pinStates(); if (states.size() < 2) { qCWarning(KLEOPATRA_LOG) << "Invalid size of pin states:" << states.size(); return false; } return states[0] == Card::NullPin; } bool NetKeyCard::hasSigGNullPin() const { const auto states = pinStates(); if (states.size() < 4) { qCWarning(KLEOPATRA_LOG) << "Invalid size of pin states:" << states.size(); return false; } return states[2] == Card::NullPin; } std::vector NetKeyCard::keys() const { return mKeys; } diff --git a/src/smartcard/netkeycard.h b/src/smartcard/netkeycard.h index 7a8f0a73b..5ebc62458 100644 --- a/src/smartcard/netkeycard.h +++ b/src/smartcard/netkeycard.h @@ -1,46 +1,49 @@ #ifndef SMARTCARD_NETKEYCARD_H #define SMARTCARD_NETKEYCARD_H /* smartcard/netkeycard.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2017 Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #include "card.h" #include namespace Kleo { namespace SmartCard { struct KeyPairInfo; /** Class to work with NetKey smartcards or compatible tokens */ class NetKeyCard: public Card { public: explicit NetKeyCard(const Card &card); static const std::string AppName; + static std::string nksPinKeyRef(); + static std::string sigGPinKeyRef(); + void setCardInfo(const std::vector< std::pair > &infos); bool hasSigGNullPin() const; bool hasNKSNullPin() const; std::vector keys() const; private: void setKeyPairInfo(const std::vector &infos); private: std::vector mKeys; }; } // namespace Smartcard } // namespace Kleopatra #endif // SMARTCARD_CARD_H diff --git a/src/view/netkeywidget.cpp b/src/view/netkeywidget.cpp index 0fc4c5e7d..3f54e698d 100644 --- a/src/view/netkeywidget.cpp +++ b/src/view/netkeywidget.cpp @@ -1,263 +1,229 @@ /* view/netkeywidget.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2017 Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #include "netkeywidget.h" #include "nullpinwidget.h" #include "keytreeview.h" #include "kleopatraapplication.h" #include "systrayicon.h" #include "kleopatra_debug.h" #include "smartcard/netkeycard.h" #include "smartcard/readerstatus.h" +#include "commands/changepincommand.h" #include "commands/createopenpgpkeyfromcardkeyscommand.h" #include "commands/learncardkeyscommand.h" #include "commands/detailscommand.h" #include #include #include #include #include #include #include #include #include using namespace Kleo; using namespace Kleo::SmartCard; using namespace Kleo::Commands; NetKeyWidget::NetKeyWidget(QWidget *parent) : QWidget(parent), mSerialNumberLabel(new QLabel(this)), mVersionLabel(new QLabel(this)), mLearnKeysLabel(new QLabel(this)), mErrorLabel(new QLabel(this)), mNullPinWidget(new NullPinWidget()), mLearnKeysBtn(new QPushButton(this)), mChangeNKSPINBtn(new QPushButton(this)), mChangeSigGPINBtn(new QPushButton(this)), mTreeView(new KeyTreeView(this)), mArea(new QScrollArea) { auto vLay = new QVBoxLayout; // Set up the scroll are mArea->setFrameShape(QFrame::NoFrame); mArea->setWidgetResizable(true); auto mAreaWidget = new QWidget; mAreaWidget->setLayout(vLay); mArea->setWidget(mAreaWidget); auto scrollLay = new QVBoxLayout(this); scrollLay->setContentsMargins(0, 0, 0, 0); scrollLay->addWidget(mArea); // Add general widgets mVersionLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); vLay->addWidget(mVersionLabel, 0, Qt::AlignLeft); mSerialNumberLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); auto hLay1 = new QHBoxLayout; hLay1->addWidget(new QLabel(i18n("Serial number:"))); hLay1->addWidget(mSerialNumberLabel); hLay1->addStretch(1); vLay->addLayout(hLay1); vLay->addWidget(mNullPinWidget); auto line1 = new QFrame(); line1->setFrameShape(QFrame::HLine); vLay->addWidget(line1); vLay->addWidget(new QLabel(QStringLiteral("%1").arg(i18n("Certificates:"))), 0, Qt::AlignLeft); mLearnKeysLabel = new QLabel(i18n("There are unknown certificates on this card.")); mLearnKeysBtn->setText(i18nc("@action", "Load Certificates")); connect(mLearnKeysBtn, &QPushButton::clicked, this, [this] () { mLearnKeysBtn->setEnabled(false); auto cmd = new LearnCardKeysCommand(GpgME::CMS); cmd->setParentWidget(this); cmd->start(); auto icon = KleopatraApplication::instance()->sysTrayIcon(); if (icon) { icon->setLearningInProgress(true); } connect(cmd, &Command::finished, this, [icon] () { ReaderStatus::mutableInstance()->updateStatus(); icon->setLearningInProgress(false); }); }); auto hLay2 = new QHBoxLayout; hLay2->addWidget(mLearnKeysLabel); hLay2->addWidget(mLearnKeysBtn); hLay2->addStretch(1); vLay->addLayout(hLay2); mErrorLabel->setVisible(false); vLay->addWidget(mErrorLabel); // The certificate view mTreeView->setHierarchicalModel(AbstractKeyListModel::createHierarchicalKeyListModel(mTreeView)); mTreeView->setHierarchicalView(true); connect(mTreeView->view(), &QAbstractItemView::doubleClicked, this, [this] (const QModelIndex &idx) { const auto klm = dynamic_cast (mTreeView->view()->model()); if (!klm) { qCDebug(KLEOPATRA_LOG) << "Unhandled Model: " << mTreeView->view()->model()->metaObject()->className(); return; } auto cmd = new DetailsCommand(klm->key(idx), nullptr); cmd->setParentWidget(this); cmd->start(); }); vLay->addWidget(mTreeView); // The action area auto line2 = new QFrame(); line2->setFrameShape(QFrame::HLine); vLay->addWidget(line2); vLay->addWidget(new QLabel(QStringLiteral("%1").arg(i18n("Actions:"))), 0, Qt::AlignLeft); auto actionLayout = new QHBoxLayout(); if (CreateOpenPGPKeyFromCardKeysCommand::isSupported()) { mKeyForCardKeysButton = new QPushButton(this); mKeyForCardKeysButton->setText(i18nc("@action:button", "Create OpenPGP Key")); mKeyForCardKeysButton->setToolTip(i18nc("@info:tooltip", "Create an OpenPGP key for the keys stored on the card.")); actionLayout->addWidget(mKeyForCardKeysButton); connect(mKeyForCardKeysButton, &QPushButton::clicked, this, &NetKeyWidget::createKeyFromCardKeys); } mChangeNKSPINBtn->setText(i18nc("NKS is an identifier for a type of keys on a NetKey card", "Change NKS PIN")); mChangeSigGPINBtn->setText(i18nc("SigG is an identifier for a type of keys on a NetKey card", "Change SigG PIN")); - connect(mChangeNKSPINBtn, &QPushButton::clicked, this, [this] () { - mChangeNKSPINBtn->setEnabled(false); - doChangePin(false); - }); - connect(mChangeSigGPINBtn, &QPushButton::clicked, this, [this] () { - mChangeSigGPINBtn->setEnabled(false); - doChangePin(true); - }); + connect(mChangeNKSPINBtn, &QPushButton::clicked, this, [this] () { doChangePin(NetKeyCard::nksPinKeyRef()); }); + connect(mChangeSigGPINBtn, &QPushButton::clicked, this, [this] () { doChangePin(NetKeyCard::sigGPinKeyRef()); }); actionLayout->addWidget(mChangeNKSPINBtn); actionLayout->addWidget(mChangeSigGPINBtn); actionLayout->addStretch(1); vLay->addLayout(actionLayout); vLay->addStretch(1); } NetKeyWidget::~NetKeyWidget() { } void NetKeyWidget::setCard(const NetKeyCard* card) { mSerialNumber = card->serialNumber(); mVersionLabel->setText(i18nc("1 is a Version number", "NetKey v%1 Card", card->appVersion())); mSerialNumberLabel->setText(QString::fromStdString(mSerialNumber)); mNullPinWidget->setSerialNumber(mSerialNumber); /* According to users of NetKey Cards it is fairly uncommon * to use SigG Certificates at all. So it should be optional to set the pins. */ mNullPinWidget->setVisible(card->hasNKSNullPin() /*|| card->hasSigGNullPin()*/); mNullPinWidget->setSigGVisible(false/*card->hasSigGNullPin()*/); mNullPinWidget->setNKSVisible(card->hasNKSNullPin()); mChangeNKSPINBtn->setEnabled(!card->hasNKSNullPin()); if (card->hasSigGNullPin()) { mChangeSigGPINBtn->setText(i18nc("SigG is an identifier for a type of keys on a NetKey card", "Set SigG PIN")); } else { mChangeSigGPINBtn->setText(i18nc("SigG is an identifier for a type of keys on a NetKey card", "Change SigG PIN")); } mLearnKeysBtn->setEnabled(true); mLearnKeysBtn->setVisible(card->canLearnKeys()); mTreeView->setVisible(!card->canLearnKeys()); mLearnKeysLabel->setVisible(card->canLearnKeys()); const auto errMsg = card->errorMsg(); if (!errMsg.isEmpty()) { mErrorLabel->setText(QStringLiteral("%1: %2").arg(i18n("Error"), errMsg)); mErrorLabel->setVisible(true); } else { mErrorLabel->setVisible(false); } const auto keys = card->keys(); mTreeView->setKeys(keys); if (mKeyForCardKeysButton) { mKeyForCardKeysButton->setEnabled(!card->hasNKSNullPin() && card->hasSigningKey() && card->hasEncryptionKey()); } } -void NetKeyWidget::handleResult(const GpgME::Error &err, QPushButton *btn) -{ - btn->setEnabled(true); - if (err.isCanceled()) { - return; - } - if (err) { - KMessageBox::error(this, i18nc("@info", - "Failed to set PIN: %1", QString::fromLatin1(err.asString())), - i18nc("@title", "Error")); - return; - } -} - -void NetKeyWidget::setSigGPinSettingResult(const GpgME::Error &err) -{ - handleResult(err, mChangeSigGPINBtn); -} - -void NetKeyWidget::setNksPinSettingResult(const GpgME::Error &err) -{ - handleResult(err, mChangeNKSPINBtn); -} - -void NetKeyWidget::doChangePin(bool sigG) +void NetKeyWidget::doChangePin(const std::string &keyRef) { - const auto nksCard = ReaderStatus::instance()->getCard(mSerialNumber); - if (!nksCard) { - KMessageBox::error(this, i18n("Failed to find the NetKey card with the serial number: %1", QString::fromStdString(mSerialNumber))); - return; - } - - if (sigG) { - ReaderStatus::mutableInstance()->startSimpleTransaction( - nksCard, "SCD PASSWD PW1.CH.SIG", this, "setSigGPinSettingResult"); - } else { - ReaderStatus::mutableInstance()->startSimpleTransaction( - nksCard, "SCD PASSWD PW1.CH", this, "setNksPinSettingResult"); - } + auto cmd = new ChangePinCommand(mSerialNumber, NetKeyCard::AppName, this); + this->setEnabled(false); + connect(cmd, &ChangePinCommand::finished, + this, [this]() { + this->setEnabled(true); + }); + cmd->setKeyRef(keyRef); + cmd->start(); } void NetKeyWidget::createKeyFromCardKeys() { auto cmd = new CreateOpenPGPKeyFromCardKeysCommand(mSerialNumber, NetKeyCard::AppName, this); this->setEnabled(false); connect(cmd, &CreateOpenPGPKeyFromCardKeysCommand::finished, this, [this]() { this->setEnabled(true); }); cmd->start(); } diff --git a/src/view/netkeywidget.h b/src/view/netkeywidget.h index 096d5c887..0d3729e43 100644 --- a/src/view/netkeywidget.h +++ b/src/view/netkeywidget.h @@ -1,64 +1,59 @@ /* view/netkeywidget.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2017 Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef VIEW_NETKEYWIDGET_H #define VIEW_NETKEYWIDGET_H #include #include #include class QLabel; class QPushButton; class QScrollArea; namespace Kleo { class NullPinWidget; class KeyTreeView; namespace SmartCard { class NetKeyCard; } // namespace SmartCard class NetKeyWidget: public QWidget { Q_OBJECT public: explicit NetKeyWidget(QWidget *parent = nullptr); ~NetKeyWidget(); void setCard(const SmartCard::NetKeyCard *card); private: - void handleResult(const GpgME::Error &err, QPushButton *btn); - void doChangePin(bool sigG); + void doChangePin(const std::string &keyRef); void createKeyFromCardKeys(); -private Q_SLOTS: - void setSigGPinSettingResult(const GpgME::Error &err); - void setNksPinSettingResult(const GpgME::Error &err); - private: std::string mSerialNumber; QLabel *mSerialNumberLabel = nullptr, *mVersionLabel = nullptr, *mLearnKeysLabel = nullptr, *mErrorLabel = nullptr; NullPinWidget *mNullPinWidget = nullptr; QPushButton *mLearnKeysBtn = nullptr, *mKeyForCardKeysButton = nullptr, *mChangeNKSPINBtn = nullptr, *mChangeSigGPINBtn = nullptr; KeyTreeView *mTreeView = nullptr; QScrollArea *mArea = nullptr; }; } // namespace Kleo #endif // VIEW_NETKEYWIDGET_H