Skip to content

Commit c1e0a6c

Browse files
committed
Use CommandAPDU instead byte_vector
Signed-off-by: Raul Metsma <[email protected]>
1 parent 7f91f6a commit c1e0a6c

File tree

2 files changed

+55
-68
lines changed

2 files changed

+55
-68
lines changed

lib/libpcsc-cpp/include/pcsc-cpp/pcsc-cpp.hpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,15 @@ struct CommandApdu
165165
d.push_back(le);
166166
}
167167

168-
virtual ~CommandApdu() noexcept = default;
168+
PCSC_CPP_CONSTEXPR_VECTOR CommandApdu(const CommandApdu &other, byte_type le) :
169+
d(other.d)
170+
{
171+
size_t pos = d.size() <= 5 ? 4 : 5 + d[4]; // Case 1/2 or 3/4
172+
d.resize(pos + 1);
173+
d[pos] = le;
174+
}
169175

170-
constexpr operator const byte_vector&() const { return d; }
176+
virtual ~CommandApdu() noexcept = default;
171177

172178
/**
173179
* A helper function to create a SELECT FILE command APDU.
@@ -249,6 +255,21 @@ struct CommandApdu
249255
return VerifyApdu {0x00, 0x20, 0x00, p2, std::move(pin)};
250256
}
251257

258+
/**
259+
* A helper function to create a GET RESPONSE command APDU.
260+
*
261+
* The ISO 7816-4 Section 7.1 GET RESPONSE command has the form:
262+
* CLA = 0x00
263+
* INS = 0xC0
264+
* P1, P2 = ‘0000’ (other values are RFU)
265+
* Lc and Data field = Empty
266+
* Le = Maximum length of data expected in response
267+
*/
268+
static PCSC_CPP_CONSTEXPR_VECTOR CommandApdu getResponse(byte_type le = 0x00)
269+
{
270+
return {0x00, 0xc0, 0x00, 0x00, le};
271+
}
272+
252273
byte_vector d;
253274
};
254275

lib/libpcsc-cpp/src/SmartCard.cpp

Lines changed: 32 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,6 @@
4141
namespace
4242
{
4343

44-
template <class K, class V = uint32_t, class D, size_t dsize, typename Func>
45-
constexpr std::map<K, V> parseTLV(const std::array<D, dsize>& data, DWORD size, Func transform)
46-
{
47-
std::map<K, V> result;
48-
for (auto p = data.cbegin(); DWORD(std::distance(data.cbegin(), p)) < size;) {
49-
auto tag = K(*p++);
50-
V value {};
51-
for (unsigned int i = 0, len = *p++; i < len; ++i)
52-
value |= V(*p++) << 8 * i;
53-
result[tag] = transform(value);
54-
}
55-
return result;
56-
}
57-
5844
constexpr uint32_t VENDOR_HID_GLOBAL = 0x076B;
5945
constexpr uint32_t OMNIKEY_3x21 = 0x3031;
6046
constexpr uint32_t OMNIKEY_6121 = 0x6632;
@@ -103,13 +89,16 @@ class CardImpl
10389
std::array<BYTE, 256> buf {};
10490
SCard(Control, cardHandle, ioctl->second, nullptr, 0U, buf.data(),
10591
DWORD(buf.size()), &size);
106-
auto properties = parseTLV<TLV_PROPERTIES>(buf, size, [](uint32_t t) { return t; });
107-
if (auto vendor = properties.find(TLV_PROPERTY_wIdVendor);
108-
vendor != properties.cend())
109-
id_vendor = vendor->second;
110-
if (auto product = properties.find(TLV_PROPERTY_wIdProduct);
111-
product != properties.cend())
112-
id_product = product->second;
92+
for (auto p = buf.cbegin(); DWORD(std::distance(buf.cbegin(), p)) < size;) {
93+
auto tag = TLV_PROPERTIES(*p++);
94+
uint32_t value {};
95+
for (unsigned int i = 0, len = *p++; i < len; ++i)
96+
value |= uint32_t(*p++) << 8 * i;
97+
if(tag == TLV_PROPERTY_wIdVendor)
98+
id_vendor = value;
99+
if(tag == TLV_PROPERTY_wIdProduct)
100+
id_product = value;
101+
}
113102
}
114103
} catch (const ScardError&) {
115104
// Ignore driver errors during card feature requests.
@@ -142,29 +131,16 @@ class CardImpl
142131
|| features.contains(FEATURE_VERIFY_PIN_DIRECT);
143132
}
144133

