Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fetch birth date from certificate when missing #1293

Merged
merged 1 commit into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading