3232#endif
3333
3434#include < array>
35- #include < map>
3635#include < utility>
3736
3837// TODO: Someday, maybe SCARD_SHARE_SHARED vs SCARD_SHARE_EXCLUSIVE and SCARD_RESET_CARD on
4140namespace
4241{
4342
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-
5843constexpr uint32_t VENDOR_HID_GLOBAL = 0x076B ;
5944constexpr uint32_t OMNIKEY_3x21 = 0x3031 ;
6045constexpr uint32_t OMNIKEY_6121 = 0x6632 ;
@@ -89,27 +74,29 @@ class CardImpl
8974
9075 try {
9176 DWORD size = 0 ;
92- std::array<PCSC_TLV_STRUCTURE, FEATURE_CCID_ESC_COMMAND> list {};
9377 SCard (Control, cardHandle, DWORD (CM_IOCTL_GET_FEATURE_REQUEST), nullptr , 0U ,
94- list .data (), DWORD (list .size () * sizeof (PCSC_TLV_STRUCTURE)), &size);
78+ features .data (), DWORD (features .size () * sizeof (PCSC_TLV_STRUCTURE)), &size);
9579 if (size == 0 || size % sizeof (PCSC_TLV_STRUCTURE)) {
9680 return ; // No features available or malformed response.
9781 }
98- for (const auto & f : list ) {
99- features[ DRIVER_FEATURES (f. tag )] = ntohl (f.value );
82+ for (auto & f : features ) {
83+ f. value = ntohl (f.value );
10084 }
10185
102- if (auto ioctl = features. find (FEATURE_GET_TLV_PROPERTIES); ioctl != features.cend ()) {
86+ if (auto ioctl = feature (FEATURE_GET_TLV_PROPERTIES); ioctl != features.cend ()) {
10387 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 ;
88+ SCard (Control, cardHandle, ioctl->value , nullptr , 0U , buf.data (), DWORD (buf.size ()),
89+ &size);
90+ for (auto p = buf.cbegin (); DWORD (std::distance (buf.cbegin (), p)) < size;) {
91+ auto tag = TLV_PROPERTIES (*p++);
92+ uint32_t value {};
93+ for (unsigned int i = 0 , len = *p++; i < len; ++i)
94+ value |= uint32_t (*p++) << 8 * i;
95+ if (tag == TLV_PROPERTY_wIdVendor)
96+ id_vendor = value;
97+ if (tag == TLV_PROPERTY_wIdProduct)
98+ id_product = value;
99+ }
113100 }
114101 } catch (const ScardError&) {
115102 // Ignore driver errors during card feature requests.
@@ -138,33 +125,20 @@ class CardImpl
138125 return false ;
139126 if (getenv (" SMARTCARDPP_NOPINPAD" ))
140127 return false ;
141- return features.contains (FEATURE_VERIFY_PIN_START )
142- || features.contains (FEATURE_VERIFY_PIN_DIRECT );
128+ return feature (FEATURE_VERIFY_PIN_START) != features.cend ( )
129+ || feature (FEATURE_VERIFY_PIN_DIRECT) != features.cend ( );
143130 }
144131
145- ResponseApdu transmitBytes (const byte_vector& commandBytes ) const
132+ ResponseApdu transmitBytes (const CommandApdu& commandApdu ) const
146133 {
147134 byte_vector responseBytes (ResponseApdu::MAX_SIZE, 0 );
148135 auto responseLength = DWORD (responseBytes.size ());
149-
150- // TODO: debug("Sending: " + bytes2hexstr(commandBytes))
151-
152- SCard (Transmit, cardHandle, &_protocol, commandBytes.data (), DWORD (commandBytes.size ()),
136+ SCard (Transmit, cardHandle, &_protocol, commandApdu.d .data (), DWORD (commandApdu.d .size ()),
153137 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;
138+ return toResponse (std::move (responseBytes), responseLength);
165139 }
166140
167- ResponseApdu transmitBytesCTL (const byte_vector& commandBytes , uint16_t lang,
141+ ResponseApdu transmitBytesCTL (const CommandApdu& commandApdu , uint16_t lang,
168142 uint8_t minlen) const
169143 {
170144 uint8_t PINFrameOffset = 0 ;
@@ -182,20 +156,20 @@ class CardImpl
182156 data->bNumberMessage = CCIDDefaultInvitationMessage;
183157 data->wLangId = lang;
184158 data->bMsgIndex = NoInvitationMessage;
185- data->ulDataLength = uint32_t (commandBytes .size ());
186- cmd.insert (cmd.cend (), commandBytes. cbegin (), commandBytes .cend ());
159+ data->ulDataLength = uint32_t (commandApdu. d .size ());
160+ cmd.insert (cmd.cend (), commandApdu. d . cbegin (), commandApdu. d .cend ());
187161
188- DWORD ioctl =
189- features. at (features. contains (FEATURE_VERIFY_PIN_START) ? FEATURE_VERIFY_PIN_START
190- : FEATURE_VERIFY_PIN_DIRECT);
162+ auto ioctl = feature (FEATURE_VERIFY_PIN_START);
163+ if ( feature (FEATURE_VERIFY_PIN_START) == features. cend ())
164+ ioctl = feature ( FEATURE_VERIFY_PIN_DIRECT);
191165 byte_vector responseBytes (ResponseApdu::MAX_SIZE, 0 );
192166 auto responseLength = DWORD (responseBytes.size ());
193- SCard (Control, cardHandle, ioctl, cmd.data (), DWORD (cmd.size ()),
167+ SCard (Control, cardHandle, ioctl-> value , cmd.data (), DWORD (cmd.size ()),
194168 LPVOID (responseBytes.data ()), DWORD (responseBytes.size ()), &responseLength);
195169
196- if (auto finish = features. find (FEATURE_VERIFY_PIN_FINISH); finish != features.cend ()) {
170+ if (auto finish = feature (FEATURE_VERIFY_PIN_FINISH); finish != features.cend ()) {
197171 responseLength = DWORD (responseBytes.size ());
198- SCard (Control, cardHandle, finish->second , nullptr , 0U , LPVOID (responseBytes.data ()),
172+ SCard (Control, cardHandle, finish->value , nullptr , 0U , LPVOID (responseBytes.data ()),
199173 DWORD (responseBytes.size ()), &responseLength);
200174 }
201175
@@ -224,10 +198,16 @@ class CardImpl
224198private:
225199 SCARDHANDLE cardHandle {};
226200 SCARD_IO_REQUEST _protocol {SCARD_PROTOCOL_UNDEFINED, sizeof (SCARD_IO_REQUEST)};
227- std::map<DRIVER_FEATURES, uint32_t > features;
201+ std::array<PCSC_TLV_STRUCTURE, FEATURE_CCID_ESC_COMMAND > features {} ;
228202 uint32_t id_vendor {};
229203 uint32_t id_product {};
230204
205+ constexpr decltype (features)::const_iterator feature(DRIVER_FEATURES tag) const
206+ {
207+ return std::find_if (features.cbegin (), features.cend (),
208+ [tag](const PCSC_TLV_STRUCTURE& tlv) { return tlv.tag == tag; });
209+ }
210+
231211 ResponseApdu toResponse (byte_vector&& responseBytes, size_t responseLength) const
232212 {
233213 if (responseLength > responseBytes.size ()) {
@@ -266,31 +246,6 @@ class CardImpl
266246 + std::to_string (_protocol.dwProtocol ));
267247 }
268248 }
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- }
294249};
295250
296251SmartCard::Session::Session (const CardImpl& card) : card(card)
@@ -309,7 +264,22 @@ SmartCard::Session::~Session() noexcept
309264
310265ResponseApdu SmartCard::Session::transmit (const CommandApdu& command) const
311266{
312- return card.transmitBytes (command);
267+ auto response = card.transmitBytes (command);
268+ if (response.sw1 == ResponseApdu::WRONG_LE_LENGTH) {
269+ response = card.transmitBytes (CommandApdu (command, response.sw2 ));
270+ }
271+ if (response.sw1 == ResponseApdu::MORE_DATA_AVAILABLE) {
272+ auto getResponseCommand = CommandApdu::getResponse ();
273+ while (response.sw1 == ResponseApdu::MORE_DATA_AVAILABLE) {
274+ getResponseCommand.d [4 ] = response.sw2 ;
275+ auto newResponse = card.transmitBytes (getResponseCommand);
276+ response.sw1 = newResponse.sw1 ;
277+ response.sw2 = newResponse.sw2 ;
278+ response.data .insert (response.data .end (), newResponse.data .cbegin (),
279+ newResponse.data .cend ());
280+ }
281+ }
282+ return response;
313283}
314284
315285ResponseApdu SmartCard::Session::transmitCTL (const CommandApdu& command, uint16_t lang,
0 commit comments