diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4c855e0..a2e760e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,237 +1,238 @@ # target_include_directories does not handle empty include paths include_directories(${GPGME_INCLUDES}) add_definitions(-DTRANSLATION_DOMAIN=\"libkleopatra\") #add_definitions( -DQT_NO_CAST_FROM_ASCII ) #add_definitions( -DQT_NO_CAST_TO_ASCII ) kde_enable_exceptions() add_definitions( -DGPGMEPP_ERR_SOURCE_DEFAULT=13 ) # 13 is GPG_ERR_SOURCE_KLEO, even if gpg-error's too old to know about add_subdirectory( pics ) if (BUILD_TESTING) add_subdirectory( tests ) endif() ########### next target ############### set(libkleo_core_SRCS kleo/checksumdefinition.cpp kleo/defaultkeyfilter.cpp kleo/defaultkeygenerationjob.cpp kleo/dn.cpp kleo/enum.cpp kleo/exception.cpp kleo/kconfigbasedkeyfilter.cpp kleo/keyfiltermanager.cpp kleo/keyresolver.cpp kleo/remarks.cpp models/keycache.cpp models/keylistmodel.cpp models/keylistsortfilterproxymodel.cpp models/keyrearrangecolumnsproxymodel.cpp models/subkeylistmodel.cpp models/useridlistmodel.cpp utils/filesystemwatcher.cpp utils/formatting.cpp utils/classify.cpp utils/gnupg.cpp utils/hex.cpp smartcard/card.cpp smartcard/openpgpcard.cpp smartcard/netkeycard.cpp smartcard/cardmanager.cpp ) ecm_qt_declare_logging_category(libkleo_core_SRCS HEADER libkleo_debug.h IDENTIFIER LIBKLEO_LOG CATEGORY_NAME org.kde.pim.libkleo) set(libkleo_ui_common_SRCS ui/dnattributeorderconfigwidget.cpp ui/kdhorizontalline.cpp ui/filenamerequester.cpp ui/messagebox.cpp ui/cryptoconfigmodule.cpp ui/cryptoconfigdialog.cpp ui/directoryserviceswidget.cpp ui/progressbar.cpp ui/progressdialog.cpp ui/auditlogviewer.cpp ) ecm_qt_declare_logging_category(libkleo_ui_common_SRCS HEADER kleo_ui_debug.h IDENTIFIER KLEO_UI_LOG CATEGORY_NAME org.kde.pim.kleo_ui) set(libkleo_ui_SRCS # make this a separate lib. ui/keylistview.cpp ui/keytreeview.cpp ui/keyselectiondialog.cpp ui/keyrequester.cpp ui/keyapprovaldialog.cpp ui/newkeyapprovaldialog.cpp ui/keyselectioncombo.cpp ui/headerview.cpp smartcard/netkeywidget.cpp smartcard/pgpcardwidget.cpp - smartcard/smartcardwidget.cpp smartcard/nullpinwidget.cpp smartcard/gencardkeydialog.cpp + smartcard/gpgcardwidget.cpp ) ki18n_wrap_ui(libkleo_ui_common_SRCS ui/directoryserviceswidget.ui ) set(kleo_LIB_SRCS ${libkleo_core_SRCS} ${libkleo_ui_SRCS} ${libkleo_ui_common_SRCS}) set(kleo_LIB_LIBS PUBLIC QGpgme Gpgmepp PRIVATE Qt5::Widgets KF5::I18n KF5::Completion KF5::ConfigCore KF5::CoreAddons KF5::WidgetsAddons KF5::ItemModels KF5::Codecs) if (KF5PimTextEdit_FOUND) add_definitions(-DHAVE_PIMTEXTEDIT) set(kleo_LIB_LIBS ${kleo_LIB_LIBS} PRIVATE KF5::PimTextEdit) endif() add_library(KF5Libkleo ${kleo_LIB_SRCS}) generate_export_header(KF5Libkleo BASE_NAME kleo) add_library(KF5::Libkleo ALIAS KF5Libkleo) if(WIN32) target_link_libraries(KF5Libkleo ${kleo_LIB_LIBS} ${GPGME_VANILLA_LIBRARIES} ) else() target_link_libraries(KF5Libkleo ${kleo_LIB_LIBS} ) endif() set_target_properties(KF5Libkleo PROPERTIES VERSION ${LIBKLEO_VERSION_STRING} SOVERSION ${LIBKLEO_SOVERSION} EXPORT_NAME Libkleo ) install(TARGETS KF5Libkleo EXPORT KF5LibkleoTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS} ${LIBRARY_NAMELINK} ) target_include_directories(KF5Libkleo PUBLIC "$") target_include_directories(KF5Libkleo INTERFACE "$") ecm_generate_headers(libkleo_CamelCase_HEADERS HEADER_NAMES ChecksumDefinition DefaultKeyFilter DefaultKeyGenerationJob Dn Enum Exception KConfigBasedKeyFilter KeyFilter KeyFilterManager KeyResolver OidMap Predicates Stl_Util REQUIRED_HEADERS libkleo_HEADERS PREFIX Libkleo RELATIVE kleo ) ecm_generate_headers(libkleo_CamelCase_models_HEADERS HEADER_NAMES KeyCache KeyListModel KeyListModelInterface KeyListSortFilterProxyModel KeyRearrangeColumnsProxyModel SubkeyListModel UserIDListModel REQUIRED_HEADERS libkleo_models_HEADERS PREFIX Libkleo RELATIVE models ) ecm_generate_headers(libkleo_CamelCase_utils_HEADERS HEADER_NAMES Classify FileSystemWatcher Formatting GnuPG Hex REQUIRED_HEADERS libkleo_utils_HEADERS PREFIX Libkleo RELATIVE utils ) ecm_generate_headers(libkleo_CamelCase_smartcard_HEADERS HEADER_NAMES Card NetKeyCard OpenPGPCard CardManager + GpgCardWidget REQUIRED_HEADERS libkleo_smartcard_HEADERS PREFIX Libkleo RELATIVE smartcard ) ecm_generate_headers(libkleo_CamelCase_ui_HEADERS HEADER_NAMES CryptoConfigDialog CryptoConfigModule DNAttributeOrderConfigWidget DirectoryServicesWidget FileNameRequester KDHorizontalLine KeyApprovalDialog NewKeyApprovalDialog KeyRequester KeySelectionCombo KeySelectionDialog MessageBox ProgressDialog REQUIRED_HEADERS libkleo_ui_HEADERS PREFIX Libkleo RELATIVE ui ) ecm_generate_pri_file(BASE_NAME Libkleo LIB_NAME KF5Libkleo DEPS "QGpgme" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/Libkleo ) install(FILES ${libkleo_CamelCase_HEADERS} ${libkleo_CamelCase_models_HEADERS} ${libkleo_CamelCase_ui_HEADERS} ${libkleo_CamelCase_utils_HEADERS} ${libkleo_CamelCase_smartcard_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/Libkleo COMPONENT Devel ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kleo_export.h ${libkleo_HEADERS} ${libkleo_models_HEADERS} ${libkleo_ui_HEADERS} ${libkleo_utils_HEADERS} ${libkleo_smartcard_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/libkleo COMPONENT Devel ) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) if ( WIN32 ) install ( FILES libkleopatrarc-win32.desktop DESTINATION ${KDE_INSTALL_CONFDIR} RENAME libkleopatrarc ) else () install ( FILES libkleopatrarc.desktop DESTINATION ${KDE_INSTALL_CONFDIR} RENAME libkleopatrarc ) endif () diff --git a/src/smartcard/card.cpp b/src/smartcard/card.cpp index 2b50a57..966d675 100644 --- a/src/smartcard/card.cpp +++ b/src/smartcard/card.cpp @@ -1,226 +1,175 @@ -/* smartcard/card.h +/* smartcard/card.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2017 by Bundesamt für Sicherheit in der Informationstechnik Software engineering by Intevation GmbH Copyright (c) 2020 by g10 Code GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "card.h" #include #include #include #include #include "libkleo_debug.h" using namespace Kleo; using namespace Kleo::SmartCard; class Card::Private { public: - Private(): mCanLearn(false), - mHasNullPin(false), - mStatus(Status::NoCard), - mAppType(UnknownApplication), - mAppVersion(-1) - { - } - - Private(const QString &gpgOutput) + Private(const QString &gpgOutput, AppType type): + mCanLearn(false), + mHasNullPin(false), + mStatus(Status::NoCard), + mAppType(UnknownApplication) { + mAppType = type; const auto lines = gpgOutput.split(QRegExp("[\r\n]"), QString::SkipEmptyParts); for (const auto &line: lines) { auto words = line.split(QLatin1Char(':')); if (words.size () < 2) { qCDebug(LIBKLEO_LOG) << "Failed to parse line:" << line; continue; } QString key = words.takeFirst (); if (key.startsWith(QLatin1Char(' '))) { qCDebug(LIBKLEO_LOG) << "Ignoring subline:" << line; continue; } key.remove(QRegExp(" \\.*$")); mProperties.insert(key, words); } + } - mReader = getSingleProperty("Reader"); - mSerialNumber = getSingleProperty("Serial number").toStdString(); + const QStringList getProperties(const char *val) const + { + return mProperties[QLatin1String(val)]; } - QString getSingleProperty(const char *val) const + const QString getSingleProperty(const char *val) const { - if (!val) { - return QString(); - } - const auto list = mProperties.value(QLatin1String(val)); + const auto &list = mProperties[QLatin1String(val)]; if (list.empty()) { return QString(); } return list.first(); } - QString mReader; bool mCanLearn; bool mHasNullPin; - Status mStatus; - std::string mSerialNumber; + Card::Status mStatus; AppType mAppType; - int mAppVersion; std::vector mPinStates; int mSlot; QString mErrMsg; QMap mProperties; }; -Card::Card(): d(new Private()) { -} - -Card::Card(const QString &gpgOutput): d(new Private(gpgOutput)) { +Card::Card(const QString &gpgOutput, AppType type): d(new Private(gpgOutput, type)) +{ } -QString Card::getSingleProperty(const char *propName) const +const QString Card::getSingleProperty(const char *propName) const { return d->getSingleProperty(propName); } -void Card::setStatus(Status s) +const QStringList Card::getProperties(const char *propName) const { - d->mStatus = s; + return d->getProperties(propName); } Card::Status Card::status() const { return d->mStatus; } -void Card::setSerialNumber(const std::string &sn) +const QString Card::serialNumber() const { - d->mSerialNumber = sn; -} - -std::string Card::serialNumber() const -{ - return d->mSerialNumber; + return getSingleProperty("Serial number"); } Card::AppType Card::appType() const { return d->mAppType; } -void Card::setAppType(AppType t) +const QString Card::appVersion() const { - d->mAppType = t; -} - -void Card::setAppVersion(int version) -{ - d->mAppVersion = version; -} - -int Card::appVersion() const -{ - return d->mAppVersion; + return getSingleProperty("Version"); } std::vector Card::pinStates() const { return d->mPinStates; } -void Card::setPinStates(const std::vector &pinStates) -{ - d->mPinStates = pinStates; -} - -void Card::setSlot(int slot) -{ - d->mSlot = slot; -} - int Card::slot() const { return d->mSlot; } bool Card::hasNullPin() const { return d->mHasNullPin; } -void Card::setHasNullPin(bool value) -{ - d->mHasNullPin = value; -} - bool Card::canLearnKeys() const { return d->mCanLearn; } -void Card::setCanLearnKeys(bool value) -{ - d->mCanLearn = value; -} - bool Card::operator == (const Card& other) const { - return d->mStatus == other.status() - && d->mSerialNumber == other.serialNumber() - && d->mAppType == other.appType() - && d->mAppVersion == other.appVersion() - && d->mPinStates == other.pinStates() - && d->mSlot == other.slot() - && d->mCanLearn == other.canLearnKeys() - && d->mHasNullPin == other.hasNullPin(); + return d->mProperties == other.properties(); } bool Card::operator != (const Card& other) const { return !operator==(other); } -void Card::setErrorMsg(const QString &msg) +QString Card::errorMsg() const { - d->mErrMsg = msg; + return d->getSingleProperty("Error"); } -QString Card::errorMsg() const +QString Card::reader() const { - return d->mErrMsg; + return d->getSingleProperty("Reader"); } -QString Card::reader() const +const QMap Card::properties() const { - return d->mReader; + return d->mProperties; } diff --git a/src/smartcard/card.h b/src/smartcard/card.h index d691131..f5d7402 100644 --- a/src/smartcard/card.h +++ b/src/smartcard/card.h @@ -1,130 +1,123 @@ #ifndef SMARTCARD_CARD_H #define SMARTCARD_CARD_H /* smartcard/card.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2017 by Bundesamt für Sicherheit in der Informationstechnik Software engineering by Intevation GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include #include #include #include "kleo_export.h" namespace Kleo { namespace SmartCard { /** Class to work with Smartcards or other Hardware tokens. */ class KLEO_EXPORT Card { public: enum AppType { UnknownApplication, OpenPGPApplication, NksApplication, P15Application, DinSigApplication, GeldkarteApplication, PIVApplication, NumAppTypes }; enum PinState { UnknownPinState, NullPin, PinBlocked, NoPin, PinOk, NumPinStates }; enum Status { NoCard, CardPresent, CardActive, CardUsable, _NumScdStates, CardError = _NumScdStates, NumStates }; - Card(); - Card(const QString &gpgCardOutput); + Card() = delete; + Card(const QString &gpgCardOutput, AppType type = UnknownApplication); virtual ~Card() {} virtual bool operator == (const Card& other) const; bool operator != (const Card& other) const; - void setStatus(Status s); Status status() const; - virtual void setSerialNumber(const std::string &sn); - std::string serialNumber() const; - - AppType appType() const; - void setAppType(AppType type); - - void setAppVersion(int version); - int appVersion() const; + const QString serialNumber() const; std::vector pinStates() const; - void setPinStates(const std::vector &pinStates); - void setSlot(int slot); int slot() const; bool hasNullPin() const; - void setHasNullPin(bool value); bool canLearnKeys() const; - void setCanLearnKeys(bool value); QString errorMsg() const; - void setErrorMsg(const QString &msg); QString reader() const; - QString getSingleProperty(const char *name) const; + AppType appType() const; + const QString appVersion() const; + + const QString getSingleProperty(const char *name) const; + const QStringList getProperties(const char *name) const; + + const QMap properties() const; private: class Private; std::shared_ptr d; }; } // namespace Smartcard } // namespace Kleopatra #endif // SMARTCARD_CARD_H diff --git a/src/smartcard/cardmanager.cpp b/src/smartcard/cardmanager.cpp index 8350543..a91ae37 100644 --- a/src/smartcard/cardmanager.cpp +++ b/src/smartcard/cardmanager.cpp @@ -1,184 +1,195 @@ /* This file is part of libkleopatra, the KDE keymanagement library Copyright (c) 2020 g10 Code GmbH Libkleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Libkleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "cardmanager.h" #include "libkleo_debug.h" #include #include +#include "openpgpcard.h" + #if GPGMEPP_VERSION < 0x10E00 // 1.14.0 # define GPGMEPP_TOO_OLD #else # include #endif using namespace Kleo; using namespace SmartCard; static CardManager *s_instance = nullptr; class CardManager::Private { public: Private(CardManager *qq): q(qq), mErrCode(0) { } - void addCard(const QString &std_out) + void addCard(const QString &std_out, const QString & app) { - Card *genericCard = new Card(std_out); - /* TODO Specialize */ + if (app == QStringLiteral("openpgp")) { + mCards << std::shared_ptr (new OpenPGPCard(std_out)); + return; + } - mCards << std::shared_ptr(genericCard); + /* TODO: Implement. */ + qCDebug(LIBKLEO_LOG) << "Unknown app:" << app; + mCards << std::shared_ptr (new Card(std_out)); } void cardListDone (const QString &std_out, const QString &std_err, int exitCode) { mErrorStr = std_err; mErrCode = exitCode; mCards.clear(); if (exitCode) { qCDebug(LIBKLEO_LOG) << "Card list failed with code:" << exitCode; Q_EMIT q->cardsMayHaveChanged (); return; } mCardsToApps.clear(); const auto lines = std_out.split(QRegExp("[\r\n]"), QString::SkipEmptyParts); + QMap readerMap; for (const auto &line: lines) { - auto words = line.split(QLatin1Char(' ')); + auto words = line.split(QLatin1Char(' '), + QString::SkipEmptyParts); /* The first word is the selection */ - words.pop_front (); + const auto reader = words.takeFirst().remove(QLatin1Char('*')); const auto key = words.takeFirst(); + readerMap.insert(reader, key); mCardsToApps.insert(key, words); } - int i = 0; - for (const auto &id: mCardsToApps.keys()) { + /* Old for loop for now because the order matters. */ + for (const auto &reader: readerMap.keys()) { + const auto &id = readerMap[reader]; const auto apps = mCardsToApps.value(id); + qDebug() << "I think that " << id << "Has app " << apps << "in reader" << reader; + /* Now for each card start a specific listing */ auto cmd = QGpgME::gpgCardJob(); QString std_out; QString std_err; int exitCode = 0; if (apps.empty()) { GpgME::Error err = cmd->exec(QStringList() << QStringLiteral("--") << QStringLiteral("list") << QStringLiteral("--no-key-lookup") - << QString::number(i), std_out, std_err, + << reader, std_out, std_err, exitCode); if (err || exitCode) { qCDebug(LIBKLEO_LOG) << "Card list failed with code:" << exitCode; qCDebug(LIBKLEO_LOG) << "Error:" << std_err; } else { - addCard(std_out); + addCard(std_out, QString()); } } else { for (const auto &app: apps) { GpgME::Error err = cmd->exec(QStringList() << QStringLiteral("--") << QStringLiteral("list") << QStringLiteral("--no-key-lookup") - << QString::number(i) + << reader << app, std_out, std_err, exitCode); if (err || exitCode) { qCDebug(LIBKLEO_LOG) << "Card list failed with code:" << exitCode; qCDebug(LIBKLEO_LOG) << "Error:" << std_err; } else { - addCard(std_out); + addCard(std_out, app); } } } - i++; } Q_EMIT q->cardsMayHaveChanged (); } QList > mCards; private: /* A map of available card ID's to the apps they support */ QMap mCardsToApps; CardManager *q; QString mErrorStr; int mErrCode; }; CardManager::CardManager(): d(new Private(this)) { } CardManager::~CardManager() { s_instance = nullptr; } void CardManager::startCardList() const { #ifdef GPGMEPP_TOO_OLD qCWarning(LIBKLEO_LOG) << "GPGME Version too old"; return; #else auto cmd = QGpgME::gpgCardJob(); connect(cmd, &QGpgME::GpgCardJob::result, this, [this] (const QString &std_out, const QString &std_err, int exitCode, const QString&, const GpgME::Error &) { d->cardListDone(std_out, std_err, exitCode); }); cmd->start(QStringList() << QStringLiteral("--") << QStringLiteral("list") << QStringLiteral("--cards") << QStringLiteral("--apps")); #endif } QList > CardManager::cards() const { return d->mCards; } /* static */ CardManager *CardManager::instance() { if (s_instance) { return s_instance; } s_instance = new CardManager(); return s_instance; } diff --git a/src/smartcard/smartcardwidget.cpp b/src/smartcard/gpgcardwidget.cpp similarity index 79% rename from src/smartcard/smartcardwidget.cpp rename to src/smartcard/gpgcardwidget.cpp index 3baeb67..7c19d25 100644 --- a/src/smartcard/smartcardwidget.cpp +++ b/src/smartcard/gpgcardwidget.cpp @@ -1,169 +1,157 @@ -/* view/smartcardwidget.cpp +/* view/gpgcardwidget.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2017 by Bundesamt für Sicherheit in der Informationstechnik Software engineering by Intevation GmbH + Copytrigh (c) 2020 g10 Code GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ -#include "smartcardwidget.h" +#include "gpgcardwidget.h" #include "openpgpcard.h" #include "netkeycard.h" #include "pgpcardwidget.h" #include "netkeywidget.h" - #include "cardmanager.h" #include "libkleo_debug.h" #include #include #include #include #include #include using namespace Kleo; using namespace Kleo::SmartCard; namespace { class PlaceHolderWidget: public QWidget { Q_OBJECT public: PlaceHolderWidget() { auto lay = new QVBoxLayout; lay->addStretch(-1); - const QStringList supported = QStringList() << QStringLiteral("OpenPGP v2.0 - v3.3") - << QStringLiteral("Gnuk") + const QStringList supported = QStringList() << QStringLiteral("OpenPGP > v2.0") + << QStringLiteral("YubiKey") + << QStringLiteral("Gnuk Token") << QStringLiteral("NetKey v3"); lay->addWidget(new QLabel(QStringLiteral("\t\t

