Page MenuHome GnuPG

card.cpp
No OneTemporary

card.cpp

/* 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"
#include <KLocalizedString>
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()
{
}
Card *Card::clone() const
{
return new Card{*this};
}
void Card::setAppType(AppType app)
{
mAppType = app;
}
AppType Card::appType() const
{
return mAppType;
}
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;
}
QString Card::publicKeyUrl() const
{
return QString::fromStdString(cardInfo("PUBKEY-URL"));
}
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::PinState> Card::pinStates() const
{
return mPinStates;
}
void Card::setPinStates(const std::vector<PinState> &pinStates)
{
mPinStates = pinStates;
}
bool Card::hasNKSNullPin() const
{
static const std::string forceNullPinSerialNumber = qgetenv("KLEO_FORCE_NULLPIN").toStdString();
if (mAppType != AppType::NetKeyApp) {
return false;
}
if (serialNumber() == forceNullPinSerialNumber) {
return true;
}
if (mPinStates.size() < 2) {
qCWarning(KLEOPATRA_LOG) << "Invalid size of pin states:" << mPinStates.size();
return false;
}
return mPinStates[0] == Card::NullPin;
}
bool Card::hasSigGNullPin() const
{
if (mAppType != AppType::NetKeyApp) {
return false;
}
if (mPinStates.size() < 4) {
qCWarning(KLEOPATRA_LOG) << "Invalid size of pin states:" << mPinStates.size();
return false;
}
return mPinStates[2] == Card::NullPin;
}
bool Card::operator==(const Card &other) const
{
return 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 && mPinCounters == other.mPinCounters
&& mPinLabels == other.mPinLabels && mAppType == other.mAppType;
}
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<KeyPairInfo> &infos)
{
mKeyInfos = infos;
}
const std::vector<KeyPairInfo> &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;
}
std::vector<int> Card::pinCounters() const
{
return mPinCounters;
}
QStringList Card::pinLabels() const
{
return mPinLabels;
}
void Card::setCardInfo(const std::vector<std::pair<std::string, std::string>> &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);
}
}
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;
}
static auto parseIntegerValues(const std::string &s)
{
const auto strings = QByteArray::fromStdString(s).simplified().split(' ');
std::vector<int> values;
values.reserve(strings.size());
std::ranges::transform(strings, std::back_inserter(values), [](const auto &s) {
return s.toInt();
});
return values;
}
}
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 if (name == "CHV-STATUS") {
mPinCounters = parseIntegerValues(value);
if (mAppName == "openpgp") {
// for OpenPGP cards the PIN retry counters are the last 3 (of 7) integers
if (mPinCounters.size() == 7) {
mPinCounters.erase(mPinCounters.begin(), mPinCounters.begin() + 4);
if (mPinLabels.empty()) {
mPinLabels = {
i18nc("@label PIN to unlock the smart card for user operations", "PIN"),
i18nc("@label PIN/Key to unblock/reset the normal PIN", "PUK"),
i18nc("@label PIN to unlock the smart card for administrative operations", "Admin PIN"),
};
}
} else {
qCDebug(KLEOPATRA_LOG) << "Invalid CHV-STATUS value. Expected 7 integers, but got" << value;
mPinCounters.clear();
}
}
qCDebug(KLEOPATRA_LOG) << "PIN counters:" << mPinCounters;
} else if (name == "CHV-LABEL") {
mPinLabels = QString::fromStdString(value).split(u' ', Qt::SkipEmptyParts);
qCDebug(KLEOPATRA_LOG) << "PIN labels:" << mPinLabels;
} else {
mCardInfo.insert({name, value});
}
if (!mPinLabels.empty() && !mPinCounters.empty() && (static_cast<int>(mPinLabels.size()) != static_cast<int>(mPinCounters.size()))) {
qCDebug(KLEOPATRA_LOG) << "Number of PIN labels does not match number of PIN counters. Clearing labels.";
mPinLabels.clear();
}
}
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);
}
void Card::setDisplayAppName(const QString &displayAppName)
{
mDisplayAppName = displayAppName;
}
QString Card::displayAppName() const
{
return mDisplayAppName;
}
std::string Card::certificateData(const std::string &keyRef) const
{
return cardInfo("KLEO-CERTIFICATE-" + keyRef);
}
void Card::setCertificateData(const std::string &keyRef, const std::string &data)
{
addCardInfo("KLEO-CERTIFICATE-" + keyRef, data);
}

File Metadata

Mime Type
text/x-c
Expires
Tue, Dec 9, 1:27 AM (1 d, 13 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
b2/26/f1e329d316fa5ac717fcb0504625

Event Timeline