145-
ResponseApdu transmitBytes(const byte_vector& commandBytes) const
134+
ResponseApdu transmitBytes(const CommandApdu& commandApdu) const
146135
{
147136
byte_vector responseBytes(ResponseApdu::MAX_SIZE, 0);
148137
auto responseLength = DWORD(responseBytes.size());
149-
150-
// TODO: debug("Sending: " + bytes2hexstr(commandBytes))
151-
152-
SCard(Transmit, cardHandle, &_protocol, commandBytes.data(), DWORD(commandBytes.size()),
138+
SCard(Transmit, cardHandle, &_protocol, commandApdu.d.data(), DWORD(commandApdu.d.size()),
153139
nullptr, responseBytes.data(), &responseLength);
154-
155-
auto response = toResponse(std::move(responseBytes), responseLength);
156-
157-
if (response.sw1 == ResponseApdu::WRONG_LE_LENGTH) {
158-
getResponseWithLE(response, commandBytes);
159-
}
160-
if (response.sw1 == ResponseApdu::MORE_DATA_AVAILABLE) {
161-
getMoreResponseData(response);
162-
}
163-
164-
return response;
140+
return toResponse(std::move(responseBytes), responseLength);
165141
}
166142

167-
ResponseApdu transmitBytesCTL(const byte_vector& commandBytes, uint16_t lang,
143+
ResponseApdu transmitBytesCTL(const CommandApdu& commandApdu, uint16_t lang,
168144
uint8_t minlen) const
169145
{
170146
uint8_t PINFrameOffset = 0;
@@ -182,8 +158,8 @@ class CardImpl
182158
data->bNumberMessage = CCIDDefaultInvitationMessage;
183159
data->wLangId = lang;
184160
data->bMsgIndex = NoInvitationMessage;
185-
data->ulDataLength = uint32_t(commandBytes.size());
186-
cmd.insert(cmd.cend(), commandBytes.cbegin(), commandBytes.cend());
161+
data->ulDataLength = uint32_t(commandApdu.d.size());
162+
cmd.insert(cmd.cend(), commandApdu.d.cbegin(), commandApdu.d.cend());
187163

188164
DWORD ioctl =
189165
features.at(features.contains(FEATURE_VERIFY_PIN_START) ? FEATURE_VERIFY_PIN_START
@@ -266,31 +242,6 @@ class CardImpl
266242
+ std::to_string(_protocol.dwProtocol));
267243
}
268244
}
269-
270-
void getMoreResponseData(ResponseApdu& response) const
271-
{
272-
byte_vector getResponseCommand {0x00, 0xc0, 0x00, 0x00, 0x00};
273-
274-
ResponseApdu newResponse {response.sw1, response.sw2};
275-
276-
while (newResponse.sw1 == ResponseApdu::MORE_DATA_AVAILABLE) {
277-
getResponseCommand[4] = newResponse.sw2;
278-
newResponse = transmitBytes(getResponseCommand);
279-
response.data.insert(response.data.end(), newResponse.data.cbegin(),
280-
newResponse.data.cend());
281-
}
282-
283-
response.sw1 = ResponseApdu::OK;
284-
response.sw2 = 0;
285-
}
286-
287-
void getResponseWithLE(ResponseApdu& response, byte_vector command) const
288-
{
289-
size_t pos = command.size() <= 5 ? 4 : 5 + command[4]; // Case 1/2 or 3/4
290-
command.resize(pos + 1);
291-
command[pos] = response.sw2;
292-
response = transmitBytes(command);
293-
}
294245
};
295246

296247
SmartCard::Session::Session(const CardImpl& card) : card(card)
@@ -309,7 +260,22 @@ SmartCard::Session::~Session() noexcept
309260

310261
ResponseApdu SmartCard::Session::transmit(const CommandApdu& command) const
311262
{
312-
return card.transmitBytes(command);
263+
auto response = card.transmitBytes(command);
264+
if (response.sw1 == ResponseApdu::WRONG_LE_LENGTH) {
265+
response = card.transmitBytes(CommandApdu(command, response.sw2));
266+
}
267+
if (response.sw1 == ResponseApdu::MORE_DATA_AVAILABLE) {
268+
auto getResponseCommand = CommandApdu::getResponse();
269+
while (response.sw1 == ResponseApdu::MORE_DATA_AVAILABLE) {
270+
getResponseCommand.d[4] = response.sw2;
271+
auto newResponse = card.transmitBytes(getResponseCommand);
272+
response.sw1 = newResponse.sw1;
273+
response.sw2 = newResponse.sw2;
274+
response.data.insert(response.data.end(), newResponse.data.cbegin(),
275+
newResponse.data.cend());
276+
}
277+
}
278+
return response;
313279
}
314280

315281
ResponseApdu SmartCard::Session::transmitCTL(const CommandApdu& command, uint16_t lang,

0 commit comments

Comments
 (0)