@@ -51,6 +51,7 @@ QString QSmartCardData::card() const { return d->card; }
5151bool QSmartCardData::isNull () const
5252{ return d->data .isEmpty () && d->authCert .isNull () && d->signCert .isNull (); }
5353bool QSmartCardData::isPinpad () const { return d->pinpad ; }
54+ bool QSmartCardData::isPUKReplacable () const { return d->pukReplacable ; }
5455bool QSmartCardData::isValid () const
5556{ return d->data .value (Expiry).toDateTime () >= QDateTime::currentDateTime (); }
5657
@@ -285,6 +286,143 @@ bool IDEMIACard::updateCounters(QPCSCReader *reader, QSmartCardDataPrivate *d) c
285286
286287
287288
289+ const QByteArray THALESCard::AID = APDU(" 00A4040C 0C A000000063504B43532D3135" );
290+
291+ QPCSCReader::Result THALESCard::change (QPCSCReader *reader, QSmartCardData::PinType type, const QString &pin_, const QString &newpin_) const
292+ {
293+ QByteArray cmd = CHANGE;
294+ QByteArray newpin = pinTemplate (newpin_);
295+ QByteArray pin = pinTemplate (pin_);
296+ cmd[3 ] = char (0x80 | type);
297+ cmd[4 ] = char (pin.size () + newpin.size ());
298+ return transfer (reader, false , cmd + pin + newpin, type, quint8 (pin.size ()), true );
299+ }
300+
301+ bool THALESCard::isSupported (const QByteArray &atr)
302+ {
303+ return atr == " 3BFF9600008031FE438031B85365494464B085051012233F1D" ;
304+ }
305+
306+ bool THALESCard::loadPerso (QPCSCReader *reader, QSmartCardDataPrivate *d) const
307+ {
308+ d->pukReplacable = false ;
309+ if (d->data .isEmpty () && reader->transfer (APDU (" 00A4080C 02 DFDD" )))
310+ {
311+ QByteArray cmd = APDU (" 00A4020C 02 5001" );
312+ for (char data = 1 ; data <= 8 ; ++data)
313+ {
314+ cmd[6 ] = data;
315+ if (!reader->transfer (cmd))
316+ return false ;
317+ QPCSCReader::Result result = reader->transfer (READBINARY);
318+ if (!result)
319+ return false ;
320+ QString record = QString::fromUtf8 (result.data .trimmed ());
321+ if (record == QChar (0 ))
322+ record.clear ();
323+ switch (data)
324+ {
325+ case QSmartCardData::SurName:
326+ case QSmartCardData::FirstName:
327+ case QSmartCardData::Citizen:
328+ case QSmartCardData::Id:
329+ case QSmartCardData::DocumentId:
330+ d->data [QSmartCardData::PersonalDataType (data)] = record;
331+ break ;
332+ case QSmartCardData::BirthDate:
333+ if (!record.isEmpty ())
334+ d->data [QSmartCardData::BirthDate] = QDate::fromString (record.left (10 ), QStringLiteral (" dd MM yyyy" ));
335+ break ;
336+ case QSmartCardData::Expiry:
337+ d->data [QSmartCardData::Expiry] = QDateTime::fromString (record, QStringLiteral (" dd MM yyyy" )).addDays (1 ).addSecs (-1 );
338+ break ;
339+ default : break ;
340+ }
341+ }
342+ }
343+
344+ bool readFailed = false ;
345+ auto readCert = [&](const QByteArray &path) {
346+ QPCSCReader::Result data = reader->transfer (path);
347+ if (!data)
348+ {
349+ readFailed = true ;
350+ return QSslCertificate ();
351+ }
352+ QHash<quint8,QByteArray> fci = parseFCI (data.data );
353+
354+ QByteArray cert;
355+ QByteArray cmd = READBINARY;
356+ for (int size = quint8 (fci[0x81 ][0 ]) << 8 | quint8 (fci[0x81 ][1 ]); cert.size () < size;)
357+ {
358+ cmd[2 ] = char (cert.size () >> 8 );
359+ cmd[3 ] = char (cert.size ());
360+ data = reader->transfer (cmd);
361+ if (!data)
362+ {
363+ readFailed = true ;
364+ return QSslCertificate ();
365+ }
366+ cert += data.data ;
367+ }
368+ return QSslCertificate (cert, QSsl::Der);
369+ };
370+ if (d->authCert .isNull ())
371+ d->authCert = readCert (APDU (" 00A40804 04 ADF1 3411 00" ));
372+ if (d->signCert .isNull ())
373+ d->signCert = readCert (APDU (" 00A40804 04 ADF2 3421 00" ));
374+
375+ if (readFailed)
376+ return false ;
377+ return updateCounters (reader, d);
378+ }
379+
380+ QByteArray THALESCard::pinTemplate (const QString &pin)
381+ {
382+ QByteArray result = pin.toUtf8 ();
383+ result += QByteArray (12 - result.size (), char (0x00 ));
384+ return result;
385+ }
386+
387+ QPCSCReader::Result THALESCard::replace (QPCSCReader *reader, QSmartCardData::PinType type, const QString &puk_, const QString &pin_) const
388+ {
389+ QByteArray puk = pinTemplate (puk_);
390+ QByteArray pin = pinTemplate (pin_);
391+ QByteArray cmd = REPLACE;
392+ cmd[3 ] = char (0x80 | type);
393+ cmd[4 ] = char (puk.size () + pin.size ());
394+ return transfer (reader, false , cmd + puk + pin, type, quint8 (puk.size ()), true );
395+ }
396+
397+ QByteArray THALESCard::sign (QPCSCReader *reader, const QByteArray &dgst) const
398+ {
399+ if (!reader->transfer (APDU (" 002241B6 09 800154840101" )))
400+ return {};
401+
402+ QByteArray send {0x90 , char (dgst.size ())};
403+ send.append (dgst);
404+ send.insert (0 , char (send.size ()));
405+ send.insert (0 , APDU (" 002A90A0" ));
406+
407+ if (!reader->transfer (send))
408+ return {};
409+
410+ return reader->transfer (APDU (" 002A9E9A 00" )).data ;
411+ }
412+
413+ bool THALESCard::updateCounters (QPCSCReader *reader, QSmartCardDataPrivate *d) const
414+ {
415+ if (auto data = reader->transfer (APDU (" 00CB00FF 05 A003830181 00" )))
416+ d->retry [QSmartCardData::Pin1Type] = quint8 (data.data [14 ]);
417+ if (auto data = reader->transfer (APDU (" 00CB00FF 05 A003830183 00" )))
418+ d->retry [QSmartCardData::PukType] = quint8 (data.data [14 ]);
419+ if (auto data = reader->transfer (APDU (" 00CB00FF 05 A003830182 00" )))
420+ d->retry [QSmartCardData::Pin2Type] = quint8 (data.data [14 ]);
421+ return true ;
422+ }
423+
424+
425+
288426QSharedPointer<QPCSCReader> QSmartCard::Private::connect (const QString &reader)
289427{
290428 qCDebug (CLog) << " Connecting to reader" << reader;
@@ -309,7 +447,8 @@ QSmartCard::ErrorType QSmartCard::Private::handlePinResult(QPCSCReader *reader,
309447 case 0x6401 : return QSmartCard::CancelError; // Cancel (OK, SCM)
310448 case 0x6402 : return QSmartCard::DifferentError;
311449 case 0x6403 : return QSmartCard::LenghtError;
312- case 0x6983 : return QSmartCard::BlockedError;
450+ case 0x6983 :
451+ case 0x6984 : return QSmartCard::BlockedError;
313452 case 0x6985 :
314453 case 0x6A80 : return QSmartCard::OldNewPinSameError;
315454 default : return QSmartCard::UnknownError;
@@ -444,7 +583,12 @@ void QSmartCard::reloadCard(const TokenData &token, bool reloadCounters)
444583 if (!selectedReader->connect () || !selectedReader->beginTransaction ())
445584 return ;
446585
447- if (!IDEMIACard::isSupported (selectedReader->atr ())) {
586+ std::unique_ptr<Card> card;
587+ if (IDEMIACard::isSupported (selectedReader->atr ()))
588+ card = std::make_unique<IDEMIACard>();
589+ else if (THALESCard::isSupported (selectedReader->atr ()))
590+ card = std::make_unique<THALESCard>();
591+ else {
448592 qDebug () << " Unsupported card" ;
449593 return ;
450594 }
@@ -454,7 +598,7 @@ void QSmartCard::reloadCard(const TokenData &token, bool reloadCounters)
454598 t = d->t .d ;
455599 t->reader = selectedReader->name ();
456600 t->pinpad = selectedReader->isPinPad ();
457- d->card = std::make_unique<IDEMIACard>( );
601+ d->card = std::move (card );
458602 if (d->card ->loadPerso (selectedReader.data (), t))
459603 {
460604 d->t .d = std::move (t);
0 commit comments