/*
* Copyright 2012 Licel LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.licel.jcardsim.smartcardio;
import com.licel.jcardsim.base.SimulatorSystem;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.util.Arrays;
import java.util.List;
import javacard.framework.ISO7816;
import javax.smartcardio.*;
import junit.framework.TestCase;
import org.bouncycastle.util.encoders.Hex;
/**
* Test Java Card Terminal emulation.
*
* @author LICEL LLC
*/
public class JCardSimProviderTest extends TestCase {
private static final ATR ETALON_ATR = new ATR(Hex.decode("3BFA1800008131FE454A434F5033315632333298"));
private static final String TEST_APPLET_AID = "010203040506070809";
protected void setUp() throws Exception {
super.setUp();
}
@Override
protected void tearDown() throws Exception {
System.clearProperty("com.licel.jcardsim.card.applet.0.AID");
System.clearProperty("com.licel.jcardsim.card.applet.0.Class");
}
public void testProvider() throws CardException, NoSuchAlgorithmException, UnsupportedEncodingException {
System.setProperty("com.licel.jcardsim.card.applet.0.AID", TEST_APPLET_AID);
System.setProperty("com.licel.jcardsim.card.applet.0.Class", "com.licel.jcardsim.samples.HelloWorldApplet");
if (Security.getProvider("jCardSim") == null) {
JCardSimProvider provider = new JCardSimProvider();
Security.addProvider(provider);
}
TerminalFactory tf = TerminalFactory.getInstance("jCardSim", null);
CardTerminals ct = tf.terminals();
List<CardTerminal> list = ct.list();
CardTerminal jcsTerminal = null;
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getName().equals("jCardSim.Terminal")) {
jcsTerminal = list.get(i);
break;
}
}
// check terminal exists
assertTrue(jcsTerminal != null);
// check if card is present
assertTrue(jcsTerminal.isCardPresent());
// check card
Card jcsCard = jcsTerminal.connect("T=0");
assertTrue(jcsCard != null);
// check card ATR
assertEquals(jcsCard.getATR(), ETALON_ATR);
// check card protocol
assertEquals(jcsCard.getProtocol(), "T=0");
// get basic channel
CardChannel jcsChannel = jcsCard.getBasicChannel();
assertTrue(jcsChannel != null);
// create applet data = aid len (byte), aid bytes, params length (byte), param
byte[] aidBytes = Hex.decode(TEST_APPLET_AID);
byte[] createData = new byte[1+aidBytes.length+1+2+3];
createData[0] = (byte) aidBytes.length;
System.arraycopy(aidBytes, 0, createData, 1, aidBytes.length);
createData[1+aidBytes.length] = (byte) 5;
createData[2+aidBytes.length] = 0; // aid
createData[3+aidBytes.length] = 0; // control
createData[4+aidBytes.length] = 2; // params
createData[5+aidBytes.length] = 0xF; // params
createData[6+aidBytes.length] = 0xF; // params
CommandAPDU createApplet = new CommandAPDU(0x80, 0xb8, 0, 0, createData);
ResponseAPDU response = jcsChannel.transmit(createApplet);
assertEquals(response.getSW(), 0x9000);
assertEquals(true, Arrays.equals(response.getData(), aidBytes));
// select applet
CommandAPDU selectApplet = new CommandAPDU(ISO7816.CLA_ISO7816, ISO7816.INS_SELECT, 4, 0, Hex.decode(TEST_APPLET_AID));
response = jcsChannel.transmit(selectApplet);
assertEquals(response.getSW(), 0x9000);
// test NOP
response = jcsChannel.transmit(new CommandAPDU(0x00, 0x02, 0x00, 0x00));
assertEquals(0x9000, response.getSW());
// test SW_INS_NOT_SUPPORTED
response = jcsChannel.transmit(new CommandAPDU(0x00, 0x05, 0x00, 0x00));
assertEquals(ISO7816.SW_INS_NOT_SUPPORTED, response.getSW());
// test hello world from card
response = jcsChannel.transmit(new CommandAPDU(0x00, 0x01, 0x00, 0x00));
assertEquals(0x9000, response.getSW());
assertEquals("Hello world !", new String(response.getData()));
// test echo
response = jcsChannel.transmit(new CommandAPDU(0x00, 0x01, 0x01, 0x00, ("Hello javacard world !").getBytes()));
assertEquals(0x9000, response.getSW());
assertEquals("Hello javacard world !", new String(response.getData()));
// test echo v2
response = jcsChannel.transmit(new CommandAPDU(0x00, 0x03, 0x00, 0x00, ("Hello javacard world !").getBytes()));
assertEquals(0x9000, response.getSW());
assertEquals("Hello javacard world !", new String(response.getData()));
// test echo install params
response = jcsChannel.transmit(new CommandAPDU(0x00, 0x04, 0x00, 0x00));
assertEquals(0x9000, response.getSW());
assertEquals(0xF, response.getData()[0]);
assertEquals(0xF, response.getData()[1]);
// test continued data
response = jcsChannel.transmit(new CommandAPDU(0x00, 0x06, 0x00, 0x00));
assertEquals(0x6107, response.getSW());
assertEquals("Hello ", new String(response.getData()));
// test https://github.com/licel/jcardsim/issues/13
byte[] listObjectsCmd = new byte[5];
listObjectsCmd[0] = (byte) 0xb0;
listObjectsCmd[1] = (byte) 0x58;
listObjectsCmd[2] = (byte) 0x00;
listObjectsCmd[3] = (byte) 0x00;
listObjectsCmd[4] = (byte) 0x0E;
response = jcsChannel.transmit(new CommandAPDU(listObjectsCmd));
assertEquals(0x9C12, response.getSW());
// application specific sw + data
response = jcsChannel.transmit(new CommandAPDU(0x00, 0x07, 0x00, 0x00));
assertEquals(0x9B00, response.getSW());
assertEquals("Hello world !", new String(response.getData()));
// sending maximum data
response = jcsChannel.transmit(new CommandAPDU(0x00, 0x08, 0x00, 0x00));
assertEquals(0x9000, response.getSW());
}
}