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