Skip to content

Commit

Permalink
Simplify APDU SW usage
Browse files Browse the repository at this point in the history
IB-8231

Signed-off-by: Raul Metsma <[email protected]>
  • Loading branch information
metsma committed Oct 2, 2024
1 parent 8e4034f commit 2731913
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 38 deletions.
39 changes: 22 additions & 17 deletions QPCSC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<typename Func, typename... Args>
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;
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -362,30 +367,30 @@ 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));
Result result2 = transfer( cmd );
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;
Expand Down Expand Up @@ -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);
Expand All @@ -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;
}

Expand Down
9 changes: 2 additions & 7 deletions QPCSC.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
22 changes: 8 additions & 14 deletions QPCSC_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
{
Expand Down

0 comments on commit 2731913

Please sign in to comment.