Commit 33381833 authored by Ingo Klöcker's avatar Ingo Klöcker
Browse files

Generalize/simplify handling of common card info (e.g. app version)

Card:
* Add parseCardInfo() for parsing the common card infos APPVERSION,
  CARDTYPE, and CARDVERSION
* Add cardtype() and cardVersion() returning the parsed card info
* Add displayAppVersion() and displayCardVersion() returning nicely
  formatted version numbers

OpenPGPCard:
* Remove unused mIsV2
* Remove obsolete setSerialNumber() overload and obsolete cardVersion()
  and mCardVersion; the app version (confusingly named mCardVersion)
  is now read from the card info by the base class
* Rename setKeyPairInfo() to more appropriate setCardInfo() (also used
  for PIVCard)

PIVCard:
* Parsing of APPVERSION is now done by the base class

ReaderStatus:
* handle_openpgp_card: Use "LEARN --force" instead of
  "LEARN --keypairinfo" to also get common card infos

ChangePinCommand, PGPCardWidget:
* Simplify checks for certain app versions

PGPCardWidget, PIVCardWidget:
* Use Card::displayAppVersion() to get app version for display
parent d292d1dc
Pipeline #36152 passed with stage
in 13 minutes and 29 seconds
......@@ -117,19 +117,9 @@ void ChangePinCommand::Private::changePin()
QByteArrayList command;
command << "SCD PASSWD";
if (card->appName() == OpenPGPCard::AppName && keyRef == OpenPGPCard::resetCodeKeyRef()) {
if (card->appName() == OpenPGPCard::AppName && card->appVersion() >= 0x0200 && keyRef == OpenPGPCard::resetCodeKeyRef()) {
// special handling for setting/changing the Reset Code of OpenPGP v2 cards
const auto pgpCard = std::dynamic_pointer_cast<OpenPGPCard>(card);
if (!pgpCard) {
error(i18n("Failed to find the OpenPGP card with the serial number: %1", QString::fromStdString(serialNumber())));
finished();
return;
}
const std::string firstTwoVersionChars = pgpCard->cardVersion().substr(0, 2);
const bool isVersion2 = !(firstTwoVersionChars == "1." || firstTwoVersionChars == "0.");
if (isVersion2) {
command << "--reset";
}
command << "--reset";
}
command << QByteArray::fromStdString(keyRef);
ReaderStatus::mutableInstance()->startSimpleTransaction(card, command.join(' '), q, "slotResult");
......
......@@ -14,6 +14,28 @@
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()
{
}
......@@ -62,6 +84,26 @@ int Card::appVersion() const
return mAppVersion;
}
QString Card::displayAppVersion() const
{
return formatVersion(mAppVersion);
}
std::string Card::cardType() const
{
return mCardType;
}
int Card::cardVersion() const
{
return mCardVersion;
}
QString Card::displayCardVersion() const
{
return formatVersion(mCardVersion);
}
std::vector<Card::PinState> Card::pinStates() const
{
return mPinStates;
......@@ -117,3 +159,29 @@ QString Card::errorMsg() const
{
return mErrMsg;
}
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;
}
}
bool Card::parseCardInfo(const std::string &name, const std::string &value)
{
if (name == "APPVERSION") {
mAppVersion = parseHexEncodedVersionTuple(value);
return true;
} else if (name == "CARDTYPE") {
mCardType = value;
return true;
} else if (name == "CARDVERSION") {
mCardVersion = parseHexEncodedVersionTuple(value);
return true;
}
return false;
}
......@@ -54,13 +54,19 @@ public:
void setStatus(Status s);
Status status() const;
virtual void setSerialNumber(const std::string &sn);
void setSerialNumber(const std::string &sn);
std::string serialNumber() const;
std::string appName() const;
void setAppVersion(int version);
int appVersion() const;
QString displayAppVersion() const;
std::string cardType() const;
int cardVersion() const;
QString displayCardVersion() const;
std::vector<PinState> pinStates() const;
void setPinStates(const std::vector<PinState> &pinStates);
......@@ -77,6 +83,8 @@ public:
protected:
void setAppName(const std::string &name);
bool parseCardInfo(const std::string &name, const std::string &value);
private:
bool mCanLearn = false;
bool mHasNullPin = false;
......@@ -84,6 +92,8 @@ private:
std::string mSerialNumber;
std::string mAppName;
int mAppVersion = -1;
std::string mCardType;
int mCardVersion = -1;
std::vector<PinState> mPinStates;
QString mErrMsg;
};
......
......@@ -68,11 +68,14 @@ std::string OpenPGPCard::authFpr() const
return mMetaInfo.value("AUTHKEY-FPR");
}
void OpenPGPCard::setKeyPairInfo(const std::vector< std::pair<std::string, std::string> > &infos)
void OpenPGPCard::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();
if (parseCardInfo(pair.first, pair.second)) {
continue;
}
if (pair.first == "KEY-FPR" ||
pair.first == "KEY-TIME") {
// Key fpr and key time need to be distinguished, the number
......@@ -121,35 +124,6 @@ void OpenPGPCard::setKeyPairInfo(const std::vector< std::pair<std::string, std::
}
}
void OpenPGPCard::setSerialNumber(const std::string &serialno)
{
char version_buffer[6];
const char *version = "";
Card::setSerialNumber(serialno);
const bool isProperOpenPGPCardSerialNumber =
serialno.size() == 32 && serialno.substr(0, 12) == "D27600012401";
if (isProperOpenPGPCardSerialNumber) {
/* Reformat the version number to be better human readable. */
const char *string = serialno.c_str();
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;
}
mIsV2 = !((*version == '1' || *version == '0') && version[1] == '.');
mCardVersion = version;
}
bool OpenPGPCard::operator == (const Card& rhs) const
{
const OpenPGPCard *other = dynamic_cast<const OpenPGPCard *>(&rhs);
......@@ -162,7 +136,6 @@ bool OpenPGPCard::operator == (const Card& rhs) const
&& encFpr() == other->encFpr()
&& authFpr() == other->authFpr()
&& manufacturer() == other->manufacturer()
&& cardVersion() == other->cardVersion()
&& cardHolder() == other->cardHolder()
&& pubkeyUrl() == other->pubkeyUrl();
}
......@@ -177,11 +150,6 @@ std::string OpenPGPCard::manufacturer() const
return mManufacturer;
}
std::string OpenPGPCard::cardVersion() const
{
return mCardVersion;
}
std::string OpenPGPCard::cardHolder() const
{
auto list = QString::fromStdString(mMetaInfo.value("DISP-NAME")).split(QStringLiteral("<<"));
......
......@@ -29,25 +29,20 @@ public:
static std::string adminPinKeyRef();
static std::string resetCodeKeyRef();
void setSerialNumber(const std::string &sn) override;
std::string encFpr() const;
std::string sigFpr() const;
std::string authFpr() const;
void setKeyPairInfo (const std::vector< std::pair<std::string, std::string> > &infos);
void setCardInfo(const std::vector< std::pair<std::string, std::string> > &infos);
bool operator == (const Card& other) const override;
void setManufacturer(const std::string &manufacturer);
std::string manufacturer() const;
std::string cardVersion() const;
std::string cardHolder() const;
std::string pubkeyUrl() const;
private:
bool mIsV2 = false;
std::string mCardVersion;
QMap <std::string, std::string> mMetaInfo;
std::string mManufacturer;
};
......
......@@ -118,23 +118,15 @@ std::string PIVCard::keyGrip(const std::string& keyRef) const
return mMetaInfo.value("KEYPAIRINFO-" + keyRef);
}
namespace {
static int parseAppVersion(const std::string &s) {
// s is a hex-encoded, unsigned int-packed version tuple
bool ok;
const auto appVersion = QByteArray::fromStdString(s).toUInt(&ok, 16);
return ok ? appVersion : -1;
}
}
void PIVCard::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();
if (pair.first == "APPVERSION") {
setAppVersion(parseAppVersion(pair.second));
} else if (pair.first == "KEYPAIRINFO") {
if (parseCardInfo(pair.first, pair.second)) {
continue;
}
if (pair.first == "KEYPAIRINFO") {
const KeyPairInfo info = KeyPairInfo::fromStatusLine(pair.second);
if (info.grip.empty()) {
qCWarning(KLEOPATRA_LOG) << "Invalid KEYPAIRINFO status line"
......
......@@ -39,7 +39,7 @@ public:
std::string keyGrip(const std::string &keyRef) const;
void setCardInfo (const std::vector< std::pair<std::string, std::string> > &infos);
void setCardInfo(const std::vector< std::pair<std::string, std::string> > &infos);
std::string displaySerialNumber() const;
void setDisplaySerialNumber(const std::string &sn);
......
......@@ -341,12 +341,12 @@ static void handle_openpgp_card(std::shared_ptr<Card> &ci, std::shared_ptr<Conte
pgpCard->setManufacturer(get_openpgp_card_manufacturer_from_serial_number(ci->serialNumber()));
}
const auto info = gpgagent_statuslines(gpg_agent, "SCD LEARN --keypairinfo", err);
const auto info = gpgagent_statuslines(gpg_agent, "SCD LEARN --force", err);
if (err.code()) {
ci->setStatus(Card::CardError);
return;
}
pgpCard->setKeyPairInfo(info);
pgpCard->setCardInfo(info);
ci.reset(pgpCard);
}
......
......@@ -208,9 +208,9 @@ PGPCardWidget::PGPCardWidget(QWidget *parent):
void PGPCardWidget::setCard(const OpenPGPCard *card)
{
const QString version = QString::fromStdString(card->cardVersion());
const QString version = card->displayAppVersion();
mIs21 = versionIsAtLeast("2.1", card->cardVersion().c_str());
mIs21 = card->appVersion() >= 0x0201;
const QString manufacturer = QString::fromStdString(card->manufacturer());
const bool manufacturerIsUnknown = manufacturer.isEmpty() || manufacturer == QLatin1String("unknown");
mVersionLabel->setText(manufacturerIsUnknown ?
......
......@@ -41,26 +41,6 @@ using namespace Kleo::Commands;
using namespace Kleo::SmartCard;
namespace {
static QString formatVersion(int value)
{
if (value < 0) {
return QLatin1String("n/a");
}
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);
}
static void layoutKeyWidgets(QGridLayout *grid, const QString &keyName, const PIVCardWidget::KeyWidgets &keyWidgets)
{
int row = grid->rowCount();
......@@ -231,11 +211,12 @@ PIVCardWidget::~PIVCardWidget()
void PIVCardWidget::setCard(const PIVCard *card)
{
mCardSerialNumber = card->serialNumber();
mVersionLabel->setText(i18nc("%1 version number", "PIV v%1 card", formatVersion(card->appVersion())));
mVersionLabel->setText(i18nc("%1 version number", "PIV v%1 card", card->displayAppVersion()));
if (card->displaySerialNumber() != card->serialNumber()) {
mSerialNumber->setText(QStringLiteral("%1 (%2)").arg(QString::fromStdString(card->displaySerialNumber()),
QString::fromStdString(card->serialNumber())));
mSerialNumber->setText(i18nc("%1 nice serial number, %2 real serial number", "%1 (%2)",
QString::fromStdString(card->displaySerialNumber()),
QString::fromStdString(card->serialNumber())));
} else {
mSerialNumber->setText(QString::fromStdString(card->serialNumber()));
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment