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 Access controller for eID card 25 */ 26 27 load("../cardsim/accesscontroller.js"); 28 29 30 31 /** 32 * Create an access controller for the Master File 33 * @Class Class implementing an access controller for the Master File 34 * @constructor 35 */ 36 function MFAccessController() { 37 AccessController.call(this); 38 this.name = "MFAccessController"; 39 } 40 MFAccessController.prototype = new AccessController(); 41 MFAccessController.constructor = MFAccessController; 42 43 44 /** 45 * Check if read access to file system node is allowed 46 * 47 * @param {eIDCommandInterpreter} ci the command interpreter 48 * @param {APDU} apdu the APDU used to access the object 49 * @param {FSNode} node the file system object 50 * @type boolean 51 * @return true if access is allowed 52 */ 53 MFAccessController.prototype.checkFileReadAccess = function(ci, apdu, node) { 54 var fid = node.getFCP().fid.toUnsigned(); 55 if ((fid == 0x011C) || (fid == 0x2F01)) { 56 return true; 57 } 58 59 if (!apdu.isSecureMessaging()) { 60 GPSystem.trace("Read access not allowed without secure messaging"); 61 return false; 62 } 63 64 if (!ci.isAuthenticatedTerminal()) { 65 GPSystem.trace("Must have passed terminal authentication"); 66 return false; 67 } 68 69 if (fid == 0x011b) { // EF.ChipSecurity only readable if priviledged terminal right is granted 70 return this.checkRight(ci, apdu, 3); 71 } 72 return true; 73 } 74 75 76 77 /** 78 * Check if access to special function is allowed 79 * 80 * @param {eIDCommandInterpreter} ci the command interpreter 81 * @param {APDU} apdu the APDU used to access the object 82 * @type boolean 83 * @return true if access is allowed 84 */ 85 MFAccessController.prototype.checkRight = function(ci, apdu, bit) { 86 if (!apdu.isSecureMessaging()) { 87 GPSystem.trace("Special functions can only be performed with secure messaging"); 88 return false; 89 } 90 91 if (!ci.isAuthenticatedTerminal()) { 92 GPSystem.trace("Must have passed terminal authentication"); 93 return false; 94 } 95 96 // Other roles than id-AT have no access 97 if (!ci.getTerminalRole().equals(new ByteString("id-AT", OID))) { 98 GPSystem.trace("No access to roles other than id-AT"); 99 return false; 100 } 101 102 // The integer value must not excced 2^32, so we only take the first 4 byte of the CHAT 103 var mask = ByteString.valueOf(1 << bit, 5); 104 print("EffRights:" + ci.effectiveRights); 105 print("ReqRights:" + mask); 106 print(mask.and(ci.effectiveRights)); 107 return ci.effectiveRights.and(mask).right(4).toUnsigned() > 0; 108 } 109 110 111 112 /** 113 * Create an access controller for the ePass application 114 * @Class Class implementing an access controller for the ePass application 115 * @constructor 116 */ 117 function ePassAccessController() { 118 AccessController.call(this); 119 this.name = "ePassAccessController"; 120 } 121 ePassAccessController.prototype = new AccessController(); 122 ePassAccessController.constructor = ePassAccessController; 123 124 125 126 /** 127 * Check if read access to file system node is allowed 128 * 129 * @param {eIDCommandInterpreter} ci the command interpreter 130 * @param {APDU} apdu the APDU used to access the object 131 * @param {FSNode} node the file system object 132 * @type boolean 133 * @return true if access is allowed 134 */ 135 ePassAccessController.prototype.checkFileReadAccess = function(ci, apdu, node) { 136 if (!apdu.isSecureMessaging()) { 137 GPSystem.trace("Read access not allowed without secure messaging"); 138 return false; 139 } 140 141 // A secure channel with id-AT or id-ST does not qualify to read DF.ePass 142 if (ci.isAuthenticatedTerminal()) { 143 if (!ci.getTerminalRole().equals(new ByteString("id-IS", OID))) { 144 GPSystem.trace("No access to roles other than id-IS"); 145 return false; 146 } 147 } 148 149 var fid = node.getFCP().fid.toUnsigned(); 150 if ((fid != 0x0103) && (fid != 0x0104)) { 151 return true; 152 } 153 154 if (!ci.isAuthenticatedTerminal()) { 155 GPSystem.trace("Must have passed terminal authentication"); 156 return false; 157 } 158 159 var mask = ByteString.valueOf(0x01 << ((fid & 0xFF) - 3), 1); 160 print("EffRights:" + ci.effectiveRights); 161 print("ReqRights:" + mask); 162 print(mask.and(ci.effectiveRights)); 163 return ci.effectiveRights.and(mask).toUnsigned() > 0; 164 } 165 166 167 168 /** 169 * Check if access to special function is allowed 170 * 171 * @param {eIDCommandInterpreter} ci the command interpreter 172 * @param {APDU} apdu the APDU used to access the object 173 * @type boolean 174 * @return true if access is allowed 175 */ 176 ePassAccessController.prototype.checkRight = function(ci, apdu, bit) { 177 return false; 178 } 179 180 181 182 /** 183 * Check if command is allowed 184 * 185 * @param {APDU} apdu the APDU to check 186 * @type boolean 187 * @return true if access is allowed 188 */ 189 ePassAccessController.prototype.checkCommandAccess = function(ci, apdu) { 190 if ((apdu.getINS() == 0xA4) && (apdu.getP1() != 0x04)) { 191 return apdu.isSecureMessaging(); 192 } 193 return true; 194 } 195 196 197 198 /** 199 * Create an access controller for the eID application 200 * @Class Class implementing an access controller for the eID application 201 * @constructor 202 */ 203 function eIDAccessController() { 204 AccessController.call(this); 205 this.name = "eIDAccessController"; 206 } 207 eIDAccessController.prototype = new AccessController(); 208 eIDAccessController.constructor = eIDAccessController; 209 210 211 212 /** 213 * Check basic access conditions for eID application 214 * 215 * @param {eIDCommandInterpreter} ci the command interpreter 216 * @param {APDU} apdu the APDU used to access the object 217 * @type boolean 218 * @return true if access is allowed based on basic checks 219 */ 220 eIDAccessController.prototype.checkBasicAccess = function(ci, apdu) { 221 if (!apdu.isSecureMessaging()) { 222 GPSystem.trace("Read access not allowed without secure messaging"); 223 return false; 224 } 225 226 if (!ci.isAuthenticatedTerminal()) { 227 GPSystem.trace("No access to unauthenticated terminal"); 228 false; 229 } 230 231 // Access to eID functions only allowed with eID PIN or if CAN allowed is granted and PACE(CAN) was performed 232 if (ci.paceao.id == 3) { 233 return true; 234 } 235 236 if (!ci.getTerminalRole().equals(new ByteString("id-AT", OID))) { 237 return true; 238 } 239 240 // CAN allowed checking only if id-AT terminal 241 if (!this.checkBit(ci, apdu, 4)) { 242 print("CAN allowed right not granted"); 243 return false; 244 } 245 246 if (ci.paceao.id != 2) { 247 print("CAN allowed only effective for PACE with CAN"); 248 return false; 249 } 250 return true; 251 } 252 253 254 /** 255 * Check if read access to file system node is allowed 256 * 257 * @param {eIDCommandInterpreter} ci the command interpreter 258 * @param {APDU} apdu the APDU used to access the object 259 * @param {FSNode} node the file system object 260 * @type boolean 261 * @return true if access is allowed 262 */ 263 eIDAccessController.prototype.checkFileReadAccess = function(ci, apdu, node) { 264 if (!this.checkBasicAccess(ci, apdu)) { 265 return false; 266 } 267 268 // Check valid range 0x0101 - 0x0115 269 var fid = node.getFCP().fid; 270 if ((fid.byteAt(0) != 0x01) || (fid.byteAt(1) < 0x01) || (fid.byteAt(1) > 0x15)) { 271 GPSystem.trace("FID " + fid + " out of defined range"); 272 return false; 273 } 274 275 // IS have generell access if GAP with CHAT was used 276 if ((ci.getTerminalRole().equals(new ByteString("id-IS", OID)) && ci.chat)) { 277 return true; 278 } 279 280 // Other roles than id-AT have no access 281 if (!ci.getTerminalRole().equals(new ByteString("id-AT", OID))) { 282 GPSystem.trace("No access to roles other than id-AT"); 283 return false; 284 } 285 286 var mask = ByteString.valueOf(0x0100 << (fid.byteAt(1) - 1), 5); 287 print("EffRights:" + ci.effectiveRights); 288 print("ReqRights:" + mask); 289 print(mask.and(ci.effectiveRights)); 290 return ci.effectiveRights.and(mask).toUnsigned() > 0; 291 } 292 293 294 295 /** 296 * Check if write access to file system node is allowed 297 * 298 * @param {eIDCommandInterpreter} ci the command interpreter 299 * @param {APDU} apdu the APDU used to access the object 300 * @param {FSNode} node the file system object 301 * @type boolean 302 * @return true if access is allowed 303 */ 304 eIDAccessController.prototype.checkFileWriteAccess = function(ci, apdu, node) { 305 if (!this.checkBasicAccess(ci, apdu)) { 306 return false; 307 } 308 309 // Check valid range 0x0101 - 0x0115 310 var fid = node.getFCP().fid; 311 if ((fid.byteAt(0) != 0x01) || (fid.byteAt(1) < 0x11) || (fid.byteAt(1) > 0x15)) { 312 GPSystem.trace("FID out of defined range"); 313 return false; 314 } 315 316 // Other roles than id-AT have no access 317 if (!ci.getTerminalRole().equals(new ByteString("id-AT", OID))) { 318 GPSystem.trace("No access to roles other than id-AT"); 319 return false; 320 } 321 322 // The integer value must not excced 2^32, so we only take the first 4 byte of the CHAT 323 var mask = ByteString.valueOf(0x20000000 >> (fid.byteAt(1) - 17), 4); 324 mask = mask.concat(new ByteString.valueOf(0, 1)); 325 print("EffRights:" + ci.effectiveRights); 326 print("ReqRights:" + mask); 327 print(mask.and(ci.effectiveRights)); 328 return ci.effectiveRights.and(mask).left(4).toUnsigned() > 0; 329 } 330 331 332 333 /** 334 * Check if access to special function is allowed 335 * 336 * @param {eIDCommandInterpreter} ci the command interpreter 337 * @param {APDU} apdu the APDU used to access the object 338 * @type boolean 339 * @return true if access is allowed 340 */ 341 eIDAccessController.prototype.checkBit = function(ci, apdu, bit) { 342 // The integer value must not excced 2^32, so we only take the first 4 byte of the CHAT 343 var mask = ByteString.valueOf(1 << bit, 5); 344 print("EffRights:" + ci.effectiveRights); 345 print("ReqRights:" + mask); 346 print(mask.and(ci.effectiveRights)); 347 return ci.effectiveRights.and(mask).right(4).toUnsigned() > 0; 348 } 349 350 351 352 /** 353 * Check if access to special function is allowed 354 * 355 * @param {eIDCommandInterpreter} ci the command interpreter 356 * @param {APDU} apdu the APDU used to access the object 357 * @type boolean 358 * @return true if access is allowed 359 */ 360 eIDAccessController.prototype.checkRight = function(ci, apdu, bit) { 361 if (!this.checkBasicAccess(ci, apdu)) { 362 return false; 363 } 364 365 // Other roles than id-AT have no access 366 if (!ci.getTerminalRole().equals(new ByteString("id-AT", OID))) { 367 GPSystem.trace("No access to roles other than id-AT"); 368 return false; 369 } 370 371 return this.checkBit(ci, apdu, bit); 372 } 373 374 375 376 /** 377 * Create an access controller for the eSign application 378 * @Class Class implementing an access controller for the eSign application 379 * @constructor 380 */ 381 function eSignAccessController() { 382 AccessController.call(this); 383 this.name = "eSignAccessController"; 384 } 385 eSignAccessController.prototype = new AccessController(); 386 eSignAccessController.constructor = eSignAccessController; 387 388 389 390 391 /** 392 * Check if read access to file system node is allowed 393 * 394 * @param {eIDCommandInterpreter} ci the command interpreter 395 * @param {APDU} apdu the APDU used to access the object 396 * @param {FSNode} node the file system object 397 * @type boolean 398 * @return true if access is allowed 399 */ 400 eSignAccessController.prototype.checkFileReadAccess = function(ci, apdu, node) { 401 if (!apdu.isSecureMessaging()) { 402 GPSystem.trace("Read access not allowed without secure messaging"); 403 return false; 404 } 405 406 if (!ci.isAuthenticatedTerminal()) { 407 GPSystem.trace("No access to unauthenticated terminal"); 408 return false; 409 } 410 411 // ST have generell access 412 if (ci.getTerminalRole().equals(new ByteString("id-ST", OID))) { 413 return true; 414 } 415 416 // AT have access may have right to install certificate 417 if (ci.getTerminalRole().equals(new ByteString("id-AT", OID))) { 418 if (ci.effectiveRights.right(1).toUnsigned() & 0xC0) { 419 return true; 420 } 421 GPSystem.trace("AT terminal has no right to install certificate"); 422 } 423 424 return false; 425 } 426 427 428 429 /** 430 * Check if write access to file system node is allowed 431 * 432 * @param {eIDCommandInterpreter} ci the command interpreter 433 * @param {APDU} apdu the APDU used to access the object 434 * @param {FSNode} node the file system object 435 * @type boolean 436 * @return true if access is allowed 437 */ 438 eSignAccessController.prototype.checkFileWriteAccess = function(ci, apdu, node) { 439 if (!apdu.isSecureMessaging()) { 440 GPSystem.trace("Write access not allowed without secure messaging"); 441 return false; 442 } 443 444 if (!ci.isAuthenticatedTerminal()) { 445 GPSystem.trace("No access to unauthenticated terminal"); 446 false; 447 } 448 449 // AT have access may have right to install certificate 450 if (ci.getTerminalRole().equals(new ByteString("id-AT", OID))) { 451 if (ci.effectiveRights.right(1).toUnsigned() & 0xC0) { 452 return true; 453 } 454 GPSystem.trace("AT terminal has no right to install certificate"); 455 } 456 457 return false; 458 } 459 460 461 462 /** 463 * Check if access to special function is allowed 464 * 465 * @param {eIDCommandInterpreter} ci the command interpreter 466 * @param {APDU} apdu the APDU used to access the object 467 * @type boolean 468 * @return true if access is allowed 469 */ 470 eSignAccessController.prototype.checkRight = function(ci, apdu, bit) { 471 if (!apdu.isSecureMessaging()) { 472 GPSystem.trace("Special functions can only be performed with secure messaging"); 473 return false; 474 } 475 476 if (!ci.isAuthenticatedTerminal()) { 477 GPSystem.trace("No access to unauthenticated terminal"); 478 false; 479 } 480 481 return true; 482 } 483