Ich habe ein Dual-Interface Chipkartenleser, den einige erweiterte Funktionen (außer Senden von APDU-Befehlen zu und Empfangen von Karten APDU Erwiderungen) aufweist.
Zum Beispiel in ihrem Dokument wird erwähnt, dass Sie Firmware-Version Ihrer Leser mit folgendem Befehl erhalten können:
GET_FIRMWARE_VERSION: FF 69 44 42 05 68 92 00 05 00
In seinem Werkzeug, eine Taste für diese Funktion ist es und es funktioniert fein:
ich schnupperte sogar USB-Anschluss, um zu sehen, was genau in der Verbindung zwischen meinem PC und meinem Leser für diese Funktion ausgetauscht:
Problem:
ich meine Leser-Version erhalten möchten (und vielleicht auch andere erweiterte Befehle senden) mit anderen Werkzeugen oder über Code, aber ich muss eine Karte in den Kartenleser stecken, um Befehle senden zu können, sonst erhalte ich No Card Present
Ausnahme, während ich keine Befehle an die Karte senden möchte! (Die Reader-Tool Antworten erfolgreich GET_FIRMWARE_VERSION ohne Karte in den Leser Slots)
Was ich bisher tat:
1.Ich versucht, einige Tools, einschließlich OpenSCTool, PyAPDUTool und ein anderes Leserwerkzeug. 2. Ich schrieb folgendes Python-Skript, um erweiterte Befehle zu senden.
#--- Importing required modules.
import sys
import time
sys.path.append("D:\\PythonX\\Lib\\site-packages")
from smartcard.scard import *
import smartcard.util
from smartcard.System import readers
#---This is the list of commands that we want to send device
cmds =[[,0xFF,0x69,0x44,0x42,0x05,0x68,0x92,0x00,0x04,0x00],]
#--- Let's to make a connection to the card reader
r=readers()
print "Available Readers :",r
print
target_reader = input("--- Select Reader (0, 1 , ...): ")
print
while(True):
try:
print "Using :",r[target_reader]
reader = r[target_reader]
connection=reader.createConnection()
connection.connect()
break
except:
print "--- Exception occured! (Wrong reader or No card present)"
ans = raw_input("--- Try again? (0:Exit/1:Again/2:Change Reader)")
if int(ans)==0:
exit()
elif int(ans)==2:
target_reader = input("Select Reader (0, 1 , ...): ")
#--- An struct for APDU responses consist of Data, SW1 and SW2
class stru:
def __init__(self):
self.data = list()
self.sw1 = 0
self.sw2 = 0
resp = stru()
def send(cmds):
for cmd in cmds:
#--- Following 5 line added to have a good format of command in the output.
temp = stru() ;
temp.data[:]=cmd[:]
temp.sw1=12
temp.sw2=32
modifyFormat(temp)
print "req: ", temp.data
resp.data,resp.sw1,resp.sw2 = connection.transmit(cmd)
modifyFormat(resp)
printResponse(resp)
def modifyFormat(resp):
resp.sw1=hex(resp.sw1)
resp.sw2=hex(resp.sw2)
if (len(resp.sw2)<4):
resp.sw2=resp.sw2[0:2]+'0'+resp.sw2[2]
for i in range(0,len(resp.data)):
resp.data[i]=hex(resp.data[i])
if (len(resp.data[i])<4):
resp.data[i]=resp.data[i][0:2]+'0'+resp.data[i][2]
def printResponse(resp):
print "res: ", resp.data,resp.sw1,resp.sw2
send(cmds)
connection.disconnect()
Ausgang:
>>> ================================ RESTART ================================
Available Readers : ['CREATOR CRT-603 (CZ1) CCR RF 0', 'CREATOR CRT-603 (CZ1) CCR SAM 0']
--- Select Reader (0, 1 , ...): 0
Using : CREATOR CRT-603 (CZ1) CCR RF 0
--- Exception occured! (Wrong reader or No card present)
--- Try again? (0:Exit/1:Again/2:Change Reader)
>>> ================================ RESTART ================================
Available Readers : ['CREATOR CRT-603 (CZ1) CCR RF 0', 'CREATOR CRT-603 (CZ1) CCR SAM 0']
--- Select Reader (0, 1 , ...): 1
Using : CREATOR CRT-603 (CZ1) CCR SAM 0
--- Exception occured! (Wrong reader or No card present)
--- Try again? (0:Exit/1:Again/2:Change Reader)
Aber beide haben das erwähnte Problem!
Fragen:
1- Wie erweiterte Befehle für den Leser zu senden, während es keine Karte verfügbar ist?
2- Warum kann ich den Befehl Header in den Sniffed-Daten nicht sehen? (Beachten Sie, dass, da Header ein vordefinierter fester Wert für alle erweiterten Befehle ist, das Reader-Tool den Header mit dem Befehl GET_FIRMWARE_VERSION nicht sendet und nur die Daten sendet! Aber wie funktioniert es?)
Update:
Mit Versuch und Irrtum fand ich etwas nützliches.
Annahmen:
- Pseudo-APDUs Fest header =
FF 69 44 42
- Pseudo-APDU Datenfeld für GET_READER_FIRMWARE_VERSION =
68 92 00 04 00
- Pseudo-APDU Datenfeld für CHANGE_SAM_SLOT =
68 92 01 00 03 XX 00 00
(Meine Leser zwei hat SAM-Steckplätze, soXX
kann01
oder02
sein) - SELECT APDU-Befehl =
00 A4 04 00 00
Ok, ich habe das folgende Java-Programm:
import java.util.List;
import java.util.Scanner;
import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;
import javax.smartcardio.TerminalFactory;
import javax.xml.bind.DatatypeConverter;
public class TestPCSC {
public static void main(String[] args) throws CardException {
TerminalFactory tf = TerminalFactory.getDefault();
List< CardTerminal> terminals = tf.terminals().list();
System.out.println("Available Readers:");
System.out.println(terminals + "\n");
Scanner scanner = new Scanner(System.in);
System.out.print("Which reader do you want to send your commands to? (0 or 1 or ...): ");
String input = scanner.nextLine();
int readerNum = Integer.parseInt(input);
CardTerminal cardTerminal = (CardTerminal) terminals.get(readerNum);
Card connection = cardTerminal.connect("DIRECT");
CardChannel cardChannel = connection.getBasicChannel();
System.out.println("Write your commands in Hex form, without '0x' or Space charaters.");
System.out.println("\n---------------------------------------------------");
System.out.println("Pseudo-APDU Mode:");
System.out.println("---------------------------------------------------");
while (true) {
System.out.println("Pseudo-APDU command: (Enter 0 to send APDU command)");
String cmd = scanner.nextLine();
if (cmd.equals("0")) {
break;
}
System.out.println("Command : " + cmd);
byte[] cmdArray = hexStringToByteArray(cmd);
byte[] resp = connection.transmitControlCommand(CONTROL_CODE(), cmdArray);
String hex = DatatypeConverter.printHexBinary(resp);
System.out.println("Response : " + hex + "\n");
}
System.out.println("\n---------------------------------------------------");
System.out.println("APDU Mode:");
System.out.println("---------------------------------------------------");
while (true) {
System.out.println("APDU command: (Enter 0 to exit)");
String cmd = scanner.nextLine();
if (cmd.equals("0")) {
break;
}
System.out.println("Command : " + cmd);
byte[] cmdArray = hexStringToByteArray(cmd);
ResponseAPDU resp = cardChannel.transmit(new CommandAPDU(cmdArray));
byte[] respB = resp.getBytes();
String hex = DatatypeConverter.printHexBinary(respB);
System.out.println("Response : " + hex + "\n");
}
connection.disconnect(true);
}
public static int CONTROL_CODE() {
String osName = System.getProperty("os.name").toLowerCase();
if (osName.indexOf("windows") > -1) {
/* Value used by both MS' CCID driver and SpringCard's CCID driver */
return (0x31 << 16 | 3500 << 2);
} else {
/* Value used by PCSC-Lite */
return 0x42000000 + 1;
}
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len/2];
for (int i = 0; i < len; i += 2) {
data[i/2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16));
}
return data;
}
}
In dem obigen Programm, ich Befehle an meine Leser mit beiden connection.transmitControlCommand
und cardChannel.transmit()
Methoden senden. Der Punkt ist, dass alle Befehle, die mit der ersten Methode an den Leser gesendet werden, als Pseudo-APDU-Befehl angenommen werden und ich den Psedo-APDU-Header für sie nicht verwenden sollte! Und alle Befehle, die mit der zweiten Methode an den Leser gesendet werden, werden als reguläre APDU-Befehle angenommen. Wenn ich also Pseudo-APDU-Befehle über die zweite Methode senden muss, muss ich den Pseudo-APDU-Header hinzufügen.
Lassen siehe Ausgabe für den kontaktlosen Leser:
run:
Available Readers:
[PC/SC terminal ACS ACR122 0,
PC/SC terminal CREATOR CRT-603 (CZ1) CCR RF 0,
PC/SC terminal CREATOR CRT-603 (CZ1) CCR SAM 0]
Which reader do you want to send your commands to? (0 or 1 or ...): 1
Write your commands in Hex form, without '0x' or Space charaters.
---------------------------------------------------
Pseudo-APDU Mode:
---------------------------------------------------
Pseudo-APDU command: (Enter 0 to send APDU command)
00A4040000
Command : 00A4040000
Response : 6800
//Based on reader's documents, 0x6800 means "Class byte is not correct"
//As I have a regular java card in the RF field of my reader, I conclude that
//this response is Reader's response (and not card response)
Pseudo-APDU command: (Enter 0 to send APDU command)
6892000400
Command : 6892000400
Response : 433630335F435A375F425F31353038323100039000
Pseudo-APDU command: (Enter 0 to send APDU command)
FF694442056892000400
Command : FF694442056892000400
Response : 6800
//Pseudo-APDU commands doesn't work in Pseudo-APDU mode if I add the Pseudo-APDU header to them.
Pseudo-APDU command: (Enter 0 to send APDU command)
00A4040000
Command : 00A4040000
Response : 6800
Pseudo-APDU command: (Enter 0 to send APDU command)
0
---------------------------------------------------
APDU Mode:
---------------------------------------------------
APDU command: (Enter 0 to exit)
00A4040000
Command : 00A4040000
Response : 6F198408A000000018434D00A50D9F6E061291921101009F6501FF9000
APDU command: (Enter 0 to exit)
6892000400
Command : 6892000400
Response : 6E00
//This is the response of my card. I can't receive Firmware version in APDU mode using this command without Pseudo-APDU header.
APDU command: (Enter 0 to exit)
FF694442056892000400
Command : FF694442056892000400
Response : 433630335F435A375F425F31353038323100099000
//I successfully received Firmware version in APDU mode using the fixed Pseudo-APDU header.
APDU command: (Enter 0 to exit)
00A4040000
Command : 00A4040000
Response : 6F198408A000000018434D00A50D9F6E061291921101009F6501FF9000
APDU command: (Enter 0 to exit)
0
BUILD SUCCESSFUL (total time: 1 minute 36 seconds)
Gibt es noch ein Problem?
Ja, zwei Probleme !:
1-das obige Programm arbeitet für seinen ersten Lauf nur in Ordnung. Ich meine, wenn ich nicht mehr ausgeführt, und wiederholen Sie es, die zweite Methode eine Ausnahme aus:
run:
Available Readers:
[PC/SC terminal ACS ACR122 0, PC/SC terminal CREATOR CRT-603 (CZ1) CCR RF 0, PC/SC terminal CREATOR CRT-603 (CZ1) CCR SAM 0]
Which reader do you want to send your commands to? (0 or 1 or ...): 1
Write your commands in Hex form, without '0x' or Space charaters.
---------------------------------------------------
Pseudo-APDU Mode:
---------------------------------------------------
Pseudo-APDU command: (Enter 0 to send APDU command)
00A4040000
Command : 00A4040000
Response : 6800
Pseudo-APDU command: (Enter 0 to send APDU command)
FF694442056892000400
Command : FF694442056892000400
Response : 6800
Pseudo-APDU command: (Enter 0 to send APDU command)
6892000400
Command : 6892000400
Response : 433630335F435A375F425F31353038323100049000
Pseudo-APDU command: (Enter 0 to send APDU command)
00A4040000
Command : 00A4040000
Response : 6800
Pseudo-APDU command: (Enter 0 to send APDU command)
0
---------------------------------------------------
APDU Mode:
---------------------------------------------------
APDU command: (Enter 0 to exit)
00A4040000
Command : 00A4040000
Exception in thread "main" javax.smartcardio.CardException: sun.security.smartcardio.PCSCException: Unknown error 0x16
at sun.security.smartcardio.ChannelImpl.doTransmit(ChannelImpl.java:219)
at sun.security.smartcardio.ChannelImpl.transmit(ChannelImpl.java:90)
at TestPCSC.main(TestPCSC.java:58)
Caused by: sun.security.smartcardio.PCSCException: Unknown error 0x16
at sun.security.smartcardio.PCSC.SCardTransmit(Native Method)
at sun.security.smartcardio.ChannelImpl.doTransmit(ChannelImpl.java:188)
... 2 more
Java Result: 1
BUILD SUCCESSFUL (total time: 39 seconds)
Wie Sie oben sehen, kann ich nicht zweite Methode verwenden mehr und ich muss Ausschalt-Leser und Leistung auf es wieder, damit es wieder gut funktioniert.
2-Die Kontaktschnittstelle (ich meine der SAM-Leser) werfen vorher immer die Ausnahme! Ich meine, die zweite Methode funktioniert überhaupt nicht (weder erster Lauf, noch zweiter und dritter ....)
Beachten Sie, dass ich verschiedene Leser versuchte, scheint es, dass dies nicht nur auf diesen Leser beschränkt ist. Einige ACS-Leser haben auch ein ähnliches oder genau das gleiche Problem mit der Wiederholung
Hat jemand eine Idee?
Und als eine Nebenfrage, hat Python irgendwelche gleich Methoden zum Senden von Pseudo-APDU wie Java?
Und schließlich, aus der Sicht von Reader, was ist der Unterschied zwischen connection.transmitControlCommand
und cardChannel.transmit()
Methoden?
Kann nicht sicher sagen, aber Leser haben oft Leser-spezifische Bibliotheken auf dem PC installiert, die parallel mit den SCID-Treibern für PCSC verwendet werden können. In diesem Fall hängt die GUI des Kartenleser-Herstellers wahrscheinlich von diesen Bibliotheken ab, da sie möglicherweise mehr kartenleserspezifische Funktionen aufweisen. Ich bin mir nicht sicher, wie sehr die Pass-Through-Probleme durch den Treiber des Smartcard-Lesers oder den PCSC-Stack selbst verursacht werden. Der Leserhersteller sollte es aber wissen. –
Sie sollten mit einem Abhängigkeits-Viewer prüfen können, welche Bibliotheken von den verschiedenen Tools verwendet werden. –
@MaartenBodewes Danke lieber Herr Bodewes. Ich habe die Frage aktualisiert. Über die Reader-spezifische Bibliothek denke ich, dass es nicht der Punkt in meinem Fall ist. Alle Tools, die mein Leser hat, ist eine portable ausführbare Datei (ohne .sys-Datei oder .dll-Bibliothek). Wie auch immer ich den 'tasklist \ M'-Befehl in der Windows-Befehlszeile verwendet habe und er gibt mir' ntdll.dll, wow64.dll, wow64win.dll, wow64cpu.dll' für diesen ausführbaren Dateiprozess zurück. – Abraham