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