3131#include < arpa/inet.h>
3232#endif
3333
34+ #include < algorithm>
3435#include < array>
35- #include < map>
3636#include < utility>
3737
3838// TODO: Someday, maybe SCARD_SHARE_SHARED vs SCARD_SHARE_EXCLUSIVE and SCARD_RESET_CARD on
4141namespace
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-
5844constexpr uint32_t VENDOR_HID_GLOBAL = 0x076B ;
5945constexpr uint32_t OMNIKEY_3x21 = 0x3031 ;
6046constexpr uint32_t OMNIKEY_6121 = 0x6632 ;
@@ -89,27 +75,29 @@ class CardImpl
8975
9076 try {
9177 DWORD size = 0 ;
92- std::array<PCSC_TLV_STRUCTURE, FEATURE_CCID_ESC_COMMAND> list {};
9378 SCard (Control, cardHandle, DWORD (CM_IOCTL_GET_FEATURE_REQUEST), nullptr , 0U ,
94- list .data (), DWORD (list .size () * sizeof (PCSC_TLV_STRUCTURE)), &size);
79+ features .data (), DWORD (features .size () * sizeof (PCSC_TLV_STRUCTURE)), &size);
9580 if (size == 0 || size % sizeof (PCSC_TLV_STRUCTURE)) {
9681 return ; // No features available or malformed response.
9782 }
98- for (const auto & f : list ) {
99- features[ DRIVER_FEATURES (f. tag )] = ntohl (f.value );
83+ for (auto & f : features ) {
84+ f. value = ntohl (f.value );
10085 }
10186
102- if (auto ioctl = features. find (FEATURE_GET_TLV_PROPERTIES); ioctl != features.cend ()) {
87+ if (auto ioctl = feature (FEATURE_GET_TLV_PROPERTIES); ioctl != features.cend ()) {
10388 std::array<BYTE, 256 > buf {};
104- SCard (Control, cardHandle, ioctl->second , nullptr , 0U , buf.data (),
105- 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 ;
89+ SCard (Control, cardHandle, ioctl->value , nullptr , 0U , buf.data (), DWORD (buf.size ()),
90+ &size);
91+ for (auto p = buf.cbegin (); DWORD (std::distance (buf.cbegin (), p)) < size;) {
92+ auto tag = TLV_PROPERTIES (*p++);
93+ uint32_t value {};
94+ for (unsigned int i = 0 , len = *p++; i < len; ++i)
95+ value |= uint32_t (*p++) << 8 * i;
96+ if (tag == TLV_PROPERTY_wIdVendor)
97+ id_vendor = value;
98+ if (tag == TLV_PROPERTY_wIdProduct)
99+ id_product = value;
100+ }
113101 }
114102 } catch (const ScardError&) {
115103 // Ignore driver errors during card feature requests.
@@ -138,33 +126,20 @@ class CardImpl
138126 return false ;
139127 if (getenv (" SMARTCARDPP_NOPINPAD" ))
140128 return false ;
141- return features.contains (FEATURE_VERIFY_PIN_START )
142- || features.contains (FEATURE_VERIFY_PIN_DIRECT );
129+ return feature (FEATURE_VERIFY_PIN_START) != features.cend ( )
130+ || feature (FEATURE_VERIFY_PIN_DIRECT) != features.cend ( );
143131 }
144132
145- ResponseApdu transmitBytes (const byte_vector& commandBytes ) const
133+ ResponseApdu transmitBytes (const CommandApdu& commandApdu ) const
146134 {
147135 byte_vector responseBytes (ResponseApdu::MAX_SIZE, 0 );
148136 auto responseLength = DWORD (responseBytes.size ());
149-
150- // TODO: debug("Sending: " + bytes2hexstr(commandBytes))
151-
152- SCard (Transmit, cardHandle, &_protocol, commandBytes.data (), DWORD (commandBytes.size ()),
137+ SCard (Transmit, cardHandle, &_protocol, commandApdu.d .data (), DWORD (commandApdu.d .size ()),
153138 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;
139+ return toResponse (std::move (responseBytes), responseLength);
165140 }
166141
167- ResponseApdu transmitBytesCTL (const byte_vector& commandBytes , uint16_t lang,
142+ ResponseApdu transmitBytesCTL (const CommandApdu& commandApdu , uint16_t lang,
168143 uint8_t minlen) const
169144 {
170145 uint8_t PINFrameOffset = 0 ;
@@ -182,20 +157,20 @@ class CardImpl
182157 data->bNumberMessage = CCIDDefaultInvitationMessage;
183158 data->wLangId = lang;
184159 data->bMsgIndex = NoInvitationMessage;
185- data->ulDataLength = uint32_t (commandBytes .size ());
186- cmd.insert (cmd.cend (), commandBytes. cbegin (), commandBytes .cend ());
160+ data->ulDataLength = uint32_t (commandApdu. d .size ());
161+ cmd.insert (cmd.cend (), commandApdu. d . cbegin (), commandApdu. d .cend ());
187162
188- DWORD ioctl =
189- features. at (features. contains (FEATURE_VERIFY_PIN_START) ? FEATURE_VERIFY_PIN_START
190- : FEATURE_VERIFY_PIN_DIRECT);
163+ auto ioctl = feature (FEATURE_VERIFY_PIN_START);
164+ if ( feature (FEATURE_VERIFY_PIN_START) == features. cend ())
165+ ioctl = feature ( FEATURE_VERIFY_PIN_DIRECT);
191166 byte_vector responseBytes (ResponseApdu::MAX_SIZE, 0 );
192167 auto responseLength = DWORD (responseBytes.size ());
193- SCard (Control, cardHandle, ioctl, cmd.data (), DWORD (cmd.size ()),
168+ SCard (Control, cardHandle, ioctl-> value , cmd.data (), DWORD (cmd.size ()),
194169 LPVOID (responseBytes.data ()), DWORD (responseBytes.size ()), &responseLength);
195170
196- if (auto finish = features. find (FEATURE_VERIFY_PIN_FINISH); finish != features.cend ()) {
171+ if (auto finish = feature (FEATURE_VERIFY_PIN_FINISH); finish != features.cend ()) {
197172 responseLength = DWORD (responseBytes.size ());
198- SCard (Control, cardHandle, finish->second , nullptr , 0U , LPVOID (responseBytes.data ()),
173+ SCard (Control, cardHandle, finish->value , nullptr , 0U , LPVOID (responseBytes.data ()),
199174 DWORD (responseBytes.size ()), &responseLength);
200175 }
201176
@@ -224,10 +199,16 @@ class CardImpl
224199private:
225200 SCARDHANDLE cardHandle {};
226201 SCARD_IO_REQUEST _protocol {SCARD_PROTOCOL_UNDEFINED, sizeof (SCARD_IO_REQUEST)};
227- std::map<DRIVER_FEATURES, uint32_t > features;
202+ std::array<PCSC_TLV_STRUCTURE, FEATURE_CCID_ESC_COMMAND > features {} ;
228203 uint32_t id_vendor {};
229204 uint32_t id_product {};
230205
206+ constexpr decltype (features)::const_iterator feature(DRIVER_FEATURES tag) const
207+ {
208+ return std::find_if (features.cbegin (), features.cend (),
209+ [tag](PCSC_TLV_STRUCTURE tlv) { return tlv.tag == tag; });
210+ }
211+
231212 ResponseApdu toResponse (byte_vector&& responseBytes, size_t responseLength) const
232213 {
233214 if (responseLength > responseBytes.size ()) {
@@ -266,31 +247,6 @@ class CardImpl
266247 + std::to_string (_protocol.dwProtocol ));
267248 }
268249 }
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- }
294250};
295251
296252SmartCard::Session::Session (const CardImpl& card) : card(card)
@@ -309,7 +265,22 @@ SmartCard::Session::~Session() noexcept
309265
310266ResponseApdu SmartCard::Session::transmit (const CommandApdu& command) const
311267{
312- return card.transmitBytes (command);
268+ auto response = card.transmitBytes (command);
269+ if (response.sw1 == ResponseApdu::WRONG_LE_LENGTH) {
270+ response = card.transmitBytes (CommandApdu (command, response.sw2 ));
271+ }
272+ if (response.sw1 == ResponseApdu::MORE_DATA_AVAILABLE) {
273+ auto getResponseCommand = CommandApdu::getResponse ();
274+ while (response.sw1 == ResponseApdu::MORE_DATA_AVAILABLE) {
275+ getResponseCommand.d [4 ] = response.sw2 ;
276+ auto newResponse = card.transmitBytes (getResponseCommand);
277+ response.sw1 = newResponse.sw1 ;
278+ response.sw2 = newResponse.sw2 ;
279+ response.data .insert (response.data .end (), newResponse.data .cbegin (),
280+ newResponse.data .cend ());
281+ }
282+ }
283+ return response;
313284}
314285
315286ResponseApdu SmartCard::Session::transmitCTL (const CommandApdu& command, uint16_t lang,
0 commit comments