From bf5fd51ea01f16a31e82fb924b7a4b0102f64f96 Mon Sep 17 00:00:00 2001 From: Vital-Z Date: Wed, 21 Jan 2026 13:06:45 +0100 Subject: [PATCH 1/2] added protocol selection based on ATR --- common/SCard.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++++++-- common/general.h | 2 +- common/util.cpp | 44 ++++++++++++++++++++++++++++++++++ common/util.h | 1 + 4 files changed, 105 insertions(+), 3 deletions(-) diff --git a/common/SCard.cpp b/common/SCard.cpp index a69f271..f4a6b71 100644 --- a/common/SCard.cpp +++ b/common/SCard.cpp @@ -249,6 +249,56 @@ void SCard::listReaders(std::vector>& readers) #endif } + +int getProtocol(const unsigned char* in, int size) { + if (!in || size <= 0) return SCARD_PROTOCOL_T0; + + const unsigned char* p = in; + int protocol = SCARD_PROTOCOL_T0; + + // first byte = T0; if no further TDx present => T=0 + if ( ((*p) & 0x80) == 0 ) { + return SCARD_PROTOCOL_T0; + } + + //get last TDx (if TDx&0X08 => there is a another TD, following TAx, TBx, TCx depending on the bits in the first nibble of T0 or following TDx bytes + while (p < in + size) { + unsigned char y = (*p) & 0xF0; // Yx in high nibble + + if ((y & 0x80) == 0) { // no TD(x) follows + break; + } + + // Skip to the next TD: advance past TA/TB/TC/TD indicated by Yx bits. + // Yx bits: 0x10(TA), 0x20(TB), 0x40(TC), 0x80(TD) + int skip = + ((y & 0x10) ? 1 : 0) + + ((y & 0x20) ? 1 : 0) + + ((y & 0x40) ? 1 : 0) + + ((y & 0x80) ? 1 : 0); + + // p currently points at T0 or TDx; the indicated interface bytes follow *after* it + // so move p forward by that many bytes to land on the next TD (or go out of bounds). + if (p + skip >= in + size) { + // Not enough bytes; bail out safely with default T=0 + return SCARD_PROTOCOL_T0; + } + p += skip; + // Now p points at the next TD (because skip includes TD itself). + // Loop continues; it will examine this TD's Y nibble. + } + + // If p points at a TD, the low nibble indicates protocol T=0,1,15 etc. + // Your original code checked bit 0x01 -> treat as T=1 + if (p < in + size) { + if ((*p & 0x0F) == 0x01) { // protocol number == 1 + protocol = SCARD_PROTOCOL_T1; + } + } + + return protocol; +} + long SCard::connect() { DECLAREFUNCTIONHEADER; @@ -257,8 +307,15 @@ long SCard::connect() return E_SRC_NO_CARD; } - DWORD ActiveProtocol = SCARD_PROTOCOL_UNDEFINED; - ret = SCardConnect(*context, name.c_str(), SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1| SCARD_PROTOCOL_T0, &hCard, &ActiveProtocol); + DWORD ActiveProtocol = SCARD_PROTOCOL_T0; + + auto bytes = hex_to_bytes(atr); + if (bytes.empty()) + ActiveProtocol = SCARD_PROTOCOL_T0; + + ActiveProtocol = getProtocol(bytes.data(), static_cast(bytes.size())); + + ret = SCardConnect(*context, name.c_str(), SCARD_SHARE_SHARED, ActiveProtocol, &hCard, &ActiveProtocol); if (ret != SCARD_S_SUCCESS) { log_error("%s: E: SCardConnect(%s) returned %08X", __func__, name.c_str(), ret); return (ret); diff --git a/common/general.h b/common/general.h index 15d8835..bf0c5a6 100755 --- a/common/general.h +++ b/common/general.h @@ -14,7 +14,7 @@ * ******************************************************************************/ -#define BEIDCONNECT_VERSION "2.11" +#define BEIDCONNECT_VERSION "2.12" #define CLEANUP(a) { ret = a; goto cleanup; } diff --git a/common/util.cpp b/common/util.cpp index 5415670..3bd12eb 100644 --- a/common/util.cpp +++ b/common/util.cpp @@ -268,3 +268,47 @@ const std::vector base64ToRaw(const std::string& bufcoded) return bufout; } + +static int hex_value(char c) { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return 10 + (c - 'a'); + if (c >= 'A' && c <= 'F') return 10 + (c - 'A'); + return -1; +} + +const std::vector hex_to_bytes(const std::string& hex) { + // Remove whitespace and common separators + std::string cleaned; + cleaned.reserve(hex.size()); + for (char c : hex) { + if (std::isspace(static_cast(c)) || + c == ':' || c == '-') { + continue; + } + cleaned.push_back(c); + } + + if (cleaned.empty()) return {}; + + // Handle odd number of hex digits + if (cleaned.size() % 2 == 1) { + cleaned.insert(cleaned.begin(), '0'); + } + + std::vector out; + out.reserve(cleaned.size() / 2); + + for (size_t i = 0; i < cleaned.size(); i += 2) { + int hi = hex_value(cleaned[i]); + int lo = hex_value(cleaned[i + 1]); + if (hi < 0 || lo < 0) { + throw std::invalid_argument("Invalid hex character"); + } + + out.push_back( + static_cast((hi << 4) | lo) + ); + } + + return out; +} diff --git a/common/util.h b/common/util.h index 97d48d8..85e4e55 100644 --- a/common/util.h +++ b/common/util.h @@ -29,5 +29,6 @@ size_t base64encode(const unsigned char *string, size_t len, unsigned char *enco std::string rawToBase64(const std::vector& raw); const std::vector base64ToRaw(const std::string& bufcoded); +const std::vector hex_to_bytes(const std::string& hex); #endif // From 1bbfadd2f1321082f9708a3a88a968e3e6d8e58c Mon Sep 17 00:00:00 2001 From: Vital-Z Date: Thu, 22 Jan 2026 16:22:08 +0100 Subject: [PATCH 2/2] skip TS byte before checking TDx bytes --- common/SCard.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/common/SCard.cpp b/common/SCard.cpp index f4a6b71..0b249c2 100644 --- a/common/SCard.cpp +++ b/common/SCard.cpp @@ -256,6 +256,7 @@ int getProtocol(const unsigned char* in, int size) { const unsigned char* p = in; int protocol = SCARD_PROTOCOL_T0; + p++; //skip TS // first byte = T0; if no further TDx present => T=0 if ( ((*p) & 0x80) == 0 ) { return SCARD_PROTOCOL_T0;