Skip to content
Open
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
62 changes: 60 additions & 2 deletions common/SCard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,57 @@ void SCard::listReaders(std::vector<std::shared_ptr<CardReader>>& 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;

p++; //skip TS
// 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;
Expand All @@ -257,8 +308,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<int>(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);
Expand Down
2 changes: 1 addition & 1 deletion common/general.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
*
******************************************************************************/

#define BEIDCONNECT_VERSION "2.11"
#define BEIDCONNECT_VERSION "2.12"

#define CLEANUP(a) { ret = a; goto cleanup; }

Expand Down
44 changes: 44 additions & 0 deletions common/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,3 +268,47 @@ const std::vector<unsigned char> 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<unsigned char> 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<unsigned char>(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<unsigned char> 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<unsigned char>((hi << 4) | lo)
);
}

return out;
}
1 change: 1 addition & 0 deletions common/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ size_t base64encode(const unsigned char *string, size_t len, unsigned char *enco

std::string rawToBase64(const std::vector<unsigned char>& raw);
const std::vector<unsigned char> base64ToRaw(const std::string& bufcoded);
const std::vector<unsigned char> hex_to_bytes(const std::string& hex);

#endif //