From 6b178ce3132b31e95230dfce491f7cb1928babde Mon Sep 17 00:00:00 2001 From: Raul Metsma Date: Wed, 14 Jan 2026 14:08:00 +0200 Subject: [PATCH] Do not allow cancel in PinPad view and clean PIN memory IB-7082 Signed-off-by: Raul Metsma --- client/QPCSC.cpp | 8 +- client/QPCSC.h | 3 +- client/QSmartCard.cpp | 239 ++++++++++++++++++++---------------- client/QSmartCard.h | 2 +- client/QSmartCard_p.h | 54 ++++---- client/dialogs/PinPopup.cpp | 84 ++++++------- client/dialogs/PinPopup.h | 11 +- 7 files changed, 216 insertions(+), 185 deletions(-) diff --git a/client/QPCSC.cpp b/client/QPCSC.cpp index c16f9f9d5..3999ecd5e 100644 --- a/client/QPCSC.cpp +++ b/client/QPCSC.cpp @@ -210,7 +210,13 @@ QPCSCReader::QPCSCReader( const QString &reader, QPCSC *parent ) SC(GetStatusChange, d->d->context, 0, &d->state, 1U); } -QPCSCReader::~QPCSCReader() +QPCSCReader::QPCSCReader(QPCSCReader &&other) noexcept + : d(other.d) +{ + other.d = new Private; +} + +QPCSCReader::~QPCSCReader() noexcept { if(d->isTransacted) SC(EndTransaction, d->card, SCARD_LEAVE_CARD); diff --git a/client/QPCSC.h b/client/QPCSC.h index 772b46a2b..5e313b30a 100644 --- a/client/QPCSC.h +++ b/client/QPCSC.h @@ -97,7 +97,8 @@ class QPCSCReader final: public QObject }; explicit QPCSCReader( const QString &reader, QPCSC *parent ); - ~QPCSCReader() final; + QPCSCReader(QPCSCReader &&) noexcept; + ~QPCSCReader() noexcept final; QByteArray atr() const; bool isPinPad() const; diff --git a/client/QSmartCard.cpp b/client/QSmartCard.cpp index f62237cec..3e3c7fffd 100644 --- a/client/QSmartCard.cpp +++ b/client/QSmartCard.cpp @@ -92,16 +92,31 @@ const QByteArray Card::READBINARY = APDU("00B00000 00"); const QByteArray Card::REPLACE = APDU("002C0000 00"); const QByteArray Card::VERIFY = APDU("00200000 00"); -QPCSCReader::Result Card::transfer(QPCSCReader *reader, bool verify, const QByteArray &apdu, - QSmartCardData::PinType type, quint8 newPINOffset, bool requestCurrentPIN) +std::unique_ptr Card::card(const QString &reader) { - if(!reader->isPinPad()) - return reader->transfer(apdu); + QPCSCReader r(reader, &QPCSC::instance()); + auto atr = r.atr(); + if(IDEMIACard::isSupported(atr)) + return std::make_unique(std::move(r)); + if(THALESCard::isSupported(atr)) + return std::make_unique(std::move(r)); + qCDebug(CLog) << "Unsupported card"; + return {}; +} + +QPCSCReader::Result Card::transfer(bool verify, QByteArray &&apdu, + QSmartCardData::PinType type, quint8 newPINOffset, bool requestCurrentPIN) const +{ + auto clean = qScopeGuard([&apdu] { + apdu.fill('0'); + }); + if(!reader.isPinPad()) + return reader.transfer(apdu); quint16 language = 0x0000; if(Settings::LANGUAGE == QLatin1String("en")) language = 0x0409; else if(Settings::LANGUAGE == QLatin1String("et")) language = 0x0425; else if(Settings::LANGUAGE == QLatin1String("ru")) language = 0x0419; - return waitFor(&QPCSCReader::transferCTL, reader, + return waitFor(&QPCSCReader::transferCTL, &reader, apdu, verify, language, QSmartCardData::minPinLen(type), newPINOffset, requestCurrentPIN); } @@ -119,6 +134,17 @@ QByteArrayView Card::parseFCI(QByteArrayView data, quint8 expectedTag) return {}; } +QByteArray Card::pinTemplate(const QString &data) const +{ + QByteArray pin = data.toUtf8(); +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) + pin.resize(12, fillChar); +#else + pin += QByteArray(12 - pin.size(), fillChar); +#endif + return pin; +} + struct TLV { quint32 tag {}; @@ -191,11 +217,9 @@ const QByteArray IDEMIACard::AID_QSCD = APDU("00A4040C 10 51534344204170706C6963 const QByteArray IDEMIACard::ATR_COSMO8 = QByteArrayLiteral("3BDB960080B1FE451F830012233F536549440F9000F1"); const QByteArray IDEMIACard::ATR_COSMOX = QByteArrayLiteral("3BDC960080B1FE451F830012233F54654944320F9000C3"); -QPCSCReader::Result IDEMIACard::change(QPCSCReader *reader, QSmartCardData::PinType type, QByteArray &&pin, QByteArray &&newpin) const +QPCSCReader::Result IDEMIACard::change(QSmartCardData::PinType type, const QByteArray &pin, const QByteArray &newpin) const { QByteArray cmd = CHANGE; - newpin = pinTemplate(std::move(newpin)); - pin = pinTemplate(std::move(pin)); switch (type) { case QSmartCardData::Pin1Type: cmd[3] = 1; @@ -204,13 +228,15 @@ QPCSCReader::Result IDEMIACard::change(QPCSCReader *reader, QSmartCardData::PinT cmd[3] = 2; break; case QSmartCardData::Pin2Type: - if(auto result = reader->transfer(AID_QSCD); !result) + if(auto result = reader.transfer(AID_QSCD); !result) return result; cmd[3] = char(0x85); break; } cmd[4] = char(pin.size() + newpin.size()); - return transfer(reader, false, cmd + pin + newpin, type, quint8(pin.size()), true); + cmd += pin; + cmd += newpin; + return transfer(false, std::move(cmd), type, quint8(pin.size()), true); } bool IDEMIACard::isSupported(const QByteArray &atr) @@ -218,18 +244,18 @@ bool IDEMIACard::isSupported(const QByteArray &atr) return atr == ATR_COSMO8 || atr == ATR_COSMOX; } -bool IDEMIACard::loadPerso(QPCSCReader *reader, QSmartCardDataPrivate *d) const +bool IDEMIACard::loadPerso(QSmartCardDataPrivate *d) const { - if(d->data.isEmpty() && reader->transfer(APDU("00A4090C 04 3F00 5000"))) + if(d->data.isEmpty() && reader.transfer(APDU("00A4090C 04 3F00 5000"))) { QByteArray cmd = APDU("00A4020C 02 5001"); using enum QSmartCardData::PersonalDataType; for(char data = SurName; data <= Expiry; ++data) { cmd[6] = data; - if(!reader->transfer(cmd)) + if(!reader.transfer(cmd)) return false; - QPCSCReader::Result result = reader->transfer(READBINARY); + QPCSCReader::Result result = reader.transfer(READBINARY); if(!result) return false; QString record = QString::fromUtf8(result.data.trimmed()); @@ -257,7 +283,7 @@ bool IDEMIACard::loadPerso(QPCSCReader *reader, QSmartCardDataPrivate *d) const } auto readCert = [&](const QByteArray &path) { - QPCSCReader::Result data = reader->transfer(path); + QPCSCReader::Result data = reader.transfer(path); if(!data) return QSslCertificate(); auto sizeTag = parseFCI(data.data, 0x80); @@ -266,14 +292,14 @@ bool IDEMIACard::loadPerso(QPCSCReader *reader, QSmartCardDataPrivate *d) const QByteArray cert; QByteArray cmd = READBINARY; qsizetype maxLe = 0; - if(reader->atr() == ATR_COSMOX) + if(reader.atr() == ATR_COSMOX) maxLe = 0xC0; for(qsizetype size = quint8(sizeTag[0]) << 8 | quint8(sizeTag[1]); cert.size() < size; ) { cmd[2] = char(cert.size() >> 8); cmd[3] = char(cert.size()); cmd[4] = char(std::min(size - cert.size(), maxLe)); - data = reader->transfer(cmd); + data = reader.transfer(cmd); if(!data) return QSslCertificate(); cert += data.data; @@ -288,58 +314,48 @@ bool IDEMIACard::loadPerso(QPCSCReader *reader, QSmartCardDataPrivate *d) const return false; if(!d->data.contains(QSmartCardData::BirthDate)) d->data[QSmartCardData::BirthDate] = IKValidator::birthDate(d->authCert.personalCode()); - return updateCounters(reader, d); + return updateCounters(d); } -QByteArray IDEMIACard::pinTemplate(QByteArray &&pin) +QPCSCReader::Result IDEMIACard::replace(QSmartCardData::PinType type, const QByteArray &puk, const QByteArray &pin) const { -#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) - pin.resize(12, char(0xFF)); -#else - pin += QByteArray(12 - pin.size(), char(0xFF)); -#endif - return std::move(pin); -} - -QPCSCReader::Result IDEMIACard::replace(QPCSCReader *reader, QSmartCardData::PinType type, QByteArray &&puk, QByteArray &&pin) const -{ - puk = pinTemplate(std::move(puk)); QByteArray cmd = VERIFY; cmd[3] = 2; cmd[4] = char(puk.size()); - if(auto result = transfer(reader, true, cmd + puk, QSmartCardData::PukType, 0, true); !result) + cmd += puk; + if(auto result = transfer(true, std::move(cmd), QSmartCardData::PukType, 0, true); !result) return result; cmd = Card::REPLACE; cmd[2] = 2; if(type == QSmartCardData::Pin2Type) { - if(auto result = reader->transfer(IDEMIACard::AID_QSCD); !result) + if(auto result = reader.transfer(IDEMIACard::AID_QSCD); !result) return result; cmd[3] = char(0x85); } else cmd[3] = char(type); - pin = pinTemplate(std::move(pin)); cmd[4] = char(pin.size()); - return transfer(reader, false, cmd + pin, type, 0, false); + cmd += pin; + return transfer(false, std::move(cmd), type, 0, false); } -bool IDEMIACard::updateCounters(QPCSCReader *reader, QSmartCardDataPrivate *d) const +bool IDEMIACard::updateCounters(QSmartCardDataPrivate *d) const { - reader->transfer(AID); - if(auto data = reader->transfer(APDU("00CB3FFF 0A 4D087006 BF8101 02A080 00"))) + reader.transfer(AID); + if(auto data = reader.transfer(APDU("00CB3FFF 0A 4D087006 BF8101 02A080 00"))) { if(auto info = TLV(data.data)[0xBF8101][0xA0]; auto retry = info[0x9B]) d->retry[QSmartCardData::Pin1Type] = quint8(retry.data[0]); } - if(auto data = reader->transfer(APDU("00CB3FFF 0A 4D087006 BF8102 02A080 00"))) + if(auto data = reader.transfer(APDU("00CB3FFF 0A 4D087006 BF8102 02A080 00"))) { if(auto info = TLV(data.data)[0xBF8102][0xA0]; auto retry = info[0x9B]) d->retry[QSmartCardData::PukType] = quint8(retry.data[0]); } - reader->transfer(AID_QSCD); - if(auto data = reader->transfer(APDU("00CB3FFF 0A 4D087006 BF8105 02A080 00"))) + reader.transfer(AID_QSCD); + if(auto data = reader.transfer(APDU("00CB3FFF 0A 4D087006 BF8105 02A080 00"))) { if(auto info = TLV(data.data)[0xBF8105][0xA0]; auto retry = info[0x9B]) d->retry[QSmartCardData::Pin2Type] = quint8(retry.data[0]); @@ -351,14 +367,14 @@ bool IDEMIACard::updateCounters(QPCSCReader *reader, QSmartCardDataPrivate *d) c const QByteArray THALESCard::AID = APDU("00A4040C 0C A000000063504B43532D3135"); -QPCSCReader::Result THALESCard::change(QPCSCReader *reader, QSmartCardData::PinType type, QByteArray &&pin, QByteArray &&newpin) const +QPCSCReader::Result THALESCard::change(QSmartCardData::PinType type, const QByteArray &pin, const QByteArray &newpin) const { QByteArray cmd = CHANGE; - newpin = pinTemplate(std::move(newpin)); - pin = pinTemplate(std::move(pin)); cmd[3] = char(0x80 | type); cmd[4] = char(pin.size() + newpin.size()); - return transfer(reader, false, cmd + pin + newpin, type, quint8(pin.size()), true); + cmd += pin; + cmd += newpin; + return transfer(false, std::move(cmd), type, quint8(pin.size()), true); } bool THALESCard::isSupported(const QByteArray &atr) @@ -366,18 +382,18 @@ bool THALESCard::isSupported(const QByteArray &atr) return atr == "3BFF9600008031FE438031B85365494464B085051012233F1D"; } -bool THALESCard::loadPerso(QPCSCReader *reader, QSmartCardDataPrivate *d) const +bool THALESCard::loadPerso(QSmartCardDataPrivate *d) const { d->pukReplacable = false; - if(d->data.isEmpty() && reader->transfer(APDU("00A4080C 02 DFDD"))) + if(d->data.isEmpty() && reader.transfer(APDU("00A4080C 02 DFDD"))) { QByteArray cmd = APDU("00A4020C 02 5001"); for(char data = 1; data <= 8; ++data) { cmd[6] = data; - if(!reader->transfer(cmd)) + if(!reader.transfer(cmd)) return false; - QPCSCReader::Result result = reader->transfer(READBINARY); + QPCSCReader::Result result = reader.transfer(READBINARY); if(!result) return false; QString record = QString::fromUtf8(result.data.trimmed()); @@ -406,7 +422,7 @@ bool THALESCard::loadPerso(QPCSCReader *reader, QSmartCardDataPrivate *d) const bool readFailed = false; auto readCert = [&](const QByteArray &path) { - QPCSCReader::Result data = reader->transfer(path); + QPCSCReader::Result data = reader.transfer(path); if(!data) { readFailed = true; @@ -421,7 +437,7 @@ bool THALESCard::loadPerso(QPCSCReader *reader, QSmartCardDataPrivate *d) const { cmd[2] = char(cert.size() >> 8); cmd[3] = char(cert.size()); - data = reader->transfer(cmd); + data = reader.transfer(cmd); if(!data) { readFailed = true; @@ -438,37 +454,26 @@ bool THALESCard::loadPerso(QPCSCReader *reader, QSmartCardDataPrivate *d) const if(readFailed) return false; - return updateCounters(reader, d); -} - -QByteArray THALESCard::pinTemplate(const QString &pin) -{ - QByteArray result = pin.toUtf8(); -#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) - result.resize(12, char(0x00)); -#else - result += QByteArray(12 - result.size(), char(0x00)); -#endif - return result; + return updateCounters(d); } -QPCSCReader::Result THALESCard::replace(QPCSCReader *reader, QSmartCardData::PinType type, QByteArray &&puk, QByteArray &&pin) const +QPCSCReader::Result THALESCard::replace(QSmartCardData::PinType type, const QByteArray &puk, const QByteArray &pin) const { - puk = pinTemplate(std::move(puk)); - pin = pinTemplate(std::move(pin)); QByteArray cmd = REPLACE; cmd[3] = char(0x80 | type); cmd[4] = char(puk.size() + pin.size()); - return transfer(reader, false, cmd + puk + pin, type, quint8(puk.size()), true); + cmd += puk; + cmd += pin; + return transfer(false, std::move(cmd), type, quint8(puk.size()), true); } -bool THALESCard::updateCounters(QPCSCReader *reader, QSmartCardDataPrivate *d) const +bool THALESCard::updateCounters(QSmartCardDataPrivate *d) const { auto apdu = APDU("00CB00FF 05 A003830180 00"); for(quint8 type = QSmartCardData::Pin1Type; type <= QSmartCardData::PukType; ++type) { apdu[9] = char(0x80 | type); - auto data = reader->transfer(apdu); + auto data = reader.transfer(apdu); if(!data) return false; if(auto info = TLV(data.data); auto retry = info[0xDF21]) @@ -506,6 +511,13 @@ bool QSmartCard::pinChange(QSmartCardData::PinType type, QSmartCard::PinAction a src = QSmartCardData::PukType; } + auto card = Card::card(d->t.reader()); + if(!card) + { + FadeInNotification::warning(parent, tr("Changing %1 failed").arg(QSmartCardData::typeString(type))); + return false; + } + if(d->t.isPinpad()) { QString bodyText; @@ -533,6 +545,8 @@ bool QSmartCard::pinChange(QSmartCardData::PinType type, QSmartCard::PinAction a } popup.reset(new PinPopup(src, flags, d->t.authCert(), parent, bodyText)); popup->open(); + oldPin = card->pinTemplate({}); + newPin = card->pinTemplate({}); } else { @@ -540,23 +554,35 @@ bool QSmartCard::pinChange(QSmartCardData::PinType type, QSmartCard::PinAction a d->t.data(QSmartCardData::Id).toString(), d->t.isPUKReplacable(), parent); if (!p.exec()) return false; - oldPin = p.firstCodeText().toUtf8(); - newPin = p.newCodeText().toUtf8(); + QString oldPinString = p.firstCodeText(); + QString newPinString = p.newCodeText(); + oldPin = card->pinTemplate(oldPinString); + newPin = card->pinTemplate(newPinString); + // Try to clean QLineEdit internal PIN copy using constData that does not detach memory + auto chars = const_cast(oldPinString.constData()); + for (int i = 0; i < oldPinString.length(); ++i) + chars[i] = '\0'; + chars = const_cast(newPinString.constData()); + for (int i = 0; i < newPinString.length(); ++i) + chars[i] = '\0'; } + auto clean = qScopeGuard([&oldPin, &newPin] { + oldPin.fill('\0'); + newPin.fill('\0'); + }); - QPCSCReader reader(d->t.reader(), &QPCSC::instance()); - if(!reader.connect()) + if(!card->reader.connect()) { FadeInNotification::warning(parent, tr("Changing %1 failed").arg(QSmartCardData::typeString(type))); return false; } auto response = action == QSmartCard::ChangeWithPin || action == QSmartCard::ActivateWithPin ? - d->card->change(&reader, type, std::move(oldPin), std::move(newPin)) : - d->card->replace(&reader, type, std::move(oldPin), std::move(newPin)); + card->change(type, oldPin, newPin) : + card->replace(type, oldPin, newPin); switch(response.SW) { case 0x9000: - d->card->updateCounters(&reader, d->t.d); + card->updateCounters(d->t.d); switch(action) { using enum QSmartCard::PinAction; @@ -577,13 +603,13 @@ bool QSmartCard::pinChange(QSmartCardData::PinType type, QSmartCard::PinAction a case 0x63C0: //pin retry count 0 case 0x6983: case 0x6984: - d->card->updateCounters(&reader, d->t.d); + card->updateCounters(d->t.d); FadeInNotification::warning(parent, tr("%1 blocked").arg(QSmartCardData::typeString(src))); return true; case 0x63C1: // Validate error, 1 tries left case 0x63C2: // Validate error, 2 tries left case 0x63C3: - d->card->updateCounters(&reader, d->t.d); + card->updateCounters(d->t.d); FadeInNotification::warning(parent, tr("Wrong %1 code. You can try %n more time(s).", nullptr, d->t.retryCount(src)).arg(QSmartCardData::typeString(src))); return false; @@ -614,55 +640,50 @@ void QSmartCard::reloadCard(const TokenData &token, bool reloadCounters) qCDebug(CLog) << "Polling"; d->token = token; Q_EMIT tokenChanged(token); - if(!reloadCounters && !d->t.isNull() && !d->t.card().isEmpty() && d->t.card() == d->token.card()) - return; - - // check if selected card is same as signer - if(!d->t.card().isEmpty() && d->token.card() != d->t.card()) + if(d->token.isNull() || d->token.card().isEmpty() || d->token.reader().isEmpty()) + { + qCDebug(CLog) << "Is null or no reader"; d->t.d = new QSmartCardDataPrivate(); + return; + } - // select signer card - if(d->t.card().isEmpty() || d->t.card() != d->token.card()) + if(d->token.card() != d->t.card()) { - QSharedDataPointer t = d->t.d; - t->card = d->token.card(); - t->data.clear(); - t->authCert.clear(); - t->signCert.clear(); - d->t.d = std::move(t); + qCDebug(CLog) << "Different token"; + d->t.d = new QSmartCardDataPrivate(); } - - if(!reloadCounters && (!d->t.isNull() || d->token.reader().isEmpty())) + else if(reloadCounters) + qCDebug(CLog) << "Reload counter"; + else return; QString reader = d->token.reader(); if(d->token.reader().endsWith(QLatin1String("..."))) { - for(const QString &test: QPCSC::instance().readers()) { - if(test.startsWith(d->token.reader().left(d->token.reader().size() - 3))) + for(auto truncated = QStringView(d->token.reader()).left(d->token.reader().size() - 3); + const QString &test: QPCSC::instance().readers()) { + if(test.startsWith(truncated)) reader = test; } } qCDebug(CLog) << "Read" << reader; - QPCSCReader selectedReader(reader, &QPCSC::instance()); - if(auto atr = selectedReader.atr(); - IDEMIACard::isSupported(atr)) - d->card = std::make_unique(); - else if(THALESCard::isSupported(atr)) - d->card = std::make_unique(); - else { - qCDebug(CLog) << "Unsupported card"; - d->card.reset(); + auto card = Card::card(reader); + if(!card) return; - } - - if(!selectedReader.connect()) + if(!card->reader.connect()) return; qCDebug(CLog) << "Read card" << d->token.card() << "info"; QSharedDataPointer t = d->t.d; - t->reader = selectedReader.name(); - t->pinpad = selectedReader.isPinPad(); - if(d->card->loadPerso(&selectedReader, t)) + t->card = d->token.card(); + t->reader = card->reader.name(); + t->pinpad = card->reader.isPinPad(); + t->data.clear(); + t->authCert.clear(); + t->signCert.clear(); + t->retry.clear(); + t->locked.clear(); + + if(card->loadPerso(t)) { d->t.d = std::move(t); emit dataChanged(d->t); diff --git a/client/QSmartCard.h b/client/QSmartCard.h index 7e553826b..390a7a099 100644 --- a/client/QSmartCard.h +++ b/client/QSmartCard.h @@ -110,6 +110,6 @@ class QSmartCard final: public QObject private: Q_DISABLE_COPY_MOVE(QSmartCard) - class Private; + struct Private; std::unique_ptr d; }; diff --git a/client/QSmartCard_p.h b/client/QSmartCard_p.h index 6015f2510..af62b11d8 100644 --- a/client/QSmartCard_p.h +++ b/client/QSmartCard_p.h @@ -29,57 +29,59 @@ #define APDU QByteArray::fromHex -class Card +struct Card { -public: + Card(QPCSCReader &&reader): reader(std::move(reader)) {} virtual ~Card() noexcept = default; - virtual QPCSCReader::Result change(QPCSCReader *reader, QSmartCardData::PinType type, QByteArray &&pin, QByteArray &&newpin) const = 0; - virtual bool loadPerso(QPCSCReader *reader, QSmartCardDataPrivate *d) const = 0; - virtual QPCSCReader::Result replace(QPCSCReader *reader, QSmartCardData::PinType type, QByteArray &&puk, QByteArray &&pin) const = 0; - static QPCSCReader::Result transfer(QPCSCReader *reader, bool verify, const QByteArray &apdu, - QSmartCardData::PinType type, quint8 newPINOffset, bool requestCurrentPIN); - virtual bool updateCounters(QPCSCReader *reader, QSmartCardDataPrivate *d) const = 0; - + virtual QPCSCReader::Result change(QSmartCardData::PinType type, const QByteArray &pin, const QByteArray &newpin) const = 0; + virtual bool loadPerso(QSmartCardDataPrivate *d) const = 0; + virtual QByteArray pinTemplate(const QString &pin) const; + virtual QPCSCReader::Result replace(QSmartCardData::PinType type, const QByteArray &puk, const QByteArray &pin) const = 0; + QPCSCReader::Result transfer(bool verify, QByteArray &&apdu, + QSmartCardData::PinType type, quint8 newPINOffset, bool requestCurrentPIN) const; + virtual bool updateCounters(QSmartCardDataPrivate *d) const = 0; + + static std::unique_ptr card(const QString &reader); static QByteArrayView parseFCI(QByteArrayView data, quint8 expectedTag); static const QByteArray CHANGE; static const QByteArray READBINARY; static const QByteArray REPLACE; static const QByteArray VERIFY; + + char fillChar = 0x00; + + QPCSCReader reader; }; -class IDEMIACard: public Card +struct IDEMIACard: public Card { -public: - QPCSCReader::Result change(QPCSCReader *reader, QSmartCardData::PinType type, QByteArray &&pin, QByteArray &&newpin) const final; - bool loadPerso(QPCSCReader *reader, QSmartCardDataPrivate *d) const final; - QPCSCReader::Result replace(QPCSCReader *reader, QSmartCardData::PinType type, QByteArray &&puk, QByteArray &&pin) const final; - bool updateCounters(QPCSCReader *reader, QSmartCardDataPrivate *d) const final; + IDEMIACard(QPCSCReader &&reader): Card(std::move(reader)) { fillChar = 0xFF; } + QPCSCReader::Result change(QSmartCardData::PinType type, const QByteArray &pin, const QByteArray &newpin) const final; + bool loadPerso(QSmartCardDataPrivate *d) const final; + QPCSCReader::Result replace(QSmartCardData::PinType type, const QByteArray &puk, const QByteArray &pin) const final; + bool updateCounters(QSmartCardDataPrivate *d) const final; static bool isSupported(const QByteArray &atr); - static QByteArray pinTemplate(QByteArray &&pin); static const QByteArray AID, AID_OT, AID_QSCD, ATR_COSMO8, ATR_COSMOX; }; -class THALESCard: public Card +struct THALESCard: public Card { -public: - QPCSCReader::Result change(QPCSCReader *reader, QSmartCardData::PinType type, QByteArray &&pin, QByteArray &&newpin) const final; - bool loadPerso(QPCSCReader *reader, QSmartCardDataPrivate *d) const final; - QPCSCReader::Result replace(QPCSCReader *reader, QSmartCardData::PinType type, QByteArray &&puk, QByteArray &&pin) const final; - bool updateCounters(QPCSCReader *reader, QSmartCardDataPrivate *d) const final; + using Card::Card; + QPCSCReader::Result change(QSmartCardData::PinType type, const QByteArray &pin, const QByteArray &newpin) const final; + bool loadPerso(QSmartCardDataPrivate *d) const final; + QPCSCReader::Result replace(QSmartCardData::PinType type, const QByteArray &puk, const QByteArray &pin) const final; + bool updateCounters(QSmartCardDataPrivate *d) const final; static bool isSupported(const QByteArray &atr); - static QByteArray pinTemplate(const QString &pin); static const QByteArray AID; }; -class QSmartCard::Private +struct QSmartCard::Private { -public: - std::unique_ptr card; TokenData token; QSmartCardData t; }; diff --git a/client/dialogs/PinPopup.cpp b/client/dialogs/PinPopup.cpp index ed77a6196..ef90b511e 100644 --- a/client/dialogs/PinPopup.cpp +++ b/client/dialogs/PinPopup.cpp @@ -24,36 +24,34 @@ #include #include -#include #include -#include #include PinPopup::PinPopup(QSmartCardData::PinType type, TokenFlags flags, const SslCertificate &c, QWidget *parent, QString text) : QDialog(parent) - , ui(new Ui::PinPopup) { - ui->setupUi(this); + Ui::PinPopup ui {}; + ui.setupUi(this); setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint); #ifdef Q_OS_WIN - ui->buttonLayout->setDirection(QBoxLayout::RightToLeft); + ui.buttonLayout->setDirection(QBoxLayout::RightToLeft); #endif for(QLineEdit *w: findChildren()) w->setAttribute(Qt::WA_MacShowFocusRect, false); - ui->pin->setValidator(regexp = new QRegularExpressionValidator(ui->pin)); + ui.pin->setValidator(regexp = new QRegularExpressionValidator(ui.pin)); new Overlay(this); - connect( ui->ok, &QPushButton::clicked, this, &PinPopup::accept ); - connect( ui->cancel, &QPushButton::clicked, this, &PinPopup::reject ); - connect( this, &PinPopup::finished, this, &PinPopup::close ); - connect(ui->pin, &QLineEdit::returnPressed, ui->ok, &QPushButton::click); + connect(ui.ok, &QPushButton::clicked, this, &PinPopup::accept); + connect(ui.cancel, &QPushButton::clicked, this, &PinPopup::reject); + connect(this, &PinPopup::finished, this, &PinPopup::close ); + connect(ui.pin, &QLineEdit::returnPressed, ui.ok, &QPushButton::click); if(!text.isEmpty()) - ui->labelPin->hide(); + ui.labelPin->hide(); else if(type == QSmartCardData::Pin2Type) { text = tr("Selected action requires sign certificate."); - ui->labelPin->setText(flags & PinpadFlag ? + ui.labelPin->setText(flags & PinpadFlag ? tr("For using sign certificate enter PIN2 at the reader") : tr("For using sign certificate enter PIN2")); setPinLen(5); @@ -61,43 +59,45 @@ PinPopup::PinPopup(QSmartCardData::PinType type, TokenFlags flags, const SslCert else { text = tr("Selected action requires authentication certificate."); - ui->labelPin->setText(flags & PinpadFlag ? + ui.labelPin->setText(flags & PinpadFlag ? tr("For using authentication certificate enter PIN1 at the reader") : tr("For using authentication certificate enter PIN1")); setPinLen(4); } - ui->label->setText(c.toString(c.showCN() ? QStringLiteral("CN, serialNumber") : QStringLiteral("GN SN, serialNumber"))); - ui->text->setText(text); + ui.label->setText(c.toString(c.showCN() ? QStringLiteral("CN, serialNumber") : QStringLiteral("GN SN, serialNumber"))); + ui.text->setText(text); if(flags & PinFinalTry) - ui->errorPin->setText(tr("%1 will be locked next failed attempt").arg(QSmartCardData::typeString(type))); + ui.errorPin->setText(tr("%1 will be locked next failed attempt").arg(QSmartCardData::typeString(type))); else if(flags & PinCountLow) - ui->errorPin->setText(tr("%1 has been entered incorrectly at least once").arg(QSmartCardData::typeString(type))); + ui.errorPin->setText(tr("%1 has been entered incorrectly at least once").arg(QSmartCardData::typeString(type))); else - ui->errorPin->hide(); + ui.errorPin->hide(); if(flags & PinpadChangeFlag) { - ui->pin->hide(); - ui->ok->hide(); - ui->cancel->hide(); - ui->errorPin->setAlignment(Qt::AlignCenter); + isPinPad = true; + ui.pin->hide(); + ui.ok->hide(); + ui.cancel->hide(); + ui.errorPin->setAlignment(Qt::AlignCenter); auto *movie = new QSvgWidget(QStringLiteral(":/images/wait.svg"), this); - movie->setFixedSize(ui->pin->size().height(), ui->pin->size().height()); + movie->setFixedSize(ui.pin->size().height(), ui.pin->size().height()); movie->show(); - ui->layoutContent->addWidget(movie, 0, Qt::AlignCenter); + ui.layoutContent->addWidget(movie, 0, Qt::AlignCenter); } else if(flags & PinpadFlag) { - ui->pin->hide(); - ui->ok->hide(); - ui->cancel->hide(); + isPinPad = true; + ui.pin->hide(); + ui.ok->hide(); + ui.cancel->hide(); auto *progress = new QProgressBar(this); progress->setRange( 0, 30 ); progress->setValue( progress->maximum() ); progress->setTextVisible( false ); progress->resize( 200, 30 ); progress->move( 153, 122 ); - ui->layoutContent->addWidget(progress); + ui.layoutContent->addWidget(progress); auto *statusTimer = new QTimeLine(progress->maximum() * 1000, this); statusTimer->setEasingCurve(QEasingCurve::Linear); statusTimer->setFrameRange( progress->maximum(), progress->minimum() ); @@ -106,24 +106,20 @@ PinPopup::PinPopup(QSmartCardData::PinType type, TokenFlags flags, const SslCert } else { - ui->pin->setFocus(); - ui->pin->setMaxLength( 12 ); - connect(ui->pin, &QLineEdit::textEdited, this, [&](const QString &text) { - ui->ok->setEnabled(regexp->regularExpression().match(text).hasMatch()); + ui.pin->setFocus(); + ui.pin->setMaxLength( 12 ); + connect(ui.pin, &QLineEdit::textEdited, this, [&](const QString &text) { + ui.ok->setEnabled(regexp->regularExpression().match(text).hasMatch()); }); - ui->text->setBuddy( ui->pin ); - ui->ok->setDisabled(true); + ui.text->setBuddy(ui.pin); + ui.ok->setDisabled(true); } if(c.type() & SslCertificate::TempelType) { regexp->setRegularExpression(QRegularExpression(QStringLiteral("^.{4,}$"))); - ui->pin->setMaxLength(32767); + ui.pin->setMaxLength(32767); } -} - -PinPopup::~PinPopup() -{ - delete ui; + pinInput = ui.pin; } void PinPopup::setPinLen(unsigned long minLen, unsigned long maxLen) @@ -132,4 +128,10 @@ void PinPopup::setPinLen(unsigned long minLen, unsigned long maxLen) regexp->setRegularExpression(QRegularExpression(QStringLiteral("^%1{%2,%3}$").arg(charPattern).arg(minLen).arg(maxLen))); } -QString PinPopup::pin() const { return ui->pin->text(); } +QString PinPopup::pin() const { return pinInput->text(); } + +void PinPopup::reject() +{ + if (!isPinPad) + QDialog::reject(); +} diff --git a/client/dialogs/PinPopup.h b/client/dialogs/PinPopup.h index ce866d51b..08f8d9e3a 100644 --- a/client/dialogs/PinPopup.h +++ b/client/dialogs/PinPopup.h @@ -24,10 +24,7 @@ #include "QSmartCard.h" #include "WaitDialog.h" -namespace Ui { -class PinPopup; -} - +class QLineEdit; class QRegularExpressionValidator; class SslCertificate; @@ -47,7 +44,6 @@ class PinPopup final : public QDialog Q_DECLARE_FLAGS(TokenFlags, TokenFlag) PinPopup(QSmartCardData::PinType type, TokenFlags flags, const SslCertificate &cert, QWidget *parent = {}, QString text = {}); - ~PinPopup() final; void setPinLen(unsigned long minLen, unsigned long maxLen = 12); QString pin() const; @@ -56,8 +52,11 @@ class PinPopup final : public QDialog void startTimer(); private: - Ui::PinPopup *ui; + void reject() final; + + QLineEdit *pinInput; QRegularExpressionValidator *regexp {}; WaitDialogHider hider; + bool isPinPad = false; };