LudovicRousseau / pyscard

pyscard smartcard library for python
http://pyscard.sourceforge.net/
GNU Lesser General Public License v2.1
383 stars 110 forks source link

Inconsistent state after unexpected disconnect #63

Closed whyscream closed 5 years ago

whyscream commented 6 years ago

We have developed a simple smartcard using application, but are having issues when the nfc card is removed too soon.

Setup: Ubuntu 16.04 (pcscd 1.8.14, libnfc5 1.7.1, libccid 1.14.22), ACS122U nfc reader, Mifare classic nfc cards.

We try to detect an available NFC card by:

cardrequest = CardRequest(timeout=1, cardType=AnyCardType())
cardservice = cardrequest.waitforcard()
cardservice.connection.connect()
cardservice.connection.getATR()

After a successful connection we can authenticate, read the tag, and decrement it. But when we remove the card from the reader too soon, the transaction breaks (most of the time during the authentication). However, when we try to check for subsequent presented cards, the above routine successfully connects and returns without errors, also when no card is actually present.

After the above situation, authenticating with the card fails, and our code crashes. How would we detect correctly whether a card is presented?

I also installed the upstream drivers from https://www.acs.com.hk/en/driver/3/acr122u-usb-nfc-reader/, but this makes no difference.

LudovicRousseau commented 6 years ago

I would need pcsc-lite logs as described in https://ccid.apdu.fr/#support In the logs indicate the moment you removed the card.

You can also use pcsc_scan (from the Ubuntu pcsc-tools package) to check if the card events are correctly reported.

whyscream commented 6 years ago

Package versions:

Possibly identified card (using /usr/share/pcsc/smartcard_list.txt): 3B 8F 80 01 80 4F 0C A0 00 00 03 06 03 00 01 00 00 00 00 6A 3B 8F 80 01 80 4F 0C A0 00 00 03 06 .. 00 01 00 00 00 00 .. Mifare Standard 1K (as per PCSC std part3) 3B 8F 80 01 80 4F 0C A0 00 00 03 06 03 00 01 00 00 00 00 6A 3B 8F 80 01 80 4F 0C A0 00 00 03 06 03 .. .. 00 00 00 00 .. RFID - ISO 14443 Type A Part 3 (as per PCSC std part3) 3B 8F 80 01 80 4F 0C A0 00 00 03 06 03 00 01 00 00 00 00 6A Philips MIFARE Standard (1 Kbytes EEPROM) http://www.nxp.com/#/pip/pip=[pfp=41863]|pp=[t=pfp,i=41863] RFID - ISO 14443 Type A - Transport for London Oyster ACOS5/1k Mirfare RFID - ISO 14443 Type A - NXP Mifare card with 1k EEPROM vivotech ViVOcard Contactless Test Card Bangkok BTS Sky SmartPass



Log file from pcscd: [pcscd-log.txt](https://github.com/LudovicRousseau/pyscard/files/2209148/pcscd-log.txt). What I'm making of this:
- Startup the daemon, init of reader, no card present
- I try a few transactions until I can trigger the behaviour. The problematic behaviour starts at line 8795.
- Card is inserted and dected, ATR is retrieved (line 8819).
- I send command 'Load Authentication Keys', and this is successful (line 8856).
- I send command 'Authenticate Data Bytes' and this fails (line 8867). This is because I removed the card.
- I'm getting the State again, unsure what the response is (line 8875). The application code tries to get the ATR here again, which is successful (but this seems invisible in the logging).
- I send the command 'Load Authentication Keys' again, which succeeds (line 8888). (but there is no card?)
- I send the command  'Authenticate Data Bytes'  again, which fails (line 8899).
- This (State, load auth keys, auth data bytes) repeats until I exit the application code (line 10386), and the client goes away.
- After the client goes away, pcscd still thinks the card is present (line 10410), but after polling (line 10414) decides that the card is gone (line 10418).

My conclusions so far:
- `NotifySlotChange` detects whether the card is present, but when a client is connected to the card, this isn't triggered, even when the card goes away.
- the ATR is only retrieved when upon first connection between card and reader, and returned from cache upon subsequent requests for the ATR. This makes requesting the ATR not a valid way to detect whether the card is still present.

So what is the correct way to detect that the card is no longer present mid-transaction? And the correct way to reconnect when the card is presented again? Shoudl I simply kill and reconnect my client after any error?
LudovicRousseau commented 6 years ago

Great debug details. Some more information: