Vor längerer Zeit habe ich ein bisschen mit JavaCards rumgespielt: Applets kodiert, auf kontaktlose Smartcard geladen und an mein NFC Smartphone gehalten. Eine wirklich sinnvolle Idee für ein Applet kam mir irgendwie nicht bis zu dem Zeitpunkt als ich wissen wollte welche Daten (APDUs) eine bestimmte Android NFC App eigentlich so an (m)eine kontaktlose Smartcard sendet und welche Daten (Response-APDUs) auslesen werden. Da kam mir die Idee zu einer Dummy Smartcard, die jede Anfrage (Command-APDU) mitloggt, mit einer OK-Quitierung (Response-APDU: 0x9000) versieht und somit relativ preiswert das Erforschen der Kommunikation zwischen NFC App und Smartcard zulässt. Ausserdem kann man damit nebenbei schlecht kodierte NFC Apps zum Absturz bringen 🙂 Wird nämlich eine Response-APDU 0x9000 mit zusätzlichen Daten erwartet und bleibt das Datenfeld leer so kann es zB zu einer ArrayIndexOutOfBoundsException kommen.
Erforderlich dafür ist allerdings eine JavaCard, die das Setzen des Default Selected Privilege zulässt, da dann alle APDUs (auch das Selektieren eines nichtvorhandenen Applets) direkt an das Logging-Applet geleitet werden. Die Blank 64k Programmable JAVA SIM Card zB kann man dafür leider nicht verwenden, da die Karte das Laden/Installieren mit Privilegien per Global Platform nicht unterstützt.
Folgende Kommandos sind in der ersten lauffähigen Version implementiert:
00100000 get version (zeigt die Applet Version an) 00400200076C6F6739303030 logging = off (t0/t1/tcl off) (schaltet das Logging aus, Karte kann nun konfiguriert werden) 004002xx logging = on (bitwise) e.g: 00400201 logging = on @ t0 contact interface 00400202 logging = on @ t1 contact interface 00400204 logging = on @ tcl contactless interface 00400207 logging = on @ all contact and contactless interfaces 00400210 get logging setting (liest Logging Bits aus) 00400300 clear log (clear all log entries) 00400400 clear cr_apdus ( 0041p1p2 set defaultSW p1p2=9000, 6D00, 6a80 (Default SW setzen) 00420000 get defaultSW (Default SW auslesen) 00500100 activate C/R-APDU: lc {data set} {data-set}={len-apdu apdu-byte1...apdu-byteN len-response-apdu rapdu0... rapduN} 00510000 get cr_index (number of C/R-APDUs) (Anzahl der konfigurierten C/R-APDUs ausgeben) 006000nn readLog n (Logeintrag n auslesen) 00610000 get log index (Anzahl der Logeinträge auslesen)
Somit kann das Logging an- und ausgeschaltet werden, Logeinträge gelöscht / konfiguriert werden und vorhandene Logeinträge aufgelistet werden.
Testkandiat
Als Proband musste die Electronic Pickpocket RFID von Identity Stronghold herhalten. Im Screenshot sieht man das angeblich eine Karte erkannt wurde.
Die geloggte APDU zeigen die Anfrage der App:
#selektieren des American Express AIDs
00 a4 04 00 05 a0 00 00 00 25
Scheinbar fragt die App nur nach einer American Express Karte.
Hall of Shame
Schlecht kodierte (ohne Überprüfung der Response APDU und ohne try-catch-Block) NFC Apps scheinen dann so auszusehen:
Interessant ist auch der Unterschied zwischen einem Android-Gerät mit NXP NFC Controller und einem Android-Gerät mit STMicroelectronics-Oberthur-Broadcom-Gespann. Mein Nexus S (mit NXP-NFC-Controller) sendet keine weiteren APDUs wenn das Phone auf die Karte gelegt wird, während das Nexus 10 (Broadcom-NFC-Controller) scheinbar alle 0.5 Sekunden versucht eine Leseanfrage an die Karte zu senden – denn nach 10 Sekunden wurden folgende APDUs geloggt:
> l9ls 0: 00B000009000 1: 00B000009000 2: 00B000009000 3: 00B000009000 4: 00B000009000 5: 00B000009000 6: 00B000009000 7: 00B000009000 8: 00B000009000 9: 00B000009000 10: 00B000009000 11: 00B000009000 12: 00B000009000 13: 00B000009000 14: 00B000009000 15: 00B000009000 16: 00B000009000 17: 00B000009000 18: 00B000009000 19: 00B000009000
Das 00B00000 entspricht einem READ-BINARY-Kommando, das wahrscheinlich genutzt wird um zu überprüfen, ob sich die Karte noch im Feld befindet.
Antworten
Jede Anfrage stumpf mit einem 0x9000 zu beantworten macht im 2.Schritt natürlich wenig Sinn, da es so zu keiner korrekten Kommunikation zwischem dem Smartphone und der Karte kommen wird. Deshalb sollte das Applet besser mit vorkonfigurierten Response-APDU antworten. Hat man die passende NFC-Smartcard zur App parat kann man so im Wechsel eine C-APDU loggen, die C-APDU an die richtige Karte senden, das Applet mit der R-APDU konfigurieren und so Schritt für Schritt quasi die Karte emulieren. Das Unterfangen ist zwar ziemlich mühsam aber für einen Logger unter 20 Euro akzeptabel.
Bei meinen Experimenten hat es sich allerdings herausgestellt, dass es Sinn macht eine Statemachine in das Applet zu implementieren, da je nach Status der Karte Anfragen unterschiedlich beantwortet werden müssen.
Btw: Das Applet kann natürlich auch zum Loggen einer kontaktbehafteten Karte, wie zB der Gesundheitskarte genutzt werden, da es der Karte nahezu egal ist über welches Interface die APDUs gesendet werden. Lesezugriffe auf Mifare Classic bzw ISO14443-3-Level kann mit der JavaCard leider nicht geloggt werden, da die Mifare Kommunikation eine Protokollebene niedriger stattfindet und nicht über die JavaCard API läuft.