aboutsummaryrefslogtreecommitdiff
path: root/src/cz/crcs/ectester/reader/CardMngr.java
diff options
context:
space:
mode:
authorJ08nY2017-01-17 02:55:31 +0100
committerJ08nY2017-01-17 03:17:08 +0100
commit4debe5adb4bb486f488878e348ee7bcf386c43f2 (patch)
tree2cacbee1b1fac0c6afb686f5c2ce6f64bc4e1499 /src/cz/crcs/ectester/reader/CardMngr.java
parentbffdcc6925d806d74179a76b2dc57a619e9c1886 (diff)
downloadECTester-4debe5adb4bb486f488878e348ee7bcf386c43f2.tar.gz
ECTester-4debe5adb4bb486f488878e348ee7bcf386c43f2.tar.zst
ECTester-4debe5adb4bb486f488878e348ee7bcf386c43f2.zip
Diffstat (limited to 'src/cz/crcs/ectester/reader/CardMngr.java')
-rw-r--r--src/cz/crcs/ectester/reader/CardMngr.java289
1 files changed, 289 insertions, 0 deletions
diff --git a/src/cz/crcs/ectester/reader/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java
new file mode 100644
index 0000000..d7a5c5f
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/CardMngr.java
@@ -0,0 +1,289 @@
+package cz.crcs.ectester.reader;
+
+import com.licel.jcardsim.io.CAD;
+import com.licel.jcardsim.io.JavaxSmartCardInterface;
+import java.util.List;
+import java.util.Scanner;
+import javacard.framework.AID;
+
+import javax.smartcardio.*;
+
+/**
+ * @author Petr Svenda petr@svenda.com
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CardMngr {
+ private CardTerminal m_terminal = null;
+ private CardChannel m_channel = null;
+ private Card m_card = null;
+
+ // Simulator related attributes
+ private CAD m_cad = null;
+ private JavaxSmartCardInterface m_simulator = null;
+
+ private boolean simulate = false;
+
+ private final byte selectCM[] = {
+ (byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x00, (byte) 0x07, (byte) 0xa0, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x18, (byte) 0x43, (byte) 0x4d};
+
+ public static final byte OFFSET_CLA = 0x00;
+ public static final byte OFFSET_INS = 0x01;
+ public static final byte OFFSET_P1 = 0x02;
+ public static final byte OFFSET_P2 = 0x03;
+ public static final byte OFFSET_LC = 0x04;
+ public static final byte OFFSET_DATA = 0x05;
+ public static final byte HEADER_LENGTH = 0x05;
+
+ public static final short DATA_RECORD_LENGTH = (short) 0x80; // 128B per record
+ public static final short NUMBER_OF_RECORDS = (short) 0x0a; // 10 records
+
+ public CardMngr() {
+ this(false);
+ }
+
+ public CardMngr(boolean simulate) {
+ this.simulate = simulate;
+ }
+
+ public boolean connectToCard() throws CardException {
+ if (simulate)
+ return true;
+
+ // TRY ALL READERS, FIND FIRST SELECTABLE
+ List<CardTerminal> terminalList = getReaderList();
+
+ if (terminalList == null || terminalList.isEmpty()) {
+ System.out.println("No terminals found");
+ return false;
+ }
+
+ //List numbers of Card readers
+ boolean cardFound = false;
+ for (int i = 0; i < terminalList.size(); i++) {
+ System.out.println(i + " : " + terminalList.get(i));
+ m_terminal = terminalList.get(i);
+ if (m_terminal.isCardPresent()) {
+ m_card = m_terminal.connect("*");
+ System.out.println("card: " + m_card);
+ m_channel = m_card.getBasicChannel();
+
+ //reset the card
+ System.out.println(Util.bytesToHex(m_card.getATR().getBytes()));
+
+ cardFound = true;
+ }
+ }
+
+ return cardFound;
+ }
+
+ public boolean connectToCardSelect() throws CardException {
+ if (simulate)
+ return true;
+
+ // Test available card - if more present, let user to select one
+ List<CardTerminal> terminalList = CardMngr.getReaderList();
+ if (terminalList == null || terminalList.isEmpty()) {
+ System.out.println("ERROR: No suitable reader with card detected. Please check your reader connection");
+ return false;
+ } else {
+ if (terminalList.size() == 1) {
+ m_terminal = terminalList.get(0); // return first and only reader
+ } else {
+ int terminalIndex = 1;
+ // Let user select target terminal
+ for (CardTerminal terminal : terminalList) {
+ Card card;
+ try {
+ card = terminal.connect("*");
+ ATR atr = card.getATR();
+ System.out.println(terminalIndex + " : " + terminal.getName() + " - " + Util.bytesToHex(atr.getBytes()));
+ terminalIndex++;
+ } catch (CardException ex) {
+ ex.printStackTrace(System.out);
+ }
+ }
+ System.out.print("Select index of target reader you like to use 1.." + (terminalIndex - 1) + ": ");
+ Scanner sc = new Scanner(System.in);
+ int answ = sc.nextInt();
+ System.out.println(String.format("%d", answ));
+ answ--; // is starting with 0
+ // BUGBUG; verify allowed index range
+ m_terminal = terminalList.get(answ);
+ }
+ }
+
+ if (m_terminal != null) {
+ m_card = m_terminal.connect("*");
+ System.out.println("card: " + m_card);
+ m_channel = m_card.getBasicChannel();
+ }
+
+ return true;
+ }
+
+ public boolean reconnectToCard(byte[] selectAPDU) throws CardException {
+ if (simulate)
+ return true;
+
+ if (connected()) {
+ disconnectFromCard();
+ }
+
+ boolean result = connectToCard();
+ if (result) {
+ // Select our application on card
+ send(selectAPDU);
+ }
+ return result;
+ }
+
+ public boolean connected() {
+ return simulate || m_card != null;
+ }
+
+ public void disconnectFromCard() throws CardException {
+ if (simulate)
+ return;
+
+ if (m_card != null) {
+ m_card.disconnect(false);
+ m_card = null;
+ }
+ }
+
+ public byte[] getCPLCData() throws Exception {
+ byte[] data;
+
+ // TODO: Modify to obtain CPLC data
+ byte apdu[] = new byte[HEADER_LENGTH];
+ apdu[OFFSET_CLA] = (byte) 0x00;
+ apdu[OFFSET_INS] = (byte) 0x00;
+ apdu[OFFSET_P1] = (byte) 0x00;
+ apdu[OFFSET_P2] = (byte) 0x00;
+ apdu[OFFSET_LC] = (byte) 0x00;
+
+ ResponseAPDU resp = send(apdu);
+ if (resp.getSW() != 0x9000) { // 0x9000 is "OK"
+ System.out.println("Fail to obtain card's response data");
+ data = null;
+ } else {
+ byte temp[] = resp.getBytes();
+ data = new byte[temp.length - 2];
+ System.arraycopy(temp, 0, data, 0, temp.length - 2);
+ // Last two bytes are status word (also obtainable by resp.getSW())
+ // Take a look at ISO7816_status_words.txt for common codes
+ }
+
+ return data;
+ }
+
+ public void probeCardCommands() throws Exception {
+ // TODO: modify to probe for instruction
+ for (int i = 0; i <= 0; i++) {
+ byte apdu[] = new byte[HEADER_LENGTH];
+ apdu[OFFSET_CLA] = (byte) 0x00;
+ apdu[OFFSET_INS] = (byte) 0x00;
+ apdu[OFFSET_P1] = (byte) 0x00;
+ apdu[OFFSET_P2] = (byte) 0x00;
+ apdu[OFFSET_LC] = (byte) 0x00;
+
+ ResponseAPDU resp = send(apdu);
+
+ System.out.println("Response: " + Integer.toHexString(resp.getSW()));
+
+ if (resp.getSW() != 0x6D00) { // Note: 0x6D00 is SW_INS_NOT_SUPPORTED
+ // something?
+ }
+ }
+ }
+
+ public static List<CardTerminal> getReaderList() {
+ try {
+ TerminalFactory factory = TerminalFactory.getDefault();
+ return factory.terminals().list();
+ } catch (CardException ex) {
+ System.out.println("Exception : " + ex);
+ return null;
+ }
+ }
+
+ public ResponseAPDU sendAPDU(CommandAPDU apdu) throws CardException {
+ System.out.println(">>>>");
+ System.out.println(apdu);
+
+ System.out.println(Util.bytesToHex(apdu.getBytes()));
+
+ long elapsed = -System.nanoTime();
+
+ ResponseAPDU responseAPDU = m_channel.transmit(apdu);
+
+ elapsed += System.nanoTime();
+
+ System.out.println(responseAPDU);
+ System.out.println(Util.bytesToHex(responseAPDU.getBytes()));
+
+ if (responseAPDU.getSW1() == (byte) 0x61) {
+ CommandAPDU apduToSend = new CommandAPDU((byte) 0x00,
+ (byte) 0xC0, (byte) 0x00, (byte) 0x00,
+ responseAPDU.getSW1());
+
+ responseAPDU = m_channel.transmit(apduToSend);
+ System.out.println(Util.bytesToHex(responseAPDU.getBytes()));
+ }
+
+ System.out.println("<<<<");
+ System.out.println("Elapsed time (ms): " + elapsed / 1000000);
+ return responseAPDU;
+ }
+
+ public ResponseAPDU sendAPDU(byte apdu[]) throws CardException {
+ CommandAPDU commandAPDU = new CommandAPDU(apdu);
+ return sendAPDU(commandAPDU);
+ }
+
+ public boolean prepareLocalSimulatorApplet(byte[] appletAIDArray, byte[] installData, Class appletClass) {
+ System.setProperty("com.licel.jcardsim.terminal.type", "2");
+ m_cad = new CAD(System.getProperties());
+ m_simulator = (JavaxSmartCardInterface) m_cad.getCardInterface();
+ AID appletAID = new AID(appletAIDArray, (short) 0, (byte) appletAIDArray.length);
+
+ AID appletAIDRes = m_simulator.installApplet(appletAID, appletClass, installData, (short) 0, (byte) installData.length);
+ return m_simulator.selectApplet(appletAID);
+ }
+
+ public ResponseAPDU sendAPDUSimulator(CommandAPDU apdu) {
+ System.out.println(">>>>");
+ System.out.println(Util.bytesToHex(apdu.getBytes()));
+
+ ResponseAPDU response = m_simulator.transmitCommand(apdu);
+ byte[] responseBytes = response.getBytes();
+
+ System.out.println(Util.bytesToHex(responseBytes));
+ System.out.println("<<<<");
+
+ return response;
+ }
+
+ public ResponseAPDU sendAPDUSimulator(byte[] apdu) {
+ CommandAPDU commandAPDU = new CommandAPDU(apdu);
+ return sendAPDUSimulator(commandAPDU);
+ }
+
+ public ResponseAPDU send(CommandAPDU apdu) throws CardException {
+ ResponseAPDU response;
+ if (simulate) {
+ response = sendAPDUSimulator(apdu);
+ } else {
+ response = sendAPDU(apdu);
+ }
+ return response;
+ }
+
+ public ResponseAPDU send(byte[] apdu) throws CardException {
+ CommandAPDU commandAPDU = new CommandAPDU(apdu);
+ return send(commandAPDU);
+ }
+
+}