/*
* Commons eID Project.
* Copyright (C) 2008-2013 FedICT.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version
* 3.0 as published by the Free Software Foundation.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, see
* http://www.gnu.org/licenses/.
*/
package test.integ.be.fedict.commons.eid.client.simulation;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
import javax.smartcardio.ATR;
import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;
public class SimulatedCard extends Card {
protected static final ResponseAPDU OK = new ResponseAPDU(new byte[]{
(byte) 0x90, 0x00});
protected static final ResponseAPDU COMMAND_NOT_AVAILABLE = new ResponseAPDU(
new byte[]{0x6d, 0x00});
protected static final ResponseAPDU FILE_NOT_FOUND = new ResponseAPDU(
new byte[]{0x6a, (byte) 0x82});
protected static final ResponseAPDU OFFSET_OUTSIDE_EF = new ResponseAPDU(
new byte[]{0x6b, (byte) 0x00});
protected ATR atr;
protected String protocol;
protected Map<BigInteger, byte[]> files;
protected byte[] selectedFile;
public SimulatedCard(final ATR atr) {
super();
this.atr = atr;
this.files = new HashMap<BigInteger, byte[]>();
}
public void setATR(final ATR atr) {
this.atr = atr;
}
@Override
public void beginExclusive() throws CardException {
throw new RuntimeException("Not Implemented In SimulatedCard");
}
@Override
public void disconnect(final boolean arg0) throws CardException {
throw new RuntimeException("Not Implemented In SimulatedCard");
}
@Override
public void endExclusive() throws CardException {
throw new RuntimeException("Not Implemented In SimulatedCard");
}
@Override
public ATR getATR() {
return this.atr;
}
@Override
public CardChannel getBasicChannel() {
return new SimulatedCardChannel(this);
}
@Override
public String getProtocol() {
return this.protocol;
}
@Override
public CardChannel openLogicalChannel() throws CardException {
throw new RuntimeException("Not Implemented In SimulatedCard");
}
@Override
public byte[] transmitControlCommand(final int arg0, final byte[] arg1)
throws CardException {
throw new RuntimeException("Not Implemented In SimulatedCard");
}
protected ResponseAPDU transmit(final CommandAPDU apdu)
throws CardException {
// "SELECT FILE"
if (apdu.getCLA() == 0x00 && apdu.getINS() == 0xA4
&& apdu.getP1() == 0x08 && apdu.getP2() == 0x0C) {
return selectFile(apdu.getData());
}
// "READ BINARY"
else if (apdu.getCLA() == 0x00 && apdu.getINS() == 0xB0) {
final int offset = (apdu.getP1() << 8) + apdu.getP2();
return readBinary(offset, (int) apdu.getNe());
}
return COMMAND_NOT_AVAILABLE;
}
protected ResponseAPDU readBinary(final int offset, final int length) {
// how many bytes left to read
int lengthToReturn = this.selectedFile.length - offset;
// limited to number of bytes requested
if (lengthToReturn > length) {
lengthToReturn = length;
}
// there are no more bytes..
if (lengthToReturn == 0) {
return OFFSET_OUTSIDE_EF;
}
// reserve number of bytes + 2 for trailer
final byte[] response = new byte[lengthToReturn + 2];
// copy the bytes from the selected file..
System.arraycopy(this.selectedFile, offset, response, 0, lengthToReturn);
// add the trailer with OK response
response[lengthToReturn] = (byte) 0x90;
response[lengthToReturn + 1] = 0x00;
// return as an BeIDCommandAPDU..
return new ResponseAPDU(response);
}
protected ResponseAPDU selectFile(final byte[] fileId) {
this.selectedFile = this.files.get(new BigInteger(fileId));
if (this.selectedFile == null) {
return FILE_NOT_FOUND;
}
return OK;
}
public SimulatedCard setFile(final byte[] fileId, final byte[] fileData) {
this.files.put(new BigInteger(fileId), fileData);
return this;
}
public SimulatedCard removeFile(final byte[] fileId) {
this.files.remove(new BigInteger(fileId));
return this;
}
}