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 The class EMVView displays data stored on emv cards.
 25  */
 26 
 27 
 28 
 29 /**
 30  * EMVView class constructor
 31  *
 32  * @class This class implements a viewer for data stored on emv cards
 33  * @constructor
 34  * @requires EMV
 35  * @param {object} emv an instance of the EMV class
 36  */
 37 function EMVView(emv) {
 38 	this.emv = emv;
 39 }
 40 
 41 
 42 
 43 /**
 44  * Display the data elements into a human readable form
 45  */
 46 EMVView.prototype.displayDataElements = function(){
 47 	print("<----------------------------Display Data Elements-----------------------------");
 48 	print();
 49 	var cardDE = this.emv.getCardDataElements();
 50 	
 51 	for (var i = 0; i < cardDE.length; i++) {
 52 		if (cardDE[i] != undefined){
 53 			var tag = i; 
 54 			var value= cardDE[i];
 55 			this.decodeDataElement(tag, value);
 56 		}
 57 	}
 58 	print("------------------------------------------------------------------------------>\n");
 59 }
 60 
 61 
 62 
 63 /**
 64  * Decodes a template containing TLV data object into a human readable form
 65  *
 66  * @param {Number}  tag containing the tag name of TLV data objects
 67  * @param {ASN1} value the template containing TLV data objects
 68  */
 69 EMVView.prototype.decodeDataElement = function(tag, value) {
 70 	switch (tag) {
 71 		case 0x50:
 72 			print("Application Label: " + value.toString(HEX) + " - " + value.toString(ASCII));
 73 			print("\n");
 74 			break;
 75 		case 0x57:
 76 			var str = value.toString(HEX);
 77 			if (str.charAt(str.length-1) == 'F') {
 78 				str = str.substr(0, str.length-1);
 79 			}
 80 			
 81 			var separatorOfs = str.indexOf("D");
 82 			var pan = str.substr(0, separatorOfs);
 83 			var exDate = str.substr(separatorOfs+1, 4);
 84 			var serCode = str.substr(separatorOfs+5, 3);
 85 			var disData = str.substr(separatorOfs+8);
 86 			
 87 			print("Track 2 Equivalent Data (Magnetic Strip): ");
 88 			print("  Primary Account Number: " + pan);
 89 			print("  Expiration Date (YYMM): " + exDate);
 90 			print("  Service Code: " + serCode);
 91 			print("  Discretionary Data: " + disData);
 92 			print("\n");
 93 			break;
 94 		case 0x82:
 95 			print("Application Interchange Profile: " + value.toString(HEX))
 96 			this.decodeAIP(value);
 97 			print();
 98 			break;
 99 		case 0x8C:
100 			print("Card Risk Management Data Object List 1 (CDOL1): " + value.toString(HEX));
101 			this.decodeDataObjectList(value);
102 			print();
103 			break;
104 		case 0x8D: 
105 			print("Card Risk Management Data Object List 2 (CDOL2): " + value.toString(HEX));
106 			this.decodeDataObjectList(value);
107 			print();
108 			break;
109 		case 0x8E: 
110 			print("Cardholder Verification Method (CVM) List: " + value.toString(HEX));
111 			this.decodeCVM(value);
112 			print();
113 			break;
114 		case 0x94:
115 			print("Application File Locator: " + value.toString(HEX));
116 			this.decodeAFL(value);
117 			print();
118 			break;
119 		case 0x5F20:
120 			print("Cardholder Name : " + value.toString(ASCII));
121 			break;
122 		case 0x5F2D:
123 			print("Language Preference : " + value.toString(ASCII));
124 			break;
125 		case 0x5F30: 
126 			var string2 = value.toString(HEX);
127 			print("Service Code: " + string2.substr(1));
128 			print();
129 			break;
130 		case 0x9F07:
131 			print("Application Usage Control: " + value.toString(HEX));
132 			this.decodeAUC(value);
133 			print();
134 			break;
135 		case 0x9F0D:
136 			print("Issuer Action Code - Default: " + value.toString(HEX));
137 			this.decodeActionCode(value);
138 			print();
139 			break;
140 		case 0x9F0E:
141 			print("Issuer Action Code - Denial: " + value.toString(HEX));
142 			this.decodeActionCode(value);
143 			print();
144 			break;
145 		case 0x9F0F:
146 			print("Issuer Action Code - Online: " + value.toString(HEX));
147 			this.decodeActionCode(value);
148 			print();
149 			break;
150 		case 0x9F38: 
151 			print("Processing Options Data Object List (PDOL): " + value.toString(HEX));
152 			this.decodeDataObjectList(value);
153 			print();
154 			break;
155 		case 0x9F49: 
156 			print("Dynamic Data Authentication Data Object List (DDOL): " + value.toString(HEX));
157 			this.decodeDataObjectList(value);
158 			print();
159 			break;
160 		default:
161 			if(typeof(EMVView.DE[tag]) == "undefined"){
162 				print("Unknown Class: " + tag.toString(HEX));
163 					print()
164 				}
165 				else{
166 					print(EMVView.DE[tag] + value.toString(HEX));
167 					print();
168 				}
169 				break;				 
170 		}
171 }
172 
173 
174 
175 /**
176  * Decode a data object list into a human readable form
177  *
178  * <p>A data object list is a concatenation of data object identifiers, which each consist of
179  *    a tag and a length field.</p>
180  *
181  * @param {ByteString} dol the data object list
182  */
183 EMVView.prototype.decodeDataObjectList = function(dol) {
184 	while (dol.length > 0) {
185 		var b = dol.byteAt(0);
186 		if ((b & 0x1F) == 0x1F){
187 			var tag = dol.left(2).toUnsigned();
188 			var length = dol.byteAt(2);		
189 			var dol = dol.bytes(3);	//Remove Tag and Length Byte		
190 		}
191 		else {
192 			var tag = dol.left(1).toUnsigned();
193 			var length = dol.byteAt(1);
194 			var dol = dol.bytes(2);   //Remove Tag and Length Byte
195 		}
196 		print("  " + tag.toString(HEX) + " - " + length + " - " + DOL[tag]);
197 	}
198 }
199 
200 
201 
202 /**
203  * Decode an action code into a human readable form
204  *
205  * @param {ByteString} actionCode the Action Code
206  */
207 EMVView.prototype.decodeActionCode = function(actionCode) {
208 
209 	for (var j = 0; j < 5; j++) {
210 		var b = actionCode.byteAt(j);
211 		print("  Byte " + (j + 1) + ": ");
212 	
213 		for (var i = 0; i < 8; i++) {
214 			var bit = 0x80 >> i;
215 			if ((b & bit) == bit) {
216 				print("    " + TVR[j][i]);
217 			}
218 		}
219 	}
220 }
221 
222 
223 
224 /**
225  * Decode an application interchange profile into a human readable form
226  *
227  * @param {ByteString} aip the Application Interchange Profile
228  */
229 EMVView.prototype.decodeAIP = function(aip) {
230 	for (var j = 0; j < 2; j++) {
231 		var b = aip.byteAt(j);
232 		print("  Byte " + (j + 1) + ": ");
233 		
234 		for (var i = 0; i < 8; i++) {
235 			var bit = 0x80 >> i;
236 			if ((b & bit) == bit) {
237 				print("    " + AIP[j][i]);
238 			}
239 		}
240 	}
241 }
242 
243 
244 
245 /**
246  * Decode an application file locator into a human readable form
247  *
248  * @param {ByteString} afl the Application File Locator
249  */
250 EMVView.prototype.decodeAFL = function(afl) {
251 	for (var i = 0; i < afl.length;) {
252 		for (var j = 0; j < 4; j++) {
253 			var b = afl.byteAt(i);
254 			//print("Hex: " + b.toString(HEX));
255 			switch(j) {
256 				case 0:
257 					var b = b >> 3;
258 					print("  SFI: " + b);
259 					break;
260 				case 1:
261 					print("  First/Only Record Number: " + b);
262 					break;
263 				case 2:
264 					print("  Last Record Number: " + b);
265 					break;
266 				case 3:
267 					print("  Number of records involved in offline data authentication: " + b);
268 					print();
269 					break;
270 				default:
271 					print("  Default: " + j);
272 					break;
273 			}
274 			i++;
275 		}
276 	}
277 }
278 
279 
280 
281 /**
282  * Decode a Cardholder Verification Method List into a human readable form
283  *
284  * @param {ByteString} cvmlist the Cardholder Verification Method List
285  */
286 EMVView.prototype.decodeCVM = function(cvmlist) {
287 	for (var i = 8; i<cvmlist.length; i = i+2) {
288 		var b = cvmlist.byteAt(i);
289 		if((b&0x40)==0x40) {
290 			print("  Apply succeeding CV Rule if this CVM is unsucccessful");
291 		}
292 		else {
293 		print("  Fail cardholder verification if this CVM is unsuccessful");
294 		}
295 		print("    " + CVM[b & 0x3F]);
296 		print("  " + CVM2[cvmlist.byteAt(i+1)]);
297 		print();
298 	}
299 }
300 
301 
302 
303 /**
304  * Decode the Application Usage Control into a human readable form
305  *
306  * @param {ByteString} auc the Application Usage Control
307  */
308 EMVView.prototype.decodeAUC = function(auc) {
309 	var byte1 = auc.byteAt(0);
310 	var byte2 = auc.byteAt(1);
311 	print("  Byte 1:");
312 	for (var i = 0; i <=7; i++) {		
313 		if(byte1 & Math.pow(2,i) == Math.pow(2,i)) {
314 			print("    " + AUC1[Math.pow(2,i)]);
315 		}
316 	}
317 	print("  Byte 2:");
318 	for (var i = 0; i <=7; i++) {		
319 		if(byte2 & Math.pow(2,i) == Math.pow(2,i)) {
320 			print("    " + AUC2[Math.pow(2,i)]);
321 		}
322 	}
323 }
324 
325 
326 AUC1 = [];
327 AUC1[0x01] = "Valid at terminals other than ATMs";
328 AUC1[0x02] = "Valid at ATMs";
329 AUC1[0x04] = "Valid for international services";
330 AUC1[0x08] = "Valid for domestic services";
331 AUC1[0x10] = "Valid for international goods";
332 AUC1[0x20] = "Valid for domestic goods";
333 AUC1[0x40] = "Valid for international cash transactions";
334 AUC1[0x80] = "Valid for domestic cash transactions";
335 
336 AUC2 = [];
337 AUC2[0x01] = "RFU";
338 AUC2[0x02] = "RFU";
339 AUC2[0x04] = "RFU";
340 AUC2[0x08] = "RFU";
341 AUC2[0x10] = "RFU";
342 AUC2[0x20] = "RFU";
343 AUC2[0x40] = "International cashback allowed";
344 AUC2[0x80] = "Domestic cashback allowed";
345 
346 TVR = [
347 		[	"Offline data authentication was not performed (b8)",
348 			"SDA failed (b7)",
349 			"ICC data missing (b6)",
350 			"Card appears on terminal exception file (b5)",
351 			"DDA failed (b4)",
352 			"CDA failed (b3)",
353 			"RFU (b2)",
354 			"RFU (b1)"
355 		],
356 		[   "ICC and terminal have different application versions (b8)",
357 		  	"Expired application (b7)",
358 		  	"Application not yet effective (b6)",
359 		  	"Requested service not allowed for card product (b5)",
360 		  	"New card (b4)",
361 			"RFU (b3)",
362 		  	"RFU (b2)",
363 		  	"RFU (b1)",
364 		],
365 		[	"Cardholder verification was not successful (b8)",
366 			"Unrecognised CVM (b7)",
367 			"PIN Try Limit exceeded (b6)",
368 			"PIN entry required and PIN pad not present or not working (b5)",
369 			"PIN entry required, PIN pad present, but PIN was not entered (b4)",
370 			"Online PIN entered (b3)",
371 			"RFU (b2)",
372 			"RFU (b1)",
373 		],
374 		[   "Transaction exceeds floor limit (b8)",
375 			"Lower consecutive offline limit exceeded (b7)",
376 			"Upper consecutive offline limit (b6)",
377 			"Transaction selected randomly for online processing (b5)",
378 			"Merchant forced transaction online (b4)",
379 			"RFU (b3)",
380 			"RFU (b2)",
381 			"RFU (b1)",
382 		],
383 		[	"Default TDOL used (b8)",
384 			"Issuer authentication failed (b7)",
385 			"Script processing failed before final GENERATE AC (b6)",
386 			"Script processing failed after final GENERATE AC (b5)",
387 			"RFU (b4)",
388 			"RFU (b3)",
389 			"RFU (b2)",
390 			"RFU (b1)",
391 		],	
392 	];
393 
394 AIP = [
395 		[	"RFU (b8)",
396 			"SDA supported (b7)",
397 			"DDA supported (b6)",
398 			"Cardholder verification is supported (b5)",
399 			"Terminal risk management is to be performed (b4)",
400 			"Issuer authentication is supported (b3)",
401 			"RFU (b2)",
402 			"CDA supported (b1)",
403 		],
404 		[	"RFU (b8)",
405 			"RFU (b7)",
406 			"RFU (b6)",
407 			"RFU (b5)",
408 			"RFU (b4)",
409 			"RFU (b3)",
410 			"RFU (b2)",
411 			"RFU (b1)",
412 		],
413 	];
414 
415 CVM = [];
416 CVM[0] = "Fail CVM processing";
417 CVM[1] = "Plaintext PIN verification performed by ICC";
418 CVM[2] = "Enciphered PIN verified online";
419 CVM[3] = "Plaintext PIN verification performed by ICC and signature (paper)";
420 CVM[4] = "Enciphered PIN verification performed by ICC";
421 CVM[5] = "Enciphered Pin verification performed by ICC and signature (paper)";
422 CVM[0x1E] = "Signature (paper)";
423 CVM[0x1F] = "No CVM required";
424 
425 CVM2 = [];
426 CVM2[0] = "Always";
427 CVM2[1] = "If unattended cash";
428 CVM2[2] = "If not unattended cash and not manual cash and not purchase with cashback";
429 CVM2[3] = "If terminal supports the CVM";
430 CVM2[4] = "If manual cash";
431 CVM2[5] = "If purchase with cashback";
432 CVM2[6] = "If transaction is in the application currency and is under X value";
433 CVM2[7] = "If transaction is in the application currency and is over X value";
434 CVM2[8] = "If transaction is in the application currency and is under Y value";
435 CVM2[9] = "If transaction is in the application currency and is over Y value";
436 CVM2[10] = "RFU";
437 CVM2[11] = "Reserved for use by individual payment systems";
438 
439 
440 DOL = [];
441 DOL[0x5F2A] = "Transaction Currency Code";
442 DOL[0x8A] = "Authorisation Response Code";
443 DOL[0x91] = "Issuer Authentication Data";
444 DOL[0x95] = "Terminal Verification Results";
445 DOL[0x9A] = "Transaction Date";
446 DOL[0x9C] = "Transaction Type";
447 DOL[0x9F02] = "Authorised amount of the transaction (excluding adjustments)";
448 DOL[0x9F03] = "Secondary amount associated with the transaction representing a cashback amount";
449 DOL[0x9F1A] = "Terminal Country Code";
450 DOL[0x9F33] = "Terminal Capabilities";
451 DOL[0x9F34] = "Cardholder Verification Method (CVM) Results";
452 DOL[0x9F35] = "Terminal Type";
453 DOL[0x9F37] = "Unpredictable Number";
454 DOL[0x9F40] = "Additional Terminal Capabilities";
455 DOL[0x9F45] = "Data Authentication Code";
456 DOL[0x9F4C] = "ICC Dynamic Number";
457 
458 
459 EMVView.DE = [];
460 EMVView.DE[0x4F] = "Application Identifier (AID) - card: ";
461 EMVView.DE[0x5A] = "Application Primary Account Number (PAN): ";
462 EMVView.DE[0x5F2D] = "Language Preference: ";
463 
464 EMVView.DE[0x5F24] = "Application Expiration Date (YYMMDD): ";
465 EMVView.DE[0x5F25] = "Application Effective Date (YYMMDD): ";
466 EMVView.DE[0x5F28] = "Issuer Country Code: ";
467 EMVView.DE[0x5F34] = "Application Primary Account Number (PAN) Sequence Number: ";
468 EMVView.DE[0x87] = "Application Priority Indicator: ";
469 EMVView.DE[0x88] = "Short File Identifier (SFI): ";
470 EMVView.DE[0x8F] = "Certification Authority Public Key Index: ";
471 EMVView.DE[0x90] = "Issuer Public Key Certificate: ";
472 EMVView.DE[0x92] = "Issuer Public Key Remainder: ";
473 EMVView.DE[0x93] = "Signed Static Application Data: ";
474 EMVView.DE[0x9F07] = "Application Usage Control: ";
475 EMVView.DE[0x9F08] = "Application Version Number: ";
476 EMVView.DE[0x9F32] = "Issuer Public Key Exponent: ";
477 EMVView.DE[0x9F42] = "Application Currency Code: ";
478 EMVView.DE[0x9F44] = "Application Currency Exponent: ";
479 EMVView.DE[0x9F45] = "Data Authentication Code: ";
480 EMVView.DE[0x9F46] = "ICC Public Key Certificate: ";
481 EMVView.DE[0x9F47] = "ICC Public Key Exponent: ";
482 EMVView.DE[0x9F48] = "ICC Public Key Remainder: ";
483 EMVView.DE[0x9F4A] = "Static Data Authentication Tag List: ";
484 EMVView.DE[0x9F62] = "Track 1 Bit Map for CVC3 (Paypass): ";
485 EMVView.DE[0x9F63] = "Track 1 Bit Map for UN and ATC (Paypass): ";
486 EMVView.DE[0x9F64] = "Track 1 Number of ATC Digits (Paypass): ";
487 EMVView.DE[0x9F65] = "Track 2 Bit Map for CVC3 (Paypass): ";
488 EMVView.DE[0x9F66] = "Track 2 Bit Map for UN and ATC (Paypass): ";
489 EMVView.DE[0x9F67] = "Track 2 Number of ATC Digits (Paypass): ";
490 EMVView.DE[0x9F68] = "Mag Stripe CVM List (Paypass): ";
491 EMVView.DE[0x9F6B] = "Track 2 Data (Paypass): ";
492 EMVView.DE[0x9F6C] = "Mag Stripe Application Version Number (Card) (Paypass): ";
493 EMVView.DE[0x9F1F] = "Track 1 Discretionary Data: ";
494 EMVView.DE[0x9F6E] = "Third Party Data: ";
495 EMVView.DE[0x56] = "Track 1 Data: ";
496