4141namespace
4242{
4343
44- using namespace pcsc_cpp ;
45-
46- constexpr SmartCard::Protocol convertToSmartCardProtocol (const DWORD protocol)
47- {
48- switch (protocol) {
49- case SCARD_PROTOCOL_UNDEFINED:
50- return SmartCard::Protocol::UNDEFINED;
51- case SCARD_PROTOCOL_T0:
52- return SmartCard::Protocol::T0;
53- case SCARD_PROTOCOL_T1:
54- return SmartCard::Protocol::T1;
55- default :
56- THROW (Error, " Unsupported card protocol: " + std::to_string (protocol));
57- }
58- }
59-
60- std::pair<SCARDHANDLE, DWORD> connectToCard (const SCARDCONTEXT ctx, const string_t & readerName)
61- {
62- const unsigned requestedProtocol =
63- SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1; // Let PCSC auto-select protocol.
64- DWORD protocolOut = SCARD_PROTOCOL_UNDEFINED;
65- SCARDHANDLE cardHandle = 0 ;
66-
67- SCard (Connect, ctx, readerName.c_str (), DWORD (SCARD_SHARE_SHARED), requestedProtocol,
68- &cardHandle, &protocolOut);
69-
70- return {cardHandle, protocolOut};
71- }
72-
7344template <class K , class V = uint32_t , class D , size_t dsize, typename Func>
7445constexpr std::map<K, V> parseTLV (const std::array<D, dsize>& data, DWORD size, Func transform)
7546{
@@ -93,21 +64,34 @@ constexpr uint32_t OMNIKEY_6121 = 0x6632;
9364namespace pcsc_cpp
9465{
9566
67+ SmartCard Reader::connectToCard () const
68+ {
69+ return {*this };
70+ }
71+
9672class CardImpl
9773{
9874public:
99- explicit CardImpl (std::pair<SCARDHANDLE, DWORD> cardParams) :
100- cardHandle(cardParams.first), _protocol {cardParams.second , sizeof (SCARD_IO_REQUEST)}
75+ explicit CardImpl (const Reader& reader)
10176 {
102- // TODO: debug("Protocol: " + to_string(protocol()))
77+ constexpr unsigned requestedProtocol =
78+ SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1; // Let PCSC auto-select protocol.
79+ SCard (Connect, reader.ctx ->handle (), reader.name .c_str (), DWORD (SCARD_SHARE_SHARED),
80+ requestedProtocol, &cardHandle, &_protocol.dwProtocol );
81+
10382 try {
10483 DWORD size = 0 ;
105- std::array<BYTE, 256 > buf {};
106- SCard (Control, cardHandle, DWORD (CM_IOCTL_GET_FEATURE_REQUEST), nullptr , 0U , buf.data (),
107- DWORD (buf.size ()), &size);
108- features = parseTLV<DRIVER_FEATURES>(buf, size, [](uint32_t t) { return ntohl (t); });
84+ std::array<PCSC_TLV_STRUCTURE, FEATURE_CCID_ESC_COMMAND> list {};
85+ SCard (Control, cardHandle, DWORD (CM_IOCTL_GET_FEATURE_REQUEST), nullptr , 0U ,
86+ list.data (), DWORD (list.size () * sizeof (PCSC_TLV_STRUCTURE)), &size);
87+ if (size % sizeof (PCSC_TLV_STRUCTURE))
88+ return ;
89+ for (const auto & f : list) {
90+ features[DRIVER_FEATURES (f.tag )] = ntohl (f.value );
91+ }
10992
11093 if (auto ioctl = features.find (FEATURE_GET_TLV_PROPERTIES); ioctl != features.cend ()) {
94+ std::array<BYTE, 256 > buf {};
11195 SCard (Control, cardHandle, ioctl->second , nullptr , 0U , buf.data (),
11296 DWORD (buf.size ()), &size);
11397 auto properties = parseTLV<TLV_PROPERTIES>(buf, size, [](uint32_t t) { return t; });
@@ -124,7 +108,7 @@ class CardImpl
124108 }
125109 }
126110
127- ~CardImpl ()
111+ ~CardImpl () noexcept
128112 {
129113 if (cardHandle) {
130114 // Cannot throw in destructor, so cannot use the SCard() macro here.
@@ -210,11 +194,24 @@ class CardImpl
210194
211195 void endTransaction () const { SCard (EndTransaction, cardHandle, DWORD (SCARD_LEAVE_CARD)); }
212196
213- DWORD protocol () const { return _protocol.dwProtocol ; }
197+ SmartCard::Protocol protocol () const
198+ {
199+ switch (_protocol.dwProtocol ) {
200+ using enum SmartCard::Protocol;
201+ case SCARD_PROTOCOL_UNDEFINED:
202+ return UNDEFINED;
203+ case SCARD_PROTOCOL_T0:
204+ return T0;
205+ case SCARD_PROTOCOL_T1:
206+ return T1;
207+ default :
208+ THROW (Error, " Unsupported card protocol: " + std::to_string (_protocol.dwProtocol ));
209+ }
210+ }
214211
215212private:
216- SCARDHANDLE cardHandle;
217- const SCARD_IO_REQUEST _protocol;
213+ SCARDHANDLE cardHandle {} ;
214+ SCARD_IO_REQUEST _protocol {SCARD_PROTOCOL_UNDEFINED, sizeof (SCARD_IO_REQUEST)} ;
218215 std::map<DRIVER_FEATURES, uint32_t > features;
219216 uint32_t id_vendor {};
220217 uint32_t id_product {};
@@ -243,7 +240,8 @@ class CardImpl
243240 break ;
244241 default :
245242 THROW (Error,
246- " Error response: '" + response + " ', protocol " + std::to_string (protocol ()));
243+ " Error response: '" + response + " ', protocol "
244+ + std::to_string (_protocol.dwProtocol ));
247245 }
248246
249247 if (response.sw1 == ResponseApdu::WRONG_LE_LENGTH) {
@@ -271,64 +269,59 @@ class CardImpl
271269 }
272270};
273271
274- SmartCard::TransactionGuard::TransactionGuard (const CardImpl& card, bool & inProgress) :
275- card (card), inProgress(inProgress)
272+ SmartCard::Session::Session (const CardImpl& card) : card(card)
276273{
277274 card.beginTransaction ();
278- inProgress = true ;
279275}
280276
281- SmartCard::TransactionGuard ::~TransactionGuard () noexcept
277+ SmartCard::Session ::~Session () noexcept
282278{
283- inProgress = false ;
284279 try {
285280 card.endTransaction ();
286281 } catch (...) {
287282 // Ignore exceptions in destructor.
288283 }
289284}
290285
291- SmartCard::SmartCard (ContextPtr context, string_t readerName, byte_vector atr) :
292- ctx (std::move(context)),
293- card (std::make_unique<CardImpl>(connectToCard(ctx->handle (), readerName))),
294- _readerName(std::move(readerName)), _atr(std::move(atr)),
295- _protocol(convertToSmartCardProtocol(card->protocol ()))
286+ ResponseApdu SmartCard::Session::transmit (const CommandApdu& command) const
296287{
297- // TODO: debug("Card ATR -> " + bytes2hexstr(atr))
288+ return card. transmitBytes (command);
298289}
299290
300- SmartCard::SmartCard () = default;
301- SmartCard::~SmartCard () noexcept = default ;
291+ ResponseApdu SmartCard::Session::transmitCTL (const CommandApdu& command, uint16_t lang,
292+ uint8_t minlen) const
293+ {
294+ return card.transmitBytesCTL (command, lang, minlen);
295+ }
302296
303- SmartCard::TransactionGuard SmartCard::beginTransaction ()
297+ bool SmartCard::Session::readerHasPinPad () const
304298{
305- REQUIRE_NON_NULL (card)
306- return {*card, transactionInProgress};
299+ return card.readerHasPinPad ();
307300}
308301
309- bool SmartCard::readerHasPinPad () const
302+ SmartCard::SmartCard (Reader _reader) :
303+ reader (std::move(_reader)), card(std::make_unique<CardImpl>(reader))
310304{
311- return card ? card->readerHasPinPad () : false ;
312305}
313306
314- ResponseApdu SmartCard::transmit (const CommandApdu& command) const
307+ SmartCard::SmartCard () noexcept = default ;
308+ SmartCard::SmartCard (SmartCard&& other) noexcept = default ;
309+ SmartCard::~SmartCard () noexcept = default ;
310+
311+ SmartCard::Session SmartCard::beginSession () const
315312{
316313 REQUIRE_NON_NULL (card)
317- if (!transactionInProgress) {
318- THROW (std::logic_error, " Call SmartCard::transmit() inside a transaction" );
319- }
320-
321- return card->transmitBytes (command);
314+ return {*card};
322315}
323316
324- ResponseApdu SmartCard::transmitCTL ( const CommandApdu& command, uint16_t lang, uint8_t minlen ) const
317+ SmartCard::Protocol SmartCard::protocol ( ) const
325318{
326- REQUIRE_NON_NULL (card)
327- if (!transactionInProgress) {
328- THROW (std::logic_error, " Call SmartCard::transmit() inside a transaction" );
329- }
319+ return card ? card->protocol () : Protocol::UNDEFINED;
320+ }
330321
331- return card->transmitBytesCTL (command, lang, minlen);
322+ bool SmartCard::readerHasPinPad () const
323+ {
324+ return card ? card->readerHasPinPad () : false ;
332325}
333326
334327} // namespace pcsc_cpp
0 commit comments