Skip to content

Commit e585457

Browse files
authored
Fix Pin Type with IDEMIA card replace command (#1372)
IB-8724 Signed-off-by: Raul Metsma <[email protected]>
1 parent b689214 commit e585457

File tree

3 files changed

+91
-141
lines changed

3 files changed

+91
-141
lines changed

client/QSmartCard.cpp

Lines changed: 86 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@
3030
#include <QtCore/QScopedPointer>
3131
#include <QtNetwork/QSslKey>
3232

33-
Q_LOGGING_CATEGORY(CLog, "qdigidoc4.QSmartCard")
33+
static Q_LOGGING_CATEGORY(CLog, "qdigidoc4.QSmartCard")
3434

3535
QSmartCardData::QSmartCardData(): d(new QSmartCardDataPrivate) {}
3636
QSmartCardData::QSmartCardData(const QSmartCardData &other) = default;
3737
QSmartCardData::QSmartCardData(QSmartCardData &&other) noexcept = default;
38-
QSmartCardData::~QSmartCardData() = default;
38+
QSmartCardData::~QSmartCardData() noexcept = default;
3939
QSmartCardData& QSmartCardData::operator =(const QSmartCardData &other) = default;
4040
QSmartCardData& QSmartCardData::operator =(QSmartCardData &&other) noexcept = default;
4141
bool QSmartCardData::operator ==(const QSmartCardData &other) const
@@ -197,15 +197,14 @@ QPCSCReader::Result IDEMIACard::change(QPCSCReader *reader, QSmartCardData::PinT
197197
QByteArray pin = pinTemplate(pin_);
198198
switch (type) {
199199
case QSmartCardData::Pin1Type:
200-
reader->transfer(AID);
201200
cmd[3] = 1;
202201
break;
203202
case QSmartCardData::PukType:
204-
reader->transfer(AID);
205203
cmd[3] = 2;
206204
break;
207205
case QSmartCardData::Pin2Type:
208-
reader->transfer(AID_QSCD);
206+
if(auto result = reader->transfer(AID_QSCD); !result)
207+
return result;
209208
cmd[3] = char(0x85);
210209
break;
211210
}
@@ -223,7 +222,8 @@ bool IDEMIACard::loadPerso(QPCSCReader *reader, QSmartCardDataPrivate *d) const
223222
if(d->data.isEmpty() && reader->transfer(APDU("00A4090C 04 3F00 5000")))
224223
{
225224
QByteArray cmd = APDU("00A4020C 02 5001");
226-
for(char data = QSmartCardData::SurName; data <= QSmartCardData::Expiry; ++data)
225+
using enum QSmartCardData::PersonalDataType;
226+
for(char data = SurName; data <= Expiry; ++data)
227227
{
228228
cmd[6] = data;
229229
if(!reader->transfer(cmd))
@@ -236,19 +236,19 @@ bool IDEMIACard::loadPerso(QPCSCReader *reader, QSmartCardDataPrivate *d) const
236236
record.clear();
237237
switch(data)
238238
{
239-
case QSmartCardData::SurName:
240-
case QSmartCardData::FirstName:
241-
case QSmartCardData::Citizen:
242-
case QSmartCardData::Id:
243-
case QSmartCardData::DocumentId:
239+
case SurName:
240+
case FirstName:
241+
case Citizen:
242+
case Id:
243+
case DocumentId:
244244
d->data[QSmartCardData::PersonalDataType(data)] = record;
245245
break;
246-
case QSmartCardData::BirthDate:
246+
case BirthDate:
247247
if(!record.isEmpty())
248-
d->data[QSmartCardData::BirthDate] = QDate::fromString(record.left(10), QStringLiteral("dd MM yyyy"));
248+
d->data[BirthDate] = QDate::fromString(record.left(10), QStringLiteral("dd MM yyyy"));
249249
break;
250-
case QSmartCardData::Expiry:
251-
d->data[QSmartCardData::Expiry] = QDateTime::fromString(record, QStringLiteral("dd MM yyyy")).addDays(1).addSecs(-1);
250+
case Expiry:
251+
d->data[Expiry] = QDateTime::fromString(record, QStringLiteral("dd MM yyyy")).addDays(1).addSecs(-1);
252252
break;
253253
default: break;
254254
}
@@ -293,29 +293,29 @@ bool IDEMIACard::loadPerso(QPCSCReader *reader, QSmartCardDataPrivate *d) const
293293
QByteArray IDEMIACard::pinTemplate(const QString &pin)
294294
{
295295
QByteArray result = pin.toUtf8();
296+
#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
297+
result.resize(12, char(0xFF));
298+
#else
296299
result += QByteArray(12 - result.size(), char(0xFF));
300+
#endif
297301
return result;
298302
}
299303

300304
QPCSCReader::Result IDEMIACard::replace(QPCSCReader *reader, QSmartCardData::PinType type, const QString &puk_, const QString &pin_) const
301305
{
302-
auto result = reader->transfer(AID);
303-
if(!result)
304-
return result;
305-
306306
QByteArray puk = pinTemplate(puk_);
307307
QByteArray cmd = VERIFY;
308308
cmd[3] = 2;
309309
cmd[4] = char(puk.size());
310-
result = transfer(reader, true, cmd + puk, type, 0, true);
311-
if(!result)
310+
if(auto result = transfer(reader, true, cmd + puk, QSmartCardData::PukType, 0, true); !result)
312311
return result;
313312

314313
cmd = Card::REPLACE;
315314
cmd[2] = 2;
316315
if(type == QSmartCardData::Pin2Type)
317316
{
318-
reader->transfer(IDEMIACard::AID_QSCD);
317+
if(auto result = reader->transfer(IDEMIACard::AID_QSCD); !result)
318+
return result;
319319
cmd[3] = char(0x85);
320320
}
321321
else
@@ -325,17 +325,6 @@ QPCSCReader::Result IDEMIACard::replace(QPCSCReader *reader, QSmartCardData::Pin
325325
return transfer(reader, false, cmd + pin, type, 0, false);
326326
}
327327

328-
QByteArray IDEMIACard::sign(QPCSCReader *reader, const QByteArray &dgst) const
329-
{
330-
if(!reader->transfer(AID_OT) ||
331-
!reader->transfer(APDU("002241A4 09 8004FF200800840181")))
332-
return {};
333-
QByteArray cmd = APDU("00880000 00 00");
334-
cmd[4] = char(std::min<size_t>(size_t(dgst.size()), 0x30));
335-
cmd.insert(5, dgst.left(0x30));
336-
return reader->transfer(cmd).data;
337-
}
338-
339328
bool IDEMIACard::updateCounters(QPCSCReader *reader, QSmartCardDataPrivate *d) const
340329
{
341330
reader->transfer(AID);
@@ -455,7 +444,11 @@ bool THALESCard::loadPerso(QPCSCReader *reader, QSmartCardDataPrivate *d) const
455444
QByteArray THALESCard::pinTemplate(const QString &pin)
456445
{
457446
QByteArray result = pin.toUtf8();
447+
#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
448+
result.resize(12, char(0x00));
449+
#else
458450
result += QByteArray(12 - result.size(), char(0x00));
451+
#endif
459452
return result;
460453
}
461454

@@ -469,22 +462,6 @@ QPCSCReader::Result THALESCard::replace(QPCSCReader *reader, QSmartCardData::Pin
469462
return transfer(reader, false, cmd + puk + pin, type, quint8(puk.size()), true);
470463
}
471464

472-
QByteArray THALESCard::sign(QPCSCReader *reader, const QByteArray &dgst) const
473-
{
474-
if(!reader->transfer(APDU("002241B6 09 800154840101")))
475-
return {};
476-
477-
QByteArray send {0x90, char(dgst.size())};
478-
send.append(dgst);
479-
send.insert(0, char(send.size()));
480-
send.insert(0, APDU("002A90A0"));
481-
482-
if(!reader->transfer(send))
483-
return {};
484-
485-
return reader->transfer(APDU("002A9E9A 00")).data;
486-
}
487-
488465
bool THALESCard::updateCounters(QPCSCReader *reader, QSmartCardDataPrivate *d) const
489466
{
490467
auto apdu = APDU("00CB00FF 05 A003830180 00");
@@ -506,18 +483,18 @@ bool THALESCard::updateCounters(QPCSCReader *reader, QSmartCardDataPrivate *d) c
506483

507484

508485

509-
QSharedPointer<QPCSCReader> QSmartCard::Private::connect(const QString &reader)
486+
std::unique_ptr<QPCSCReader> QSmartCard::Private::connect(const QString &reader)
510487
{
511488
qCDebug(CLog) << "Connecting to reader" << reader;
512-
QSharedPointer<QPCSCReader> r(new QPCSCReader(reader, &QPCSC::instance()));
489+
auto r = std::make_unique<QPCSCReader>(reader, &QPCSC::instance());
513490
if(!r->connect() || !r->beginTransaction())
514-
r.clear();
491+
r.reset();
515492
return r;
516493
}
517494

518-
QSmartCard::ErrorType QSmartCard::Private::handlePinResult(QPCSCReader *reader, const QPCSCReader::Result &response, bool forceUpdate)
495+
QSmartCard::ErrorType QSmartCard::Private::handlePinResult(QPCSCReader *reader, const QPCSCReader::Result &response)
519496
{
520-
if(!response || forceUpdate)
497+
if(!response)
521498
card->updateCounters(reader, t.d);
522499
switch(response.SW)
523500
{
@@ -546,90 +523,91 @@ QSmartCard::QSmartCard(QObject *parent)
546523
{
547524
}
548525

549-
QSmartCard::~QSmartCard() = default;
550-
551-
QSmartCard::ErrorType QSmartCard::change(QSmartCardData::PinType type, QWidget* parent, const QString &newpin, const QString &pin, const QString &title, const QString &bodyText)
552-
{
553-
PinPopup::PinFlags flags = {};
554-
switch(type)
555-
{
556-
case QSmartCardData::Pin1Type: flags = PinPopup::Pin1Type; break;
557-
case QSmartCardData::Pin2Type: flags = PinPopup::Pin2Type; break;
558-
case QSmartCardData::PukType: flags = PinPopup::PukType; break;
559-
default: return UnknownError;
560-
}
561-
QSharedPointer<QPCSCReader> reader(d->connect(d->t.reader()));
562-
if(!reader)
563-
return UnknownError;
564-
565-
QScopedPointer<PinPopup> p;
566-
if(d->t.isPinpad())
567-
{
568-
p.reset(new PinPopup(PinPopup::PinFlags(flags|PinPopup::PinpadChangeFlag), title, {}, parent, bodyText));
569-
p->open();
570-
}
571-
return d->handlePinResult(reader.data(), d->card->change(reader.data(), type, pin, newpin), true);
572-
}
526+
QSmartCard::~QSmartCard() noexcept = default;
573527

574528
QSmartCardData QSmartCard::data() const { return d->t; }
575529

576530
QSmartCard::ErrorType QSmartCard::pinChange(QSmartCardData::PinType type, QSmartCard::PinAction action, QWidget* parent)
577531
{
578-
QScopedPointer<PinUnblock> p;
532+
std::unique_ptr<PinPopup,QScopedPointerDeleteLater> popup;
579533
QByteArray oldPin, newPin;
580-
QString title, textBody;
581534

582535
if (!d->t.isPinpad())
583536
{
584-
p.reset(new PinUnblock(type, action, d->t.retryCount(type), d->t.data(QSmartCardData::BirthDate).toDate(),
585-
d->t.data(QSmartCardData::Id).toString(), d->t.isPUKReplacable(), parent));
586-
if (!p->exec())
537+
PinUnblock p(type, action, d->t.retryCount(type), d->t.data(QSmartCardData::BirthDate).toDate(),
538+
d->t.data(QSmartCardData::Id).toString(), d->t.isPUKReplacable(), parent);
539+
if (!p.exec())
587540
return CancelError;
588-
oldPin = p->firstCodeText().toUtf8();
589-
newPin = p->newCodeText().toUtf8();
541+
oldPin = p.firstCodeText().toUtf8();
542+
newPin = p.newCodeText().toUtf8();
590543
}
591544
else
592545
{
593546
SslCertificate cert = d->t.authCert();
594-
title = cert.toString(cert.showCN() ? QStringLiteral("CN, serialNumber") : QStringLiteral("GN SN, serialNumber"));
595-
textBody = tr("To change %1 on a PinPad reader the old %1 code has to be entered first and then the new %1 code twice.").arg(QSmartCardData::typeString(type));
547+
QString title = cert.toString(cert.showCN() ? QStringLiteral("CN, serialNumber") : QStringLiteral("GN SN, serialNumber"));
548+
PinPopup::PinFlags flags = {};
549+
switch(type)
550+
{
551+
case QSmartCardData::Pin1Type: flags = PinPopup::Pin1Type; break;
552+
case QSmartCardData::Pin2Type: flags = PinPopup::Pin2Type; break;
553+
case QSmartCardData::PukType: flags = PinPopup::PukType; break;
554+
default: return UnknownError;
555+
}
556+
popup.reset(new PinPopup(PinPopup::PinFlags(flags|PinPopup::PinpadChangeFlag), title, {}, parent,
557+
tr("To change %1 on a PinPad reader the old %1 code has to be entered first and then the new %1 code twice.").arg(QSmartCardData::typeString(type))));
558+
popup->open();
596559
}
597-
return change(type, parent, newPin, oldPin, title, textBody);
560+
561+
if(auto reader = Private::connect(d->t.reader()))
562+
return d->handlePinResult(reader.get(), d->card->change(reader.get(), type, oldPin, newPin));
563+
return UnknownError;
598564
}
599565

600566
QSmartCard::ErrorType QSmartCard::pinUnblock(QSmartCardData::PinType type, QSmartCard::PinAction action, QWidget* parent)
601567
{
602-
QScopedPointer<PinUnblock> p;
603-
QByteArray puk, newPin;
604-
QString title, textBody;
568+
std::unique_ptr<PinPopup,QScopedPointerDeleteLater> popup;
569+
QByteArray puk, pin;
605570

606571
if (!d->t.isPinpad())
607572
{
608-
p.reset(new PinUnblock(type, action,
609-
d->t.retryCount(QSmartCardData::PukType), d->t.data(QSmartCardData::BirthDate).toDate(), d->t.data(QSmartCardData::Id).toString(), d->t.isPUKReplacable(), parent));
610-
if (!p->exec())
573+
PinUnblock p(type, action, d->t.retryCount(QSmartCardData::PukType), d->t.data(QSmartCardData::BirthDate).toDate(),
574+
d->t.data(QSmartCardData::Id).toString(), d->t.isPUKReplacable(), parent);
575+
if (!p.exec())
611576
return CancelError;
612-
puk = p->firstCodeText().toUtf8();
613-
newPin = p->newCodeText().toUtf8();
577+
puk = p.firstCodeText().toUtf8();
578+
pin = p.newCodeText().toUtf8();
614579
}
615580
else
616581
{
617582
SslCertificate cert = d->t.authCert();
618-
title = cert.toString(cert.showCN() ? QStringLiteral("CN, serialNumber") : QStringLiteral("GN SN, serialNumber"));
583+
QString title = cert.toString(cert.showCN() ? QStringLiteral("CN, serialNumber") : QStringLiteral("GN SN, serialNumber"));
584+
QString bodyText;
619585
switch(action)
620586
{
621587
case QSmartCard::ActivateWithPuk:
622588
case QSmartCard::ChangeWithPuk:
623-
textBody = tr("To change %1 code with the PUK code on a PinPad reader the PUK code has to be entered first and then the %1 code twice.").arg(QSmartCardData::typeString(type));
589+
bodyText = tr("To change %1 code with the PUK code on a PinPad reader the PUK code has to be entered first and then the %1 code twice.").arg(QSmartCardData::typeString(type));
624590
break;
625591
case QSmartCard::UnblockWithPuk:
626-
textBody = tr("To unblock the %1 code on a PinPad reader the PUK code has to be entered first and then the %1 code twice.").arg(QSmartCardData::typeString(type));
592+
bodyText = tr("To unblock the %1 code on a PinPad reader the PUK code has to be entered first and then the %1 code twice.").arg(QSmartCardData::typeString(type));
627593
break;
628594
default:
629595
break;
630596
}
597+
PinPopup::PinFlags flags = {};
598+
switch(type)
599+
{
600+
case QSmartCardData::Pin1Type: flags = PinPopup::Pin1Type; break;
601+
case QSmartCardData::Pin2Type: flags = PinPopup::Pin2Type; break;
602+
default: return UnknownError;
603+
}
604+
popup.reset(new PinPopup(PinPopup::PinFlags(flags|PinPopup::PinpadChangeFlag), title, {}, parent, bodyText));
605+
popup->open();
631606
}
632-
return unblock(type, parent, newPin, puk, title, textBody);
607+
608+
if(auto reader = Private::connect(d->t.reader()))
609+
return d->handlePinResult(reader.get(), d->card->replace(reader.get(), type, puk, pin));
610+
return UnknownError;
633611
}
634612

635613
void QSmartCard::reloadCounters()
@@ -663,25 +641,24 @@ void QSmartCard::reloadCard(const TokenData &token, bool reloadCounters)
663641
return;
664642

665643
QString reader = token.reader();
666-
if(token.reader().endsWith(QStringLiteral("..."))) {
644+
if(token.reader().endsWith(QLatin1String("..."))) {
667645
for(const QString &test: QPCSC::instance().readers()) {
668646
if(test.startsWith(token.reader().left(token.reader().size() - 3)))
669647
reader = test;
670648
}
671649
}
672650

673651
qCDebug(CLog) << "Read" << reader;
674-
QScopedPointer<QPCSCReader> selectedReader(new QPCSCReader(reader, &QPCSC::instance()));
675-
if(!selectedReader->connect() || !selectedReader->beginTransaction())
652+
auto selectedReader = Private::connect(reader);
653+
if(!selectedReader)
676654
return;
677655

678-
std::unique_ptr<Card> card;
679656
if(IDEMIACard::isSupported(selectedReader->atr()))
680-
card = std::make_unique<IDEMIACard>();
657+
d->card = std::make_unique<IDEMIACard>();
681658
else if(THALESCard::isSupported(selectedReader->atr()))
682-
card = std::make_unique<THALESCard>();
659+
d->card = std::make_unique<THALESCard>();
683660
else {
684-
qDebug() << "Unsupported card";
661+
qCDebug(CLog) << "Unsupported card";
685662
return;
686663
}
687664

@@ -690,36 +667,14 @@ void QSmartCard::reloadCard(const TokenData &token, bool reloadCounters)
690667
t = d->t.d;
691668
t->reader = selectedReader->name();
692669
t->pinpad = selectedReader->isPinPad();
693-
d->card = std::move(card);
694-
if(d->card->loadPerso(selectedReader.data(), t))
670+
if(d->card->loadPerso(selectedReader.get(), t))
695671
{
696672
d->t.d = std::move(t);
697673
emit dataChanged(d->t);
698674
}
699675
else
700-
qDebug() << "Failed to read card info, try again next round";
676+
qCDebug(CLog) << "Failed to read card info, try again next round";
701677
}
702678

703679
TokenData QSmartCard::tokenData() const { return d->token; }
704680

705-
QSmartCard::ErrorType QSmartCard::unblock(QSmartCardData::PinType type, QWidget* parent, const QString &pin, const QString &puk, const QString &title, const QString &bodyText)
706-
{
707-
PinPopup::PinFlags flags = {};
708-
switch(type)
709-
{
710-
case QSmartCardData::Pin1Type: flags = PinPopup::Pin1Type; break;
711-
case QSmartCardData::Pin2Type: flags = PinPopup::Pin2Type; break;
712-
default: return UnknownError;
713-
}
714-
QSharedPointer<QPCSCReader> reader(d->connect(d->t.reader()));
715-
if(!reader)
716-
return UnknownError;
717-
718-
QScopedPointer<PinPopup> p;
719-
if(d->t.isPinpad())
720-
{
721-
p.reset(new PinPopup(PinPopup::PinFlags(flags|PinPopup::PinpadChangeFlag), title, {}, parent, bodyText));
722-
p->open();
723-
}
724-
return d->handlePinResult(reader.data(), d->card->replace(reader.data(), type, puk, pin), true);
725-
}

0 commit comments

Comments
 (0)