1 /** 2 * --------- 3 * |.##> <##.| SmartCard-HSM Support Scripts 4 * |# #| 5 * |# #| Copyright (c) 2011-2012 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 SmartCard-HSM Card Service 25 */ 26 27 // Imports 28 var CVC = require("scsh/eac/CVC").CVC; 29 var PublicKeyReference = require("scsh/eac/PublicKeyReference").PublicKeyReference; 30 var ChipAuthentication = require("scsh/eac/ChipAuthentication").ChipAuthentication; 31 var PKCS1 = require("scsh/pkcs/PKCS1").PKCS1; 32 var DKEK = require("scsh/sc-hsm/DKEK").DKEK; 33 34 35 36 /** 37 * Create a SmartCard-HSM access object 38 * @class Class implementing support for SmartCard-HSM access 39 * @constructor 40 * @param {Card} card the card object 41 */ 42 function SmartCardHSM(card) { 43 this.card = card; 44 45 this.maxCAPDU = 1232; // APDU buffer limit in JCOP 3 46 this.maxRAPDU = 1232; 47 this.limitedAPDUTransport = false; // The APDU transport does not support the full response side 48 49 if (card.readerName.indexOf("Secure Flash Card") == 0) { 50 this.maxCAPDU = 478; 51 this.maxRAPDU = 506; 52 this.limitedAPDUTransport = true; 53 } else if (card.readerName.indexOf("REINER SCT cyberJack") == 0) { 54 this.maxCAPDU = 1014; 55 this.maxRAPDU = 1014; 56 this.limitedAPDUTransport = true; 57 } else if (card.readerName.indexOf("ACS APG8201") == 0) { 58 this.maxCAPDU = 1141; 59 this.maxRAPDU = 1141; 60 this.limitedAPDUTransport = true; 61 } else if (card.readerName.indexOf("Gemalto IDBridge") == 0) { 62 this.maxCAPDU = 262; 63 this.maxRAPDU = 499; 64 this.limitedAPDUTransport = true; 65 } 66 67 if (typeof(this.card.maxReaderCAPDU) != "undefined") { 68 if (this.card.maxReaderCAPDU < this.maxCAPDU) { 69 this.maxCAPDU = this.card.maxReaderCAPDU; 70 this.limitedAPDUTransport = true; 71 } 72 } 73 74 if (typeof(this.card.maxReaderRAPDU) != "undefined") { 75 if (this.card.maxReaderRAPDU < this.maxRAPDU) { 76 this.maxRAPDU = this.card.maxReaderRAPDU; 77 this.limitedAPDUTransport = true; 78 } 79 } 80 81 // 9 Byte CLA|INS|P1|P2|LcEx||LeEx 82 // 19 Byte SM overhead (Tag 85, 3 byte length, 1 byte padding indicator, tag 97 02 <Le> and tag 8E 08 <mac> 83 // 1 byte required for padding 84 this.maxCData = Math.floor((this.maxCAPDU - 9 - 19) / 16) * 16 - 1; 85 // print("maxCData=" + this.maxCData); 86 87 // 19 Byte SM overhead (Tag 85, 3 byte length, 1 byte padding indicator, tag 99 02 SW1SW2 and tag 8E 08 <mac> 88 // 2 byte SW1/SW2 89 // 1 byte required for padding 90 this.maxRData = Math.floor((this.maxRAPDU - 18 - 2) / 16) * 16 - 1; 91 // print("maxRData=" + this.maxRData); 92 93 this.useExternalHashInECDSA = false; // Disable hashing in card if affected by bug #93 94 95 // Check if SmartCard-HSM is already selected and authenticated 96 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x20, 0x00, 0x81, 0); 97 98 if (this.card.SW != 0x9000) { 99 this.logout(); // Select application 100 } 101 102 this.namemap = []; 103 this.idmap = []; 104 } 105 106 exports.SmartCardHSM = SmartCardHSM; 107 108 109 SmartCardHSM.C_DevAut = new ByteString("2F02", HEX); 110 SmartCardHSM.EF_TokenInfo = new ByteString("2F03", HEX); 111 SmartCardHSM.EF_StaticTokenInfo = new ByteString("CB00", HEX); 112 113 SmartCardHSM.PrK_DevAut = 0; 114 SmartCardHSM.PIN_User = 0x81; 115 116 SmartCardHSM.PRKDPREFIX = 0xC4; 117 SmartCardHSM.CERTDPREFIX = 0xC8; 118 SmartCardHSM.KEYMETAPREFIX = 0xCB; // Changed in V2.3 119 SmartCardHSM.READONLYDATAPREFIX = 0xCB; // Starting with V2.3 120 SmartCardHSM.KEYPREFIX = 0xCC; 121 SmartCardHSM.CONFIDENTIALDATAPREFIX = 0xCD; 122 SmartCardHSM.EECERTIFICATEPREFIX = 0xCE; 123 SmartCardHSM.CACERTIFICATEPREFIX = 0xCA; 124 125 SmartCardHSM.ALGORITHMS = []; 126 127 // Symmetric 128 SmartCardHSM.ALG_CBC_ENC = 0x10; 129 SmartCardHSM.ALG_CBC_DEC = 0x11; 130 SmartCardHSM.ALG_CMAC = 0x18; 131 132 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_CBC_ENC] = "CBC_ENC"; 133 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_CBC_DEC] = "CBC_DEC"; 134 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_CMAC] = "CMAC"; 135 136 137 // RSA Block 138 SmartCardHSM.ALG_RSA_SIGN_RAW = 0x20; 139 SmartCardHSM.ALG_RSA_DECRYPT_RAW = 0x21; 140 SmartCardHSM.ALG_RSA_DECRYPT_V15 = 0x22; 141 SmartCardHSM.ALG_RSA_DECRYPT_OAEP = 0x23; 142 143 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_SIGN_RAW] = "RSA_RAW"; 144 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_DECRYPT_RAW] = "RSA_DECRYPT_RAW"; 145 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_DECRYPT_V15] = "RSA_DECRYPT_V15"; 146 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_DECRYPT_OAEP] = "RSA_DECRYPT_OAEP"; 147 148 149 // RSA Sign with hash and PKCS#1 V1.5 150 SmartCardHSM.ALG_RSA_SIGN_V15_SHA1 = 0x31; 151 SmartCardHSM.ALG_RSA_SIGN_V15_SHA256 = 0x33; 152 SmartCardHSM.ALG_RSA_SIGN_V15_SHA512 = 0x35; 153 154 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_SIGN_V15_SHA1] = "RSA_V15_SHA1"; 155 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_SIGN_V15_SHA256] = "RSA_V15_SHA256"; 156 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_SIGN_V15_SHA512] = "RSA_V15_SHA512"; 157 158 159 // RSA Sign with hash and PSS 160 SmartCardHSM.ALG_RSA_SIGN_PSS = 0x40; 161 SmartCardHSM.ALG_RSA_SIGN_PSS_SHA1 = 0x41; 162 SmartCardHSM.ALG_RSA_SIGN_PSS_SHA256 = 0x43; 163 SmartCardHSM.ALG_RSA_SIGN_PSS_SHA512 = 0x45; 164 165 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_SIGN_PSS] = "RSA_PSS"; 166 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_SIGN_PSS_SHA1] = "RSA_PSS_SHA1"; 167 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_SIGN_PSS_SHA256] = "RSA_PSS_SHA256"; 168 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_SIGN_PSS_SHA512] = "RSA_PSS_SHA512"; 169 170 171 // ECDSA 172 SmartCardHSM.ALG_ECDSA = 0x70; 173 SmartCardHSM.ALG_ECDSA_SHA1 = 0x71; 174 SmartCardHSM.ALG_ECDSA_SHA224 = 0x72; 175 SmartCardHSM.ALG_ECDSA_SHA256 = 0x73; 176 SmartCardHSM.ALG_ECDSA_SHA384 = 0x74; 177 SmartCardHSM.ALG_ECDSA_SHA512 = 0x75; 178 179 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_ECDSA] = "ECDSA"; 180 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_ECDSA_SHA1] = "ECDSA_SHA1"; 181 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_ECDSA_SHA224] = "ECDSA_SHA224"; 182 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_ECDSA_SHA256] = "ECDSA_SHA256"; 183 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_ECDSA_SHA384] = "ECDSA_SHA384"; 184 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_ECDSA_SHA512] = "ECDSA_SHA512"; 185 186 187 // ECDH 188 SmartCardHSM.ALG_ECDH = 0x80; 189 SmartCardHSM.ALG_ECDHAutPuk = 0x83; 190 SmartCardHSM.ALG_ECDHXKEK = 0x84; 191 192 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_ECDH] = "ECDH"; 193 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_ECDHAutPuk] = "ECDH_AUTPUK"; 194 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_ECDHXKEK] = "ECDH_XKEK"; 195 196 197 // Wrap 198 SmartCardHSM.ALG_WRAP = 0x92; 199 SmartCardHSM.ALG_UNWRAP = 0x93; 200 SmartCardHSM.ALG_REPLACE = 0x94; 201 202 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_WRAP] = "WRAP"; 203 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_UNWRAP] = "UNWRAP"; 204 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_REPLACE] = "REPLACE"; 205 206 207 // Derive 208 SmartCardHSM.ALG_DERIVE_EC_KEY = 0x98; 209 SmartCardHSM.ALG_DERIVE_SP800_56C = 0x99; 210 211 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_DERIVE_EC_KEY] = "DERIVE_EC"; 212 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_DERIVE_SP800_56C] = "DERIVE_SP800_56C"; 213 214 215 SmartCardHSM.ALG_SIGN_DEFAULT = 0xA0; 216 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_SIGN_DEFAULT] = "SIGN_DEFAULT"; 217 218 219 // Key Generation 220 SmartCardHSM.ALG_GENERATE_AES128 = 0xB0; 221 SmartCardHSM.ALG_GENERATE_AES192 = 0xB1; 222 SmartCardHSM.ALG_GENERATE_AES256 = 0xB2; 223 224 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_GENERATE_AES128] = "GENERATE_AES128"; 225 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_GENERATE_AES192] = "GENERATE_AES192"; 226 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_GENERATE_AES256] = "GENERATE_AES256"; 227 228 229 SmartCardHSM.ALGOMAP = {}; 230 for (var i = 0; i < SmartCardHSM.ALGORITHMS.length; i++) { 231 var name = SmartCardHSM.ALGORITHMS[i]; 232 if (typeof(name) != "undefined") { 233 SmartCardHSM.ALGOMAP[name] = i; 234 } 235 } 236 237 238 SmartCardHSM.rootCerts = { 239 DESRCACC100001: new CVC(new ByteString("7F218201B47F4E82016C5F290100420E44455352434143433130303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A78641046D025A8026CDBA245F10DF1B72E9880FFF746DAB40A43A3D5C6BEBF27707C30F6DEA72430EE3287B0665C1EAA6EAA4FA26C46303001983F82BD1AA31E03DA0628701015F200E44455352434143433130303030317F4C10060B2B0601040181C31F0301015301C05F25060102010100095F24060302010100085F37409DBB382B1711D2BAACB0C623D40C6267D0B52BA455C01F56333DC9554810B9B2878DAF9EC3ADA19C7B065D780D6C9C3C2ECEDFD78DEB18AF40778ADF89E861CA", HEX)), 240 UTSRCACC100001: new CVC(new ByteString("7F218201B47F4E82016C5F290100420E55545352434143433130303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7864104A041FEB2FD116B2AD19CA6B7EACD71C9892F941BB88D67DCEEC92501F070011957E22122BA6C2CF5FF02936F482E35A6129CCBBA8E9383836D3106879C408EF08701015F200E55545352434143433130303030317F4C10060B2B0601040181C31F0301015301C05F25060102010100095F24060302010100085F3740914DD0FA00615C44048D1467435400423A4AD1BD37FD98D6DE84FD8037489582325C72956D4FDFABC6EDBA48184A754F37F1BE5142DD1C27D66569308CE19AAF", HEX)) 241 } 242 243 SmartCardHSM.devAutPuk = new Key(); 244 SmartCardHSM.devAutPuk.setType(Key.PUBLIC); 245 SmartCardHSM.devAutPuk.setComponent(Key.ECC_CURVE_OID, new ByteString("brainpoolP256r1", OID)); 246 SmartCardHSM.devAutPuk.setComponent(Key.ECC_QX, new ByteString("4C01EA36C5065FF47E8F0676A77CDCED6C8F745E6784F7807F5520124F81ED05", HEX)); 247 SmartCardHSM.devAutPuk.setComponent(Key.ECC_QY, new ByteString("4112DCE471CA003442830A10C75B31F9BFADD60628F47131628C7254AD8B956A", HEX)); 248 249 250 251 /** 252 * Remove Root Certificate of Development SRCA 253 * 254 * Always call this on a productive system 255 */ 256 SmartCardHSM.disableUTSRCA = function() { 257 delete SmartCardHSM.rootCerts.UTSRCACC100001; 258 } 259 260 261 262 /** 263 * Parse list of CVC in a binary blob 264 * 265 * @param {ByteString} a binary blob (e.g an EF) containing concatenated CVCs 266 * @type CVC[] 267 * @return the list of CVCs 268 */ 269 SmartCardHSM.parseCertificateList = function(bin) { 270 var a = new ASN1((new ASN1(0x30, bin)).getBytes()); 271 var list = []; 272 for (var i = 0; i < a.elements; i++) { 273 list.push(new CVC(a.get(i))); 274 } 275 return list; 276 } 277 278 279 280 /** 281 * Validate device certificate chain 282 * 283 * @param {Crypto} crypto the crypto provider to use 284 * @param {ByteString} devAutCert the device certificate chain read from EF.C_DevAut 285 * @type Key 286 * @return the device authentication public key 287 */ 288 SmartCardHSM.validateCertificateChain = function(crypto, devAutCert) { 289 // Device device certificate 290 var cvc = new CVC(devAutCert); 291 GPSystem.trace("Device Certificate : " + cvc); 292 293 if (cvc.getCAR().toString() == "DECA00001") { // CA used for development version up to 0.17 294 if (typeof(SmartCardHSM.rootCerts.UTSRCACC100001) == "undefined") { 295 GPSystem.trace("Device certificate DECA00001 disabled"); 296 return null; 297 } 298 if (!cvc.verifyWith(crypto, SmartCardHSM.devAutPuk)) { 299 GPSystem.trace("Device certificate verification failed for CAR=DECA00001"); 300 return null; 301 } 302 var path = "/" + cvc.getCAR().getHolder() + "/" + cvc.getCHR().getHolder(); 303 return { devicecert: cvc, publicKey:cvc.getPublicKey(), path:path }; 304 } 305 306 // Decode device issuer certificate 307 var len = cvc.getASN1().size; 308 var cvc = new CVC(devAutCert.left(len)); 309 var dica = new CVC(devAutCert.bytes(len)); 310 GPSystem.trace("Device Issuer CA : " + dica); 311 312 if (typeof(SmartCardHSM.rootCerts[dica.getCAR()]) == "undefined") { 313 GPSystem.trace("Unknown or disabled root CA " + dica.getCAR()); 314 return null; 315 } 316 317 // Determine root certificateSmartCardHSM.rootCerts[dica.getCAR()] 318 var srca = SmartCardHSM.rootCerts[dica.getCAR()]; 319 GPSystem.trace("SmartCard-HSM Root CA : " + srca); 320 321 // Validate chain 322 var srcapuk = srca.getPublicKey(); 323 var oid = srca.getPublicKeyOID(); 324 if (!dica.verifyWith(crypto, srcapuk, oid)) { 325 GPSystem.trace("DICA certificate not verified"); 326 return null; 327 } 328 329 var dicapuk = dica.getPublicKey(srcapuk); 330 if (!cvc.verifyWith(crypto, dicapuk, oid)) { 331 GPSystem.trace("Device certificate verification failed"); 332 return null; 333 } 334 335 var path = "/" + srca.getCHR().getHolder() + "/" + dica.getCHR().getHolder() + "/" + cvc.getCHR().getHolder(); 336 return { srca: srca, dica: dica, devicecert: cvc, publicKey:cvc.getPublicKey(srcapuk), path:path }; 337 } 338 339 340 341 /** 342 * Decode algorithm list and return string array with names 343 * 344 * @param {ByteString} list the algorithm list, e.g. as returned in the key meta data 345 * @type String[] 346 * @return the list of algorithm names 347 */ 348 SmartCardHSM.decodeAlgorithmList = function(list) { 349 var a = []; 350 for (var i = 0; i < list.length; i++) { 351 a.push(SmartCardHSM.ALGORITHMS[list.byteAt(i)]); 352 } 353 354 return a; 355 } 356 357 358 359 /** 360 * Parse and encode the algorithm list containing either algorithm ids or names 361 * 362 * @param {String | String[]} list the list of algorithms 363 * @type ByteString 364 * @return the algorithm list 365 */ 366 SmartCardHSM.encodeAlgorithmList = function(list) { 367 if (typeof(list) == "string") { 368 if (list.indexOf(".") != -1) { 369 list = list.split("."); 370 } else { 371 list = list.split(","); 372 } 373 } 374 375 var bb = new ByteBuffer(); 376 377 for (var i = 0; i < list.length; i++) { 378 var e = list[i].trim(); 379 var id = NaN; 380 if (e.length == 2) { 381 id = parseInt(e, 16); 382 } 383 if (isNaN(id)) { 384 var id = SmartCardHSM.ALGOMAP[e.toUpperCase()]; 385 if (typeof(id) == "undefined") { 386 print("Unknown keyword or number " + list[i]); 387 return null; 388 } 389 } 390 bb.append(id); 391 } 392 393 return bb.toByteString(); 394 } 395 396 397 398 /** 399 * Return a string describing the SmartCard-HSM Version 400 * 401 * @type String 402 * @return the version string 403 */ 404 SmartCardHSM.prototype.getVersionInfo = function() { 405 if (typeof(this.major) == "undefined") { 406 return "Version unknown"; 407 } 408 409 var str = "Version " + this.major + "." + this.minor; 410 411 if (typeof(this.platform) != "undefined") { 412 switch(this.platform) { 413 case 0: str += " on JCOP"; break; 414 case 1: str += " Demo on JCOP"; break; 415 case 2: str += " on JCOP 2.4.1r3"; break; 416 case 3: str += " on JCOP 2.4.2r3"; break; 417 case 4: str += " on JCOP 2.4.2r1"; break; 418 case 5: str += " on JCOP 3"; break; 419 case 6: str += " on JCOP 4"; break; 420 } 421 } 422 return str; 423 } 424 425 426 427 /** 428 * Return the native OCF SmartCardHSMCardService 429 * 430 * @type de.cardcontact.opencard.service.smartcardhsm.SmartCardHSMCardService 431 * @return the OCF SmartCardHSMCardService 432 */ 433 SmartCardHSM.prototype.getNativeCardService = function() { 434 if (this.nativeCardService) { 435 return this.nativeCardService; 436 } 437 this.nativeCardService = this.card.getCardService("de.cardcontact.opencard.service.smartcardhsm.SmartCardHSMCardService"); 438 439 return this.nativeCardService; 440 } 441 442 443 444 /** 445 * Validate device certificate chain 446 * 447 * @param {Crypto} crypto the crypto provider to use 448 * @type Key 449 * @return the device authentication public key 450 */ 451 SmartCardHSM.prototype.validateCertificateChain = function(crypto) { 452 // Read concatenation of both certificates 453 var devAutCert = this.readBinary(SmartCardHSM.C_DevAut); 454 var chain = SmartCardHSM.validateCertificateChain(crypto, devAutCert); 455 if (chain == null) { 456 return null; 457 } 458 return chain.publicKey; 459 } 460 461 462 463 /** 464 * Open a secure channel using device authentication 465 * 466 * @param {Crypto} crypto the crypto provider to use 467 * @param {Key} devAuthPK the device authentication public key 468 * @param {Number} Key.AES or Key.DES to request AES or DES secure messaging (Default probe) 469 * @type ISOSecureChannel 470 * @return the initialized secure channel 471 */ 472 SmartCardHSM.prototype.openSecureChannel = function(crypto, devAuthPK, smtype) { 473 474 var type; 475 476 if (smtype) { 477 type = smtype; 478 } else { 479 type = Key.AES; 480 } 481 482 if (type == Key.DES) { 483 var protocol = new ByteString("id-CA-ECDH-3DES-CBC-CBC", OID); 484 } else { 485 var protocol = new ByteString("id-CA-ECDH-AES-CBC-CMAC-128", OID); 486 } 487 488 // Try AES first and fallback to DES is not supported by card 489 490 var bb = new ByteBuffer(); 491 bb.append(new ASN1(0x80, protocol).getBytes()); 492 493 this.card.sendSecMsgApdu(Card.CPRO|Card.CENC|Card.RPRO, 0x00, 0x22, 0x41, 0xA4, bb.toByteString(), [0x9000, 0x6A80]); 494 495 if (this.card.SW == 0x6A80) { 496 if (smtype) { 497 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 3, "Requested secure messaging not supported"); 498 } 499 500 type = Key.DES; 501 502 var protocol = new ByteString("id-CA-ECDH-3DES-CBC-CBC", OID); 503 504 var bb = new ByteBuffer(); 505 bb.append(new ASN1(0x80, protocol).getBytes()); 506 507 this.card.sendSecMsgApdu(Card.CPRO|Card.CENC|Card.RPRO, 0x00, 0x22, 0x41, 0xA4, bb.toByteString(), [0x9000]); 508 } 509 510 var ca = new ChipAuthentication(crypto, protocol, devAuthPK); // For domain parameter 511 ca.noPadding = true; 512 ca.generateEphemeralCAKeyPair(); 513 514 var ephemeralPublicKeyIfd = ca.getEphemeralPublicKey(); 515 516 var dado = new ASN1(0x7C, new ASN1(0x80, ephemeralPublicKeyIfd)); 517 518 var dadobin = this.card.sendSecMsgApdu(Card.CPRO|Card.CENC|Card.RPRO|Card.RENC, 0x00, 0x86, 0x00, 0x00, dado.getBytes(), 0, [0x9000]); 519 520 // GPSystem.trace(dadobin); 521 522 var dado = new ASN1(dadobin); 523 assert(dado.tag == 0x7C); 524 assert(dado.elements == 2); 525 var nonceDO = dado.get(0); 526 assert(nonceDO.tag == 0x81); 527 var nonce = nonceDO.value; 528 529 var authTokenDO = dado.get(1); 530 assert(authTokenDO.tag == 0x82); 531 var authToken = authTokenDO.value; 532 533 var enc = new ByteString("04", HEX); 534 enc = enc.concat(devAuthPK.getComponent(Key.ECC_QX)); 535 enc = enc.concat(devAuthPK.getComponent(Key.ECC_QY)); 536 537 GPSystem.trace("Encoded CA public key: " + enc); 538 ca.performKeyAgreement(enc, nonce); 539 var result = ca.verifyAuthenticationToken(authToken); 540 541 if (!result) { 542 GPSystem.trace("Authentication token invalid"); 543 throw new Error("Authentication token invalid"); 544 } 545 GPSystem.trace("Authentication token valid"); 546 547 if (type == Key.DES) { 548 var sm = new IsoSecureChannel(crypto); 549 sm.setEncKey(ca.kenc); 550 sm.setMacKey(ca.kmac); 551 sm.setMACSendSequenceCounter(new ByteString("0000000000000000", HEX)); 552 } else { 553 var sm = new IsoSecureChannel(crypto, IsoSecureChannel.SSC_SYNC_ENC_POLICY); 554 sm.setEncKey(ca.kenc); 555 sm.setMacKey(ca.kmac); 556 sm.setMACSendSequenceCounter(new ByteString("00000000000000000000000000000000", HEX)); 557 } 558 559 this.card.setCredential(sm); 560 this.smactive = true; 561 return sm; 562 } 563 564 565 566 /** 567 * Update transparent EF referenced by file identifier 568 * 569 * @param {ByteString} fid the two byte file identifier 570 * @param {Number} offset the offset into the EF 571 * @param {ByteString} data the data to write 572 */ 573 SmartCardHSM.prototype.updateBinary = function(fid, offset, data) { 574 if (typeof(offset) == "undefined") { 575 offset = 0; 576 } 577 578 var bytesLeft = data.length; 579 var sent = 0; 580 581 // 8 bytes are required for T54(4) and T53(4) 582 var blksize = this.maxCData - 8; 583 584 while (bytesLeft > 0) { 585 var toSend = bytesLeft >= blksize ? blksize : bytesLeft; 586 587 var t54 = new ASN1(0x54, ByteString.valueOf(offset, 2)); 588 var t53 = new ASN1(0x53, data.bytes(sent, toSend)); 589 590 var cdata = t54.getBytes().concat(t53.getBytes()); 591 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, fid.byteAt(0), fid.byteAt(1), cdata, [0x9000]); 592 593 bytesLeft -= toSend; 594 offset += toSend; 595 sent += toSend; 596 } 597 } 598 599 600 601 /** 602 * Read transparent EF referenced by file identifier 603 * 604 * @param {ByteString} fid the two byte file identifier (optional - use currently selected EF if absent) 605 * @param {Number} offset the offset into the EF (optional) 606 * @param {Number} length the number of byte to read (optional) 607 * @type ByteString 608 * @return the data read from the EF 609 */ 610 SmartCardHSM.prototype.readBinary = function(fid, offset, length) { 611 if (typeof(offset) == "undefined") { 612 offset = 0; 613 } 614 if (typeof(fid) == "undefined") { 615 fid = new ByteString("0000", HEX); 616 } 617 618 var rsp = new ByteBuffer(); 619 do { 620 var t54 = new ASN1(0x54, ByteString.valueOf(offset, 2)); 621 622 if (length || this.limitedAPDUTransport || this.smactive) { // Is a length defined ? 623 var le = (!length || (length > this.maxRData)) ? this.maxRData: length; // Truncate if larger than maximum APDU size ? 624 } else { 625 var le = this.maxRAPDU <= 256 ? 0 : 65536; // Get all with Le=0 in either short or extended APDU mode 626 } 627 628 var data = this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xB1, fid.byteAt(0), fid.byteAt(1), t54.getBytes(), le, [0x9000, 0x6282]); 629 630 if (data.length == 0) { 631 break; 632 } 633 634 rsp.append(data); 635 offset += data.length; 636 637 if (length) { // Length was defined, see if we already got everything 638 length -= data.length; 639 if (length <= 0) { 640 break; 641 } 642 } 643 } while ((this.card.SW == 0x9000) || (this.card.SW == 0x6282)); 644 645 return rsp.toByteString(); 646 } 647 648 649 650 /** 651 * Select the file or key an return the FCP 652 * 653 * @param {ByteString} fid the two byte file object identifier 654 */ 655 SmartCardHSM.prototype.selectFile = function(fid) { 656 var fcp = this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xA4, 0x00, 0x04, fid, 0, [0x9000]); 657 return fcp; 658 } 659 660 661 662 /** 663 * Try selecting the file to see if is present 664 * 665 * @param {ByteString} fid the two byte file object identifier 666 */ 667 SmartCardHSM.prototype.hasFile = function(fid) { 668 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xA4, 0x00, 0x04, fid, 0); 669 return this.card.SW == 0x9000; 670 } 671 672 673 674 /** 675 * Delete file system object (EF or key) 676 * 677 * @param {ByteString} fid the two byte file object identifier 678 */ 679 SmartCardHSM.prototype.deleteFile = function(fid) { 680 return this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xE4, 0x02, 0x00, fid, [0x9000]); 681 } 682 683 684 685 /** 686 * Strips leading zeros of a ByteString 687 * 688 * @param {ByteString} value the ByteString value 689 * @return the stripped ByteString object, may be an empty ByteString 690 * @type ByteString 691 */ 692 SmartCardHSM.stripLeadingZeros = function(value) { 693 var i = 0; 694 for (; (i < value.length) && (value.byteAt(i) == 0); i++); 695 696 return value.right(value.length - i); 697 } 698 699 700 701 /** 702 * Build input for Generate Asymmetric Key Pair command for generating an ECC key pair 703 * 704 * @param {PublicKeyReference} innerCAR the CA the request shall be directed to 705 * @param {ByteString} algo the public key algorithm 706 * @param {PublicKeyReference} chr the certificate holder reference associated with this key 707 * @param {Key} dp the domain parameter for the key 708 * @param {PublicKeyReference} outerCAR the certificate holder reference of the public key for verifying the outer signature 709 * @param {Key} privateKey optional parameter to supply a private key value for import. This only works with the development version 710 * of the SmartCard-HSM. 711 * @type ByteString 712 * @return the encoded C-Data for GENERATE ASYMMETRIC KEY PAIR 713 */ 714 SmartCardHSM.buildGAKPwithECC = function(innerCAR, algo, chr, dp, outerCAR, priKey) { 715 716 // Encode G 717 var bb = new ByteBuffer(); 718 // uncompressed encoding 719 bb.append(new ByteString("04", HEX)); 720 bb.append(dp.getComponent(Key.ECC_GX)); 721 bb.append(dp.getComponent(Key.ECC_GY)); 722 var G = bb.toByteString(); 723 724 var t = new ASN1(0x30, 725 new ASN1("CPI", 0x5F29, new ByteString("00", HEX)), 726 new ASN1("CAR", 0x42, innerCAR.getBytes()), 727 new ASN1("Public Key", 0x7F49, 728 new ASN1("Object Identifier", 0x06, algo), 729 new ASN1("Prime Modulus", 0x81, dp.getComponent(Key.ECC_P)), 730 new ASN1("First coefficient a", 0x82, dp.getComponent(Key.ECC_A)), 731 new ASN1("Second coefficient b", 0x83, dp.getComponent(Key.ECC_B)), 732 new ASN1("Base Point G", 0x84, G), 733 new ASN1("Order of the base point", 0x85, dp.getComponent(Key.ECC_N)), 734 new ASN1("Cofactor f", 0x87, SmartCardHSM.stripLeadingZeros(dp.getComponent(Key.ECC_H))) 735 ), 736 new ASN1("CHR", 0x5F20, chr.getBytes()) 737 ); 738 739 if (typeof(outerCAR) != "undefined") { 740 t.add(new ASN1("OuterCAR", 0x45, outerCAR.getBytes())); 741 } 742 743 if (priKey != undefined) { 744 var d = new ASN1("Private Key", 0x8A, priKey.getComponent(Key.ECC_D)); 745 t.get(2).add(d); 746 // GPSystem.trace(t); 747 } 748 return t.value; 749 } 750 751 752 753 /** 754 * Build input for Generate Asymmetric Key Pair command for generating a RSA key pair 755 * 756 * @param {PublicKeyReference} innerCAR the CA the request shall be directed to 757 * @param {ByteString} algo the public key algorithm 758 * @param {PublicKeyReference} chr the certificate holder reference associated with this key 759 * @param {Number} keysize the module size in bits (1024, 1536 or 2048) 760 * @param {PublicKeyReference} outerCAR the certificate holder reference of the public key for verifying the outer signature 761 * @type ByteString 762 * @return the encoded C-Data for GENERATE ASYMMETRIC KEY PAIR 763 */ 764 SmartCardHSM.buildGAKPwithRSA = function(innerCAR, algo, chr, keysize, outerCAR) { 765 766 var t = new ASN1(0x30, 767 new ASN1("CPI", 0x5F29, new ByteString("00", HEX)), 768 new ASN1("CAR", 0x42, innerCAR.getBytes()), 769 new ASN1("Public Key", 0x7F49, 770 new ASN1("Object Identifier", 0x06, algo), 771 new ASN1("Public Key Exponent", 0x82, ByteString.valueOf(65537)), 772 new ASN1("Key Size", 0x02, ByteString.valueOf(keysize)) 773 ), 774 new ASN1("CHR", 0x5F20, chr.getBytes()) 775 ); 776 777 if (typeof(outerCAR) != "undefined") { 778 t.add(new ASN1("OuterCAR", 0x45, outerCAR.getBytes())); 779 } 780 return t.value; 781 } 782 783 784 785 /** 786 * Create a PKCS#15 PrivateECCKey description 787 * 788 * @param {Number/ByteString} keyid the key identifier 789 * @param {String} label the key label 790 * @type ASN1 791 * @return the PrivateECCKey description 792 */ 793 SmartCardHSM.buildPrkDforECC = function(keyid, label, keysize) { 794 if (typeof(keyid) == "number") { 795 keyid = ByteString.valueOf(keyid); 796 } 797 798 var prkd = new ASN1(0xA0, 799 new ASN1(ASN1.SEQUENCE, 800 new ASN1(ASN1.UTF8String, new ByteString(label, UTF8)) 801 // new ASN1(ASN1.BIT_STRING, new ByteString("0780", HEX)), 802 // new ASN1(ASN1.OCTET_STRING, new ByteString("01", HEX)) 803 ), 804 new ASN1(ASN1.SEQUENCE, 805 new ASN1(ASN1.OCTET_STRING, keyid), 806 new ASN1(ASN1.BIT_STRING, new ByteString("072080", HEX)) 807 ), 808 new ASN1(0xA1, 809 new ASN1(ASN1.SEQUENCE, 810 new ASN1(ASN1.SEQUENCE, 811 new ASN1(ASN1.OCTET_STRING, new ByteString("", HEX)) 812 ) 813 ) 814 ) 815 ); 816 817 if (keysize != undefined) { 818 assert(keysize > 0, "Key size must be > 0"); 819 var tlvint = ByteString.valueOf(keysize); 820 if (tlvint.byteAt(0) >= 0x80) { 821 tlvint = (new ByteString("00", HEX)).concat(tlvint); 822 } 823 prkd.get(2).get(0).add(new ASN1(ASN1.INTEGER, tlvint)); 824 } 825 826 // GPSystem.trace(prkd); 827 return prkd; 828 } 829 830 831 832 /** 833 * Create a PKCS#15 PrivateRSAKey description 834 * 835 * @param {Number/ByteString} keyid the key identifier 836 * @param {String} label the key label 837 * @param {Number} modulussize 838 * @type ASN1 839 * @return the PrivateECCKey description 840 */ 841 SmartCardHSM.buildPrkDforRSA = function(keyid, label, modulussize) { 842 if (typeof(keyid) == "number") { 843 keyid = ByteString.valueOf(keyid); 844 } 845 846 var prkd = new ASN1(0x30, 847 new ASN1(ASN1.SEQUENCE, 848 new ASN1(ASN1.UTF8String, new ByteString(label, UTF8)) 849 // new ASN1(ASN1.BIT_STRING, new ByteString("0780", HEX)), 850 // new ASN1(ASN1.OCTET_STRING, new ByteString("01", HEX)) 851 ), 852 new ASN1(ASN1.SEQUENCE, 853 new ASN1(ASN1.OCTET_STRING, keyid), 854 new ASN1(ASN1.BIT_STRING, new ByteString("0274", HEX)) 855 ), 856 new ASN1(0xA1, 857 new ASN1(ASN1.SEQUENCE, 858 new ASN1(ASN1.SEQUENCE, 859 new ASN1(ASN1.OCTET_STRING, new ByteString("", HEX)) 860 ), 861 new ASN1(ASN1.INTEGER, ByteString.valueOf(modulussize)) 862 ) 863 ) 864 ); 865 // GPSystem.trace(prkd); 866 return prkd; 867 } 868 869 870 871 /** 872 * Create a PKCS#15 SecretKey description 873 * 874 * @param {Number/ByteString} keyid the key identifier 875 * @param {String} label the key label 876 * @param {Number} keysize 877 * @type ASN1 878 * @return the secret key description 879 */ 880 SmartCardHSM.buildSKDforAES = function(keyid, label, keysize) { 881 if (typeof(keyid) == "number") { 882 keyid = ByteString.valueOf(keyid); 883 } 884 885 var skd = 886 new ASN1(0xA8, 887 // CommonObjectAttributes 888 new ASN1(ASN1.SEQUENCE, 889 new ASN1(ASN1.UTF8String, new ByteString(label, UTF8)) 890 // new ASN1(ASN1.BIT_STRING, new ByteString("0780", HEX)), 891 // new ASN1(ASN1.OCTET_STRING, new ByteString("01", HEX)) 892 ), 893 // ClassAttributes: CommonKeyAttributes 894 new ASN1(ASN1.SEQUENCE, 895 new ASN1(ASN1.OCTET_STRING, keyid), 896 new ASN1(ASN1.BIT_STRING, new ByteString("07C010", HEX)) 897 ), 898 // SubClassAttribute: CommonSecretKeyAttributes 899 new ASN1(0xA0, 900 new ASN1(ASN1.SEQUENCE, 901 new ASN1(ASN1.INTEGER, ByteString.valueOf(keysize, 2)) 902 ) 903 ), 904 new ASN1(0xA1, 905 new ASN1(ASN1.SEQUENCE, 906 new ASN1(ASN1.SEQUENCE, 907 new ASN1(ASN1.OCTET_STRING, new ByteString("", HEX)) 908 ) 909 ) 910 ) 911 912 ); 913 // GPSystem.trace(skd); 914 return skd; 915 } 916 917 918 919 /** 920 * Create a PKCS#15 certificate description 921 * 922 * @param {ByteString} commonObjectFlags default value is '0640' 923 * @param {String} label the key label 924 * @param {Key} pubKey the public key 925 * @param {ByteString} certFID the file identifier of the certificate 926 * @type ASN1 927 * @return the PrivateECCKey description 928 */ 929 SmartCardHSM.buildCertDescription = function(label, commonObjectFlags, pubKey, certFID) { 930 if (!commonObjectFlags) { 931 commonObjectFlags = new ByteString("0x0640", HEX); 932 } 933 934 // generate subject key id 935 var qx = pubKey.getComponent(Key.ECC_QX) 936 if (qx) { 937 var enc = qx; 938 } else { 939 var enc = pubKey.getComponent(Key.MODULUS); 940 } 941 var crypto = new Crypto(); 942 var subjectKeyID = crypto.digest(Crypto.SHA_1, enc); 943 944 var desc = new ASN1(ASN1.SEQUENCE, 945 new ASN1(ASN1.SEQUENCE, // common object attributes 946 new ASN1(ASN1.UTF8String, new ByteString(label, UTF8)), 947 new ASN1(ASN1.BIT_STRING, commonObjectFlags) 948 ), 949 new ASN1(ASN1.SEQUENCE, // common certificate attributes 950 new ASN1(ASN1.OCTET_STRING, subjectKeyID) 951 ), 952 new ASN1(0xA1, // type attributes 953 new ASN1(ASN1.SEQUENCE, // x.509 certificate attributes 954 new ASN1(ASN1.SEQUENCE, // path 955 new ASN1(ASN1.OCTET_STRING, certFID) 956 ) 957 ) 958 ) 959 ); 960 return desc; 961 } 962 963 964 965 /** 966 * Dump C-Data of Generate Asymmetric Key Pair command 967 * 968 * @param {ByteString} keydata the content of C-Data 969 */ 970 SmartCardHSM.dumpKeyData = function(keydata) { 971 GPSystem.trace(keydata); 972 var a = new ASN1(0x30, keydata); 973 var a = new ASN1(a.getBytes()); 974 for (var i = 0; i < a.elements; i++) { 975 GPSystem.trace(a.get(i)); 976 } 977 } 978 979 980 981 /** 982 * Generate an asymmetric key pair 983 * 984 * @param {Number} newkid key identifier for new key 985 * @param {Number} signkid key identifier for signing the new public key 986 * @param {ByteString} keydata the key data template 987 * @type ByteString 988 * @return the certificate signing request containing the new public key 989 */ 990 SmartCardHSM.prototype.generateAsymmetricKeyPair = function(newkid, signkid, keydata) { 991 992 if (!this.limitedAPDUTransport) { // Use extended length 993 var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x46, newkid, signkid, keydata, 65536, [0x9000]); 994 } else { 995 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x46, newkid, signkid, keydata, [0x9000]); 996 var rsp = this.readBinary(ByteString.valueOf(0xCE00 + newkid), 0); 997 } 998 999 return rsp; 1000 } 1001 1002 1003 1004 /** 1005 * Generate a symmetric key 1006 * 1007 * @param {Number} newkid key identifier for new key 1008 * @param {Number} algo key generation algorithm 1009 * @param {ByteString} keydata the key data template 1010 * @type ByteString 1011 * @return 1012 */ 1013 SmartCardHSM.prototype.generateSymmetricKey = function(newkid, algo, keydata) { 1014 1015 var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x48, newkid, algo, keydata, 0, [0x9000]); 1016 return rsp; 1017 } 1018 1019 1020 1021 /** 1022 * Return true is SmartCard-HSM is initialized 1023 * 1024 * @type Boolean 1025 * @return true if initialized 1026 */ 1027 SmartCardHSM.prototype.isInitialized = function() { 1028 var sw = this.queryUserPINStatus(); 1029 if ((sw == 0x6984) || (sw == 0x6A88)) { // V1.2: Not initialized / V2.0: Transport PIN 1030 var sw = this.queryInitializationCodeStatus(); 1031 if (sw == 0x6A88) { 1032 return false; 1033 } 1034 } 1035 return true; 1036 } 1037 1038 1039 1040 /** 1041 * Initialize device and clear all keys and files 1042 * 1043 * @param {ByteString} options two byte option mask 1044 * @param {ByteString} initialPIN initial user PIN value 1045 * @param {ByteString} initializationCode secret code for device initialization (set during first use) 1046 * @param {Number} retryCounterInitial retry counter for user PIN 1047 * @param {Number} keyshares number of device key encryption key shares (optional) 1048 */ 1049 SmartCardHSM.prototype.initDevice = function(options, initialPIN, initializationCode, retryCounterInitial, keyshares) { 1050 var s = new ASN1(0x30, 1051 new ASN1(0x80, options), 1052 new ASN1(0x81, initialPIN), 1053 new ASN1(0x82, initializationCode), 1054 new ASN1(0x91, ByteString.valueOf(retryCounterInitial)) 1055 ); 1056 1057 if (typeof(keyshares) != "undefined") { 1058 s.add(new ASN1(0x92, ByteString.valueOf(keyshares))); 1059 } 1060 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000]); 1061 } 1062 1063 1064 1065 /** 1066 * Determine free memory 1067 * 1068 * @type Number 1069 * @return the number of available bytes (this values is capped to 32767 on JCOP 2.4.1) 1070 */ 1071 SmartCardHSM.prototype.getFreeMemory = function() { 1072 var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, 0, [0x9000, 0x6700]); 1073 1074 if (this.card.SW != 0x9000) { 1075 return -1; 1076 } 1077 1078 this.options = rsp.bytes(0, 2).toUnsigned(); 1079 this.major = rsp.byteAt(rsp.length - 2); 1080 this.minor = rsp.byteAt(rsp.length - 1); 1081 this.platform = rsp.byteAt(rsp.length - 3); 1082 return rsp.bytes(rsp.length - 7, 4).toUnsigned(); 1083 } 1084 1085 1086 1087 /** 1088 * Check if the RESET RETRY COUNTER command is enabled 1089 * 1090 * @type Boolean 1091 * @return true if enable during initialization 1092 */ 1093 SmartCardHSM.prototype.isResetRetryCounterEnabled = function() { 1094 if (typeof(this.options) == "undefined") { 1095 this.getFreeMemory(); 1096 } 1097 return (this.options & 1) == 1; 1098 } 1099 1100 1101 1102 /** 1103 * Check if the RESET RETRY COUNTER command can reset the PIN 1104 * 1105 * @type Boolean 1106 * @return true if enable during initialization 1107 */ 1108 SmartCardHSM.prototype.isPINResetEnabled = function() { 1109 if (typeof(this.options) == "undefined") { 1110 this.getFreeMemory(); 1111 } 1112 return (this.options & 0x20) == 0; 1113 } 1114 1115 1116 1117 /** 1118 * Parse the key domain status returned from the device 1119 * 1120 * @param {ByteString} status the R-DATA from the MANAGE KEY DOMAIN command 1121 * @type object 1122 * @return the decoded status Info 1123 */ 1124 SmartCardHSM.prototype.parseKeyDomainStatus = function(status) { 1125 if (status.length == 0) { 1126 return { sw: this.card.SW }; 1127 } 1128 1129 var statusObject = { 1130 sw: this.card.SW, 1131 shares: status.byteAt(0), 1132 outstanding: status.byteAt(1), 1133 kcv: status.bytes(2, 8) 1134 } 1135 1136 if (status.length > 10) { 1137 statusObject.keyDomain = status.bytes(10); 1138 } 1139 1140 return statusObject; 1141 } 1142 1143 1144 1145 /* 1146 * Create DKEK Key Domain 1147 * 1148 * @param {Number} keyDomain number of key domain in the range 0 to the maximum defined in the INITIALIZE DEVICE command 1149 * @param {Number} shares the number of DKEK shares to import 1150 * @type Object 1151 * @return object with properties sw{Number}, shares{Number}, outstanding{Number} and kcv{ByteString} 1152 */ 1153 SmartCardHSM.prototype.createDKEKKeyDomain = function(keyDomain, shares) { 1154 if (typeof(keyDomain) != "number") { 1155 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be a number"); 1156 } 1157 if (typeof(shares) != "number") { 1158 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "shares must be a number"); 1159 } 1160 1161 var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x01, keyDomain, ByteString.valueOf(shares), 0); 1162 1163 return this.parseKeyDomainStatus(status); 1164 } 1165 1166 1167 1168 /** 1169 * Create XKEK Key Domain 1170 * 1171 * @param {Number} keyDomain number of key domain in the range 0 to the maximum defined in the INITIALIZE DEVICE command 1172 * @param {ByteString} keyDomainMembership either a 64 byte signature (old format) or a encoded TLV object with tag 54 or 55 1173 * @return object with properties sw{Number}, shares{Number}, outstanding{Number}, kcv{ByteString} and the key domain UID{ByteString} 1174 * @type Object 1175 */ 1176 SmartCardHSM.prototype.createXKEKKeyDomain = function(keyDomain, groupSignerPublicKey, keyDomainMembership) { 1177 if (typeof(keyDomain) != "number") { 1178 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be a number"); 1179 } 1180 if ((keyDomain < 0) || (keyDomain > 0xFF)) { 1181 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be between 0 and 255"); 1182 } 1183 if (!(groupSignerPublicKey instanceof CVC)) { 1184 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "groupSignerPublicKey must be a CVC instance"); 1185 } 1186 if (!(keyDomainMembership instanceof ByteString)) { 1187 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomainMembership must be a ByteString"); 1188 } 1189 1190 var car = groupSignerPublicKey.getOuterCAR().getBytes(); 1191 1192 var pukrefdo = new ASN1(0x83, car); 1193 var pukref = pukrefdo.getBytes(); 1194 1195 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000]); 1196 1197 if (keyDomainMembership.length == 64) { 1198 keyDomainMembership = new ASN1(0x53, keyDomainMembership).getBytes(); 1199 } 1200 var cdata = groupSignerPublicKey.getASN1().value.concat(keyDomainMembership); 1201 1202 if (cdata.length <= this.maxCData) { 1203 var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x02, keyDomain, cdata, 0); 1204 } else { 1205 this.updateBinary(ByteString.valueOf(0x2F10), 0, cdata); 1206 var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x02, keyDomain, 0); 1207 } 1208 1209 return this.parseKeyDomainStatus(status); 1210 } 1211 1212 1213 1214 /** 1215 * Associate XKEK Key Domain 1216 * 1217 * @param {Number} keyDomain number of key domain in the range 0 to the maximum defined in the INITIALIZE DEVICE command 1218 * @param {ByteString} keyDomainUID a encoded TLV object with tag 51 containing the key domain uid of the associated domain 1219 * @param {ByteString} keyDomainAssociation a encoded TLV object with tag 56 or 57 1220 * @return object with properties sw{Number}, shares{Number}, outstanding{Number}, kcv{ByteString} and the key domain UID{ByteString} 1221 * @type Object 1222 */ 1223 SmartCardHSM.prototype.associateXKEKKeyDomain = function(keyDomain, groupSignerPublicKey, keyDomainUID, keyDomainAssociation) { 1224 if (typeof(keyDomain) != "number") { 1225 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be a number"); 1226 } 1227 if ((keyDomain < 0) || (keyDomain > 0xFF)) { 1228 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be between 0 and 255"); 1229 } 1230 if (!(groupSignerPublicKey instanceof CVC)) { 1231 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "groupSignerPublicKey must be a ByteString"); 1232 } 1233 if (!(keyDomainUID instanceof ByteString)) { 1234 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomainUID must be a ByteString"); 1235 } 1236 if (!(keyDomainAssociation instanceof ByteString)) { 1237 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomainAssociation must be a ByteString"); 1238 } 1239 1240 var car = groupSignerPublicKey.getOuterCAR().getBytes(); 1241 1242 var pukrefdo = new ASN1(0x83, car); 1243 var pukref = pukrefdo.getBytes(); 1244 1245 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000]); 1246 1247 var cdata = groupSignerPublicKey.getASN1().value.concat(keyDomainUID).concat(keyDomainAssociation); 1248 1249 if (cdata.length <= this.maxCData) { 1250 var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x05, keyDomain, cdata, 0); 1251 } else { 1252 this.updateBinary(ByteString.valueOf(0x2F10), 0, cdata); 1253 var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x05, keyDomain, 0); 1254 } 1255 1256 return this.parseKeyDomainStatus(status); 1257 } 1258 1259 1260 1261 /** 1262 * Derive XKEK 1263 * 1264 * @param {Number} keyDomain number of key domain in the range 0 to the maximum defined in the INITIALIZE DEVICE command 1265 * @param {ByteString} derivationParam 1266 * @return object with properties sw{Number}, shares{Number}, outstanding{Number}, kcv{ByteString} and the key domain UID{ByteString} 1267 * @type Object 1268 */ 1269 SmartCardHSM.prototype.deriveXKEK = function(keyid, peerPublicKey, derivationParam) { 1270 if (typeof(keyid) != "number") { 1271 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyid must be a number"); 1272 } 1273 if ((keyid < 1) || (keyid > 0xFF)) { 1274 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyid must be between 1 and 255"); 1275 } 1276 if (!(peerPublicKey instanceof CVC)) { 1277 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "peerPublicKey must be a CVC"); 1278 } 1279 if (!(derivationParam instanceof ByteString)) { 1280 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "derivationParam must be a ByteString"); 1281 } 1282 1283 var car = peerPublicKey.getOuterCAR().getBytes(); 1284 1285 var pukrefdo = new ASN1(0x83, car); 1286 var pukref = pukrefdo.getBytes(); 1287 1288 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000]); 1289 1290 var kdp = new ASN1(0x50, derivationParam).getBytes(); 1291 var cdata = peerPublicKey.getASN1().value.concat(kdp); 1292 1293 if (cdata.length <= this.maxCData) { 1294 // Le is usually not required, but versions 3.1 to 3.3 fail without Le (#178) 1295 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x62, keyid, 0x84, cdata, 0, [0x9000]); 1296 } else { 1297 this.updateBinary(ByteString.valueOf(0x2F10), 0, cdata); 1298 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x62, keyid, 0x84, [0x9000]); 1299 } 1300 } 1301 1302 1303 1304 /** 1305 * Query the status of the key domain 1306 * 1307 * @param {Number} keyDomain the number of the key domain which will be queried, default is 0 1308 * @type Object 1309 * @return object with properties sw{Number}, shares{Number}, outstanding{Number}, kcv{ByteString} and for a XKEK key domain the key domain UID{ByteString} 1310 */ 1311 SmartCardHSM.prototype.queryKeyDomainStatus = function(keyDomain) { 1312 if (!keyDomain) { 1313 keyDomain = 0; 1314 } 1315 1316 var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x00, keyDomain, 0); 1317 1318 return this.parseKeyDomainStatus(status); 1319 } 1320 1321 1322 1323 /** 1324 * Delete the key encryption key in a key domain 1325 * 1326 * @param {Number} keyDomain the number of the key domain 1327 */ 1328 SmartCardHSM.prototype.deleteKEK = function(keyDomain) { 1329 var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x04, keyDomain, [0x9000]); 1330 1331 return this.parseKeyDomainStatus(status); 1332 } 1333 1334 1335 1336 /** 1337 * Delete the empty key domain 1338 * 1339 * @param {Number} keyDomain the number of the key domain 1340 */ 1341 SmartCardHSM.prototype.deleteKeyDomain = function(keyDomain) { 1342 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x03, keyDomain, [0x9000]); 1343 } 1344 1345 1346 1347 /** 1348 * Import DKEK share or query status 1349 * 1350 * @param {Number} keyDomain the number of the key domain 1351 * @param {ByteString} keyshare 32 byte key share 1352 * @type Object 1353 * @return object with properties sw{Number}, shares{Number}, outstanding{Number} and kcv{ByteString} 1354 */ 1355 SmartCardHSM.prototype.importKeyShare = function(keyDomain, keyshare) { 1356 if (typeof(keyDomain) != "number") { 1357 keyshare = keyDomain; 1358 keyDomain = 0; 1359 } 1360 if (typeof(keyshare) != "undefined") { 1361 var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x00, keyDomain, keyshare, 0, [0x9000]); 1362 } else { 1363 var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x00, keyDomain, 0); 1364 } 1365 if (status.length == 0) { 1366 return { sw: this.card.SW }; 1367 } 1368 1369 var statusObject = { 1370 sw: this.card.SW, 1371 shares: status.byteAt(0), 1372 outstanding: status.byteAt(1), 1373 kcv: status.bytes(2, 8) 1374 } 1375 1376 if (status.length > 10) { 1377 statusObject.keyDomain = status.bytes(10); 1378 } 1379 1380 return statusObject; 1381 } 1382 1383 1384 1385 /** 1386 * Decrypt and import a DKEK share 1387 * 1388 * @param {ByteString} keyshare the encrypted key share as read from the .pbe file 1389 * @param {ByteString} password the password 1390 * @param {Number} keyDomain the number of the key domain 1391 * @return object with properties sw{Number}, shares{Number}, outstanding{Number} and kcv{ByteString} 1392 */ 1393 SmartCardHSM.prototype.importEncryptedKeyShare = function(keyshare, password, keyDomain) { 1394 if (typeof(keyDomain) == "undefined") { 1395 keyDomain = 0; 1396 } 1397 1398 var dkek = DKEK.decryptKeyShare(keyshare, password); 1399 // print("Importing into SmartCard-HSM"); 1400 var r = this.importKeyShare(keyDomain, dkek); 1401 dkek.clear(); 1402 return r; 1403 } 1404 1405 1406 1407 /** 1408 * Wrap key under DKEK 1409 * 1410 * @param {Number} id key id 1411 * @type ByteString 1412 * @return key blob with encrypted key value 1413 */ 1414 SmartCardHSM.prototype.wrapKey = function(id) { 1415 var keyblob = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x72, id, 0x92, 65536, [0x9000]); 1416 return keyblob; 1417 } 1418 1419 1420 1421 /** 1422 * Unwrap key with DKEK 1423 * 1424 * @param {Number} id key id 1425 * @param {ByteString} keyblob the wrapped key 1426 */ 1427 SmartCardHSM.prototype.unwrapKey = function(id, keyblob) { 1428 if (keyblob.length < this.maxCData) { 1429 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x74, id, 0x93, keyblob, [0x9000]); 1430 } else { 1431 this.updateBinary(ByteString.valueOf(0x2F10), 0, keyblob); 1432 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x74, id, 0x93, [0x9000]); 1433 } 1434 } 1435 1436 1437 1438 /** 1439 * Replace symmetric key value encrypted under current key 1440 * 1441 * @param {Number} id key id 1442 * @param {ByteString} keyblob the wrapped key 1443 */ 1444 SmartCardHSM.prototype.unwrapAndReplaceKey = function(id, keyblob) { 1445 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x74, id, 0x94, keyblob, [0x9000]); 1446 } 1447 1448 1449 1450 /** 1451 * Derive Symmetric Key 1452 * 1453 * @param {Number} id key id 1454 * @param {Number} algo algorithm id (one of ALG_CBC_ENC, ALG_CBC_DEC, ALG_CMAC or ALG_DERIVE_SP800_56C) 1455 * @param {ByteString} derivationParam the derivation parameter 1456 * @type ByteString 1457 * @return derived key value 1458 */ 1459 SmartCardHSM.prototype.deriveSymmetricKey = function(id, algo, derivationParam) { 1460 var derivedKeyValue = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x78, id, algo, derivationParam, 0, [0x9000]); 1461 return derivedKeyValue; 1462 } 1463 1464 1465 1466 /** 1467 * Verify User PIN 1468 * 1469 * @param {ByteString} userPIN user PIN value 1470 * @return the status word SW1/SW2 returned by the device 1471 */ 1472 SmartCardHSM.prototype.verifyUserPIN = function(userPIN) { 1473 if (userPIN) { 1474 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x20, 0x00, 0x81, userPIN); 1475 return this.card.SW; 1476 } else { 1477 var cs = this.getNativeCardService(); 1478 cs.verifyPassword(); 1479 return this.queryUserPINStatus(); 1480 } 1481 } 1482 1483 1484 1485 /** 1486 * Logout 1487 * 1488 */ 1489 SmartCardHSM.prototype.logout = function() { 1490 this.card.clearCredential(); 1491 var fcp = this.card.sendApdu(0x00, 0xA4, 0x04, 0x04, new ByteString("E82B0601040181C31F0201", HEX), 0, [0x9000]); 1492 var a = new ASN1(fcp); 1493 var v = a.find(0x85).value; 1494 this.options = v.bytes(0, 2).toUnsigned(); 1495 this.major = v.byteAt(v.length - 2); 1496 this.minor = v.byteAt(v.length - 1); 1497 if (v.length >= 5) { 1498 this.platform = v.byteAt(v.length - 3); 1499 } 1500 } 1501 1502 1503 1504 /** 1505 * Change User PIN 1506 * 1507 * @param {ByteString} currentPIN current user PIN value 1508 * @param {ByteString} newPIN new user PIN value 1509 */ 1510 SmartCardHSM.prototype.changeUserPIN = function(currentPIN, newPIN) { 1511 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x24, 0x00, 0x81, currentPIN.concat(newPIN), [0x9000]); 1512 } 1513 1514 1515 1516 /** 1517 * Unblock and set User PIN 1518 * 1519 * @param {ByteString} initializationCode the initialization code 1520 * @param {ByteString} newPIN new user PIN value (optional) 1521 */ 1522 SmartCardHSM.prototype.unblockUserPIN = function(initializationCode, newPIN) { 1523 if (newPIN) { 1524 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x2C, 0x00, 0x81, initializationCode.concat(newPIN), [0x9000]); 1525 } else { 1526 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x2C, 0x01, 0x81, initializationCode, [0x9000]); 1527 } 1528 } 1529 1530 1531 1532 /** 1533 * Change InitializationCode 1534 * 1535 * @param {ByteString} initializationCode current initialization code 1536 * @param {ByteString} newInitializationCode new initialization code 1537 */ 1538 SmartCardHSM.prototype.changeInitializationCode = function(initializationCode, newInitializationCode) { 1539 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x24, 0x00, 0x88, initializationCode.concat(newInitializationCode), [0x9000]); 1540 } 1541 1542 1543 1544 SmartCardHSM.describePINStatus = function(sw, name) { 1545 var str; 1546 switch(sw) { 1547 case 0x9000: 1548 str = name + " authenticated"; 1549 break; 1550 case 0x6984: 1551 str = name + " in transport mode or device not initialized"; 1552 break; 1553 case 0x6A88: 1554 str = name + " not initialized"; 1555 break; 1556 case 0x6983: 1557 str = name + " blocked"; 1558 break; 1559 case 0x6300: 1560 str = name + " not authenticated"; 1561 break; 1562 default: 1563 str = name + " not verified, " + (sw & 0xF) + " tries remaining"; 1564 break; 1565 } 1566 return str + " (" + ByteString.valueOf(sw).toString(HEX) + ")"; 1567 } 1568 1569 1570 1571 /** 1572 * Request PIN Status Information 1573 * 1574 * @param {Number} p2 the PIN object id 1575 * @type Number 1576 * @return the status word SW1/SW2 returned by the device 1577 */ 1578 SmartCardHSM.prototype.queryPINStatus = function(p2) { 1579 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x20, 0x00, p2, 0); 1580 return this.card.SW; 1581 } 1582 1583 1584 1585 /** 1586 * Request PIN Status Information 1587 * 1588 * @type Number 1589 * @return the status word SW1/SW2 returned by the device 1590 */ 1591 SmartCardHSM.prototype.queryUserPINStatus = function() { 1592 return this.queryPINStatus(0x81); 1593 } 1594 1595 1596 1597 /** 1598 * Request Initialization Code Status 1599 * 1600 * @type Number 1601 * @return the status word SW1/SW2 returned by the device 1602 */ 1603 SmartCardHSM.prototype.queryInitializationCodeStatus = function() { 1604 return this.queryPINStatus(0x88); 1605 } 1606 1607 1608 1609 /** 1610 * Enumerate Objects 1611 * 1612 * @return the enumeration 1613 */ 1614 SmartCardHSM.prototype.enumerateObjects = function() { 1615 var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x58, 0x00, 0x00, 65536, [0x9000]); 1616 return rsp; 1617 } 1618 1619 1620 1621 /** 1622 * Generate random data 1623 * 1624 * @param {Number} length number of bytes 1625 * @return the random bytes 1626 */ 1627 SmartCardHSM.prototype.generateRandom = function(length) { 1628 var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x84, 0x00, 0x00, length, [0x9000]); 1629 return rsp; 1630 } 1631 1632 1633 1634 /** 1635 * Sign data using referenced key 1636 * 1637 * @param {Number} keyid the key identifier for signing 1638 * @param {algo} algo the algorithm identifier 1639 * @param {ByteString} data the data to be signed 1640 * @return the signature value 1641 */ 1642 SmartCardHSM.prototype.sign = function(keyid, algo, data) { 1643 if (data.length <= this.maxCData) { 1644 var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x68, keyid, algo, data, 0x10000, [0x9000]); 1645 } else { 1646 this.updateBinary(ByteString.valueOf(0x2F10), 0, data); 1647 var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x68, keyid, algo, 0x10000, [0x9000]); 1648 } 1649 1650 return rsp; 1651 } 1652 1653 1654 1655 /** 1656 * Decipher cryptogram or agree shared secret using Diffie-Hellman 1657 * 1658 * @param {Number} keyid the key identifier 1659 * @param {Number} algo the algorithm identifier 1660 * @param {ByteString} data the the cryptogram or concatenation of x || y of ECC public key 1661 * @return the plain output 1662 */ 1663 SmartCardHSM.prototype.decipher = function(keyid, algo, data) { 1664 var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x62, keyid, algo, data, 0x00, [0x9000]); 1665 return rsp; 1666 } 1667 1668 1669 1670 /** 1671 * Verify card verifiable certificate 1672 * 1673 * @param {CVC} cvc the card verifiable certificate 1674 **/ 1675 SmartCardHSM.prototype.verifyCertificate = function(cvc) { 1676 1677 // Check if public key is already known 1678 var chr = cvc.getCHR().getBytes(); 1679 1680 var pukrefdo = new ASN1(0x83, chr); 1681 var pukref = pukrefdo.getBytes(); 1682 1683 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000, 0x6A88]); 1684 1685 if (this.card.SW == 0x9000) { 1686 return; 1687 } 1688 1689 // Select public key for verification 1690 var car = cvc.getCAR().getBytes(); 1691 1692 var pukrefdo = new ASN1(0x83, car); 1693 var pukref = pukrefdo.getBytes(); 1694 1695 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000]); 1696 1697 // Extract value of 7F21 1698 var tl = new TLVList(cvc.getBytes(), TLV.EMV); 1699 var t = tl.index(0); 1700 var v = t.getValue(); 1701 1702 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x2A, 0x00, 0xBE, v, [0x9000]); 1703 } 1704 1705 1706 1707 /** 1708 * Enumerate CA certificates 1709 * 1710 * @type String[] 1711 * @return the list of certificate labels 1712 */ 1713 SmartCardHSM.prototype.enumerateCACertificates = function() { 1714 this.canamemap = []; 1715 this.caidmap = [] 1716 this.caids = []; 1717 var certlist = []; 1718 1719 var fobs = this.enumerateObjects(); 1720 1721 // Process PKCS#15 certificate descriptions 1722 for (var i = 0; i < fobs.length; i+= 2) { 1723 if (fobs.byteAt(i) == SmartCardHSM.CERTDPREFIX) { 1724 var id = fobs.byteAt(i + 1); 1725 this.caids.push(id); 1726 var fid = ByteString.valueOf((SmartCardHSM.CACERTIFICATEPREFIX << 8) + id); 1727 var descbin = this.readBinary(fobs.bytes(i, 2)); 1728 var asn = new ASN1(descbin); 1729 var coa = asn.get(0); 1730 if (coa.elements > 0) { 1731 var label = coa.get(0).value.toString(ASCII); 1732 } else { 1733 var label = "No label (" + i + ")"; 1734 } 1735 var cert = this.readBinary(fid); 1736 certlist.push(label); 1737 this.canamemap[label] = cert; 1738 cert.id = id; 1739 this.caidmap[label] = id; 1740 } 1741 } 1742 1743 return certlist; 1744 } 1745 1746 1747 1748 /** 1749 * Return CA certificate with label 1750 * 1751 * @param {String} label the certificate label 1752 * @type ByteString 1753 * @return the encoded certificate 1754 */ 1755 SmartCardHSM.prototype.getCACertificate = function(label) { 1756 if (typeof(this.caids) == "undefined") { 1757 this.enumerateCACertificates(); 1758 } 1759 1760 return this.canamemap[label]; 1761 } 1762 1763 1764 1765 /** 1766 * Determine an unused CA certificate identifier 1767 * 1768 * @type Number 1769 * @return a free CA certificate identifier or -1 if all identifier in use 1770 */ 1771 SmartCardHSM.prototype.determineFreeCAId = function() { 1772 if (typeof(this.caids) == "undefined") { 1773 this.enumerateCACertificates(); 1774 } 1775 1776 if (this.caids.length == 0) { 1777 return 0; 1778 } 1779 1780 var id = Math.max.apply(null, this.caids) + 1; 1781 if (id > 256) { 1782 return -1; 1783 } 1784 return id; 1785 } 1786 1787 1788 1789 /** 1790 * Add a new CA certificate to the map 1791 * 1792 * @param {X509} cert the CA certificate 1793 * @param {Number} id the corresponding id 1794 * @param {String} label the corresponding label 1795 */ 1796 SmartCardHSM.prototype.addCACertificateToMap = function(cert, id, label) { 1797 if (!this.caidmap[label]) { 1798 // new id 1799 this.caids.push(id); 1800 this.caidmap[label] = id; 1801 } 1802 this.canamemap[label] = cert; 1803 } 1804 1805 1806 1807 /** 1808 * Enumerate key objects in the SmartCard-HSM and build the map of keys 1809 * 1810 * @type String[] 1811 * @return the list of key labels 1812 */ 1813 SmartCardHSM.prototype.enumerateKeys = function() { 1814 this.namemap = []; 1815 this.idmap = []; 1816 this.idlist = []; 1817 this.p15idmap = []; 1818 1819 var fobs = this.enumerateObjects(); 1820 1821 // Process keys 1822 for (var i = 0; i < fobs.length; i += 2) { 1823 if ((fobs.byteAt(i) == SmartCardHSM.KEYPREFIX) || (fobs.byteAt(i) == 0xFF)) { 1824 var kid = fobs.byteAt(i + 1); 1825 if (kid > 0) { 1826 // GPSystem.trace("Found key: " + kid); 1827 var key = new SmartCardHSMKey(this, kid); 1828 this.idmap[kid] = key; 1829 this.idlist.push(kid); 1830 this.updateKey(key); 1831 } 1832 } 1833 } 1834 1835 var keylist = []; 1836 // Process PKCS#15 private key descriptions 1837 for (var i = 0; i < fobs.length; i += 2) { 1838 if (fobs.byteAt(i) == SmartCardHSM.PRKDPREFIX) { 1839 var kid = fobs.byteAt(i + 1); 1840 var descbin = this.readBinary(fobs.bytes(i, 2)); 1841 if (descbin.length > 2) { 1842 try { 1843 var desc = new ASN1(descbin); 1844 if (desc.elements < 3) { 1845 continue; 1846 } 1847 } 1848 catch(e) { 1849 continue; 1850 } 1851 var key = this.idmap[kid]; 1852 if (key) { 1853 key.setDescription(desc); 1854 var label = key.getLabel(); 1855 // GPSystem.trace(key.getId() + " - " + label); 1856 if (label) { 1857 keylist.push(label); 1858 this.namemap[label] = key; 1859 } 1860 var p15id = key.getPKCS15Id(); 1861 this.p15idmap[p15id.toString(HEX)] = key; 1862 } 1863 } 1864 } 1865 } 1866 1867 return keylist; 1868 } 1869 1870 1871 1872 /** 1873 * Get key ids 1874 * 1875 * @type Number[] 1876 * @return a list of key identifier 1877 */ 1878 SmartCardHSM.prototype.getKeyIds = function() { 1879 if (typeof(this.idlist) == "undefined") { 1880 this.enumerateKeys(); 1881 } 1882 return this.idlist; 1883 } 1884 1885 1886 1887 /** 1888 * Determine an unused key identifier 1889 * 1890 * @type Number 1891 * @return a free key identifier or -1 if all key identifier in use 1892 */ 1893 SmartCardHSM.prototype.determineFreeKeyId = function() { 1894 if (typeof(this.idlist) == "undefined") { 1895 this.enumerateKeys(); 1896 } 1897 for (var i = 1; i < 256; i++) { 1898 if (this.idmap[i] == undefined) { 1899 return i; 1900 } 1901 } 1902 throw new GPError("SmartCardHSM", GPError.OUT_OF_MEMORY, 1, "Key idx exhausted"); 1903 } 1904 1905 1906 1907 /** 1908 * Update key attributes, in particular the use counter 1909 * 1910 * @param {HSMKey} key the HSM key 1911 */ 1912 SmartCardHSM.prototype.updateKey = function(key) { 1913 var fid = ByteString.valueOf((SmartCardHSM.KEYPREFIX << 8) + key.getId()); 1914 try { 1915 var fcp = this.selectFile(fid); 1916 } 1917 catch(e) { 1918 return; 1919 } 1920 var a = new ASN1(fcp); 1921 var pi = a.find(0xA5); 1922 if (!pi) { 1923 return; 1924 } 1925 var kc = pi.find(0x90); 1926 if (kc) { 1927 var c = kc.value.toUnsigned(); 1928 1929 if (c != 0xFFFFFFFF) { 1930 key.useCounter = c; 1931 } 1932 } 1933 1934 var kd = pi.find(0x91); 1935 if (kd) { 1936 key.algorithms = kd.value; 1937 } 1938 1939 var kd = pi.find(0x92); 1940 if (kd) { 1941 key.keyDomain = kd.value.toUnsigned(); 1942 } 1943 } 1944 1945 1946 1947 /** 1948 * Add a new key to the map of keys 1949 * 1950 * @param {HSMKey} key the HSM key 1951 */ 1952 SmartCardHSM.prototype.addKeyToMap = function(key) { 1953 var id = key.getId(); 1954 this.idmap[id] = key; 1955 1956 var label = key.getLabel(); 1957 if (label) { 1958 this.namemap[label] = key; 1959 } 1960 1961 var p15id = key.getPKCS15Id(); 1962 if (p15id) { 1963 this.p15idmap[p15id.toString(HEX)] = key; 1964 } 1965 } 1966 1967 1968 1969 /** 1970 * Get a key reference object 1971 * 1972 * @param {String/Number/ByteString} labelOrId label or id of key 1973 * @returns the key or null if not found 1974 * @type Key 1975 */ 1976 SmartCardHSM.prototype.getKey = function(labelOrId) { 1977 if (typeof(this.idlist) == "undefined") { 1978 this.enumerateKeys(); 1979 } 1980 1981 if (typeof(labelOrId) == "number") { 1982 var key = this.idmap[labelOrId]; 1983 } else if (typeof(labelOrId) == "string") { 1984 var key = this.namemap[labelOrId]; 1985 } else { 1986 var key = this.p15idmap[labelOrId.toString(HEX)]; 1987 } 1988 1989 if (key == undefined) { 1990 return null; 1991 } 1992 return key; 1993 } 1994 1995 1996 1997 /** 1998 * Return a list of key objects 1999 * 2000 * @type SmartCardHSMKey[] 2001 * @return the list of keys 2002 */ 2003 SmartCardHSM.prototype.getKeys = function() { 2004 if (typeof(this.idlist) == "undefined") { 2005 this.enumerateKeys(); 2006 } 2007 2008 var keylist = []; 2009 for (var i in this.idmap) { 2010 keylist.push(this.idmap[i]); 2011 } 2012 return keylist; 2013 } 2014 2015 2016 2017 /** 2018 * Get crypto object 2019 * 2020 * @type HSMCrypto 2021 * @return the HSMCrypto object 2022 */ 2023 SmartCardHSM.prototype.getCrypto = function() { 2024 if (this.crypto == undefined) { 2025 this.crypto = new SmartCardHSMCrypto(new Crypto()); 2026 } 2027 return this.crypto; 2028 } 2029 2030 2031 2032 /** 2033 * @private 2034 */ 2035 SmartCardHSM.prototype.getTokenInfo = function() { 2036 if (this.tokenInfo != undefined) { 2037 return this.tokenInfo; 2038 } 2039 2040 if (!this.hasFile(SmartCardHSM.EF_TokenInfo)) { 2041 return; 2042 } 2043 2044 var bin = this.readBinary(SmartCardHSM.EF_TokenInfo); 2045 this.tokenInfo = new ASN1(bin); 2046 return this.tokenInfo; 2047 } 2048 2049 2050 2051 /** 2052 * Get Token Label 2053 * 2054 * @type String 2055 * @return the token label from CIAInfo 2056 */ 2057 SmartCardHSM.prototype.getLabel = function() { 2058 var ti = this.getTokenInfo(); 2059 if (!ti) { 2060 return; 2061 } 2062 2063 var a = ti.find(0x80); 2064 if (!a) { 2065 return; 2066 } 2067 return a.value.toString(UTF8); 2068 } 2069 2070 2071 2072 /** 2073 * @private 2074 */ 2075 SmartCardHSM.prototype.getStaticTokenInfo = function() { 2076 if (this.staticTokenInfo != undefined) { 2077 return this.staticTokenInfo; 2078 } 2079 2080 if (!this.hasFile(SmartCardHSM.EF_StaticTokenInfo)) { 2081 return; 2082 } 2083 2084 var bin = this.readBinary(SmartCardHSM.EF_StaticTokenInfo); 2085 this.staticTokenInfo = new ASN1(bin); 2086 return this.staticTokenInfo; 2087 } 2088 2089 2090 2091 /** 2092 * Get ProvisioningURL 2093 * 2094 * @type String 2095 * @return the configured ProvisioningURL or undefined 2096 */ 2097 SmartCardHSM.prototype.getProvisioningURL = function() { 2098 var ti = this.getStaticTokenInfo(); 2099 if (!ti) { 2100 return; 2101 } 2102 2103 var a = ti.find(0x80); 2104 if (!a) { 2105 return; 2106 } 2107 return a.value.toString(UTF8); 2108 } 2109 2110 2111 2112 /** 2113 * Get Key Check Value of Token Management Key 2114 * 2115 * @type ByteString 2116 * @return the configured KCV of the Token Management Key or undefined 2117 */ 2118 SmartCardHSM.prototype.getTokenManagementKeyKCV = function() { 2119 var ti = this.getStaticTokenInfo(); 2120 if (!ti) { 2121 return; 2122 } 2123 2124 var a = ti.find(0x81); 2125 if (!a) { 2126 return; 2127 } 2128 return a.value; 2129 } 2130 2131 2132 2133 /** 2134 * Get salt for SO-PIN derivation using the Token Management Key 2135 * 2136 * @type ByteString 2137 * @return the configured salt 2138 */ 2139 SmartCardHSM.prototype.getTokenManagementKeySalt = function() { 2140 var ti = this.getStaticTokenInfo(); 2141 if (!ti) { 2142 return; 2143 } 2144 2145 var a = ti.find(0x82); 2146 if (!a) { 2147 return; 2148 } 2149 return a.value; 2150 } 2151 2152 2153 2154 /** 2155 * Create crypto object implementing access to the SmartCard-HSM 2156 * 2157 * @class Wrapper to provide Crypto interface to SmartCard-HSM 2158 * @constructor 2159 * @param {Crypto} crypto the backend crypto provider 2160 */ 2161 function SmartCardHSMCrypto(crypto) { 2162 this.crypto = crypto; 2163 } 2164 2165 2166 2167 /** 2168 * Sign a message using the defined mechanism and key 2169 * 2170 * @param {HSMKey} key the private key 2171 * @param {Number} mech the mechanism (e.g. Crypto.ECDSA) 2172 * @param {ByteString} message the message to be signed 2173 * @type ByteString 2174 * @return the signature 2175 */ 2176 SmartCardHSMCrypto.prototype.sign = function(key, mech, message) { 2177 if (key instanceof SmartCardHSMKey) { 2178 return key.sign(mech, message); 2179 } else { 2180 return this.crypto.sign(key, mech, message); 2181 } 2182 } 2183 2184 2185 2186 /** 2187 * Decrypt a message using the defined mechanism and key 2188 * 2189 * @param {HSMKey} key the private key 2190 * @param {Number} mech the mechanism (e.g. Crypto.RSA_PKCS1) 2191 * @param {ByteString} data the cryptogram 2192 * @param {ByteString} iv the initialization vector for symmetric ciphers 2193 * @type ByteString 2194 * @return the plain text 2195 */ 2196 SmartCardHSMCrypto.prototype.decrypt = function(key, mech, data, iv) { 2197 if (key instanceof SmartCardHSMKey) { 2198 return key.decrypt(mech, data); 2199 } else { 2200 return this.crypto.decrypt(key, mech, data, iv); 2201 } 2202 } 2203 2204 2205 2206 /** 2207 * Verify a message using the defined mechanism and key 2208 * 2209 * @param {Key} key the public key 2210 * @param {Number} mech the mechanism (e.g. Crypto.ECDSA) 2211 * @param {ByteString} message the message to be signed 2212 * @param {ByteString} signature the signature to verify 2213 * @type Boolean 2214 * @return true if signature is valid 2215 */ 2216 SmartCardHSMCrypto.prototype.verify = function(key, mech, message, signature) { 2217 return this.crypto.verify(key, mech, message, signature); 2218 } 2219 2220 2221 2222 /** 2223 * Create a key access object 2224 * 2225 * @class Class implementing key access 2226 * @param {SmartCardHSM} sc the card access object 2227 * @param {Number} id the key identifier 2228 */ 2229 function SmartCardHSMKey(sc, id) { 2230 this.sc = sc; 2231 this.id = id; 2232 if (this.sc.useExternalHashInECDSA) { 2233 this.crypto = new Crypto(); 2234 } 2235 } 2236 2237 exports.SmartCardHSMKey = SmartCardHSMKey; 2238 2239 2240 /** 2241 * Set the PKCS#15 private key description 2242 * 2243 * @param {ASN1} desc the description 2244 */ 2245 SmartCardHSMKey.prototype.setDescription = function(desc) { 2246 this.desc = desc; 2247 } 2248 2249 2250 2251 /** 2252 * Return the key identifier 2253 * 2254 * @type Number 2255 * @return the key identifier 2256 */ 2257 SmartCardHSMKey.prototype.getId = function() { 2258 return this.id; 2259 } 2260 2261 2262 2263 /** 2264 * Return the key label as encoded in the PKCS#15 structure 2265 * 2266 * @type String 2267 * @return the key label 2268 */ 2269 SmartCardHSMKey.prototype.getLabel = function() { 2270 if (this.desc == undefined) { 2271 return undefined; 2272 } 2273 if ((this.desc.get(0).elements == 0) || this.desc.get(0).get(0).tag != 0x0C) { 2274 return undefined; 2275 } 2276 2277 return this.desc.get(0).get(0).value.toString(UTF8); 2278 } 2279 2280 2281 2282 /** 2283 * Return the key id as encoded in the PKCS#15 structure 2284 * 2285 * @type ByteString 2286 * @return the key identifier 2287 */ 2288 SmartCardHSMKey.prototype.getPKCS15Id = function() { 2289 if (this.desc == undefined) { 2290 return undefined; 2291 } 2292 return this.desc.get(1).get(0).value; 2293 } 2294 2295 2296 2297 /** 2298 * Return the key size in bits 2299 * 2300 * @type Number 2301 * @return the key size in bits 2302 */ 2303 SmartCardHSMKey.prototype.getSize = function() { 2304 if (this.desc == undefined) { 2305 return undefined; 2306 } 2307 // GPSystem.trace(this.desc); 2308 if (this.desc.get(2).elements > 1) { // Fix a bug from early versions 2309 return this.desc.get(2).get(1).value.toUnsigned(); 2310 } else { 2311 return this.desc.get(2).get(0).get(1).value.toUnsigned(); 2312 } 2313 } 2314 2315 2316 2317 /** 2318 * Return the key size in bits 2319 * 2320 * @type Number 2321 * @return the key size in bits 2322 */ 2323 SmartCardHSMKey.prototype.getType = function() { 2324 if (this.desc == undefined) { 2325 return undefined; 2326 } 2327 2328 if (this.desc.tag == 0xA0) { 2329 return "EC"; 2330 } else if (this.desc.tag == 0x30) { 2331 return "RSA"; 2332 } else if (this.desc.tag == 0xA8) { 2333 return "AES"; 2334 } 2335 2336 return undefined; 2337 } 2338 2339 2340 2341 /** 2342 * Sign data using a key in the SmartCard-HSM 2343 * 2344 * @param {Number} mech the signing mechanism 2345 * @param {ByteString} data to be signed 2346 * @type ByteString 2347 * @return the signature 2348 */ 2349 SmartCardHSMKey.prototype.sign = function(mech, data) { 2350 var algo; 2351 if (mech) { 2352 switch(mech) { 2353 case Crypto.RSA: 2354 algo = 0x20; 2355 break; 2356 case Crypto.RSA_SHA1: 2357 algo = 0x31; 2358 break; 2359 case Crypto.RSA_SHA256: 2360 algo = 0x33; 2361 break; 2362 case Crypto.RSA_PKCS1: 2363 algo = 0x20; 2364 var keysize = this.getSize(); 2365 if (!keysize) { 2366 throw new GPError(module.id, GPError.INVALID_DATA, 0, "Can't determine key size"); 2367 } 2368 data = PKCS1.encode_EMSA_V15(keysize, data); 2369 break; 2370 // case Crypto.RSA_PSS: 2371 case 0x80: 2372 algo = 0x40; 2373 break; 2374 case Crypto.RSA_PSS_SHA1: 2375 algo = 0x41; 2376 break; 2377 case Crypto.RSA_PSS_SHA256: 2378 algo = 0x43; 2379 break; 2380 case Crypto.ECDSA: 2381 algo = 0x70; 2382 break; 2383 case Crypto.ECDSA_SHA1: 2384 if (this.sc.useExternalHashInECDSA) { 2385 algo = 0x70; 2386 var data = this.crypto.digest(Crypto.SHA_1, data); 2387 } else { 2388 algo = 0x71; 2389 } 2390 break; 2391 case Crypto.ECDSA_SHA224: 2392 if (this.sc.useExternalHashInECDSA) { 2393 algo = 0x70; 2394 var data = this.crypto.digest(Crypto.SHA_224, data); 2395 } else { 2396 algo = 0x72; 2397 } 2398 break; 2399 case Crypto.ECDSA_SHA256: 2400 if (this.sc.useExternalHashInECDSA) { 2401 algo = 0x70; 2402 var data = this.crypto.digest(Crypto.SHA_256, data); 2403 } else { 2404 algo = 0x73; 2405 } 2406 break; 2407 case Crypto.AES_CMAC: 2408 return this.sc.deriveSymmetricKey(this.id, SmartCardHSM.ALG_CMAC, data); 2409 default: 2410 throw new GPError("SmartCardHSMKey", GPError.INVALID_DATA, mech, "Unsupported crypto mechanism"); 2411 } 2412 } 2413 2414 return this.sc.sign(this.id, algo, data); 2415 } 2416 2417 2418 2419 /** 2420 * Decrypt data using a key in the SmartCard-HSM 2421 * 2422 * @param {Number} mech the decipher mechanism 2423 * @param {ByteString} data to be deciphered 2424 * @type ByteString 2425 * @return the plain message 2426 */ 2427 SmartCardHSMKey.prototype.decrypt = function(mech, data) { 2428 var algo; 2429 if (mech) { 2430 switch(mech) { 2431 case Crypto.RSA: 2432 break; 2433 case Crypto.RSA_PKCS1: 2434 break; 2435 case Crypto.RSA_OAEP_SHA224: 2436 algo = Crypto.SHA_224; 2437 break; 2438 case Crypto.RSA_OAEP_SHA256: 2439 algo = Crypto.SHA_256; 2440 break; 2441 case Crypto.RSA_OAEP_SHA384: 2442 algo = Crypto.SHA_384; 2443 break; 2444 case Crypto.RSA_OAEP_SHA512: 2445 algo = Crypto.SHA_512; 2446 break; 2447 default: 2448 throw new GPError("SmartCardHSMKey", GPError.INVALID_DATA, mech, "Unsupported crypto mechanism"); 2449 } 2450 } 2451 2452 var em = this.sc.decipher(this.id, 0x21, data); 2453 2454 var plain = em; 2455 2456 if (mech != Crypto.RSA) { 2457 if (mech == Crypto.RSA_PKCS1) { 2458 var plain = PKCS1.decode_EME_V15(em); 2459 } else { 2460 var crypto = this.sc.getCrypto().crypto; 2461 2462 var plain = PKCS1.decode_EME_OAEP(crypto, null, algo, em); 2463 } 2464 2465 if (!plain) { 2466 throw new GPError("SmartCardHSMKey", GPError.CRYPTO_FAILED, mech, "Decryption failed"); 2467 } 2468 } 2469 2470 return plain; 2471 } 2472 2473 2474 2475 /** 2476 * Return human readable string 2477 */ 2478 SmartCardHSMKey.prototype.toString = function() { 2479 return "SmartCardHSMKey(id=" + this.id + ")"; 2480 } 2481 2482 2483 2484 /** 2485 * Initialize SmartCard-HSM 2486 * 2487 * @class Class implementing the device initialization methods 2488 * @param {Card} card the card object 2489 */ 2490 function SmartCardHSMInitializer(card) { 2491 this.card = card; 2492 this.initializationCode = new ByteString("57621880", ASCII); 2493 this.userPIN = new ByteString("648219", ASCII); 2494 this.userPINSet = false; 2495 this.useDefaultUserPIN = true; 2496 this.retryCounterInitial = 3; 2497 this.options = 0x0001; 2498 this.keyshares = -1; 2499 this.keyDomains = -1; 2500 this.numberOfPublicKeys = 0; 2501 this.requiredPublicKeysForAuthentication = 0; 2502 this.bioslot = []; 2503 this.label = undefined; 2504 } 2505 2506 exports.SmartCardHSMInitializer = SmartCardHSMInitializer; 2507 2508 2509 2510 /** 2511 * Set the initialization code 2512 * 2513 * @param {ByteString} initializationCode an 8 byte code 2514 */ 2515 SmartCardHSMInitializer.prototype.setInitializationCode = function(initializationCode) { 2516 if (!(initializationCode instanceof ByteString)) { 2517 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "initializationCode must be a ByteString"); 2518 } 2519 if (initializationCode.length != 8) { 2520 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "initializationCode must have 8 bytes"); 2521 } 2522 2523 this.initializationCode = initializationCode; 2524 } 2525 2526 2527 2528 /** 2529 * Set the User PIN 2530 * 2531 * @param {ByteString} userPIN a 6 to 16 byte code 2532 */ 2533 SmartCardHSMInitializer.prototype.setUserPIN = function(userPIN) { 2534 if (!(userPIN instanceof ByteString)) { 2535 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "userPIN must be a ByteString"); 2536 } 2537 if ((userPIN.length < 6) || (userPIN.length > 16)) { 2538 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "userPIN must be between 6 and 16 bytes"); 2539 } 2540 2541 this.userPIN = userPIN; 2542 this.userPINSet = true; 2543 this.useDefaultUserPIN = false; 2544 } 2545 2546 2547 2548 /** 2549 * Set the retry counter 2550 * 2551 * The SmartCard-HSM enforces a retry counter <= 3 for PIN length 6 2552 * The SmartCard-HSM enforces a retry counter <= 5 for PIN length 7 2553 * The SmartCard-HSM enforces a retry counter <= 10 for PIN length larger than 7 2554 * 2555 * @param {Number} retryCounterInitial in the range 1 to 10. 2556 */ 2557 SmartCardHSMInitializer.prototype.setRetryCounterInitial = function(retryCounterInitial) { 2558 if (typeof(retryCounterInitial) != "number") { 2559 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "retryCounterInitial must be a number"); 2560 } 2561 if ((retryCounterInitial < 1) || (retryCounterInitial > 10)) { 2562 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "retryCounterInitial must be between 1 and 10"); 2563 } 2564 this.retryCounterInitial = retryCounterInitial; 2565 } 2566 2567 2568 2569 /** 2570 * Set the number of DKEK shares 2571 * 2572 * @param {Number} keyshares number of DKEK shares in the range 0 to 255 2573 */ 2574 SmartCardHSMInitializer.prototype.setDKEKShares = function(keyshares) { 2575 if (typeof(keyshares) != "number") { 2576 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyshares must be a number"); 2577 } 2578 if ((keyshares < 0) || (keyshares > 255)) { 2579 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyshares must be between 0 and 255"); 2580 } 2581 this.keyshares = keyshares; 2582 this.keyDomains = -1; 2583 } 2584 2585 2586 2587 /** 2588 * Set the number of key domains 2589 * 2590 * @param {Number} keyDomains number of key domains 2591 */ 2592 SmartCardHSMInitializer.prototype.setKeyDomains = function(keyDomains) { 2593 if (typeof(keyDomains) != "number") { 2594 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyDomains must be a number"); 2595 } 2596 2597 this.keyDomains = keyDomains; 2598 this.keyshares = -1; 2599 } 2600 2601 2602 2603 /** 2604 * Enable or disable RESET RETRY COUNTER command 2605 * 2606 * @param {Boolean} enable true (default) to allow RESET RETRY COUNTER command to reset user PIN using the initialization code 2607 */ 2608 SmartCardHSMInitializer.prototype.setResetRetryCounterMode = function(enable) { 2609 if (typeof(enable) == "undefined") { 2610 var enable = false; 2611 } 2612 2613 this.options = (this.options & 0xFFFE) + (enable ? 1 : 0); 2614 } 2615 2616 2617 2618 /** 2619 * Enable or disable transport PIN mode 2620 * 2621 * @param {Boolean} enable true (non-default) to set user PIN to transport state 2622 */ 2623 SmartCardHSMInitializer.prototype.setTransportPINMode = function(enable) { 2624 if (typeof(enable) == "undefined") { 2625 var enable = true; 2626 } 2627 2628 this.options = (this.options & 0xFFFD) + (enable ? 2 : 0); 2629 } 2630 2631 2632 2633 /** 2634 * Enable or disable session PIN mode 2635 * 2636 * @param {Number} 0 - disable, 1 - enable with clear-on-reset 3 - enable with explicit clearing 2637 */ 2638 SmartCardHSMInitializer.prototype.setSessionPINMode = function(mode) { 2639 assert(typeof(mode) == "number", "Argument mode must be number"); 2640 assert(mode >= 0 && mode <= 3 && mode != 2, "Argument mode must be 0, 1 or 3"); 2641 2642 this.options = (this.options & 0xFFF3) + (mode << 2); 2643 } 2644 2645 2646 2647 /** 2648 * Enable or disable replacing of a PKA key 2649 * 2650 * @param {Boolean} enable true (non-default) to allow replacing of a PKA key 2651 */ 2652 SmartCardHSMInitializer.prototype.setReplacePKAKeyMode = function(enable) { 2653 if (typeof(enable) == "undefined") { 2654 var enable = false; 2655 } 2656 2657 this.options = (this.options & 0xFFF7) + (enable ? 8 : 0); 2658 } 2659 2660 2661 2662 /** 2663 * Enable the combined authentication mode of user pin and public key authentication. 2664 * 2665 * @param {Boolean} enable true (non-default) to require public key authentication and user authentication 2666 */ 2667 SmartCardHSMInitializer.prototype.setCombinedAuthenticationMode = function(enable) { 2668 if (typeof(enable) == "undefined") { 2669 var enable = false; 2670 } 2671 2672 this.options = (this.options & 0xFFEF) + (enable ? 16 : 0); 2673 } 2674 2675 2676 2677 /** 2678 * If enabled RESET RETRY COUNTER only resets the error counter. 2679 * Otherwise RRC allows changing the PIN 2680 * 2681 * @param {Boolean} resetOnly true to only reset the error counter, false otherwise (default) 2682 */ 2683 SmartCardHSMInitializer.prototype.setResetRetryCounterResetOnlyMode = function(resetOnly) { 2684 if (typeof(resetOnly) == "undefined") { 2685 var resetOnly = false; 2686 } 2687 2688 this.options = (this.options & 0xFFDF) + (resetOnly ? 32 : 0); 2689 } 2690 2691 2692 2693 /** 2694 * Set parameter for public key authentication with n-of-m scheme, namely the values for n and m 2695 * 2696 * @param {Number} requiredPublicKeysForAuthentication number of key that must be authenticated for access 2697 * @param {Number} numberOfPublicKeys to register 2698 */ 2699 SmartCardHSMInitializer.prototype.setPublicKeyAuthenticationParameter = function(requiredPublicKeysForAuthentication, numberOfPublicKeys) { 2700 if ((numberOfPublicKeys < 1) || (numberOfPublicKeys > 90)) { 2701 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "numberOfPublicKeys must be between 1 and 90"); 2702 } 2703 if ((requiredPublicKeysForAuthentication < 1) || (requiredPublicKeysForAuthentication > numberOfPublicKeys)) { 2704 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 2, "requiredPublicKeysForAuthentication must be between 1 and " + numberOfPublicKeys); 2705 } 2706 this.numberOfPublicKeys = numberOfPublicKeys; 2707 this.requiredPublicKeysForAuthentication = requiredPublicKeysForAuthentication; 2708 this.useDefaultUserPIN = false; 2709 } 2710 2711 2712 2713 /** 2714 * Select the biometric matching server for a one of the biometric templates 2715 * 2716 * @param {Number} slot either 0 or 1 for first or second template 2717 * @param {ByteString} aid the application identifier of the on-card biometric server 2718 * @param {Number} param one byte parameter passed to the server during initialization 2719 */ 2720 SmartCardHSMInitializer.prototype.setBioTemplate = function(slot, aid, param) { 2721 assert(typeof(slot) == "number", "slot must be a number"); 2722 assert(slot >= 0 && slot <= 1, "slot must be either 0 or 1"); 2723 assert(aid instanceof ByteString, "aid must be a ByteString"); 2724 assert(typeof(param) == "number", "param must be a number"); 2725 assert(param >= 0 && param <= 255, "param must be between 0 and 255"); 2726 2727 this.bioslot[slot] = { aid: aid, param: param }; 2728 this.useDefaultUserPIN = false; 2729 } 2730 2731 2732 2733 /** 2734 * Set the label to be written to a minimal CIAInfo in EF 2F03 2735 * 2736 * @param {String} label the label 2737 */ 2738 SmartCardHSMInitializer.prototype.setLabel = function(label) { 2739 this.label = label; 2740 } 2741 2742 2743 2744 /** 2745 * Set the provisioning URL to be written to fixed parameter in CB00. 2746 * 2747 * @param {String} provisioningURL the URL at which this SE will be provisioned 2748 */ 2749 SmartCardHSMInitializer.prototype.setProvisioningURL = function(provisioningURL) { 2750 this.provisioningURL = provisioningURL; 2751 } 2752 2753 2754 2755 /** 2756 * Set the key check value of the token management key and the optional salt 2757 * used for SO-PIN derivation 2758 * 2759 * @param {ByteString} kcv the key check value of the token management key 2760 * @param {ByteString} salt the salt used to derive the SO-PIN 2761 */ 2762 SmartCardHSMInitializer.prototype.setTokenManagementKey = function(kcv, salt) { 2763 this.tokenManagementKeyKCV = kcv; 2764 this.tokenManagementKeySalt = salt; 2765 } 2766 2767 2768 2769 /** 2770 * Perform Initialization 2771 */ 2772 SmartCardHSMInitializer.prototype.initialize = function() { 2773 var s = new ASN1(0x30, new ASN1(0x80, ByteString.valueOf(this.options, 2))); 2774 2775 if (this.userPINSet || this.useDefaultUserPIN) { 2776 s.add(new ASN1(0x81, this.userPIN)); 2777 } 2778 2779 s.add(new ASN1(0x82, this.initializationCode)); 2780 2781 if (this.userPINSet || this.useDefaultUserPIN) { 2782 s.add(new ASN1(0x91, ByteString.valueOf(this.retryCounterInitial))); 2783 } 2784 2785 if (this.keyshares != -1) { 2786 s.add(new ASN1(0x92, ByteString.valueOf(this.keyshares))); 2787 } 2788 2789 if (this.keyDomains != -1) { 2790 s.add(new ASN1(0x97, ByteString.valueOf(this.keyDomains))); 2791 } 2792 2793 if (this.numberOfPublicKeys > 0) { 2794 s.add(new ASN1(0x93, ByteString.valueOf(this.numberOfPublicKeys).concat(ByteString.valueOf(this.requiredPublicKeysForAuthentication)))); 2795 } 2796 2797 if (this.bioslot[0]) { 2798 var o = this.bioslot[0]; 2799 s.add(new ASN1(0x95, ByteString.valueOf(o.param).concat(o.aid))); 2800 } 2801 2802 if (this.bioslot[1]) { 2803 var o = this.bioslot[1]; 2804 s.add(new ASN1(0x96, ByteString.valueOf(o.param).concat(o.aid))); 2805 } 2806 2807 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000, 0x6A84]); 2808 2809 if (this.card.SW == 0x6A84) { 2810 // Due to the nature of the JCRE, a first call to initialize may run out of memory, 2811 // as the garbage collector for the removed objects is only run during the next 2812 // APDU invocation. 2813 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000]); 2814 } 2815 2816 if (this.label) { 2817 var a = new ASN1(0x30, 2818 new ASN1(0x54, new ByteString("0000", HEX)), 2819 new ASN1(0x53, 2820 new ASN1(0x30, 2821 new ASN1(0x02, new ByteString("00", HEX)), 2822 new ASN1(0x80, new ByteString(this.label, UTF8)), 2823 new ASN1(0x03, new ByteString("0500", HEX))) 2824 ) 2825 ); 2826 2827 var p1 = SmartCardHSM.EF_TokenInfo.byteAt(0); 2828 var p2 = SmartCardHSM.EF_TokenInfo.byteAt(1); 2829 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, p1, p2, a.value, [0x9000]); 2830 } 2831 2832 if (this.provisioningURL || this.tokenManagementKeyKCV || this.tokenManagementKeySalt) { 2833 var l = new ASN1(ASN1.SEQUENCE); 2834 if (this.provisioningURL) { 2835 l.add(new ASN1(0x80, new ByteString(this.provisioningURL, UTF8))); 2836 } 2837 if (this.tokenManagementKeyKCV) { 2838 l.add(new ASN1(0x81, this.tokenManagementKeyKCV)); 2839 } 2840 if (this.tokenManagementKeySalt) { 2841 l.add(new ASN1(0x82, this.tokenManagementKeySalt)); 2842 } 2843 2844 var a = new ASN1(0x30, 2845 new ASN1(0x54, new ByteString("0000", HEX)), 2846 new ASN1(0x53, l) 2847 ); 2848 2849 var p1 = SmartCardHSM.EF_StaticTokenInfo.byteAt(0); 2850 var p2 = SmartCardHSM.EF_StaticTokenInfo.byteAt(1); 2851 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, p1, p2, a.value, [0x9000]); 2852 } 2853 } 2854 2855 2856 2857 /** 2858 * Create a key specification generator instance 2859 * 2860 * @class Class implementing an encoder for the C-Data required in GENERATE ASYMMETRIC KEY PAIR 2861 * @param {Number} keytype must be either Crypto.RSA, Crypto.EC or Crypto.AES 2862 * @param {Number/Key} keysizeOrDP must be 1024, 1536, 2048, 3072 or 4096 for RSA, 128, 192 or 256 for AES and key object with Key.ECC_CURVE_OID set for EC 2863 */ 2864 function SmartCardHSMKeySpecGenerator(keytype, keysizeOrDP) { 2865 this.keytype = keytype; 2866 2867 switch(keytype) { 2868 case Crypto.RSA: 2869 if (typeof(keysizeOrDP) != "number") { 2870 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be of a number for RSA keys"); 2871 } 2872 this.keysize = keysizeOrDP; 2873 this.defaultAlgo = new ByteString("id-TA-RSA-v1-5-SHA-256", OID); 2874 break; 2875 case Crypto.EC: 2876 if ((typeof(keysizeOrDP) != "object") || !(keysizeOrDP instanceof Key)) { 2877 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be a Key instance"); 2878 } 2879 this.domainParameter = keysizeOrDP; 2880 this.defaultAlgo = new ByteString("id-TA-ECDSA-SHA-256", OID); 2881 break; 2882 case Crypto.AES: 2883 if (typeof(keysizeOrDP) != "number") { 2884 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be of a number for AES keys"); 2885 } 2886 this.keysize = keysizeOrDP; 2887 break; 2888 default: 2889 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keytype must be Crypto.RSA or Crypto.EC"); 2890 } 2891 this.CHR = new PublicKeyReference("UTDUMMY00001"); 2892 this.innerCAR = new PublicKeyReference("UTDUMMY00001"); 2893 } 2894 2895 exports.SmartCardHSMKeySpecGenerator = SmartCardHSMKeySpecGenerator; 2896 2897 2898 2899 /** 2900 * Set key use counter for key 2901 * 2902 * @param {keyUseCounter} keyUseCounter in the range 1 to 2^64 - 2 2903 */ 2904 SmartCardHSMKeySpecGenerator.prototype.setKeyUseCounter = function(keyUseCounter) { 2905 if ((keyUseCounter < 0) || (keyUseCounter >= 0xFFFFFFFF)) { 2906 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 1, "keyUseCounter must be between 0 and 0xFFFFFFFF"); 2907 } 2908 this.keyUseCounter = keyUseCounter; 2909 } 2910 2911 2912 2913 /** 2914 * Set key domain 2915 * 2916 * @param {Number} keyDomain the key domain to which the key shall be added 2917 */ 2918 SmartCardHSMKeySpecGenerator.prototype.setKeyDomain = function(keyDomain) { 2919 this.keyDomain = keyDomain; 2920 } 2921 2922 2923 2924 /** 2925 * Set wrapping key 2926 * 2927 * @param {Number} wrappingKey the key to used for wrapping a newly generated symmetric key 2928 */ 2929 SmartCardHSMKeySpecGenerator.prototype.setWrappingKey = function(wrappingKey) { 2930 this.wrappingKey = wrappingKey; 2931 } 2932 2933 2934 2935 /** 2936 * Set algorithm list 2937 * 2938 * @param {ByteString} algorithms the list of algorithms allowed for this key 2939 */ 2940 SmartCardHSMKeySpecGenerator.prototype.setAlgorithms = function(algorithms) { 2941 this.algorithms = algorithms; 2942 } 2943 2944 2945 2946 /** 2947 * Set certificate holder reference for key 2948 * 2949 * @param {PublicKeyReference} CHR certificate holder reference 2950 */ 2951 SmartCardHSMKeySpecGenerator.prototype.setCHR = function(CHR) { 2952 this.CHR = CHR; 2953 } 2954 2955 2956 2957 /** 2958 * Set certificate holder reference of CA this request shall be sent to 2959 * 2960 * @param {PublicKeyReference} CAR certificate holder reference 2961 */ 2962 SmartCardHSMKeySpecGenerator.prototype.setInnerCAR = function(CAR) { 2963 this.innerCAR = CAR; 2964 } 2965 2966 2967 2968 /** 2969 * Set holder reference of the key signing this request 2970 * 2971 * @param {PublicKeyReference} CAR certificate holder reference 2972 */ 2973 SmartCardHSMKeySpecGenerator.prototype.setOuterCAR = function(CAR) { 2974 this.outerCAR = CAR; 2975 } 2976 2977 2978 2979 /** 2980 * @private 2981 */ 2982 SmartCardHSMKeySpecGenerator.prototype.encodeRSAKeySpec = function() { 2983 var p = new ASN1("Public Key", 0x7F49, 2984 new ASN1("Object Identifier", 0x06, this.defaultAlgo), 2985 new ASN1("Public Key Exponent", 0x82, ByteString.valueOf(65537)), 2986 new ASN1("Key Size", 0x02, ByteString.valueOf(this.keysize)) 2987 ); 2988 return p; 2989 } 2990 2991 2992 2993 /** 2994 * @private 2995 */ 2996 SmartCardHSMKeySpecGenerator.prototype.encodeECKeySpec = function() { 2997 // Encode G 2998 var bb = new ByteBuffer(); 2999 // uncompressed encoding 3000 bb.append(new ByteString("04", HEX)); 3001 bb.append(this.domainParameter.getComponent(Key.ECC_GX)); 3002 bb.append(this.domainParameter.getComponent(Key.ECC_GY)); 3003 var G = bb.toByteString(); 3004 3005 var p = new ASN1("Public Key", 0x7F49, 3006 new ASN1("Object Identifier", 0x06, this.defaultAlgo), 3007 new ASN1("Prime Modulus", 0x81, this.domainParameter.getComponent(Key.ECC_P)), 3008 new ASN1("First coefficient a", 0x82, this.domainParameter.getComponent(Key.ECC_A)), 3009 new ASN1("Second coefficient b", 0x83, this.domainParameter.getComponent(Key.ECC_B)), 3010 new ASN1("Base Point G", 0x84, G), 3011 new ASN1("Order of the base point", 0x85, this.domainParameter.getComponent(Key.ECC_N)), 3012 new ASN1("Cofactor f", 0x87, SmartCardHSM.stripLeadingZeros(this.domainParameter.getComponent(Key.ECC_H))) 3013 ); 3014 return p; 3015 } 3016 3017 3018 3019 /** 3020 * @private 3021 */ 3022 SmartCardHSMKeySpecGenerator.prototype.encodeKeySpec = function() { 3023 if (this.keytype == Crypto.RSA) { 3024 return this.encodeRSAKeySpec(); 3025 } else { 3026 return this.encodeECKeySpec(); 3027 } 3028 } 3029 3030 3031 3032 /** 3033 * Return the encoded key specification 3034 * 3035 * @type ByteString 3036 * @return the encoded C-Data for GENERATE ASYMMETRIC KEY PAIR 3037 */ 3038 SmartCardHSMKeySpecGenerator.prototype.encode = function() { 3039 var t = new ASN1(0x30); 3040 3041 if (this.keytype != Crypto.AES) { 3042 t.add(new ASN1("CPI", 0x5F29, new ByteString("00", HEX))); 3043 3044 if ((typeof(this.innerCAR) != "undefined") && (this.innerCAR)) { 3045 t.add(new ASN1("CAR", 0x42, this.innerCAR.getBytes())); 3046 } 3047 3048 t.add(this.encodeKeySpec()); 3049 t.add(new ASN1("CHR", 0x5F20, this.CHR.getBytes())); 3050 3051 if (typeof(this.outerCAR) != "undefined") { 3052 t.add(new ASN1("OuterCAR", 0x45, this.outerCAR.getBytes())); 3053 } 3054 } 3055 3056 if (typeof(this.keyUseCounter) != "undefined") { 3057 t.add(new ASN1("Key use counter", 0x90, ByteString.valueOf(this.keyUseCounter, 4))); 3058 } 3059 3060 if (typeof(this.algorithms) != "undefined") { 3061 t.add(new ASN1("Algorithms", 0x91, this.algorithms)); 3062 } 3063 3064 if (typeof(this.keyDomain) != "undefined") { 3065 t.add(new ASN1("KeyDomain", 0x92, ByteString.valueOf(this.keyDomain))); 3066 } 3067 3068 if (typeof(this.wrappingKey) != "undefined") { 3069 t.add(new ASN1("Wrapping Key", 0x93, ByteString.valueOf(this.wrappingKey))); 3070 } 3071 3072 return t.value; 3073 } 3074 3075 3076 3077 /** 3078 * Create a key specification generator instance for AES keys 3079 * 3080 * @class Class implementing an encoder for the C-Data required in Generate Symmetric Key 3081 * @param {ByteString} allowedAlgorithms the list of allowed algorithm identifier 3082 */ 3083 function SmartCardHSMSymmetricKeySpecGenerator(allowedAlgorithms) { 3084 this.algorithms = allowedAlgorithms; 3085 } 3086 3087 exports.SmartCardHSMSymmetricKeySpecGenerator = SmartCardHSMSymmetricKeySpecGenerator; 3088 3089 3090 3091 /** 3092 * Set key domain 3093 * 3094 * @param {Number} keyDomain the key domain to which the key shall be added 3095 */ 3096 SmartCardHSMSymmetricKeySpecGenerator.prototype.setKeyDomain = function(keyDomain) { 3097 this.keyDomain = keyDomain; 3098 } 3099 3100 3101 3102 /** 3103 * Return the encoded AES key specification 3104 * 3105 * @type ByteString 3106 * @return the encoded C-Data for Generate Symmetric Key 3107 */ 3108 SmartCardHSMSymmetricKeySpecGenerator.prototype.encode = function() { 3109 var t = new ASN1(0x30); 3110 3111 t.add(new ASN1("Algorithms", 0x91, this.algorithms)); 3112 3113 if (typeof(this.keyUseCounter) != "undefined") { 3114 t.add(new ASN1("Key use counter", 0x90, ByteString.valueOf(this.keyUseCounter, 4))); 3115 } 3116 3117 if (typeof(this.keyDomain) != "undefined") { 3118 t.add(new ASN1("Key Domain", 0x92, ByteString.valueOf(this.keyDomain))); 3119 } 3120 3121 if (typeof(this.wrappingKey) != "undefined") { 3122 t.add(new ASN1("Wrapping Key", 0x93, this.wrappingKey)); 3123 } 3124 3125 return t.value; 3126 } 3127 3128 3129 3130 SmartCardHSM.test = function() { 3131 var crypto = new Crypto(); 3132 var card = new Card(_scsh3.reader); 3133 var sc = new SmartCardHSM(card); 3134 3135 var sci = new SmartCardHSMInitializer(card); 3136 sci.initialize(); 3137 3138 var pubKey = sc.validateCertificateChain(crypto); 3139 sc.openSecureChannel(crypto, pubKey); 3140 3141 sc.verifyUserPIN(sci.userPIN); 3142 3143 var kg = new SmartCardHSMKeySpecGenerator(Crypto.RSA, 1024); 3144 sc.generateAsymmetricKeyPair(1, 0, kg.encode()); 3145 3146 var dp = new Key(); 3147 dp.setComponent(Key.ECC_CURVE_OID, new ByteString("brainpoolP256r1", OID)); 3148 3149 var kg = new SmartCardHSMKeySpecGenerator(Crypto.EC, dp); 3150 sc.generateAsymmetricKeyPair(2, 0, kg.encode()); 3151 3152 var list = sc.enumerateKeys(); 3153 GPSystem.trace("Keys on device: " + list); 3154 3155 var crypto = sc.getCrypto(); 3156 var message = new ByteString("Hello World", ASCII); 3157 3158 var key = sc.getKey(1); 3159 var signature = crypto.sign(key, Crypto.RSA_SHA256, message); 3160 GPSystem.trace("Signature: " + signature); 3161 3162 var key = sc.getKey(2); 3163 var signature = crypto.sign(key, Crypto.ECDSA, message); 3164 GPSystem.trace("Signature: " + signature); 3165 } 3166