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,33 @@ 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+ BYTE len = *p++;
94+ if (DWORD (std::distance (buf.cbegin (), p)) + len > size) {
95+ break ; // Malformed TLV data.
96+ }
97+ uint32_t value {};
98+ for (BYTE i = 0 ; i < len; ++i)
99+ value |= uint32_t (*p++) << 8 * i;
100+ if (tag == TLV_PROPERTY_wIdVendor)
101+ id_vendor = value;
102+ if (tag == TLV_PROPERTY_wIdProduct)
103+ id_product = value;
104+ }
113105 }
114106 } catch (const ScardError&) {
115107 // Ignore driver errors during card feature requests.
@@ -138,33 +130,20 @@ class CardImpl
138130 return false ;
139131 if (getenv (" SMARTCARDPP_NOPINPAD" ))
140132 return false ;
141- return features.contains (FEATURE_VERIFY_PIN_START )
142- || features.contains (FEATURE_VERIFY_PIN_DIRECT );
133+ return feature (FEATURE_VERIFY_PIN_START) != features.cend ( )
134+ || feature (FEATURE_VERIFY_PIN_DIRECT) != features.cend ( );
143135 }
144136
145- ResponseApdu transmitBytes (const byte_vector& commandBytes ) const
137+ ResponseApdu transmitBytes (const CommandApdu& commandApdu ) const
146138 {
147139 byte_vector responseBytes (ResponseApdu::MAX_SIZE, 0 );
148140 auto responseLength = DWORD (responseBytes.size ());
149-
150- // TODO: debug("Sending: " + bytes2hexstr(commandBytes))
151-
152- SCard (Transmit, cardHandle, &_protocol, commandBytes.data (), DWORD (commandBytes.size ()),
141+ SCard (Transmit, cardHandle, &_protocol, commandApdu.d .data (), DWORD (commandApdu.d .size ()),
153142 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;
143+ return toResponse (std::move (responseBytes), responseLength);
165144 }
166145
167- ResponseApdu transmitBytesCTL (const byte_vector& commandBytes , uint16_t lang,
146+ ResponseApdu transmitBytesCTL (const CommandApdu& commandApdu , uint16_t lang,
168147 uint8_t minlen) const
169148 {
170149 uint8_t PINFrameOffset = 0 ;
@@ -182,20 +161,20 @@ class CardImpl
182161 data->bNumberMessage = CCIDDefaultInvitationMessage;
183162 data->wLangId = lang;
184163 data->bMsgIndex = NoInvitationMessage;
185- data->ulDataLength = uint32_t (commandBytes .size ());
186- cmd.insert (cmd.cend (), commandBytes. cbegin (), commandBytes .cend ());
164+ data->ulDataLength = uint32_t (commandApdu. d .size ());
165+ cmd.insert (cmd.cend (), commandApdu. d . cbegin (), commandApdu. d .cend ());
187166
188- DWORD ioctl =
189- features. at (features. contains (FEATURE_VERIFY_PIN_START) ? FEATURE_VERIFY_PIN_START
190- : FEATURE_VERIFY_PIN_DIRECT);
167+ auto ioctl = feature (FEATURE_VERIFY_PIN_START);
168+ if ( feature (FEATURE_VERIFY_PIN_START) == features. cend ())
169+ ioctl = feature ( FEATURE_VERIFY_PIN_DIRECT);
191170 byte_vector responseBytes (ResponseApdu::MAX_SIZE, 0 );
192171 auto responseLength = DWORD (responseBytes.size ());
193- SCard (Control, cardHandle, ioctl, cmd.data (), DWORD (cmd.size ()),
172+ SCard (Control, cardHandle, ioctl-> value , cmd.data (), DWORD (cmd.size ()),
194173 LPVOID (responseBytes.data ()), DWORD (responseBytes.size ()), &responseLength);
195174
196- if (auto finish = features. find (FEATURE_VERIFY_PIN_FINISH); finish != features.cend ()) {
175+ if (auto finish = feature (FEATURE_VERIFY_PIN_FINISH); finish != features.cend ()) {
197176 responseLength = DWORD (responseBytes.size ());
198- SCard (Control, cardHandle, finish->second , nullptr , 0U , LPVOID (responseBytes.data ()),
177+ SCard (Control, cardHandle, finish->value , nullptr , 0U , LPVOID (responseBytes.data ()),
199178 DWORD (responseBytes.size ()), &responseLength);
200179 }
201180
@@ -224,10 +203,16 @@ class CardImpl
224203private:
225204 SCARDHANDLE cardHandle {};
226205 SCARD_IO_REQUEST _protocol {SCARD_PROTOCOL_UNDEFINED, sizeof (SCARD_IO_REQUEST)};
227- std::map<DRIVER_FEATURES, uint32_t > features;
206+ std::array<PCSC_TLV_STRUCTURE, FEATURE_CCID_ESC_COMMAND > features {} ;
228207 uint32_t id_vendor {};
229208 uint32_t id_product {};
230209
210+ constexpr decltype (features)::const_iterator feature(DRIVER_FEATURES tag) const
211+ {
212+ return std::find_if (features.cbegin (), features.cend (),
213+ [tag](PCSC_TLV_STRUCTURE tlv) { return tlv.tag == tag; });
214+ }
215+
231216 ResponseApdu toResponse (byte_vector&& responseBytes, size_t responseLength) const
232217 {
233218 if (responseLength > responseBytes.size ()) {
@@ -266,31 +251,6 @@ class CardImpl
266251 + std::to_string (_protocol.dwProtocol ));
267252 }
268253 }
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- }
294254};
295255
296256SmartCard::Session::Session (const CardImpl& card) : card(card)
@@ -309,7 +269,22 @@ SmartCard::Session::~Session() noexcept
309269
310270ResponseApdu SmartCard::Session::transmit (const CommandApdu& command) const
311271{
312- return card.transmitBytes (command);
272+ auto response = card.transmitBytes (command);
273+ if (response.sw1 == ResponseApdu::WRONG_LE_LENGTH) {
274+ response = card.transmitBytes (CommandApdu (command, response.sw2 ));
275+ }
276+ if (response.sw1 == ResponseApdu::MORE_DATA_AVAILABLE) {
277+ auto getResponseCommand = CommandApdu::getResponse ();
278+ while (response.sw1 == ResponseApdu::MORE_DATA_AVAILABLE) {
279+ getResponseCommand.d [4 ] = response.sw2 ;
280+ auto newResponse = card.transmitBytes (getResponseCommand);
281+ response.sw1 = newResponse.sw1 ;
282+ response.sw2 = newResponse.sw2 ;
283+ response.data .insert (response.data .end (), newResponse.data .cbegin (),
284+ newResponse.data .cend ());
285+ }
286+ }
287+ return response;
313288}
314289
315290ResponseApdu SmartCard::Session::transmitCTL (const CommandApdu& command, uint16_t lang,
0 commit comments