1 /** 2 * --------- 3 * |.##> <##.| Open Smart Card Development Platform (www.openscdp.org) 4 * |# #| 5 * |# #| Copyright (c) 1999-2009 CardContact Software & System Consulting 6 * |'##> <##'| Andreas Schwier, 32429 Minden, Germany (www.cardcontact.de) 7 * --------- 8 * 9 * This file is part of OpenSCDP. 10 * 11 * OpenSCDP is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License version 2 as 13 * published by the Free Software Foundation. 14 * 15 * OpenSCDP is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with OpenSCDP; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 * 24 * @fileoverview A simple EMV card simulation 25 */ 26 27 load("../../cardsim/filesystem.js"); 28 load("../emv.js"); 29 30 load("emvcommandinterpreter.js"); 31 load("emvdatamodel.js"); 32 33 34 var dataModel = new EMVDataModel(); 35 36 37 /** 38 * Create a card simulation object 39 * 40 * @class Class implementing a simple EMV card simulation 41 * @constructor 42 */ 43 function EMVSimulator() { 44 this.mf = new DF(FCP.newDF("3F00", null)); 45 46 var aid = new ByteString("A000000000", HEX); 47 var fcipt = new ASN1("FCI Proprietary Template", 0xA5, 48 new ASN1("SFI of the Directory Elementary File", 0x88, ByteString.valueOf(1)) 49 ); 50 51 var psd = new ASN1(0x70, 52 new ASN1(0x61, 53 new ASN1(0x4F, aid), 54 new ASN1(0x50, new ByteString("EMV Simulator", ASCII)) 55 ) 56 ); 57 var records = [ psd.getBytes() ]; 58 var paysysddf = new DF(FCP.newDF(null, EMV.PSE1, fcipt.getBytes()), 59 new LinearEF(FCP.newLinearEF("EF01", 1, FCP.LINEARVARIABLE, 1, 100), records) 60 ); 61 62 this.mf.add(paysysddf); 63 64 var fcipt = new ASN1("FCI Proprietary Template", 0xA5, 65 new ASN1("Application Label", 0x50, new ByteString("EMV Simulator", ASCII)) 66 ); 67 68 var adf = new DF(FCP.newDF(null, aid, fcipt.getBytes()) 69 ); 70 71 adf.addMeta("ApplicationInterchangeProfile", dataModel.getApplicationInterchangeProfile()); 72 adf.addMeta("ApplicationFileLocator", dataModel.getApplicationFileLocator()); 73 74 // Create file system from data model 75 for each (var file in dataModel.getFiles()) { 76 var fid = ByteString.valueOf(0xEF00 + file.sfi, 2).toString(HEX); 77 adf.add(new LinearEF(FCP.newLinearEF(fid, file.sfi, FCP.LINEARVARIABLE, file.records.length, 256), file.records)); 78 } 79 80 this.mf.add(adf); 81 82 print(this.mf.dump("")); 83 84 this.initialize(); 85 } 86 87 88 89 /** 90 * Initialize card runtime 91 */ 92 EMVSimulator.prototype.initialize = function() { 93 this.fileSelector = new FileSelector(this.mf); 94 this.commandInterpreter = new EMVCommandInterpreter(this.fileSelector); 95 } 96 97 98 99 /** 100 * Process an inbound APDU 101 * 102 * @param {ByteString} capdu the command APDU 103 * @type ByteString 104 * @return the response APDU 105 */ 106 EMVSimulator.prototype.processAPDU = function(capdu) { 107 print("Command APDU : " + capdu); 108 109 var apdu; 110 111 try { 112 apdu = new APDU(capdu); 113 } 114 catch(e) { 115 GPSystem.trace(e); 116 var sw = APDU.SW_GENERALERROR; 117 if (e instanceof GPError) { 118 sw = e.reason; 119 } 120 return ByteString.valueOf(sw, 2); 121 } 122 123 this.commandInterpreter.processAPDU(apdu); 124 125 var rapdu = apdu.getResponseAPDU(); 126 print("Response APDU: " + rapdu); 127 return rapdu; 128 } 129 130 131 132 /** 133 * Respond to reset request 134 * 135 * @param {Number} type reset type (One of Card.RESET_COLD or Card.RESET.WARM) 136 * @type ByteString 137 * @return answer to reset 138 */ 139 EMVSimulator.prototype.reset = function(type) { 140 print("Reset type: " + type); 141 142 this.initialize(); 143 144 var atr = new ByteString("3B600000", HEX); 145 return atr; 146 } 147 148 149 150 /** 151 * Create new simulation and register with existing or newly created adapter singleton. 152 * 153 */ 154 EMVSimulator.newInstance = function() { 155 var sim = new EMVSimulator(); 156 157 if (typeof(CARDSIM) == "undefined") { 158 var adapter = new CardSimulationAdapter("JCOPSimulation", "8050"); 159 adapter.setSimulationObject(sim); 160 adapter.start(); 161 CARDSIM = adapter; 162 print("Simulation running..."); 163 } else { 164 CARDSIM.setSimulationObject(sim); 165 print("Simulation replaced..."); 166 } 167 } 168 169 170 171 EMVSimulator.newInstance(); 172