") + i18n("Please insert a compatible smartcard.") + QStringLiteral("

"))); lay->addSpacing(10); lay->addWidget(new QLabel(QStringLiteral("\t\t") + i18n("Kleopatra currently supports the following card types:") + QStringLiteral("
  • ") + supported.join(QLatin1String("
  • ")) + QStringLiteral("
"))); lay->addSpacing(10); lay->addWidget(new QLabel(i18n("Refresh the view (F5) to update the smartcard status."))); lay->addStretch(-1); auto hLay = new QHBoxLayout(this); hLay->addStretch(-1); hLay->addLayout(lay); hLay->addStretch(-1); lay->addStretch(-1); } }; } // namespace -class SmartCardWidget::Private +class GpgCardWidget::Private { public: - Private(SmartCardWidget *qq) : q(qq), mManager(CardManager::instance()) + Private(GpgCardWidget *qq) : q(qq) { - QPushButton *backBtn = new QPushButton(QIcon::fromTheme(QStringLiteral("arrow-left")), i18n("Back")); - QHBoxLayout *backH = new QHBoxLayout; - backH->addWidget(backBtn); - backH->addWidget(new QLabel(QStringLiteral("

") + i18n("Smartcard Management") + - QStringLiteral("

"))); - backH->addStretch(-1); - QVBoxLayout *vLay = new QVBoxLayout(q); - - connect(backBtn, &QPushButton::clicked, q, [this] () {Q_EMIT (q->backRequested());}); - - vLay->addLayout(backH); - mStack = new QStackedWidget; vLay->addWidget(mStack); mPGPCardWidget = new PGPCardWidget; mStack->addWidget(mPGPCardWidget); mNetKeyWidget = new NetKeyWidget; mStack->addWidget(mNetKeyWidget); mPlaceHolderWidget = new PlaceHolderWidget; mStack->addWidget(mPlaceHolderWidget); mStack->setCurrentWidget(mPlaceHolderWidget); - connect (mManager, &CardManager::cardsMayHaveChanged, q, [this] () { - const auto cards = mManager->cards(); + connect (CardManager::instance(), &CardManager::cardsMayHaveChanged, q, [this] () { + const auto cards = CardManager::instance()->cards(); if (!cards.size()) { - setCard(std::shared_ptr(new Card())); + setCard(std::shared_ptr(nullptr)); } else { // No support for multiple reader / cards currently setCard(cards[0]); } }); } void setCard(std::shared_ptr card) { + if (!card) { + qCDebug(LIBKLEO_LOG) << "No card parsable"; + mStack->setCurrentWidget(mPlaceHolderWidget); + } if (card->appType() == Card::OpenPGPApplication) { mPGPCardWidget->setCard(static_cast (card.get())); mStack->setCurrentWidget(mPGPCardWidget); } else if (card->appType() == Card::NksApplication) { mNetKeyWidget->setCard(static_cast (card.get())); mStack->setCurrentWidget(mNetKeyWidget); } else { + qCDebug(LIBKLEO_LOG) << "Ignoring unknown card: " << card->serialNumber(); mStack->setCurrentWidget(mPlaceHolderWidget); } } - void reload() - { - mManager->startCardList(); - } - private: - SmartCardWidget *q; + GpgCardWidget *q; NetKeyWidget *mNetKeyWidget; PGPCardWidget *mPGPCardWidget; PlaceHolderWidget *mPlaceHolderWidget; QStackedWidget *mStack; - CardManager *mManager; }; -SmartCardWidget::SmartCardWidget(QWidget *parent): +GpgCardWidget::GpgCardWidget(QWidget *parent): QWidget(parent), d(new Private(this)) { } -void SmartCardWidget::reload() +void GpgCardWidget::reload() { - d->reload(); + CardManager::instance()->startCardList(); } -#include "smartcardwidget.moc" +#include "gpgcardwidget.moc" diff --git a/src/smartcard/smartcardwidget.h b/src/smartcard/gpgcardwidget.h similarity index 80% rename from src/smartcard/smartcardwidget.h rename to src/smartcard/gpgcardwidget.h index 1c191f5..506c521 100644 --- a/src/smartcard/smartcardwidget.h +++ b/src/smartcard/gpgcardwidget.h @@ -1,59 +1,61 @@ -#ifndef VIEW_SMARTCARDWIDGET_H -#define VIEW_SMARTCARDWIDGET_H -/* smartcard/smartcardwidget.h +#ifndef VIEW_GPGCARDWIDGET_H +#define VIEW_GPGCARDWIDGET_H +/* view/gpgcardwidget.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2017 by Bundesamt für Sicherheit in der Informationstechnik Software engineering by Intevation GmbH + Copyright (c) 2020 g10 Code GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include +#include "kleo_export.h" + namespace Kleo { -/* SmartCardWidget a generic widget to interact with smartcards */ -class SmartCardWidget: public QWidget +/* GpgCardWidget a generic widget to interact with smartcards. + * It's a frontend for gpg-card and as such it requires at + * least GnuPG 2.3 */ +class KLEO_EXPORT GpgCardWidget: public QWidget { Q_OBJECT public: - explicit SmartCardWidget(QWidget *parent = nullptr); + explicit GpgCardWidget(QWidget *parent = nullptr); public Q_SLOTS: void reload(); -Q_SIGNALS: - void backRequested(); - private: class Private; std::shared_ptr d; }; } // namespace Kleo -#endif // VIEW_SMARTCARDWIDGET_H +#endif // VIEW_GPGCARDWIDGET_H diff --git a/src/smartcard/netkeycard.cpp b/src/smartcard/netkeycard.cpp index 2884002..155fc88 100644 --- a/src/smartcard/netkeycard.cpp +++ b/src/smartcard/netkeycard.cpp @@ -1,139 +1,143 @@ /* smartcard/netkeycard.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2017 Intevation GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "netkeycard.h" #include "libkleo_debug.h" #include #include #include #include #include using namespace Kleo; using namespace Kleo::SmartCard; class NetKeyCard::Private { public: - Private () + Private (const QString &std_out): + mCanLearn(false) { + Q_UNUSED(std_out); } + bool mCanLearn; std::vector mKeys; }; namespace { static std::string parse_keypairinfo(const std::string &kpi) { static const char hexchars[] = "0123456789abcdefABCDEF"; return '&' + kpi.substr(0, kpi.find_first_not_of(hexchars)); } static GpgME::Key parse_keypairinfo_and_lookup_key(GpgME::Context *ctx, const std::string &kpi) { if (!ctx) { return GpgME::Key(); } const std::string pattern = parse_keypairinfo(kpi); qCDebug(LIBKLEO_LOG) << "parse_keypairinfo_and_lookup_key: pattern=" << pattern.c_str(); if (const auto err = ctx->startKeyListing(pattern.c_str())) { qCDebug(LIBKLEO_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(LIBKLEO_LOG) << "parse_keypairinfo_and_lookup_key: e=" << e.code() << "; key.isNull()" << key.isNull(); return key; } } // namespace -NetKeyCard::NetKeyCard(): d(new Private()) +NetKeyCard::NetKeyCard(const QString &std_out): + Card(std_out, NksApplication), + d(new Private(std_out)) { - setAppType(Card::NksApplication); } 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); + d->mCanLearn = false; d->mKeys.clear(); for (const auto &info: infos) { const auto key = parse_keypairinfo_and_lookup_key(klc.get(), info); if (key.isNull()) { - setCanLearnKeys(true); + d->mCanLearn = true; } d->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(LIBKLEO_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(LIBKLEO_LOG) << "Invalid size of pin states:" << states.size(); return false; } return states[2] == Card::NullPin; } std::vector NetKeyCard::keys() const { return d->mKeys; } diff --git a/src/smartcard/netkeycard.h b/src/smartcard/netkeycard.h index 3c80dd2..237ba0c 100644 --- a/src/smartcard/netkeycard.h +++ b/src/smartcard/netkeycard.h @@ -1,67 +1,68 @@ #ifndef SMARTCARD_NETKEYCARD_H #define SMARTCARD_NETKEYCARD_H /* smartcard/openpgpcard.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2017 Intevation GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "card.h" #include #include #include "kleo_export.h" namespace Kleo { namespace SmartCard { /** Class to work with OpenPGP Smartcards or compatible tokens */ class KLEO_EXPORT NetKeyCard: public Card { public: - NetKeyCard (); + NetKeyCard() = delete; + NetKeyCard (const QString &std_out); void setKeyPairInfo (const std::vector &infos); bool hasSigGNullPin() const; bool hasNKSNullPin() const; std::vector keys() const; private: class Private; std::shared_ptr d; }; } // namespace Smartcard } // namespace Kleopatra #endif // SMARTCARD_CARD_H diff --git a/src/smartcard/netkeywidget.cpp b/src/smartcard/netkeywidget.cpp index a2a580d..32d173b 100644 --- a/src/smartcard/netkeywidget.cpp +++ b/src/smartcard/netkeywidget.cpp @@ -1,248 +1,248 @@ /* view/netkeywidget.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2017 Intevation GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "netkeywidget.h" #include "nullpinwidget.h" #include "ui/keytreeview.h" #include "libkleo_debug.h" #include "smartcard/netkeycard.h" #include "models/keylistmodel.h" #include #include #include #include #include #include #include #include using namespace Kleo; using namespace Kleo::SmartCard; NetKeyWidget::NetKeyWidget() : mSerialNumber(new QLabel), mVersionLabel(new QLabel), mLearnKeysLabel(new QLabel), mErrorLabel(new QLabel), mNullPinWidget(new NullPinWidget()), mLearnKeysBtn(new QPushButton), mChangeNKSPINBtn(new QPushButton), mChangeSigGPINBtn(new QPushButton), 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->addWidget(mArea); // Add general widgets mVersionLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); vLay->addWidget(mVersionLabel, 0, Qt::AlignLeft); mSerialNumber->setTextInteractionFlags(Qt::TextBrowserInteraction); auto hLay1 = new QHBoxLayout; hLay1->addWidget(new QLabel(i18n("Serial number:"))); hLay1->addWidget(mSerialNumber); 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] () { #if 0 mLearnKeysBtn->setEnabled(false); auto cmd = new LearnCardKeysCommand(GpgME::CMS); cmd->setParentWidget(this); cmd->start(); TODO libkleo port auto icon = KleopatraApplication::instance()->sysTrayIcon(); if (icon) { icon->setLearningInProgress(true); } connect(cmd, &Command::finished, this, [icon] () { ReaderStatus::mutableInstance()->updateStatus(); icon->setLearningInProgress(false); }); #endif }); 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); #if 0 TODO libkleo port: connect(mTreeView->view(), &QAbstractItemView::doubleClicked, this, [this] (const QModelIndex &idx) { const auto klm = dynamic_cast (mTreeView->view()->model()); if (!klm) { qCDebug(LIBKLEO_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); #endif // 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); 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); }); auto hLay3 = new QHBoxLayout(); hLay3->addWidget(mChangeNKSPINBtn); hLay3->addWidget(mChangeSigGPINBtn); hLay3->addStretch(1); vLay->addLayout(hLay3); vLay->addStretch(1); } void NetKeyWidget::setCard(const NetKeyCard* card) { mVersionLabel->setText(i18nc("1 is a Version number", "NetKey v%1 Card", card->appVersion())); - mSerialNumber->setText(QString::fromStdString(card->serialNumber())); + mSerialNumber->setText(card->serialNumber()); /* 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")).arg(errMsg)); mErrorLabel->setVisible(true); } else { mErrorLabel->setVisible(false); } const auto keys = card->keys(); mTreeView->setKeys(keys); } 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) { #if 0 TODO libkleo port: if (sigG) { ReaderStatus::mutableInstance() ->startSimpleTransaction("SCD PASSWD PW1.CH.SIG", this, "setSigGPinSettingResult"); } else { ReaderStatus::mutableInstance() ->startSimpleTransaction("SCD PASSWD PW1.CH", this, "setNksPinSettingResult"); } #endif } diff --git a/src/smartcard/openpgpcard.cpp b/src/smartcard/openpgpcard.cpp index e60b95f..66a9c7e 100644 --- a/src/smartcard/openpgpcard.cpp +++ b/src/smartcard/openpgpcard.cpp @@ -1,250 +1,122 @@ /* smartcard/openpgpcard.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2017 by Bundesamt für Sicherheit in der Informationstechnik Software engineering by Intevation GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ /* Code in this file is partly based on the GNU Privacy Assistant * (cm-openpgp.c) git rev. 0a78795146661234070681737b3e08228616441f * * Whis is: * Copyright (C) 2008, 2009 g10 Code GmbH * * And may be licensed under the GNU General Public License * as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. */ #include "openpgpcard.h" #include "libkleo_debug.h" using namespace Kleo; using namespace Kleo::SmartCard; -#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ - *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) -#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) - -namespace -{ -static const char * get_manufacturer (unsigned int no) -{ - switch (no) { - case 0x0001: return "PPC Card Systems"; - case 0x0002: return "Prism"; - case 0x0003: return "OpenFortress"; - case 0x0004: return "Wewid"; - case 0x0005: return "ZeitControl"; - case 0x0006: return "Yubico"; - case 0x0007: return "OpenKMS"; - case 0x0008: return "LogoEmail"; - - case 0x002A: return "Magrathea"; - - case 0x1337: return "Warsaw Hackerspace"; - - case 0xF517: return "FSIJ"; - - /* 0x0000 and 0xFFFF are defined as test cards per spec, - 0xFF00 to 0xFFFE are assigned for use with randomly created - serial numbers. */ - case 0x0000: - case 0xffff: return "test card"; - default: return (no & 0xff00) == 0xff00? "unmanaged S/N range":"unknown"; - } -} - -} // namespace class OpenPGPCard::Private { public: Private (): mIsV2(false) { } bool mIsV2 = false; std::string mCardVersion; - QMap mMetaInfo; std::string mManufacturer; }; -OpenPGPCard::OpenPGPCard(): d(new Private()) -{ - setAppType(Card::OpenPGPApplication); -} - -OpenPGPCard::OpenPGPCard(const std::string &serialno): OpenPGPCard() +OpenPGPCard::OpenPGPCard(const QString &std_out): + Card(std_out, Card::OpenPGPApplication), + d(new Private()) { - setSerialNumber(serialno); } -std::string OpenPGPCard::sigFpr() const +const QString OpenPGPCard::sigFpr() const { - return d->mMetaInfo.value("SIGKEY-FPR"); + return QString(); } -std::string OpenPGPCard::encFpr() const +const QString OpenPGPCard::encFpr() const { - return d->mMetaInfo.value("ENCKEY-FPR"); + return QString(); } -std::string OpenPGPCard::authFpr() const +const QString OpenPGPCard::authFpr() const { - return d->mMetaInfo.value("AUTHKEY-FPR"); -} - -void OpenPGPCard::setKeyPairInfo(const std::vector< std::pair > &infos) -{ - qCDebug(LIBKLEO_LOG) << "Card" << serialNumber().c_str() << "info:"; - for (const auto &pair: infos) { - qCDebug(LIBKLEO_LOG) << pair.first.c_str() << ":" << pair.second.c_str(); - if (pair.first == "KEY-FPR" || - pair.first == "KEY-TIME") { - // Key fpr and key time need to be distinguished, the number - // of the key decides the usage. - const auto values = QString::fromStdString(pair.second).split(QLatin1Char(' ')); - if (values.size() < 2) { - qCWarning(LIBKLEO_LOG) << "Invalid entry."; - setStatus(Card::CardError); - continue; - } - const auto usage = values[0]; - const auto fpr = values[1].toStdString(); - if (usage == QLatin1Char('1')) { - d->mMetaInfo.insert(std::string("SIG") + pair.first, fpr); - } else if (usage == QLatin1Char('2')) { - d->mMetaInfo.insert(std::string("ENC") + pair.first, fpr); - } else if (usage == QLatin1Char('3')) { - d->mMetaInfo.insert(std::string("AUTH") + pair.first, fpr); - } else { - // d->maybe more keyslots in the future? - qCDebug(LIBKLEO_LOG) << "Unhandled keyslot"; - } - } else if (pair.first == "KEYPAIRINFO") { - // Fun, same as above but the other way around. - const auto values = QString::fromStdString(pair.second).split(QLatin1Char(' ')); - if (values.size() < 2) { - qCWarning(LIBKLEO_LOG) << "Invalid entry."; - setStatus(Card::CardError); - continue; - } - const auto usage = values[1]; - const auto grip = values[0].toStdString(); - if (usage == QLatin1String("OPENPGP.1")) { - d->mMetaInfo.insert(std::string("SIG") + pair.first, grip); - } else if (usage == QLatin1String("OPENPGP.2")) { - d->mMetaInfo.insert(std::string("ENC") + pair.first, grip); - } else if (usage == QLatin1String("OPENPGP.3")) { - d->mMetaInfo.insert(std::string("AUTH") + pair.first, grip); - } else { - // d->maybe more keyslots in the future? - qCDebug(LIBKLEO_LOG) << "Unhandled keyslot"; - } - } else { - d->mMetaInfo.insert(pair.first, pair.second); - } - } -} - -void OpenPGPCard::setSerialNumber(const std::string &serialno) -{ - char version_buffer[6]; - const char *version = ""; - const char *string = serialno.c_str(); - - Card::setSerialNumber(serialno); - if (strncmp(string, "D27600012401", 12) || strlen(string) != 32 ) { - /* Not a proper OpenPGP card serialnumber. Display the full - serialnumber. */ - d->mManufacturer = "unknown"; - } else { - /* Reformat the version number to be better human readable. */ - char *p = version_buffer; - if (string[12] != '0') { - *p++ = string[12]; - } - *p++ = string[13]; - *p++ = '.'; - if (string[14] != '0') { - *p++ = string[14]; - } - *p++ = string[15]; - *p++ = '\0'; - version = version_buffer; - - /* Get the manufacturer. */ - d->mManufacturer = get_manufacturer(xtoi_2(string + 16)*256 + xtoi_2(string + 18)); - } - - d->mIsV2 = !((*version == '1' || *version == '0') && version[1] == '.'); - d->mCardVersion = version; + return QString(); } bool OpenPGPCard::operator == (const Card& rhs) const { const OpenPGPCard *other = dynamic_cast(&rhs); if (!other) { return false; } return Card::operator ==(rhs) && sigFpr() == other->sigFpr() && encFpr() == other->encFpr() && authFpr() == other->authFpr() && manufacturer() == other->manufacturer() && cardVersion() == other->cardVersion() && cardHolder() == other->cardHolder() && pubkeyUrl() == other->pubkeyUrl(); } -std::string OpenPGPCard::manufacturer() const +const QString OpenPGPCard::manufacturer() const { - return d->mManufacturer; + return getSingleProperty("Manufacturer"); } -std::string OpenPGPCard::cardVersion() const +const QString OpenPGPCard::cardVersion() const { - return d->mCardVersion; + return getSingleProperty("Version"); } -std::string OpenPGPCard::cardHolder() const +const QString OpenPGPCard::cardHolder() const { - auto list = QString::fromStdString(d->mMetaInfo.value("DISP-NAME")).split(QStringLiteral("<<")); - std::reverse(list.begin(), list.end()); - return list.join(QLatin1Char(' ')).toStdString(); + return getSingleProperty("Name of cardholder"); } -std::string OpenPGPCard::pubkeyUrl() const +const QString OpenPGPCard::pubkeyUrl() const { - return d->mMetaInfo.value("PUBKEY-URL"); + return getSingleProperty("URL of public key"); } diff --git a/src/smartcard/openpgpcard.h b/src/smartcard/openpgpcard.h index e96d3e1..9991a65 100644 --- a/src/smartcard/openpgpcard.h +++ b/src/smartcard/openpgpcard.h @@ -1,75 +1,73 @@ #ifndef SMARTCARD_OPENPGPCARD_H #define SMARTCARD_OPENPGPCARD_H /* smartcard/openpgpcard.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2017 by Bundesamt für Sicherheit in der Informationstechnik Software engineering by Intevation GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include #include "card.h" +#include #include "kleo_export.h" namespace Kleo { namespace SmartCard { /** Class to work with OpenPGP Smartcards or compatible tokens */ class KLEO_EXPORT OpenPGPCard: public Card { public: - OpenPGPCard (); - OpenPGPCard (const std::string &serialno); - void setSerialNumber(const std::string &sn) override; + OpenPGPCard() = delete; + OpenPGPCard(const QString &std_out); - std::string encFpr() const; - std::string sigFpr() const; - std::string authFpr() const; - - void setKeyPairInfo (const std::vector< std::pair > &infos); + const QString encFpr() const; + const QString sigFpr() const; + const QString authFpr() const; bool operator == (const Card& other) const override; - std::string manufacturer() const; - std::string cardVersion() const; - std::string cardHolder() const; - std::string pubkeyUrl() const; + const QString manufacturer() const; + const QString cardVersion() const; + const QString cardHolder() const; + const QString pubkeyUrl() const; private: class Private; std::shared_ptr d; }; } // namespace Smartcard } // namespace Kleopatra #endif // SMARTCARD_CARD_H diff --git a/src/smartcard/pgpcardwidget.cpp b/src/smartcard/pgpcardwidget.cpp index 1f1a33e..41ba042 100644 --- a/src/smartcard/pgpcardwidget.cpp +++ b/src/smartcard/pgpcardwidget.cpp @@ -1,517 +1,543 @@ /* smartcard/pgpcardwiget.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2017 by Bundesamt für Sicherheit in der Informationstechnik Software engineering by Intevation GmbH Copyright (c) 2020 g10 Code GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "pgpcardwidget.h" #include "libkleo_debug.h" #include "smartcard/openpgpcard.h" #include "gencardkeydialog.h" #include "utils/gnupg.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "models/keycache.h" #include "utils/formatting.h" #include #include #include #include #if GPGMEPP_VERSION > 0x10801 // 1.8.1 // TODO remove ifdef once > 1.8.1 is required #include # define GPGME_CAN_GENCARDKEY #endif +#if GPGMEPP_VERSION >= 0x10E00 // 1.14.0 +# define GPGME_CAN_GPGCARD +# include +# include +#endif + using namespace Kleo; using namespace Kleo::SmartCard; namespace { #ifdef GPGME_CAN_GENCARDKEY class GenKeyThread: public QThread { Q_OBJECT public: - explicit GenKeyThread(const GenCardKeyDialog::KeyParams ¶ms, const std::string &serial): - mSerial(serial), + explicit GenKeyThread(const GenCardKeyDialog::KeyParams ¶ms, const QString &serial): + mSerial(serial.toStdString()), mParams(params) { } GpgME::Error error() { return mErr; } std::string bkpFile() { return mBkpFile; } protected: void run() override { GpgME::GpgGenCardKeyInteractor *ei = new GpgME::GpgGenCardKeyInteractor(mSerial); ei->setKeySize(mParams.keysize); ei->setNameUtf8(mParams.name.toStdString()); ei->setEmailUtf8(mParams.email.toStdString()); ei->setDoBackup(mParams.backup); const auto ctx = std::shared_ptr (GpgME::Context::createForProtocol(GpgME::OpenPGP)); QGpgME::QByteArrayDataProvider dp; GpgME::Data data(&dp); mErr = ctx->cardEdit(GpgME::Key(), std::unique_ptr (ei), data); mBkpFile = ei->backupFileName(); } private: GpgME::Error mErr; std::string mSerial; GenCardKeyDialog::KeyParams mParams; std::string mBkpFile; }; #endif } // Namespace -PGPCardWidget::PGPCardWidget(): - mSerialNumber(new QLabel), - mCardHolderLabel(new QLabel), - mVersionLabel(new QLabel), - mSigningKey(new QLabel), - mEncryptionKey(new QLabel), - mAuthKey(new QLabel), - mUrlLabel(new QLabel), - mCardIsEmpty(false) +class PGPCardWidget::Private +{ +public: + Private(): + mSerialNumber(new QLabel), + mCardHolderLabel(new QLabel), + mVersionLabel(new QLabel), + mSigningKey(new QLabel), + mEncryptionKey(new QLabel), + mAuthKey(new QLabel), + mUrlLabel(new QLabel), + mCardIsEmpty(false) + { + } + + QLabel *mSerialNumber = nullptr, + *mCardHolderLabel = nullptr, + *mVersionLabel = nullptr, + *mSigningKey = nullptr, + *mEncryptionKey = nullptr, + *mAuthKey = nullptr, + *mUrlLabel = nullptr; + QString mUrl; + bool mCardIsEmpty = false; + bool mIs21 = false; + QString mRealSerial; +}; + +PGPCardWidget::PGPCardWidget(): d(new Private()) { 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(d->mVersionLabel, row++, 0, 1, 2); + d->mVersionLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); grid->addWidget(new QLabel(i18n("Serial number:")), row, 0); - grid->addWidget(mSerialNumber, row++, 1); - mSerialNumber->setTextInteractionFlags(Qt::TextBrowserInteraction); + grid->addWidget(d->mSerialNumber, row++, 1); + d->mSerialNumber->setTextInteractionFlags(Qt::TextBrowserInteraction); // Cardholder Row grid->addWidget(new QLabel(i18nc("The owner of a smartcard. GnuPG refers to this as cardholder.", "Cardholder:")), row, 0); - grid->addWidget(mCardHolderLabel, row, 1); - mCardHolderLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + grid->addWidget(d->mCardHolderLabel, row, 1); + d->mCardHolderLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); auto nameButtton = new QPushButton; nameButtton->setIcon(QIcon::fromTheme(QStringLiteral("cell_edit"))); nameButtton->setToolTip(i18n("Change")); grid->addWidget(nameButtton, row++, 2); connect(nameButtton, &QPushButton::clicked, this, &PGPCardWidget::changeNameRequested); // URL Row grid->addWidget(new QLabel(i18nc("The URL under which a public key that " "corresponds to a smartcard can be downloaded", "Pubkey URL:")), row, 0); - grid->addWidget(mUrlLabel, row, 1); + grid->addWidget(d->mUrlLabel, row, 1); - mUrlLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + d->mUrlLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); auto urlButtton = new QPushButton; urlButtton->setIcon(QIcon::fromTheme(QStringLiteral("cell_edit"))); urlButtton->setToolTip(i18n("Change")); grid->addWidget(urlButtton, row++, 2); connect(urlButtton, &QPushButton::clicked, this, &PGPCardWidget::changeUrlRequested); // The keys auto line1 = new QFrame(); line1->setFrameShape(QFrame::HLine); grid->addWidget(line1, row++, 0, 1, 4); grid->addWidget(new QLabel(QStringLiteral("%1").arg(i18n("Keys:"))), row++, 0); grid->addWidget(new QLabel(i18n("Signature:")), row, 0); - grid->addWidget(mSigningKey, row++, 1); - mSigningKey->setTextInteractionFlags(Qt::TextBrowserInteraction); + grid->addWidget(d->mSigningKey, row++, 1); + d->mSigningKey->setTextInteractionFlags(Qt::TextBrowserInteraction); grid->addWidget(new QLabel(i18n("Encryption:")), row, 0); - grid->addWidget(mEncryptionKey, row++, 1); - mEncryptionKey->setTextInteractionFlags(Qt::TextBrowserInteraction); + grid->addWidget(d->mEncryptionKey, row++, 1); + d->mEncryptionKey->setTextInteractionFlags(Qt::TextBrowserInteraction); grid->addWidget(new QLabel(i18n("Authentication:")), row, 0); - grid->addWidget(mAuthKey, row++, 1); - mAuthKey->setTextInteractionFlags(Qt::TextBrowserInteraction); + grid->addWidget(d->mAuthKey, row++, 1); + d->mAuthKey->setTextInteractionFlags(Qt::TextBrowserInteraction); auto line2 = new QFrame(); line2->setFrameShape(QFrame::HLine); grid->addWidget(line2, row++, 0, 1, 4); grid->addWidget(new QLabel(QStringLiteral("%1").arg(i18n("Actions:"))), row++, 0); auto actionLayout = new QHBoxLayout; #ifdef GPGME_CAN_GENCARDKEY auto generateButton = new QPushButton(i18n("Generate new Keys")); generateButton->setToolTip(i18n("Create a new primary key and generate subkeys on the card.")); actionLayout->addWidget(generateButton); connect(generateButton, &QPushButton::clicked, this, &PGPCardWidget::genkeyRequested); #endif auto pinButtton = new QPushButton(i18n("Change PIN")); pinButtton->setToolTip(i18n("Change the PIN required to unblock the smartcard.")); actionLayout->addWidget(pinButtton); connect(pinButtton, &QPushButton::clicked, this, [this] () {doChangePin(1);}); auto pukButton = new QPushButton(i18n("Change Admin PIN")); pukButton->setToolTip(i18n("Change the PIN required to unlock the smartcard.")); actionLayout->addWidget(pukButton); connect(pukButton, &QPushButton::clicked, this, [this] () {doChangePin(3);}); auto resetCodeButton = new QPushButton(i18n("Change Reset Code")); pukButton->setToolTip(i18n("Change the PIN required to reset the smartcard to an empty state.")); actionLayout->addWidget(resetCodeButton); connect(resetCodeButton, &QPushButton::clicked, this, [this] () {doChangePin(2);}); actionLayout->addStretch(-1); grid->addLayout(actionLayout, row++, 0, 1, 4); grid->setColumnStretch(4, -1); } void PGPCardWidget::setCard(const OpenPGPCard *card) { - const QString version = QString::fromStdString(card->cardVersion()); + const QString version = card->cardVersion(); - mIs21 = versionIsAtLeast("2.1", card->cardVersion().c_str()); - mVersionLabel->setText(i18nc("First placeholder is manufacturer, second placeholder is a version number", - "%1 OpenPGP v%2 card", QString::fromStdString(card->manufacturer()), + d->mIs21 = versionIsAtLeast("2.1", card->cardVersion().toLatin1().constData()); + d->mVersionLabel->setText(i18nc("First placeholder is manufacturer, second placeholder is a version number", + "%1 OpenPGP v%2 card", card->manufacturer(), version)); - const QString sn = QString::fromStdString(card->serialNumber()).mid(16, 12); - mSerialNumber->setText(sn); - mRealSerial = card->serialNumber(); - - const auto holder = QString::fromStdString(card->cardHolder()); - const auto url = QString::fromStdString(card->pubkeyUrl()); - mCardHolderLabel->setText(holder.isEmpty() ? i18n("not set") : holder); - mUrl = url; - mUrlLabel->setText(url.isEmpty() ? i18n("not set") : + const QString sn = card->serialNumber().mid(16, 12); + d->mSerialNumber->setText(sn); + d->mRealSerial = card->serialNumber(); + + const auto holder = card->cardHolder(); + const auto url = card->pubkeyUrl(); + d->mCardHolderLabel->setText(holder.isEmpty() ? i18n("not set") : holder); + d->mUrl = url; + d->mUrlLabel->setText(url.isEmpty() ? i18n("not set") : QStringLiteral("%1").arg(url.toHtmlEscaped())); - mUrlLabel->setOpenExternalLinks(true); + d->mUrlLabel->setOpenExternalLinks(true); - updateKey(mSigningKey, card->sigFpr()); - updateKey(mEncryptionKey, card->encFpr()); - updateKey(mAuthKey, card->authFpr()); - mCardIsEmpty = card->authFpr().empty() && card->sigFpr().empty() && card->encFpr().empty(); + updateKey(d->mSigningKey, card->sigFpr()); + updateKey(d->mEncryptionKey, card->encFpr()); + updateKey(d->mAuthKey, card->authFpr()); + d->mCardIsEmpty = card->authFpr().isEmpty() && card->sigFpr().isEmpty() && card->encFpr().isEmpty(); } void PGPCardWidget::doChangePin(int slot) { qCWarning(LIBKLEO_LOG) << "Not implemented."; } #ifdef GPGME_CAN_GENCARDKEY void PGPCardWidget::doGenKey(GenCardKeyDialog *dlg) { const auto params = dlg->getKeyParams(); auto progress = new QProgressDialog(this, Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::Dialog); progress->setAutoClose(true); progress->setMinimumDuration(0); progress->setMaximum(0); progress->setMinimum(0); progress->setModal(true); progress->setCancelButton(nullptr); progress->setWindowTitle(i18nc("@title:window", "Generating Keys")); - progress->setLabel(new QLabel(i18n("This may take several minutes..."))); - GenKeyThread *workerThread = new GenKeyThread(params, mRealSerial); + progress->setLabel(new QLabel(i18n("Thisd->may take several minutes..."))); + GenKeyThread *workerThread = new GenKeyThread(params,d->mRealSerial); connect(workerThread, &QThread::finished, this, [this, workerThread, progress] { progress->accept(); progress->deleteLater(); genKeyDone(workerThread->error(), workerThread->bkpFile()); delete workerThread; }); workerThread->start(); progress->exec(); } void PGPCardWidget::genKeyDone(const GpgME::Error &err, const std::string &backup) { if (err) { KMessageBox::error(this, i18nc("@info", "Failed to generate new key: %1", QString::fromLatin1(err.asString())), i18nc("@title", "Error")); return; } if (err.isCanceled()) { return; } if (!backup.empty()) { const auto bkpFile = QString::fromStdString(backup); QFileInfo fi(bkpFile); const auto target = QFileDialog::getSaveFileName(this, i18n("Save backup of encryption key"), fi.fileName(), QStringLiteral("%1 (*.gpg)").arg(i18n("Backup Key"))); if (!target.isEmpty() && !QFile::copy(bkpFile, target)) { KMessageBox::error(this, i18nc("@info", - "Failed to move backup. The backup key is still stored under: %1", bkpFile), + "Failed tod->move backup. The backup key is still stored under: %1", bkpFile), i18nc("@title", "Error")); } else if (!target.isEmpty()) { QFile::remove(bkpFile); } } KMessageBox::information(this, i18nc("@info", "Successfully generated a new key for this card."), i18nc("@title", "Success")); } #else void PGPCardWidget::doGenKey(GenCardKeyDialog *) {} void PGPCardWidget::genKeyDone(const GpgME::Error &, const std::string &) {} #endif void PGPCardWidget::genkeyRequested() { - if (!mCardIsEmpty) { + if (!d->mCardIsEmpty) { auto ret = KMessageBox::warningContinueCancel(this, i18n("The existing keys on this card will be deleted " "and replaced by new keys.") + QStringLiteral("

") + i18n("It will no longer be possible to decrypt past communication " "encrypted for the existing key."), i18n("Secret Key Deletion"), KStandardGuiItem::guiItem(KStandardGuiItem::Delete), KStandardGuiItem::cancel(), QString(), KMessageBox::Notify | KMessageBox::Dangerous); if (ret != KMessageBox::Continue) { return; } } GenCardKeyDialog *dlg = new GenCardKeyDialog(this); std::vector sizes; sizes.push_back(1024); sizes.push_back(2048); sizes.push_back(3072); // There is probably a better way to check for capabilities - if (mIs21) { + if (d->mIs21) { sizes.push_back(4096); } dlg->setSupportedSizes(sizes); connect(dlg, &QDialog::accepted, this, [this, dlg] () { doGenKey(dlg); dlg->deleteLater(); }); dlg->setModal(true); dlg->show(); } void PGPCardWidget::changePinResult(const GpgME::Error &err) { if (err) { KMessageBox::error(this, i18nc("@info", "PIN change failed: %1", QString::fromLatin1(err.asString())), i18nc("@title", "Error")); return; } if (!err.isCanceled()) { KMessageBox::information(this, i18nc("@info", "Code successfully changed."), i18nc("@title", "Success")); } } void PGPCardWidget::changeNameRequested() { - QString text = mCardHolderLabel->text(); + QString text =d->mCardHolderLabel->text(); while (true) { bool ok = false; text = QInputDialog::getText(this, i18n("Change cardholder"), i18n("New name:"), QLineEdit::Normal, text, &ok, Qt::WindowFlags(), Qt::ImhLatinOnly); if (!ok) { return; } // Some additional restrictions imposed by gnupg if (text.contains(QLatin1Char('<'))) { KMessageBox::error(this, i18nc("@info", - "The \"<\" character may not be used."), + "The \"<\" characterd->may not be used."), i18nc("@title", "Error")); continue; } if (text.contains(QLatin1String(" "))) { KMessageBox::error(this, i18nc("@info", "Double spaces are not allowed"), i18nc("@title", "Error")); continue; } if (text.size() > 38) { KMessageBox::error(this, i18nc("@info", - "The size of the name may not exceed 38 characters."), + "The size of the named->may not exceed 38 characters."), i18nc("@title", "Error")); } break; } auto parts = text.split(QLatin1Char(' ')); const auto lastName = parts.takeLast(); const QString formatted = lastName + QStringLiteral("<<") + parts.join(QLatin1Char('<')); #if 0 TODO libkleo-port ReaderStatus::mutableInstance() ->startSimpleTransaction(QStringLiteral("SCD SETATTR DISP-NAME %1").arg(formatted).toUtf8().constData(), this, "changeNameResult"); #endif } void PGPCardWidget::changeNameResult(const GpgME::Error &err) { if (err) { KMessageBox::error(this, i18nc("@info", "Name change failed: %1", QString::fromLatin1(err.asString())), i18nc("@title", "Error")); return; } if (!err.isCanceled()) { KMessageBox::information(this, i18nc("@info", "Name successfully changed."), i18nc("@title", "Success")); #if 0 TODO libkleo-port ReaderStatus::mutableInstance()->updateStatus(); #endif } } void PGPCardWidget::changeUrlRequested() { - QString text = mUrl; + QString text =d->mUrl; while (true) { bool ok = false; text = QInputDialog::getText(this, i18n("Change the URL where the pubkey can be found"), i18n("New pubkey URL:"), QLineEdit::Normal, text, &ok, Qt::WindowFlags(), Qt::ImhLatinOnly); if (!ok) { return; } // Some additional restrictions imposed by gnupg if (text.size() > 254) { KMessageBox::error(this, i18nc("@info", - "The size of the URL may not exceed 254 characters."), + "The size of the URLd->may not exceed 254 characters."), i18nc("@title", "Error")); } break; } #if 0 TODO libkleo-port ReaderStatus::mutableInstance() ->startSimpleTransaction(QStringLiteral("SCD SETATTR PUBKEY-URL %1").arg(text).toUtf8().constData(), this, "changeUrlResult"); #endif } void PGPCardWidget::changeUrlResult(const GpgME::Error &err) { if (err) { KMessageBox::error(this, i18nc("@info", "URL change failed: %1", QString::fromLatin1(err.asString())), i18nc("@title", "Error")); return; } if (!err.isCanceled()) { KMessageBox::information(this, i18nc("@info", "URL successfully changed."), i18nc("@title", "Success")); #if 0 TODO libkleo-port ReaderStatus::mutableInstance()->updateStatus(); #endif } } -void PGPCardWidget::updateKey(QLabel *label, const std::string &fpr) +void PGPCardWidget::updateKey(QLabel *label, const QString &fpr) { - label->setText(QString::fromStdString(fpr)); + label->setText(fpr); - if (fpr.empty()) { + if (fpr.isEmpty()) { label->setText(i18n("Slot empty")); return; } std::vector vec; - std::string keyid = fpr; + std::string keyid = fpr.toStdString(); keyid.erase(0, keyid.size() - 16); vec.push_back(keyid); const auto subkeys = KeyCache::instance()->findSubkeysByKeyID(vec); if (subkeys.empty() || subkeys[0].isNull()) { label->setToolTip(i18n("Public key not found.")); return; } QStringList toolTips; 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); } label->setToolTip(toolTips.join(QLatin1String("
"))); return; } #include "pgpcardwidget.moc" diff --git a/src/smartcard/pgpcardwidget.h b/src/smartcard/pgpcardwidget.h index 5d0c991..a28a2cd 100644 --- a/src/smartcard/pgpcardwidget.h +++ b/src/smartcard/pgpcardwidget.h @@ -1,88 +1,80 @@ /* smartcard/pgpcardwiget.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2017 by Bundesamt für Sicherheit in der Informationstechnik Software engineering by Intevation GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef VIEW_PGPCARDWIDGET_H #define VIEW_PGPCARDWIDGET_H #include #include #include +#include #include "kleo_export.h" class QLabel; namespace Kleo { class GenCardKeyDialog; namespace SmartCard { class OpenPGPCard; } // namespace SmartCard class KLEO_EXPORT PGPCardWidget: public QWidget { Q_OBJECT public: PGPCardWidget(); void setCard(const SmartCard::OpenPGPCard* card); void doChangePin(int slot); void doGenKey(GenCardKeyDialog *dlg); void genKeyDone(const GpgME::Error &err, const std::string &backup); public Q_SLOTS: void genkeyRequested(); void changePinResult(const GpgME::Error &err); void changeNameRequested(); void changeNameResult(const GpgME::Error &err); void changeUrlRequested(); void changeUrlResult(const GpgME::Error &err); private: - void updateKey(QLabel *label, const std::string &fpr); - QLabel *mSerialNumber = nullptr, - *mCardHolderLabel = nullptr, - *mVersionLabel = nullptr, - *mSigningKey = nullptr, - *mEncryptionKey = nullptr, - *mAuthKey = nullptr, - *mUrlLabel = nullptr; - QString mUrl; - bool mCardIsEmpty = false; - bool mIs21 = false; - std::string mRealSerial; + void updateKey(QLabel *label, const QString &fpr); + class Private; + std::shared_ptr d; }; } // namespace Kleo #endif // VIEW_PGPCARDWIDGET_H