Skip to content

Commit

Permalink
Fetch birth date from certificate when missing (#1293)
Browse files Browse the repository at this point in the history
IB-8131

Signed-off-by: Raul Metsma <raul@metsma.ee>
  • Loading branch information
metsma authored Oct 17, 2024
1 parent d59f384 commit 6a75965
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 52 deletions.
75 changes: 36 additions & 39 deletions client/QSmartCard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,16 @@

#include "QSmartCard_p.h"

#include "IKValidator.h"
#include "QCardLock.h"
#include "Settings.h"
#include "Utils.h"
#include "dialogs/PinPopup.h"
#include "dialogs/PinUnblock.h"

#include <QtCore/QDateTime>
#include <QtCore/QDebug>
#include <QtCore/QLoggingCategory>
#include <QtCore/QScopedPointer>
#include <QtCore/QTimer>
#include <QtNetwork/QSslKey>

Q_LOGGING_CATEGORY(CLog, "qdigidoc4.QSmartCard")
Expand Down Expand Up @@ -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");
Expand All @@ -111,7 +108,7 @@ QPCSCReader::Result Card::transfer(QPCSCReader *reader, bool verify, const QByte
QHash<quint8,QByteArray> Card::parseFCI(const QByteArray &data)
{
QHash<quint8,QByteArray> 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);
Expand All @@ -129,7 +126,7 @@ QHash<quint8,QByteArray> 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");

Expand Down Expand Up @@ -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))
Expand All @@ -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<quint8,QByteArray> 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)
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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>(size_t(dgst.size()), 0x30));
cmd.insert(5, dgst.left(0x30));
return reader->transfer(cmd).data;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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<IDEMIACard>();
if(d->card->loadPerso(selectedReader.data(), t))
{
Expand Down
20 changes: 10 additions & 10 deletions client/QSmartCard.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -84,7 +84,7 @@ class QSmartCard final: public QObject
{
Q_OBJECT
public:
enum ErrorType
enum ErrorType : quint8
{
NoError,
UnknownError,
Expand Down
3 changes: 0 additions & 3 deletions client/QSmartCard_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ class Card

static QHash<quint8,QByteArray> 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;
Expand All @@ -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);

Expand Down

0 comments on commit 6a75965

Please sign in to comment.