      1 /**
      2  *  ---------
      3  * |.##> <##.|  Open Smart Card Development Platform (www.openscdp.org)
      4  * |#       #|
      5  * |#       #|  Copyright (c) 1999-2018 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 Implementation of a ISO 7816-4 file system simulation
     25  */
     26
     27
     28
     29 /**
     30  * Create a File Control Parameter containing information about a file system node
     31  *
     32  * @class Class storing File Control Parameter for a file system node
     33  * @constructor
     34  */
     35 function FCP() {
     36 }
     37
     38 exports.FCP = FCP;
     39
     40
     41 /** File type for DF */
     42 FCP.DEDICATEDFILE = 0x38;
     43
     44 /** File type for transparent EF */
     45 FCP.TRANSPARENT   = 0x01;
     46
     47 /** File type for record oriented EF with fixed record size */
     48 FCP.LINEARFIXED   = 0x02;
     49
     50 /** File type for record oriented EF with variable record size */
     51 FCP.LINEARVARIABLE   = 0x04;
     52
     53
     54 /**
     55  * Convert an integer value into an two byte ByteString
     56  *
     57  * @param {Number} val the value
     58  * @type ByteString
     59  * @return the 2 byte encoded value MSB||LSB
     60  */
     61 FCP.short2bytestring = function(val) {
     62 	var bb = new ByteBuffer();
     63 	bb.append(val >> 8);
     64 	bb.append(val & 0xFF);
     65 	return(bb.toByteString());
     66 }
     67
     68
     69
     70 /**
     71  * Construct a new FCP object from parameters.
     72  *
     73  * <p>This function should never be called directly. Use newTransparentDF(), newDF() or newLinearEF() instead.</p>
     74  *
     75  * @param {String|ByteString} fid the file identifier (2 Bytes)
     76  * @param {Number} sfi the short file identifier or -1 or 0 if not defined
     77  * @param {Number} type the file type, one of FCP.DEDICATEDFILE, FCP.TRANSPARENT or FCP.LINEAR*
     78  * @param {Boolean} shareable true, if file may be shared between logical channels
     79  * @param {Boolean} internal true, if file is internal only and not externally selectable
     80  * @param {ByteString} supl supplemental information
     81  * @type FCP
     82  * @return the newly constructed FCP object
     83  */
     84 FCP.newFCP = function(fid, sfi, type, shareable, internal, supl) {
     85 	var fcp = new FCP();
     86
     87 	if (fid != null) {
     88 		if (typeof(fid) == "string") {
     89 			if (fid.length != 4) {
     90 				throw new GPError("FCP", GPError.INVALID_DATA, 0, "File Identifier must be 2 bytes");
     91 			}
     92 			fcp.fid = new ByteString(fid, HEX);
     93 		} else if (fid instanceof ByteString) {
     94 			if (fid.length != 2) {
     95 				throw new GPError("FCP", GPError.INVALID_DATA, 0, "File Identifier must be 2 bytes");
     96 			}
     97 			fcp.fid = fid;
     98 		} else {
     99 			throw new GPError("FCP", GPError.INVALID_TYPE, 0, "Argument must be of type String or ByteString");
    100 		}
    101 	}
    102
    103 	if (typeof(sfi) != "number") {
    104 		throw new GPError("FCP", GPError.INVALID_TYPE, 1, "Argument must be of type Number");
    105 	}
    106 	if ((sfi >= -1) && (sfi <= 30)) {
    107 		if (sfi > 0) {
    108 			fcp.sfi = sfi;
    109 		}
    110 	} else {
    111 		throw new GPError("FCP", GPError.INVALID_DATA, 1, "SFI must be in the range 1 to 30 or 0 if not defined");
    112 	}
    113
    114 	if (typeof(type) != "number") {
    115 		throw new GPError("FCP", GPError.INVALID_TYPE, 2, "Argument must be of type Number");
    116 	}
    117 	fcp.type = type;
    118
    119 	if (typeof(shareable) != "boolean") {
    120 		throw new GPError("FCP", GPError.INVALID_TYPE, 3, "Argument must be of type Boolean");
    121 	}
    122 	fcp.shareable = shareable;
    123
    124 	if (typeof(internal) != "boolean") {
    125 		throw new GPError("FCP", GPError.INVALID_TYPE, 4, "Argument must be of type Boolean");
    126 	}
    127 	fcp.internal = internal;
    128
    129 	fcp.supl = supl;
    130 	return fcp;
    131 }
    132
    133
    134
    135 /**
    136  * Construct a new FCP object for an EF of type transparent.
    137  *
    138  * @param {String|ByteString} fid the file identifier (2 Bytes)
    139  * @param {Number} sfi the short file identifier or -1 or 0 if not defined
    140  * @param {Number} size the file size
    141  * @param {ByteString} supl supplemental information
    142  * @type FCP
    143  * @return the newly constructed FCP object
    144  */
    145 FCP.newTransparentEF = function(fid, sfi, size, supl) {
    146 	if (typeof(size) != "number") {
    147 		throw new GPError("FCP", GPError.INVALID_TYPE, 2, "Argument size must be of type Number");
    148 	}
    149
    150 	var fcp = FCP.newFCP(fid, sfi, FCP.TRANSPARENT, false, false, supl);
    151
    152 	fcp.size = size;
    153 	return fcp;
    154 }
    155
    156
    157
    158 /**
    159  * Construct a new FCP object for a DF.
    160  *
    161  * @param {String|ByteString} fid the file identifier (2 Bytes)
    162  * @param {ByteString} aid the DF's application identifier (DFName)
    163  * @param {ByteString} supl supplemental information
    164  * @type FCP
    165  * @return the newly constructed FCP object
    166  */
    167 FCP.newDF = function(fid, aid, supl) {
    168 	var fcp = FCP.newFCP(fid, -1, FCP.DEDICATEDFILE, false, false, supl);
    169
    170 	if (aid != null) {
    171 		if ((typeof(aid) != "object") && !(aid instanceof(ByteString))) {
    172 			throw new GPError("FCP", GPError.INVALID_TYPE, 2, "Argument size must be of type Number");
    173 		}
    174 		fcp.aid = aid;
    175 	}
    176
    177 	return fcp;
    178 }
    179
    180
    181
    182 /**
    183  * Construct a new FCP object for an EF of type linear.
    184  *
    185  * @param {String|ByteString} fid the file identifier (2 Bytes)
    186  * @param {Number} sfi the short file identifier or -1 or 0 if not defined
    187  * @param {Number} type the file type, one of FCP.LINEARFIXED or FCP.LINEARVARIABLE
    188  * @param {Number} recno the maximum number of records
    189  * @param {Number} recsize the maximum or fixed record size
    190  * @param {ByteString} supl supplemental information
    191  * @type FCP
    192  * @return the newly constructed FCP object
    193  */
    194 FCP.newLinearEF = function(fid, sfi, type, recno, recsize, supl) {
    195 	if (typeof(recsize) != "number") {
    196 		throw new GPError("FCP", GPError.INVALID_TYPE, 3, "Argument recsize must be of type Number");
    197 	}
    198 	if (typeof(recno) != "number") {
    199 		throw new GPError("FCP", GPError.INVALID_TYPE, 4, "Argument recno must be of type Number");
    200 	}
    201
    202 	var fcp = FCP.newFCP(fid, sfi, type, false, false, supl);
    203 	return fcp;
    204 }
    205
    206
    207
    208 /**
    209  * Returns the File Identifier (FID)
    210  *
    211  * @type ByteString
    212  * @return the FID
    213  */
    214 FCP.prototype.getFID = function() {
    215 	return this.fid;
    216 }
    217
    218
    219
    220 /**
    221  * Returns the Application Identifier (AID)
    222  *
    223  * @type ByteString
    224  * @return the AID
    225  */
    226 FCP.prototype.getAID = function() {
    227 	return this.aid;
    228 }
    229
    230
    231
    232 /**
    233  * Returns the Short File Identifier (SFI)
    234  *
    235  * @type Number
    236  * @return the SFI
    237  */
    238 FCP.prototype.getSFI = function() {
    239 	return this.sfi;
    240 }
    241
    242
    243
    244 /**
    245  * Returns the encoded FCP
    246  *
    247  * @type ByteString
    248  * @return the encoded FCP
    249  */
    250 FCP.prototype.getBytes = function() {
    251 	var fcp = new ASN1("fcp", 0x62);
    252
    253 	if (typeof(this.size) != "undefined") {
    254 		fcp.add(new ASN1("fileSizeTransparent", 0x80, FCP.short2bytestring(this.size)));
    255 	}
    256
    257 	var bb = new ByteBuffer();
    258 	bb.append(this.type);
    259
    260 	// ToDo: extra type bytes
    261
    262 	fcp.add(new ASN1("fileDescriptor", 0x82, bb.toByteString()));
    263
    264 	if (typeof(this.fid) != "undefined") {
    265 		fcp.add(new ASN1("fileIdentifier", 0x83, this.fid));
    266 	}
    267
    268 	if (typeof(this.aid) != "undefined") {
    269 		fcp.add(new ASN1("dFName", 0x84, this.aid));
    270 	}
    271
    272 	if (typeof(this.sfi) != "undefined") {
    273 		var bb = new ByteBuffer();
    274 		bb.append(this.sfi << 3);
    275 		fcp.add(new ASN1("shortFileIdentifier", 0x88, bb.toByteString()));
    276 	}
    277
    278 	return(fcp.getBytes());
    279 }
    280
    281
    282
    283 /**
    284  * Returns the FCI
    285  *
    286  * @type ASN1
    287  * @return the FCI
    288  */
    289 FCP.prototype.getFCI = function() {
    290 	var fci = new ASN1("fci", 0x6F);
    291
    292 	if (typeof(this.aid) != "undefined") {
    293 		fci.add(new ASN1("dFName", 0x84, this.aid));
    294 	}
    295
    296 	if (this.supl) {
    297 		fci.add(new ASN1(this.supl));
    298 	}
    299
    300 	return(fci);
    301 }
    302
    303
    304
    305 /**
    306  * Return a human readible string for this object
    307  *
    308  * @type String
    309  * @return the string
    310  */
    311 FCP.prototype.toString = function() {
    312 	var str = "FCP(";
    313
    314 	for (var i in this) {
    315 		if (typeof(this[i]) != "function") {
    316 			str += i + "=" + this[i] + ",";
    317 		}
    318 	}
    319 	str += ")";
    320 	return str;
    321 }
    322