diff --git a/QPCSC.cpp b/QPCSC.cpp index 57f20e5..6a23afd 100644 --- a/QPCSC.cpp +++ b/QPCSC.cpp @@ -41,6 +41,11 @@ namespace Qt { Q_LOGGING_CATEGORY(APDU,"QPCSC.APDU") Q_LOGGING_CATEGORY(SCard,"QPCSC.SCard") +static quint16 toUInt16(const QByteArray &data, int size) +{ + return size >= 2 ? quint16((quint16(data[size - 2]) << 8) | quint16(data[size - 1])) : 0; +} + static QStringList stateToString(DWORD state) { QStringList result; @@ -58,10 +63,10 @@ static QStringList stateToString(DWORD state) return result; } -template < typename Func, typename... Args> -LONG SCCall( const char *file, int line, const char *function, Func func, Args... args) +template +static auto SCCall(const char *file, int line, const char *function, Func func, Args... args) { - LONG err = func(args...); + auto err = func(args...); if(SCard().isDebugEnabled()) QMessageLogger(file, line, function, SCard().categoryName()).debug() << function << Qt::hex << (unsigned long)err; @@ -284,7 +289,7 @@ void QPCSCReader::disconnect( Reset reset ) if( d->card ) SC(Disconnect, d->card, reset); d->io.dwProtocol = SCARD_PROTOCOL_UNDEFINED; - d->card = 0; + d->card = {}; d->featuresList.clear(); updateState(); } @@ -362,19 +367,19 @@ QPCSCReader::Result QPCSCReader::transfer( const QByteArray &apdu ) const QByteArray data( 1024, 0 ); auto size = DWORD(data.size()); - qCDebug(APDU).nospace() << 'T' << d->io.dwProtocol - 1 << "> " << apdu.toHex().constData(); + qCDebug(APDU).nospace().noquote() << 'T' << d->io.dwProtocol - 1 << "> " << apdu.toHex(); LONG ret = SC(Transmit, d->card, &d->io, LPCBYTE(apdu.constData()), DWORD(apdu.size()), nullptr, LPBYTE(data.data()), &size); if( ret != SCARD_S_SUCCESS ) return { {}, {}, quint32(ret) }; - Result result = { data.mid(int(size - 2), 2), data.left(int(size - 2)), quint32(ret) }; - qCDebug(APDU).nospace() << 'T' << d->io.dwProtocol - 1 << "< " << result.SW.toHex().constData(); - if(!result.data.isEmpty()) qCDebug(APDU).nospace() << data.left(int(size)).toHex().constData(); + Result result { data.left(int(size - 2)), toUInt16(data, size), quint32(ret) }; + qCDebug(APDU).nospace() << 'T' << d->io.dwProtocol - 1 << "< " << Qt::hex << result.SW; + if(!result.data.isEmpty()) qCDebug(APDU).nospace().noquote() << result.data.toHex(); - switch(result.SW.at(0)) + switch(result.SW & 0xFF00) { - case 0x61: // Read more + case 0x6100: // Read more { QByteArray cmd( "\x00\xC0\x00\x00\x00", 5 ); cmd[4] = data.at(int(size - 1)); @@ -382,10 +387,10 @@ QPCSCReader::Result QPCSCReader::transfer( const QByteArray &apdu ) const result2.data.prepend(result.data); return result2; } - case 0x6C: // Excpected lenght + case 0x6C00: // Excpected lenght { QByteArray cmd = apdu; - cmd[4] = result.SW.at(1); + cmd[4] = char(result.SW); return transfer(cmd); } default: return result; @@ -454,8 +459,8 @@ QPCSCReader::Result QPCSCReader::transferCTL(const QByteArray &apdu, bool verify if( !ioctl ) ioctl = features.value( verify ? FEATURE_VERIFY_PIN_DIRECT : FEATURE_MODIFY_PIN_DIRECT ); - qCDebug(APDU).nospace() << 'T' << d->io.dwProtocol - 1 << "> " << apdu.toHex().constData(); - qCDebug(APDU).nospace() << "CTL" << "> " << cmd.toHex().constData(); + qCDebug(APDU).nospace().noquote() << 'T' << d->io.dwProtocol - 1 << "> " << apdu.toHex(); + qCDebug(APDU).nospace().noquote() << "CTL" << "> " << cmd.toHex(); QByteArray data( 255 + 3, 0 ); auto size = DWORD(data.size()); LONG err = SC(Control, d->card, ioctl, cmd.constData(), DWORD(cmd.size()), LPVOID(data.data()), DWORD(data.size()), &size); @@ -466,9 +471,9 @@ QPCSCReader::Result QPCSCReader::transferCTL(const QByteArray &apdu, bool verify err = SC(Control, d->card, finish, nullptr, 0U, LPVOID(data.data()), DWORD(data.size()), &size); } - Result result { data.mid(int(size - 2), 2), data.left(int(size - 2)), quint32(err) }; - qCDebug(APDU).nospace() << 'T' << d->io.dwProtocol - 1 << "< " << result.SW.toHex().constData(); - if(!result.data.isEmpty()) qCDebug(APDU).nospace() << data.left(int(size)).toHex().constData(); + Result result { data.left(int(size - 2)), toUInt16(data, size), quint32(err) }; + qCDebug(APDU).nospace() << 'T' << d->io.dwProtocol - 1 << "< " << Qt::hex << result.SW; + if(!result.data.isEmpty()) qCDebug(APDU).nospace().noquote() << result.data.toHex(); return result; } diff --git a/QPCSC.h b/QPCSC.h index dd7ed07..a0eb283 100644 --- a/QPCSC.h +++ b/QPCSC.h @@ -56,15 +56,10 @@ class QPCSCReader final: public QObject Q_OBJECT public: struct Result { - QByteArray SW; QByteArray data; + quint16 SW; quint32 err = 0; - inline operator bool() const { return resultOk(); } - inline bool resultOk() const - { - static const QByteArray OK("\x90\x00", 2); - return SW == OK; - } + constexpr operator bool() const { return SW == 0x9000; } }; enum Properties { diff --git a/QPCSC_p.h b/QPCSC_p.h index 19fab0b..4ffa83b 100644 --- a/QPCSC_p.h +++ b/QPCSC_p.h @@ -47,7 +47,7 @@ // http://ludovic.rousseau.free.fr/softwares/pcsc-lite/SecurePIN%20discussion%20v5.pdf #define CM_IOCTL_GET_FEATURE_REQUEST SCARD_CTL_CODE(3400) -enum DRIVER_FEATURES { +enum DRIVER_FEATURES : quint8 { FEATURE_VERIFY_PIN_START = 0x01, FEATURE_VERIFY_PIN_FINISH = 0x02, FEATURE_MODIFY_PIN_START = 0x03, @@ -69,13 +69,9 @@ FEATURE_GET_TLV_PROPERTIES = 0x12, FEATURE_CCID_ESC_COMMAND = 0x13 }; -#ifdef Q_OS_MAC -#pragma pack(1) -#else #pragma pack(push, 1) -#endif -using PCSC_TLV_STRUCTURE = struct +struct PCSC_TLV_STRUCTURE { quint8 tag; quint8 length; @@ -128,7 +124,7 @@ enum bConfirmPIN : quint8 AdvancedModify = 1 << 2, }; -using PIN_VERIFY_STRUCTURE = struct +struct PIN_VERIFY_STRUCTURE { quint8 bTimerOut; // timeout in seconds (00 means use default timeout) quint8 bTimerOut2; // timeout in seconds after first key stroke @@ -145,7 +141,7 @@ using PIN_VERIFY_STRUCTURE = struct quint8 abData[1]; // Data to send to the ICC }; -using PIN_MODIFY_STRUCTURE = struct +struct PIN_MODIFY_STRUCTURE { quint8 bTimerOut; // timeout in seconds (00 means use default timeout) quint8 bTimerOut2; // timeout in seconds after first key stroke @@ -167,22 +163,20 @@ using PIN_MODIFY_STRUCTURE = struct quint8 abData[1]; // Data to send to the ICC }; -using PIN_PROPERTIES_STRUCTURE = struct { +struct PIN_PROPERTIES_STRUCTURE +{ quint16 wLcdLayout; quint8 bEntryValidationCondition; quint8 bTimeOut2; }; -using DISPLAY_PROPERTIES_STRUCTURE = struct { +struct DISPLAY_PROPERTIES_STRUCTURE +{ quint16 wLcdMaxCharacters; quint16 wLcdMaxLines; }; -#ifdef Q_OS_MAC -#pragma pack() -#else #pragma pack(pop) -#endif class QPCSC::Private {