From 2e6f94f6308544a1df64d09966a7d1af5ab92502 Mon Sep 17 00:00:00 2001 From: Raul Metsma Date: Wed, 9 Oct 2024 12:36:36 +0300 Subject: [PATCH] Fetch birth date from certificate when missing IB-8131 Signed-off-by: Raul Metsma --- client/QSmartCard.cpp | 75 +++++++++++++++++++++---------------------- client/QSmartCard.h | 20 ++++++------ client/QSmartCard_p.h | 3 -- 3 files changed, 46 insertions(+), 52 deletions(-) diff --git a/client/QSmartCard.cpp b/client/QSmartCard.cpp index a65562b6..c1cebe67 100644 --- a/client/QSmartCard.cpp +++ b/client/QSmartCard.cpp @@ -19,6 +19,7 @@ #include "QSmartCard_p.h" +#include "IKValidator.h" #include "QCardLock.h" #include "Settings.h" #include "Utils.h" @@ -26,10 +27,8 @@ #include "dialogs/PinUnblock.h" #include -#include #include #include -#include #include Q_LOGGING_CATEGORY(CLog, "qdigidoc4.QSmartCard") @@ -87,8 +86,6 @@ QString QSmartCardData::typeString(QSmartCardData::PinType type) return {}; } -const QByteArray Card::MASTER_FILE = APDU("00A4000C"); -const QByteArray Card::MUTUAL_AUTH = APDU("00880000 00 00"); const QByteArray Card::CHANGE = APDU("00240000 00"); const QByteArray Card::READBINARY = APDU("00B00000 00"); const QByteArray Card::REPLACE = APDU("002C0000 00"); @@ -111,7 +108,7 @@ QPCSCReader::Result Card::transfer(QPCSCReader *reader, bool verify, const QByte QHash Card::parseFCI(const QByteArray &data) { QHash result; - for(QByteArray::const_iterator i = data.constBegin(); i != data.constEnd(); ++i) + for(auto i = data.constBegin(); i != data.constEnd(); ++i) { quint8 tag(*i), size(*++i); result[tag] = QByteArray(i + 1, size); @@ -129,7 +126,7 @@ QHash Card::parseFCI(const QByteArray &data) -const QByteArray IDEMIACard::AID = APDU("00A40400 10 A000000077010800070000FE00000100"); +const QByteArray IDEMIACard::AID = APDU("00A4040C 10 A000000077010800070000FE00000100"); const QByteArray IDEMIACard::AID_OT = APDU("00A4040C 0D E828BD080FF2504F5420415750"); const QByteArray IDEMIACard::AID_QSCD = APDU("00A4040C 10 51534344204170706C69636174696F6E"); @@ -163,13 +160,10 @@ bool IDEMIACard::isSupported(const QByteArray &atr) bool IDEMIACard::loadPerso(QPCSCReader *reader, QSmartCardDataPrivate *d) const { - if(!reader->transfer(AID) || - !reader->transfer(MASTER_FILE)) - return false; - if(d->data.isEmpty() && reader->transfer(APDU("00A4010C025000"))) + if(d->data.isEmpty() && reader->transfer(APDU("00A4090C 04 3F00 5000"))) { - QByteArray cmd = APDU("00A4020C025001"); - for(char data = 1; data <= 8; ++data) + QByteArray cmd = APDU("00A4020C 02 5001"); + for(char data = QSmartCardData::SurName; data <= QSmartCardData::Expiry; ++data) { cmd[6] = data; if(!reader->transfer(cmd)) @@ -182,38 +176,40 @@ bool IDEMIACard::loadPerso(QPCSCReader *reader, QSmartCardDataPrivate *d) const record.clear(); switch(data) { - case 1: d->data[QSmartCardData::SurName] = record; break; - case 2: d->data[QSmartCardData::FirstName] = record; break; - case 4: d->data[QSmartCardData::Citizen] = record; break; - case 5: + case QSmartCardData::SurName: + case QSmartCardData::FirstName: + case QSmartCardData::Citizen: + case QSmartCardData::Id: + case QSmartCardData::DocumentId: + d->data[QSmartCardData::PersonalDataType(data)] = record; + break; + case QSmartCardData::BirthDate: if(!record.isEmpty()) - { - QStringList data = record.split(' '); - if(data.size() > 3) - data.removeLast(); - d->data[QSmartCardData::BirthDate] = QDate::fromString(data.join('.'), QStringLiteral("dd.MM.yyyy")); - } + d->data[QSmartCardData::BirthDate] = QDate::fromString(record.left(10), QStringLiteral("dd MM yyyy")); + break; + case QSmartCardData::Expiry: + d->data[QSmartCardData::Expiry] = QDateTime::fromString(record, QStringLiteral("dd MM yyyy")).addDays(1).addSecs(-1); break; - case 6: d->data[QSmartCardData::Id] = record; break; - case 7: d->data[QSmartCardData::DocumentId] = record; break; - case 8: d->data[QSmartCardData::Expiry] = QDateTime::fromString(record, QStringLiteral("dd MM yyyy")).addDays(1).addSecs(-1); break; default: break; } } } bool readFailed = false; - auto readCert = [&](const QByteArray &file1, const QByteArray &file2) { - if(!reader->transfer(MASTER_FILE) || !reader->transfer(file1)) + auto readCert = [&](const QByteArray &path) { + QPCSCReader::Result data = reader->transfer(path); + if(!data) { readFailed = true; return QSslCertificate(); } - QPCSCReader::Result data = reader->transfer(file2); - if(!data) - return QSslCertificate(); QHash fci = parseFCI(data.data); - int size = fci.contains(0x80) ? quint8(fci[0x80][0]) << 8 | quint8(fci[0x80][1]) : 0x0600; + if(!fci.contains(0x80)) + { + readFailed = true; + return QSslCertificate(); + } + int size = quint8(fci[0x80][0]) << 8 | quint8(fci[0x80][1]); QByteArray cert; QByteArray cmd = READBINARY; while(cert.size() < size) @@ -231,9 +227,11 @@ bool IDEMIACard::loadPerso(QPCSCReader *reader, QSmartCardDataPrivate *d) const return QSslCertificate(cert, QSsl::Der); }; if(d->authCert.isNull()) - d->authCert = readCert(APDU("00A4010C02ADF1"), APDU("00A4020402340100")); + d->authCert = readCert(APDU("00A40904 06 3F00 ADF1 3401 00")); if(d->signCert.isNull()) - d->signCert = readCert(APDU("00A4010C02ADF2"), APDU("00A4020402341F00")); + d->signCert = readCert(APDU("00A40904 06 3F00 ADF2 341F 00")); + if(!d->data.contains(QSmartCardData::BirthDate) && !d->authCert.isNull()) + d->data[QSmartCardData::BirthDate] = IKValidator::birthDate(d->authCert.personalCode()); if(readFailed) return false; @@ -269,7 +267,7 @@ QPCSCReader::Result IDEMIACard::replace(QPCSCReader *reader, QSmartCardData::Pin cmd[3] = char(0x85); } else - cmd[3] = type; + cmd[3] = char(type); QByteArray pin = pinTemplate(pin_); cmd[4] = char(pin.size()); return transfer(reader, false, cmd + pin, type, 0, false); @@ -280,7 +278,7 @@ QByteArray IDEMIACard::sign(QPCSCReader *reader, const QByteArray &dgst) const if(!reader->transfer(AID_OT) || !reader->transfer(APDU("002241A4 09 8004FF200800840181"))) return {}; - QByteArray cmd = MUTUAL_AUTH; + QByteArray cmd = APDU("00880000 00 00"); cmd[4] = char(std::min(size_t(dgst.size()), 0x30)); cmd.insert(5, dgst.left(0x30)); return reader->transfer(cmd).data; @@ -289,12 +287,12 @@ QByteArray IDEMIACard::sign(QPCSCReader *reader, const QByteArray &dgst) const bool IDEMIACard::updateCounters(QPCSCReader *reader, QSmartCardDataPrivate *d) const { reader->transfer(AID); - if(auto data = reader->transfer(APDU("00CB3FFF 0A 4D087006BF810102A08000"))) + if(auto data = reader->transfer(APDU("00CB3FFF 0A 4D087006BF810102A080 00"))) d->retry[QSmartCardData::Pin1Type] = quint8(data.data[13]); - if(auto data = reader->transfer(APDU("00CB3FFF 0A 4D087006BF810202A08000"))) + if(auto data = reader->transfer(APDU("00CB3FFF 0A 4D087006BF810202A080 00"))) d->retry[QSmartCardData::PukType] = quint8(data.data[13]); reader->transfer(AID_QSCD); - if(auto data = reader->transfer(APDU("00CB3FFF 0A 4D087006BF810502A08000"))) + if(auto data = reader->transfer(APDU("00CB3FFF 0A 4D087006BF810502A080 00"))) d->retry[QSmartCardData::Pin2Type] = quint8(data.data[13]); return true; } @@ -471,7 +469,6 @@ void QSmartCard::reloadCard(const TokenData &token, bool reloadCounters) t = d->t.d; t->reader = selectedReader->name(); t->pinpad = selectedReader->isPinPad(); - d->card.reset(); d->card = std::make_unique(); if(d->card->loadPerso(selectedReader.data(), t)) { diff --git a/client/QSmartCard.h b/client/QSmartCard.h index d1d14575..6aa97848 100644 --- a/client/QSmartCard.h +++ b/client/QSmartCard.h @@ -32,17 +32,17 @@ class TokenData; class QSmartCardData { public: - enum PersonalDataType + enum PersonalDataType : char { - SurName, - FirstName, - Citizen, - BirthDate, - Id, - DocumentId, - Expiry, + SurName = 1, + FirstName = 2, + Citizen = 4, + BirthDate = 5, + Id = 6, + DocumentId = 7, + Expiry = 8, }; - enum PinType + enum PinType : char { Pin1Type = 1, Pin2Type, @@ -84,7 +84,7 @@ class QSmartCard final: public QObject { Q_OBJECT public: - enum ErrorType + enum ErrorType : quint8 { NoError, UnknownError, diff --git a/client/QSmartCard_p.h b/client/QSmartCard_p.h index 13780bad..f9f61a77 100644 --- a/client/QSmartCard_p.h +++ b/client/QSmartCard_p.h @@ -44,8 +44,6 @@ class Card static QHash parseFCI(const QByteArray &data); - static const QByteArray MASTER_FILE; - static const QByteArray MUTUAL_AUTH; static const QByteArray CHANGE; static const QByteArray READBINARY; static const QByteArray REPLACE; @@ -61,7 +59,6 @@ class IDEMIACard: public Card QByteArray sign(QPCSCReader *reader, const QByteArray &dgst) const final; bool updateCounters(QPCSCReader *reader, QSmartCardDataPrivate *d) const final; - static QString cardNR(QPCSCReader *reader); static bool isSupported(const QByteArray &atr); static QByteArray pinTemplate(const QString &pin);