package de.persosim.simulator.platform; import static org.globaltester.logging.BasicLogger.TRACE; import static org.globaltester.logging.BasicLogger.log; import java.util.LinkedList; import java.util.List; import org.globaltester.logging.InfoSource; import org.globaltester.simulator.LogTags; import de.persosim.simulator.exception.AccessDeniedException; import de.persosim.simulator.perso.Personalization; import de.persosim.simulator.processing.ProcessingData; import de.persosim.simulator.processing.UpdatePropagation; import de.persosim.simulator.utils.HexString; import de.persosim.simulator.utils.Utils; /** * Main entry point for the persoSim simulation. Handles instantiation of * platform layers and coordinates propagation of processing data through the * different layers. * * @author amay * */ public class PersoSimKernel implements InfoSource { private List<Layer> layers; /** * Constructor that provides the inital {@link Personalization} * @throws AccessDeniedException */ public PersoSimKernel() throws AccessDeniedException { super(); } /** * Performs initialization of object. * @param perso */ public void init(Personalization perso) { log(this, "init called", TRACE); perso.initialize(); layers = perso.getLayerList(); log(this, "init finished", TRACE); } public byte[] powerOff() { //power off all Layers from top to bottom for (int curLayerId = layers.size()-1; curLayerId >= 0; curLayerId--) { layers.get(curLayerId).powerOff(); } return Utils.toUnsignedByteArray(Iso7816.SW_9000_NO_ERROR); } public byte[] powerOn() { //power on all Layers from bottom for (int curLayerId = 0; curLayerId < layers.size(); curLayerId++) { layers.get(curLayerId).powerOn(); } //TODO AMY move atr definition to Personalization String atr = "3BE800008131FE00506572736F53696D" + "AA"; // P e r s o S i m XOR Checksum (required for T=1) return HexString.toByteArray(atr); } public byte[] reset() { // currently we support only cold reset as powerOff() followed by powerOn() // if a warm reset is needed this neds to be propagated accordingly powerOff(); return powerOn(); } @Override public String getIDString() { return "PersoSimKernel"; } /** * This method represents the simulator's actual core. APDUs and * accompanying ProcessingData-Objects are propagated through all available * layers from bottom to the top and back down again. * * @param commandApduData * the APDU that was recently received */ public byte[] process(byte[] commandApduData) { log(this, "processing incoming APDU", TRACE); log("Processing APDU: " + HexString.encode(commandApduData)); log(HexString.encode(commandApduData), LogTags.APDU_TAG_IN); log(this, "incoming APDU:\n" + HexString.dump(commandApduData), TRACE); ProcessingData processingData = new ProcessingData(); processingData.addUpdatePropagation(this, "initial hardware info", new HardwareCommandApduPropagation(commandApduData)); //propagate the event all layers up int curLayerId = 0; Layer currentLayer; for (; curLayerId < layers.size(); curLayerId++) { currentLayer = layers.get(curLayerId); currentLayer.processAscending(processingData); } //propagate the event all layers down for (curLayerId--; curLayerId >= 0; curLayerId--) { currentLayer = layers.get(curLayerId); currentLayer.processDescending(processingData); } //extract prepared response byte[] responseApduData; LinkedList<UpdatePropagation> hardwareResponses = processingData.getUpdatePropagations(HardwareResponseApduPropagation.class); UpdatePropagation lastHardwareResponseUpdate = hardwareResponses.getLast(); if (lastHardwareResponseUpdate != null && lastHardwareResponseUpdate instanceof HardwareResponseApduPropagation) { responseApduData = ((HardwareResponseApduPropagation)lastHardwareResponseUpdate).getResponseApdu(); } else { responseApduData = Utils.toUnsignedByteArray(Iso7816.SW_6F00_UNKNOWN+0x45); } log(this, "finished processing APDU"); log(this, "outgoing APDU:\n" + HexString.dump(responseApduData), TRACE); log(HexString.encode(responseApduData), LogTags.APDU_TAG_OUT); return responseApduData; } }