diff --git a/src/smartcard/card.cpp b/src/smartcard/card.cpp index cd35fbe16..c1bcecd8c 100644 --- a/src/smartcard/card.cpp +++ b/src/smartcard/card.cpp @@ -1,371 +1,346 @@ /* smartcard/card.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2017 Bundesamt für Sicherheit in der Informationstechnik SPDX-FileContributor: Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #include "card.h" #include "readerstatus.h" #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::SmartCard; namespace { static QString formatVersion(int value) { if (value < 0) { return QString(); } const unsigned int a = ((value >> 24) & 0xff); const unsigned int b = ((value >> 16) & 0xff); const unsigned int c = ((value >> 8) & 0xff); const unsigned int d = ((value ) & 0xff); if (a) { return QStringLiteral("%1.%2.%3.%4").arg(QString::number(a), QString::number(b), QString::number(c), QString::number(d)); } else if (b) { return QStringLiteral("%1.%2.%3").arg(QString::number(b), QString::number(c), QString::number(d)); } else if (c) { return QStringLiteral("%1.%2").arg(QString::number(c), QString::number(d)); } return QString::number(d); } } Card::Card() { } Card::~Card() { } void Card::setStatus(Status s) { mStatus = s; } Card::Status Card::status() const { return mStatus; } void Card::setSerialNumber(const std::string &sn) { mSerialNumber = sn; } std::string Card::serialNumber() const { return mSerialNumber; } QString Card::displaySerialNumber() const { return mDisplaySerialNumber; } void Card::setDisplaySerialNumber(const QString &serialNumber) { mDisplaySerialNumber = serialNumber; } std::string Card::appName() const { return mAppName; } void Card::setAppName(const std::string &name) { mAppName = name; } void Card::setAppVersion(int version) { mAppVersion = version; } int Card::appVersion() const { return mAppVersion; } QString Card::displayAppVersion() const { return formatVersion(mAppVersion); } void Card::setManufacturer(const std::string &value) { if (!manufacturer().empty()) { qCDebug(KLEOPATRA_LOG) << "Card manufacturer is already set; overwriting existing value"; mCardInfo.erase("MANUFACTURER"); } mCardInfo.insert({"MANUFACTURER", value}); } std::string Card::manufacturer() const { return cardInfo("MANUFACTURER"); } std::string Card::cardType() const { return mCardType; } int Card::cardVersion() const { return mCardVersion; } QString Card::displayCardVersion() const { return formatVersion(mCardVersion); } QString Card::cardHolder() const { return mCardHolder; } void Card::setSigningKeyRef(const std::string &keyRef) { mSigningKeyRef = keyRef; } std::string Card::signingKeyRef() const { return mSigningKeyRef; } bool Card::hasSigningKey() const { return !keyInfo(mSigningKeyRef).grip.empty(); } void Card::setEncryptionKeyRef(const std::string &keyRef) { mEncryptionKeyRef = keyRef; } std::string Card::encryptionKeyRef() const { return mEncryptionKeyRef; } bool Card::hasEncryptionKey() const { return !keyInfo(mEncryptionKeyRef).grip.empty(); } void Card::setAuthenticationKeyRef(const std::string &keyRef) { mAuthenticationKeyRef = keyRef; } std::string Card::authenticationKeyRef() const { return mAuthenticationKeyRef; } bool Card::hasAuthenticationKey() const { return !keyInfo(mAuthenticationKeyRef).grip.empty(); } std::vector Card::pinStates() const { return mPinStates; } void Card::setPinStates(const std::vector &pinStates) { mPinStates = pinStates; } bool Card::hasNullPin() const { return mHasNullPin; } void Card::setHasNullPin(bool value) { mHasNullPin = value; } bool Card::canLearnKeys() const { return mCanLearn; } void Card::setCanLearnKeys(bool value) { mCanLearn = value; } -bool Card::operator == (const Card &other) const -{ - return mCanLearn == other.mCanLearn - && mHasNullPin == other.mHasNullPin - && mStatus == other.mStatus - && mSerialNumber == other.mSerialNumber - && mAppName == other.mAppName - && mAppVersion == other.mAppVersion - && mCardType == other.mCardType - && mCardVersion == other.mCardVersion - && mCardHolder == other.mCardHolder - && mSigningKeyRef == other.mSigningKeyRef - && mEncryptionKeyRef == other.mEncryptionKeyRef - && mAuthenticationKeyRef == other.mAuthenticationKeyRef - && mPinStates == other.mPinStates - && mErrMsg == other.mErrMsg - && mKeyInfos == other.mKeyInfos - && mCardInfo == other.mCardInfo; -} - -bool Card::operator != (const Card &other) const -{ - return !operator==(other); -} - void Card::setErrorMsg(const QString &msg) { mErrMsg = msg; } QString Card::errorMsg() const { return mErrMsg; } void Card::setInitialKeyInfos(const std::vector &infos) { mKeyInfos = infos; } const std::vector & Card::keyInfos() const { return mKeyInfos; } const KeyPairInfo & Card::keyInfo(const std::string &keyRef) const { static const KeyPairInfo nullKey; for (const KeyPairInfo &k : mKeyInfos) { if (k.keyRef == keyRef) { return k; } } return nullKey; } void Card::setCardInfo(const std::vector> &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); } processCardInfo(); } namespace { static int parseHexEncodedVersionTuple(const std::string &s) { // s is a hex-encoded, unsigned int-packed version tuple, // i.e. each byte represents one part of the version tuple bool ok; const auto version = QByteArray::fromStdString(s).toUInt(&ok, 16); return ok ? version : -1; } } void Card::parseCardInfo(const std::string &name, const std::string &value) { if (name == "APPVERSION") { mAppVersion = parseHexEncodedVersionTuple(value); } else if (name == "CARDTYPE") { mCardType = value; } else if (name == "CARDVERSION") { mCardVersion = parseHexEncodedVersionTuple(value); } else if (name == "DISP-NAME") { auto list = QString::fromUtf8(QByteArray::fromStdString(value)). split(QStringLiteral("<<"), Qt::SkipEmptyParts); std::reverse(list.begin(), list.end()); mCardHolder = list.join(QLatin1Char(' ')).replace(QLatin1Char('<'), QLatin1Char(' ')); } else if (name == "KEYPAIRINFO") { const KeyPairInfo info = KeyPairInfo::fromStatusLine(value); if (info.grip.empty()) { qCWarning(KLEOPATRA_LOG) << "Invalid KEYPAIRINFO status line" << QString::fromStdString(value); setStatus(Card::CardError); } else { updateKeyInfo(info); } } else if (name == "KEY-FPR") { // handle OpenPGP key fingerprints const auto values = QString::fromStdString(value).split(QLatin1Char(' ')); if (values.size() < 2) { qCWarning(KLEOPATRA_LOG) << "Invalid KEY-FPR status line" << QString::fromStdString(value); setStatus(Card::CardError); } 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')) { addCardInfo("KLEO-FPR-" + keyRef, fpr); } else { // Maybe more keyslots in the future? qCDebug(KLEOPATRA_LOG) << "Unhandled keyslot" << keyNumber; } } else if (name == "MANUFACTURER") { // the value of MANUFACTURER is the manufacturer ID as unsigned number // optionally followed by the name of the manufacturer, e.g. // 6 Yubico // 65534 unmanaged S/N range // for PKCS#15 cards the manufacturer ID is always 0, e.g. // 0 www.atos.net/cardos [R&S] const auto startOfManufacturerName = value.find(' '); if (startOfManufacturerName != std::string::npos) { addCardInfo(name, value.substr(startOfManufacturerName + 1)); } } else { mCardInfo.insert({name, value}); } } void Card::processCardInfo() { } void Card::addCardInfo(const std::string &name, const std::string &value) { mCardInfo.insert({name, value}); } std::string Card::cardInfo(const std::string &name) const { const auto range = mCardInfo.equal_range(name); return range.first != range.second ? range.first->second : std::string(); } void Card::updateKeyInfo(const KeyPairInfo& keyPairInfo) { for (KeyPairInfo &k : mKeyInfos) { if (k.keyRef == keyPairInfo.keyRef) { k.update(keyPairInfo); return; } } mKeyInfos.push_back(keyPairInfo); } std::string Card::keyFingerprint(const std::string &keyRef) const { return cardInfo("KLEO-FPR-" + keyRef); } diff --git a/src/smartcard/card.h b/src/smartcard/card.h index f65fa75a9..368304f45 100644 --- a/src/smartcard/card.h +++ b/src/smartcard/card.h @@ -1,148 +1,147 @@ #pragma once /* smartcard/card.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2017 Bundesamt für Sicherheit in der Informationstechnik SPDX-FileContributor: Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #include "keypairinfo.h" #include #include #include #include namespace Kleo { namespace SmartCard { /** Class representing an application on a smartcard or similar hardware token. */ class Card { public: enum PinState { UnknownPinState, NullPin, PinBlocked, NoPin, PinOk, NumPinStates }; enum Status { NoCard, CardPresent, CardActive, CardUsable, _NumScdStates, CardError = _NumScdStates, NumStates }; Card(); virtual ~Card(); - virtual bool operator == (const Card &other) const; - bool operator != (const Card &other) const; + bool operator==(const Card &) const = default; void setStatus(Status s); Status status() const; void setSerialNumber(const std::string &sn); std::string serialNumber() const; void setCardInfo(const std::vector> &infos); QString displaySerialNumber() const; void setDisplaySerialNumber(const QString &sn); std::string appName() const; void setAppVersion(int version); int appVersion() const; QString displayAppVersion() const; void setManufacturer(const std::string &manufacturer); std::string manufacturer() const; std::string cardType() const; int cardVersion() const; QString displayCardVersion() const; QString cardHolder() const; void setSigningKeyRef(const std::string &keyRef); std::string signingKeyRef() const; bool hasSigningKey() const; void setEncryptionKeyRef(const std::string &keyRef); std::string encryptionKeyRef() const; bool hasEncryptionKey() const; void setAuthenticationKeyRef(const std::string &keyRef); std::string authenticationKeyRef() const; bool hasAuthenticationKey() const; std::vector pinStates() const; void setPinStates(const std::vector &pinStates); bool hasNullPin() const; void setHasNullPin(bool value); bool canLearnKeys() const; void setCanLearnKeys(bool value); QString errorMsg() const; void setErrorMsg(const QString &msg); const std::vector & keyInfos() const; const KeyPairInfo & keyInfo(const std::string &keyRef) const; std::string keyFingerprint(const std::string &keyRef) const; protected: void setAppName(const std::string &name); void setInitialKeyInfos(const std::vector &infos); virtual void processCardInfo(); void addCardInfo(const std::string &name, const std::string &value); std::string cardInfo(const std::string &name) const; private: void parseCardInfo(const std::string &name, const std::string &value); void updateKeyInfo(const KeyPairInfo &keyPairInfo); private: bool mCanLearn = false; bool mHasNullPin = false; Status mStatus = NoCard; std::string mSerialNumber; QString mDisplaySerialNumber; std::string mAppName; int mAppVersion = -1; std::string mCardType; int mCardVersion = -1; QString mCardHolder; std::string mSigningKeyRef; std::string mEncryptionKeyRef; std::string mAuthenticationKeyRef; std::vector mPinStates; QString mErrMsg; std::vector mKeyInfos; std::multimap mCardInfo; }; } // namespace Smartcard } // namespace Kleopatra diff --git a/src/smartcard/keypairinfo.cpp b/src/smartcard/keypairinfo.cpp index f9db8eada..602ddfd87 100644 --- a/src/smartcard/keypairinfo.cpp +++ b/src/smartcard/keypairinfo.cpp @@ -1,100 +1,84 @@ /* smartcard/keypairinfo.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include "keypairinfo.h" #include #include using namespace Kleo::SmartCard; // static KeyPairInfo KeyPairInfo::fromStatusLine(const std::string &s) { // The format of a KEYPAIRINFO line is // KEYPAIRINFO [usage] [keytime] [algostr] // The string s does not contain the leading "KEYPAIRINFO ". KeyPairInfo info; const auto values = QString::fromStdString(s).split(QLatin1Char(' ')); if (values.size() < 2) { return info; } info.grip = values[0].toStdString(); info.keyRef = values[1].toStdString(); if (values.size() >= 3) { info.usage = values[2].toStdString(); } if (values.size() >= 4) { info.keyTime = values[3].toStdString(); } if (values.size() >= 5) { info.algorithm = values[4].toStdString(); } return info; } bool KeyPairInfo::canAuthenticate() const { return usage.find('a') != std::string::npos; } bool KeyPairInfo::canCertify() const { return usage.find('c') != std::string::npos; } bool KeyPairInfo::canEncrypt() const { return usage.find('e') != std::string::npos; } bool KeyPairInfo::canSign() const { return usage.find('s') != std::string::npos; } void KeyPairInfo::update(const KeyPairInfo &other) { Q_ASSERT(keyRef == other.keyRef); if (keyRef != other.keyRef) { return; } if (grip != other.grip) { // reset all infos if the grip changed grip = other.grip; usage = std::string(); keyTime = std::string(); algorithm = std::string(); } // now update all infos from other's infos unless other's infos are empty or not specified if (!other.usage.empty() && other.usage != "-") { usage = other.usage; } if (!other.keyTime.empty() && other.keyTime != "-") { keyTime = other.keyTime; } if (!other.algorithm.empty() && other.algorithm != "-") { algorithm = other.algorithm; } } - -// C++20: Replace with defaulted equality operator -bool KeyPairInfo::operator==(const KeyPairInfo &other) const -{ - return keyRef == other.keyRef - && grip == other.grip - && usage == other.usage - && keyTime == other.keyTime - && algorithm == other.algorithm; -} - -// C++20: Remove -bool KeyPairInfo::operator!=(const KeyPairInfo &other) const -{ - return !operator==(other); -} diff --git a/src/smartcard/keypairinfo.h b/src/smartcard/keypairinfo.h index 13ac732a6..fac73c6bc 100644 --- a/src/smartcard/keypairinfo.h +++ b/src/smartcard/keypairinfo.h @@ -1,38 +1,37 @@ /* smartcard/keypairinfo.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include namespace Kleo { namespace SmartCard { struct KeyPairInfo { static KeyPairInfo fromStatusLine(const std::string &s); bool canAuthenticate() const; bool canCertify() const; bool canEncrypt() const; bool canSign() const; void update(const KeyPairInfo &other); - bool operator==(const KeyPairInfo &other) const; - bool operator!=(const KeyPairInfo &other) const; + bool operator==(const KeyPairInfo &) const = default; std::string keyRef; std::string grip; std::string usage; std::string keyTime; std::string algorithm; }; } // namespace Smartcard } // namespace Kleopatra