Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify APDU SW usage #137

Merged
merged 1 commit into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading