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.major = rsp.byteAt(rsp.length - 2); 1079 this.minor = rsp.byteAt(rsp.length - 1); 1080 this.platform = rsp.byteAt(rsp.length - 3); 1081 return rsp.bytes(rsp.length - 7, 4).toUnsigned(); 1082 } 1083 1084 1085 1086 /** 1087 * Parse the key domain status returned from the device 1088 * 1089 * @param {ByteString} status the R-DATA from the MANAGE KEY DOMAIN command 1090 * @type object 1091 * @return the decoded status Info 1092 */ 1093 SmartCardHSM.prototype.parseKeyDomainStatus = function(status) { 1094 if (status.length == 0) { 1095 return { sw: this.card.SW }; 1096 } 1097 1098 var statusObject = { 1099 sw: this.card.SW, 1100 shares: status.byteAt(0), 1101 outstanding: status.byteAt(1), 1102 kcv: status.bytes(2, 8) 1103 } 1104 1105 if (status.length > 10) { 1106 statusObject.keyDomain = status.bytes(10); 1107 } 1108 1109 return statusObject; 1110 } 1111 1112 1113 1114 /* 1115 * Create DKEK Key Domain 1116 * 1117 * @param {Number} keyDomain number of key domain in the range 0 to the maximum defined in the INITIALIZE DEVICE command 1118 * @param {Number} shares the number of DKEK shares to import 1119 * @type Object 1120 * @return object with properties sw{Number}, shares{Number}, outstanding{Number} and kcv{ByteString} 1121 */ 1122 SmartCardHSM.prototype.createDKEKKeyDomain = function(keyDomain, shares) { 1123 if (typeof(keyDomain) != "number") { 1124 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be a number"); 1125 } 1126 if (typeof(shares) != "number") { 1127 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "shares must be a number"); 1128 } 1129 1130 var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x01, keyDomain, ByteString.valueOf(shares), 0); 1131 1132 return this.parseKeyDomainStatus(status); 1133 } 1134 1135 1136 1137 /** 1138 * Create XKEK Key Domain 1139 * 1140 * @param {Number} keyDomain number of key domain in the range 0 to the maximum defined in the INITIALIZE DEVICE command 1141 * @param {ByteString} keyDomainMembership either a 64 byte signature (old format) or a encoded TLV object with tag 54 or 55 1142 * @return object with properties sw{Number}, shares{Number}, outstanding{Number}, kcv{ByteString} and the key domain UID{ByteString} 1143 * @type Object 1144 */ 1145 SmartCardHSM.prototype.createXKEKKeyDomain = function(keyDomain, groupSignerPublicKey, keyDomainMembership) { 1146 if (typeof(keyDomain) != "number") { 1147 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be a number"); 1148 } 1149 if ((keyDomain < 0) || (keyDomain > 0xFF)) { 1150 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be between 0 and 255"); 1151 } 1152 if (!(groupSignerPublicKey instanceof CVC)) { 1153 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "groupSignerPublicKey must be a CVC instance"); 1154 } 1155 if (!(keyDomainMembership instanceof ByteString)) { 1156 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomainMembership must be a ByteString"); 1157 } 1158 1159 var car = groupSignerPublicKey.getOuterCAR().getBytes(); 1160 1161 var pukrefdo = new ASN1(0x83, car); 1162 var pukref = pukrefdo.getBytes(); 1163 1164 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000]); 1165 1166 if (keyDomainMembership.length == 64) { 1167 keyDomainMembership = new ASN1(0x53, keyDomainMembership).getBytes(); 1168 } 1169 var cdata = groupSignerPublicKey.getASN1().value.concat(keyDomainMembership); 1170 1171 if (cdata.length <= this.maxCData) { 1172 var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x02, keyDomain, cdata, 0); 1173 } else { 1174 this.updateBinary(ByteString.valueOf(0x2F10), 0, cdata); 1175 var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x02, keyDomain, 0); 1176 } 1177 1178 return this.parseKeyDomainStatus(status); 1179 } 1180 1181 1182 1183 /** 1184 * Associate XKEK Key Domain 1185 * 1186 * @param {Number} keyDomain number of key domain in the range 0 to the maximum defined in the INITIALIZE DEVICE command 1187 * @param {ByteString} keyDomainUID a encoded TLV object with tag 51 containing the key domain uid of the associated domain 1188 * @param {ByteString} keyDomainAssociation a encoded TLV object with tag 56 or 57 1189 * @return object with properties sw{Number}, shares{Number}, outstanding{Number}, kcv{ByteString} and the key domain UID{ByteString} 1190 * @type Object 1191 */ 1192 SmartCardHSM.prototype.associateXKEKKeyDomain = function(keyDomain, groupSignerPublicKey, keyDomainUID, keyDomainAssociation) { 1193 if (typeof(keyDomain) != "number") { 1194 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be a number"); 1195 } 1196 if ((keyDomain < 0) || (keyDomain > 0xFF)) { 1197 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be between 0 and 255"); 1198 } 1199 if (!(groupSignerPublicKey instanceof CVC)) { 1200 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "groupSignerPublicKey must be a ByteString"); 1201 } 1202 if (!(keyDomainUID instanceof ByteString)) { 1203 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomainUID must be a ByteString"); 1204 } 1205 if (!(keyDomainAssociation instanceof ByteString)) { 1206 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomainAssociation must be a ByteString"); 1207 } 1208 1209 var car = groupSignerPublicKey.getOuterCAR().getBytes(); 1210 1211 var pukrefdo = new ASN1(0x83, car); 1212 var pukref = pukrefdo.getBytes(); 1213 1214 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000]); 1215 1216 var cdata = groupSignerPublicKey.getASN1().value.concat(keyDomainUID).concat(keyDomainAssociation); 1217 1218 if (cdata.length <= this.maxCData) { 1219 var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x05, keyDomain, cdata, 0); 1220 } else { 1221 this.updateBinary(ByteString.valueOf(0x2F10), 0, cdata); 1222 var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x05, keyDomain, 0); 1223 } 1224 1225 return this.parseKeyDomainStatus(status); 1226 } 1227 1228 1229 1230 /** 1231 * Derive XKEK 1232 * 1233 * @param {Number} keyDomain number of key domain in the range 0 to the maximum defined in the INITIALIZE DEVICE command 1234 * @param {ByteString} derivationParam 1235 * @return object with properties sw{Number}, shares{Number}, outstanding{Number}, kcv{ByteString} and the key domain UID{ByteString} 1236 * @type Object 1237 */ 1238 SmartCardHSM.prototype.deriveXKEK = function(keyid, peerPublicKey, derivationParam) { 1239 if (typeof(keyid) != "number") { 1240 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyid must be a number"); 1241 } 1242 if ((keyid < 1) || (keyid > 0xFF)) { 1243 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyid must be between 1 and 255"); 1244 } 1245 if (!(peerPublicKey instanceof CVC)) { 1246 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "peerPublicKey must be a CVC"); 1247 } 1248 if (!(derivationParam instanceof ByteString)) { 1249 throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "derivationParam must be a ByteString"); 1250 } 1251 1252 var car = peerPublicKey.getOuterCAR().getBytes(); 1253 1254 var pukrefdo = new ASN1(0x83, car); 1255 var pukref = pukrefdo.getBytes(); 1256 1257 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000]); 1258 1259 var kdp = new ASN1(0x50, derivationParam).getBytes(); 1260 var cdata = peerPublicKey.getASN1().value.concat(kdp); 1261 1262 if (cdata.length <= this.maxCData) { 1263 // Le is usually not required, but versions 3.1 to 3.3 fail without Le (#178) 1264 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x62, keyid, 0x84, cdata, 0, [0x9000]); 1265 } else { 1266 this.updateBinary(ByteString.valueOf(0x2F10), 0, cdata); 1267 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x62, keyid, 0x84, [0x9000]); 1268 } 1269 } 1270 1271 1272 1273 /** 1274 * Query the status of the key domain 1275 * 1276 * @param {Number} keyDomain the number of the key domain which will be queried, default is 0 1277 * @type Object 1278 * @return object with properties sw{Number}, shares{Number}, outstanding{Number}, kcv{ByteString} and for a XKEK key domain the key domain UID{ByteString} 1279 */ 1280 SmartCardHSM.prototype.queryKeyDomainStatus = function(keyDomain) { 1281 if (!keyDomain) { 1282 keyDomain = 0; 1283 } 1284 1285 var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x00, keyDomain, 0); 1286 1287 return this.parseKeyDomainStatus(status); 1288 } 1289 1290 1291 1292 /** 1293 * Delete the key encryption key in a key domain 1294 * 1295 * @param {Number} keyDomain the number of the key domain 1296 */ 1297 SmartCardHSM.prototype.deleteKEK = function(keyDomain) { 1298 var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x04, keyDomain, [0x9000]); 1299 1300 return this.parseKeyDomainStatus(status); 1301 } 1302 1303 1304 1305 /** 1306 * Delete the empty key domain 1307 * 1308 * @param {Number} keyDomain the number of the key domain 1309 */ 1310 SmartCardHSM.prototype.deleteKeyDomain = function(keyDomain) { 1311 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x03, keyDomain, [0x9000]); 1312 } 1313 1314 1315 1316 /** 1317 * Import DKEK share or query status 1318 * 1319 * @param {Number} keyDomain the number of the key domain 1320 * @param {ByteString} keyshare 32 byte key share 1321 * @type Object 1322 * @return object with properties sw{Number}, shares{Number}, outstanding{Number} and kcv{ByteString} 1323 */ 1324 SmartCardHSM.prototype.importKeyShare = function(keyDomain, keyshare) { 1325 if (typeof(keyDomain) != "number") { 1326 keyshare = keyDomain; 1327 keyDomain = 0; 1328 } 1329 if (typeof(keyshare) != "undefined") { 1330 var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x00, keyDomain, keyshare, 0, [0x9000]); 1331 } else { 1332 var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x00, keyDomain, 0); 1333 } 1334 if (status.length == 0) { 1335 return { sw: this.card.SW }; 1336 } 1337 1338 var statusObject = { 1339 sw: this.card.SW, 1340 shares: status.byteAt(0), 1341 outstanding: status.byteAt(1), 1342 kcv: status.bytes(2, 8) 1343 } 1344 1345 if (status.length > 10) { 1346 statusObject.keyDomain = status.bytes(10); 1347 } 1348 1349 return statusObject; 1350 } 1351 1352 1353 1354 /** 1355 * Decrypt and import a DKEK share 1356 * 1357 * @param {ByteString} keyshare the encrypted key share as read from the .pbe file 1358 * @param {ByteString} password the password 1359 * @param {Number} keyDomain the number of the key domain 1360 * @return object with properties sw{Number}, shares{Number}, outstanding{Number} and kcv{ByteString} 1361 */ 1362 SmartCardHSM.prototype.importEncryptedKeyShare = function(keyshare, password, keyDomain) { 1363 if (typeof(keyDomain) == "undefined") { 1364 keyDomain = 0; 1365 } 1366 1367 var dkek = DKEK.decryptKeyShare(keyshare, password); 1368 // print("Importing into SmartCard-HSM"); 1369 var r = this.importKeyShare(keyDomain, dkek); 1370 dkek.clear(); 1371 return r; 1372 } 1373 1374 1375 1376 /** 1377 * Wrap key under DKEK 1378 * 1379 * @param {Number} id key id 1380 * @type ByteString 1381 * @return key blob with encrypted key value 1382 */ 1383 SmartCardHSM.prototype.wrapKey = function(id) { 1384 var keyblob = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x72, id, 0x92, 65536, [0x9000]); 1385 return keyblob; 1386 } 1387 1388 1389 1390 /** 1391 * Unwrap key with DKEK 1392 * 1393 * @param {Number} id key id 1394 * @param {ByteString} keyblob the wrapped key 1395 */ 1396 SmartCardHSM.prototype.unwrapKey = function(id, keyblob) { 1397 if (keyblob.length < this.maxCData) { 1398 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x74, id, 0x93, keyblob, [0x9000]); 1399 } else { 1400 this.updateBinary(ByteString.valueOf(0x2F10), 0, keyblob); 1401 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x74, id, 0x93, [0x9000]); 1402 } 1403 } 1404 1405 1406 1407 /** 1408 * Replace symmetric key value encrypted under current key 1409 * 1410 * @param {Number} id key id 1411 * @param {ByteString} keyblob the wrapped key 1412 */ 1413 SmartCardHSM.prototype.unwrapAndReplaceKey = function(id, keyblob) { 1414 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x74, id, 0x94, keyblob, [0x9000]); 1415 } 1416 1417 1418 1419 /** 1420 * Derive Symmetric Key 1421 * 1422 * @param {Number} id key id 1423 * @param {Number} algo algorithm id (one of ALG_CBC_ENC, ALG_CBC_DEC, ALG_CMAC or ALG_DERIVE_SP800_56C) 1424 * @param {ByteString} derivationParam the derivation parameter 1425 * @type ByteString 1426 * @return derived key value 1427 */ 1428 SmartCardHSM.prototype.deriveSymmetricKey = function(id, algo, derivationParam) { 1429 var derivedKeyValue = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x78, id, algo, derivationParam, 0, [0x9000]); 1430 return derivedKeyValue; 1431 } 1432 1433 1434 1435 /** 1436 * Verify User PIN 1437 * 1438 * @param {ByteString} userPIN user PIN value 1439 * @return the status word SW1/SW2 returned by the device 1440 */ 1441 SmartCardHSM.prototype.verifyUserPIN = function(userPIN) { 1442 if (userPIN) { 1443 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x20, 0x00, 0x81, userPIN); 1444 return this.card.SW; 1445 } else { 1446 var cs = this.getNativeCardService(); 1447 cs.verifyPassword(); 1448 return this.queryUserPINStatus(); 1449 } 1450 } 1451 1452 1453 1454 /** 1455 * Logout 1456 * 1457 */ 1458 SmartCardHSM.prototype.logout = function() { 1459 this.card.clearCredential(); 1460 var fcp = this.card.sendApdu(0x00, 0xA4, 0x04, 0x04, new ByteString("E82B0601040181C31F0201", HEX), 0, [0x9000]); 1461 var a = new ASN1(fcp); 1462 var v = a.find(0x85).value; 1463 this.options = v.bytes(0, 2).toUnsigned(); 1464 this.major = v.byteAt(v.length - 2); 1465 this.minor = v.byteAt(v.length - 1); 1466 if (v.length >= 5) { 1467 this.platform = v.byteAt(v.length - 3); 1468 } 1469 } 1470 1471 1472 1473 /** 1474 * Change User PIN 1475 * 1476 * @param {ByteString} currentPIN current user PIN value 1477 * @param {ByteString} newPIN new user PIN value 1478 */ 1479 SmartCardHSM.prototype.changeUserPIN = function(currentPIN, newPIN) { 1480 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x24, 0x00, 0x81, currentPIN.concat(newPIN), [0x9000]); 1481 } 1482 1483 1484 1485 /** 1486 * Unblock and set User PIN 1487 * 1488 * @param {ByteString} initializationCode the initialization code 1489 * @param {ByteString} newPIN new user PIN value (optional) 1490 */ 1491 SmartCardHSM.prototype.unblockUserPIN = function(initializationCode, newPIN) { 1492 if (newPIN) { 1493 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x2C, 0x00, 0x81, initializationCode.concat(newPIN), [0x9000]); 1494 } else { 1495 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x2C, 0x01, 0x81, initializationCode, [0x9000]); 1496 } 1497 } 1498 1499 1500 1501 /** 1502 * Change InitializationCode 1503 * 1504 * @param {ByteString} initializationCode current initialization code 1505 * @param {ByteString} newInitializationCode new initialization code 1506 */ 1507 SmartCardHSM.prototype.changeInitializationCode = function(initializationCode, newInitializationCode) { 1508 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x24, 0x00, 0x88, initializationCode.concat(newInitializationCode), [0x9000]); 1509 } 1510 1511 1512 1513 SmartCardHSM.describePINStatus = function(sw, name) { 1514 var str; 1515 switch(sw) { 1516 case 0x9000: 1517 str = name + " authenticated"; 1518 break; 1519 case 0x6984: 1520 str = name + " in transport mode or device not initialized"; 1521 break; 1522 case 0x6A88: 1523 str = name + " not initialized"; 1524 break; 1525 case 0x6983: 1526 str = name + " blocked"; 1527 break; 1528 case 0x6300: 1529 str = name + " not authenticated"; 1530 break; 1531 default: 1532 str = name + " not verified, " + (sw & 0xF) + " tries remaining"; 1533 break; 1534 } 1535 return str + " (" + ByteString.valueOf(sw).toString(HEX) + ")"; 1536 } 1537 1538 1539 1540 /** 1541 * Request PIN Status Information 1542 * 1543 * @param {Number} p2 the PIN object id 1544 * @type Number 1545 * @return the status word SW1/SW2 returned by the device 1546 */ 1547 SmartCardHSM.prototype.queryPINStatus = function(p2) { 1548 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x20, 0x00, p2, 0); 1549 return this.card.SW; 1550 } 1551 1552 1553 1554 /** 1555 * Request PIN Status Information 1556 * 1557 * @type Number 1558 * @return the status word SW1/SW2 returned by the device 1559 */ 1560 SmartCardHSM.prototype.queryUserPINStatus = function() { 1561 return this.queryPINStatus(0x81); 1562 } 1563 1564 1565 1566 /** 1567 * Request Initialization Code Status 1568 * 1569 * @type Number 1570 * @return the status word SW1/SW2 returned by the device 1571 */ 1572 SmartCardHSM.prototype.queryInitializationCodeStatus = function() { 1573 return this.queryPINStatus(0x88); 1574 } 1575 1576 1577 1578 /** 1579 * Enumerate Objects 1580 * 1581 * @return the enumeration 1582 */ 1583 SmartCardHSM.prototype.enumerateObjects = function() { 1584 var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x58, 0x00, 0x00, 65536, [0x9000]); 1585 return rsp; 1586 } 1587 1588 1589 1590 /** 1591 * Generate random data 1592 * 1593 * @param {Number} length number of bytes 1594 * @return the random bytes 1595 */ 1596 SmartCardHSM.prototype.generateRandom = function(length) { 1597 var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x84, 0x00, 0x00, length, [0x9000]); 1598 return rsp; 1599 } 1600 1601 1602 1603 /** 1604 * Sign data using referenced key 1605 * 1606 * @param {Number} keyid the key identifier for signing 1607 * @param {algo} algo the algorithm identifier 1608 * @param {ByteString} data the data to be signed 1609 * @return the signature value 1610 */ 1611 SmartCardHSM.prototype.sign = function(keyid, algo, data) { 1612 if (data.length <= this.maxCData) { 1613 var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x68, keyid, algo, data, 0x10000, [0x9000]); 1614 } else { 1615 this.updateBinary(ByteString.valueOf(0x2F10), 0, data); 1616 var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x68, keyid, algo, 0x10000, [0x9000]); 1617 } 1618 1619 return rsp; 1620 } 1621 1622 1623 1624 /** 1625 * Decipher cryptogram or agree shared secret using Diffie-Hellman 1626 * 1627 * @param {Number} keyid the key identifier 1628 * @param {Number} algo the algorithm identifier 1629 * @param {ByteString} data the the cryptogram or concatenation of x || y of ECC public key 1630 * @return the plain output 1631 */ 1632 SmartCardHSM.prototype.decipher = function(keyid, algo, data) { 1633 var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x62, keyid, algo, data, 0x00, [0x9000]); 1634 return rsp; 1635 } 1636 1637 1638 1639 /** 1640 * Verify card verifiable certificate 1641 * 1642 * @param {CVC} cvc the card verifiable certificate 1643 **/ 1644 SmartCardHSM.prototype.verifyCertificate = function(cvc) { 1645 1646 // Check if public key is already known 1647 var chr = cvc.getCHR().getBytes(); 1648 1649 var pukrefdo = new ASN1(0x83, chr); 1650 var pukref = pukrefdo.getBytes(); 1651 1652 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000, 0x6A88]); 1653 1654 if (this.card.SW == 0x9000) { 1655 return; 1656 } 1657 1658 // Select public key for verification 1659 var car = cvc.getCAR().getBytes(); 1660 1661 var pukrefdo = new ASN1(0x83, car); 1662 var pukref = pukrefdo.getBytes(); 1663 1664 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000]); 1665 1666 // Extract value of 7F21 1667 var tl = new TLVList(cvc.getBytes(), TLV.EMV); 1668 var t = tl.index(0); 1669 var v = t.getValue(); 1670 1671 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x2A, 0x00, 0xBE, v, [0x9000]); 1672 } 1673 1674 1675 1676 /** 1677 * Enumerate CA certificates 1678 * 1679 * @type String[] 1680 * @return the list of certificate labels 1681 */ 1682 SmartCardHSM.prototype.enumerateCACertificates = function() { 1683 this.canamemap = []; 1684 this.caidmap = [] 1685 this.caids = []; 1686 var certlist = []; 1687 1688 var fobs = this.enumerateObjects(); 1689 1690 // Process PKCS#15 certificate descriptions 1691 for (var i = 0; i < fobs.length; i+= 2) { 1692 if (fobs.byteAt(i) == SmartCardHSM.CERTDPREFIX) { 1693 var id = fobs.byteAt(i + 1); 1694 this.caids.push(id); 1695 var fid = ByteString.valueOf((SmartCardHSM.CACERTIFICATEPREFIX << 8) + id); 1696 var descbin = this.readBinary(fobs.bytes(i, 2)); 1697 var asn = new ASN1(descbin); 1698 var coa = asn.get(0); 1699 if (coa.elements > 0) { 1700 var label = coa.get(0).value.toString(ASCII); 1701 } else { 1702 var label = "No label (" + i + ")"; 1703 } 1704 var cert = this.readBinary(fid); 1705 certlist.push(label); 1706 this.canamemap[label] = cert; 1707 cert.id = id; 1708 this.caidmap[label] = id; 1709 } 1710 } 1711 1712 return certlist; 1713 } 1714 1715 1716 1717 /** 1718 * Return CA certificate with label 1719 * 1720 * @param {String} label the certificate label 1721 * @type ByteString 1722 * @return the encoded certificate 1723 */ 1724 SmartCardHSM.prototype.getCACertificate = function(label) { 1725 if (typeof(this.caids) == "undefined") { 1726 this.enumerateCACertificates(); 1727 } 1728 1729 return this.canamemap[label]; 1730 } 1731 1732 1733 1734 /** 1735 * Determine an unused CA certificate identifier 1736 * 1737 * @type Number 1738 * @return a free CA certificate identifier or -1 if all identifier in use 1739 */ 1740 SmartCardHSM.prototype.determineFreeCAId = function() { 1741 if (typeof(this.caids) == "undefined") { 1742 this.enumerateCACertificates(); 1743 } 1744 1745 if (this.caids.length == 0) { 1746 return 0; 1747 } 1748 1749 var id = Math.max.apply(null, this.caids) + 1; 1750 if (id > 256) { 1751 return -1; 1752 } 1753 return id; 1754 } 1755 1756 1757 1758 /** 1759 * Add a new CA certificate to the map 1760 * 1761 * @param {X509} cert the CA certificate 1762 * @param {Number} id the corresponding id 1763 * @param {String} label the corresponding label 1764 */ 1765 SmartCardHSM.prototype.addCACertificateToMap = function(cert, id, label) { 1766 if (!this.caidmap[label]) { 1767 // new id 1768 this.caids.push(id); 1769 this.caidmap[label] = id; 1770 } 1771 this.canamemap[label] = cert; 1772 } 1773 1774 1775 1776 /** 1777 * Enumerate key objects in the SmartCard-HSM and build the map of keys 1778 * 1779 * @type String[] 1780 * @return the list of key labels 1781 */ 1782 SmartCardHSM.prototype.enumerateKeys = function() { 1783 this.namemap = []; 1784 this.idmap = []; 1785 this.idlist = []; 1786 this.p15idmap = []; 1787 1788 var fobs = this.enumerateObjects(); 1789 1790 // Process keys 1791 for (var i = 0; i < fobs.length; i += 2) { 1792 if ((fobs.byteAt(i) == SmartCardHSM.KEYPREFIX) || (fobs.byteAt(i) == 0xFF)) { 1793 var kid = fobs.byteAt(i + 1); 1794 if (kid > 0) { 1795 // GPSystem.trace("Found key: " + kid); 1796 var key = new SmartCardHSMKey(this, kid); 1797 this.idmap[kid] = key; 1798 this.idlist.push(kid); 1799 this.updateKey(key); 1800 } 1801 } 1802 } 1803 1804 var keylist = []; 1805 // Process PKCS#15 private key descriptions 1806 for (var i = 0; i < fobs.length; i += 2) { 1807 if (fobs.byteAt(i) == SmartCardHSM.PRKDPREFIX) { 1808 var kid = fobs.byteAt(i + 1); 1809 var descbin = this.readBinary(fobs.bytes(i, 2)); 1810 if (descbin.length > 2) { 1811 try { 1812 var desc = new ASN1(descbin); 1813 if (desc.elements < 3) { 1814 continue; 1815 } 1816 } 1817 catch(e) { 1818 continue; 1819 } 1820 var key = this.idmap[kid]; 1821 if (key) { 1822 key.setDescription(desc); 1823 var label = key.getLabel(); 1824 // GPSystem.trace(key.getId() + " - " + label); 1825 if (label) { 1826 keylist.push(label); 1827 this.namemap[label] = key; 1828 } 1829 var p15id = key.getPKCS15Id(); 1830 this.p15idmap[p15id.toString(HEX)] = key; 1831 } 1832 } 1833 } 1834 } 1835 1836 return keylist; 1837 } 1838 1839 1840 1841 /** 1842 * Get key ids 1843 * 1844 * @type Number[] 1845 * @return a list of key identifier 1846 */ 1847 SmartCardHSM.prototype.getKeyIds = function() { 1848 if (typeof(this.idlist) == "undefined") { 1849 this.enumerateKeys(); 1850 } 1851 return this.idlist; 1852 } 1853 1854 1855 1856 /** 1857 * Determine an unused key identifier 1858 * 1859 * @type Number 1860 * @return a free key identifier or -1 if all key identifier in use 1861 */ 1862 SmartCardHSM.prototype.determineFreeKeyId = function() { 1863 if (typeof(this.idlist) == "undefined") { 1864 this.enumerateKeys(); 1865 } 1866 for (var i = 1; i < 256; i++) { 1867 if (this.idmap[i] == undefined) { 1868 return i; 1869 } 1870 } 1871 throw new GPError("SmartCardHSM", GPError.OUT_OF_MEMORY, 1, "Key idx exhausted"); 1872 } 1873 1874 1875 1876 /** 1877 * Update key attributes, in particular the use counter 1878 * 1879 * @param {HSMKey} key the HSM key 1880 */ 1881 SmartCardHSM.prototype.updateKey = function(key) { 1882 var fid = ByteString.valueOf((SmartCardHSM.KEYPREFIX << 8) + key.getId()); 1883 try { 1884 var fcp = this.selectFile(fid); 1885 } 1886 catch(e) { 1887 return; 1888 } 1889 var a = new ASN1(fcp); 1890 var pi = a.find(0xA5); 1891 if (!pi) { 1892 return; 1893 } 1894 var kc = pi.find(0x90); 1895 if (kc) { 1896 var c = kc.value.toUnsigned(); 1897 1898 if (c != 0xFFFFFFFF) { 1899 key.useCounter = c; 1900 } 1901 } 1902 1903 var kd = pi.find(0x91); 1904 if (kd) { 1905 key.algorithms = kd.value; 1906 } 1907 1908 var kd = pi.find(0x92); 1909 if (kd) { 1910 key.keyDomain = kd.value.toUnsigned(); 1911 } 1912 } 1913 1914 1915 1916 /** 1917 * Add a new key to the map of keys 1918 * 1919 * @param {HSMKey} key the HSM key 1920 */ 1921 SmartCardHSM.prototype.addKeyToMap = function(key) { 1922 var id = key.getId(); 1923 this.idmap[id] = key; 1924 1925 var label = key.getLabel(); 1926 if (label) { 1927 this.namemap[label] = key; 1928 } 1929 1930 var p15id = key.getPKCS15Id(); 1931 if (p15id) { 1932 this.p15idmap[p15id.toString(HEX)] = key; 1933 } 1934 } 1935 1936 1937 1938 /** 1939 * Get a key reference object 1940 * 1941 * @param {String/Number/ByteString} labelOrId label or id of key 1942 * @returns the key or null if not found 1943 * @type Key 1944 */ 1945 SmartCardHSM.prototype.getKey = function(labelOrId) { 1946 if (typeof(this.idlist) == "undefined") { 1947 this.enumerateKeys(); 1948 } 1949 1950 if (typeof(labelOrId) == "number") { 1951 var key = this.idmap[labelOrId]; 1952 } else if (typeof(labelOrId) == "string") { 1953 var key = this.namemap[labelOrId]; 1954 } else { 1955 var key = this.p15idmap[labelOrId.toString(HEX)]; 1956 } 1957 1958 if (key == undefined) { 1959 return null; 1960 } 1961 return key; 1962 } 1963 1964 1965 1966 /** 1967 * Return a list of key objects 1968 * 1969 * @type SmartCardHSMKey[] 1970 * @return the list of keys 1971 */ 1972 SmartCardHSM.prototype.getKeys = function() { 1973 if (typeof(this.idlist) == "undefined") { 1974 this.enumerateKeys(); 1975 } 1976 1977 var keylist = []; 1978 for (var i in this.idmap) { 1979 keylist.push(this.idmap[i]); 1980 } 1981 return keylist; 1982 } 1983 1984 1985 1986 /** 1987 * Get crypto object 1988 * 1989 * @type HSMCrypto 1990 * @return the HSMCrypto object 1991 */ 1992 SmartCardHSM.prototype.getCrypto = function() { 1993 if (this.crypto == undefined) { 1994 this.crypto = new SmartCardHSMCrypto(new Crypto()); 1995 } 1996 return this.crypto; 1997 } 1998 1999 2000 2001 /** 2002 * @private 2003 */ 2004 SmartCardHSM.prototype.getTokenInfo = function() { 2005 if (this.tokenInfo != undefined) { 2006 return this.tokenInfo; 2007 } 2008 2009 if (!this.hasFile(SmartCardHSM.EF_TokenInfo)) { 2010 return; 2011 } 2012 2013 var bin = this.readBinary(SmartCardHSM.EF_TokenInfo); 2014 this.tokenInfo = new ASN1(bin); 2015 return this.tokenInfo; 2016 } 2017 2018 2019 2020 /** 2021 * Get Token Label 2022 * 2023 * @type String 2024 * @return the token label from CIAInfo 2025 */ 2026 SmartCardHSM.prototype.getLabel = function() { 2027 var ti = this.getTokenInfo(); 2028 if (!ti) { 2029 return; 2030 } 2031 2032 var a = ti.find(0x80); 2033 if (!a) { 2034 return; 2035 } 2036 return a.value.toString(UTF8); 2037 } 2038 2039 2040 2041 /** 2042 * @private 2043 */ 2044 SmartCardHSM.prototype.getStaticTokenInfo = function() { 2045 if (this.staticTokenInfo != undefined) { 2046 return this.staticTokenInfo; 2047 } 2048 2049 if (!this.hasFile(SmartCardHSM.EF_StaticTokenInfo)) { 2050 return; 2051 } 2052 2053 var bin = this.readBinary(SmartCardHSM.EF_StaticTokenInfo); 2054 this.staticTokenInfo = new ASN1(bin); 2055 return this.staticTokenInfo; 2056 } 2057 2058 2059 2060 /** 2061 * Get ProvisioningURL 2062 * 2063 * @type String 2064 * @return the configured ProvisioningURL or undefined 2065 */ 2066 SmartCardHSM.prototype.getProvisioningURL = function() { 2067 var ti = this.getStaticTokenInfo(); 2068 if (!ti) { 2069 return; 2070 } 2071 2072 var a = ti.find(0x80); 2073 if (!a) { 2074 return; 2075 } 2076 return a.value.toString(UTF8); 2077 } 2078 2079 2080 2081 /** 2082 * Get Key Check Value of Token Management Key 2083 * 2084 * @type ByteString 2085 * @return the configured KCV of the Token Management Key or undefined 2086 */ 2087 SmartCardHSM.prototype.getTokenManagementKeyKCV = function() { 2088 var ti = this.getStaticTokenInfo(); 2089 if (!ti) { 2090 return; 2091 } 2092 2093 var a = ti.find(0x81); 2094 if (!a) { 2095 return; 2096 } 2097 return a.value; 2098 } 2099 2100 2101 2102 /** 2103 * Get salt for SO-PIN derivation using the Token Management Key 2104 * 2105 * @type ByteString 2106 * @return the configured salt 2107 */ 2108 SmartCardHSM.prototype.getTokenManagementKeySalt = function() { 2109 var ti = this.getStaticTokenInfo(); 2110 if (!ti) { 2111 return; 2112 } 2113 2114 var a = ti.find(0x82); 2115 if (!a) { 2116 return; 2117 } 2118 return a.value; 2119 } 2120 2121 2122 2123 /** 2124 * Create crypto object implementing access to the SmartCard-HSM 2125 * 2126 * @class Wrapper to provide Crypto interface to SmartCard-HSM 2127 * @constructor 2128 * @param {Crypto} crypto the backend crypto provider 2129 */ 2130 function SmartCardHSMCrypto(crypto) { 2131 this.crypto = crypto; 2132 } 2133 2134 2135 2136 /** 2137 * Sign a message using the defined mechanism and key 2138 * 2139 * @param {HSMKey} key the private key 2140 * @param {Number} mech the mechanism (e.g. Crypto.ECDSA) 2141 * @param {ByteString} message the message to be signed 2142 * @type ByteString 2143 * @return the signature 2144 */ 2145 SmartCardHSMCrypto.prototype.sign = function(key, mech, message) { 2146 if (key instanceof SmartCardHSMKey) { 2147 return key.sign(mech, message); 2148 } else { 2149 return this.crypto.sign(key, mech, message); 2150 } 2151 } 2152 2153 2154 2155 /** 2156 * Decrypt a message using the defined mechanism and key 2157 * 2158 * @param {HSMKey} key the private key 2159 * @param {Number} mech the mechanism (e.g. Crypto.RSA_PKCS1) 2160 * @param {ByteString} data the cryptogram 2161 * @param {ByteString} iv the initialization vector for symmetric ciphers 2162 * @type ByteString 2163 * @return the plain text 2164 */ 2165 SmartCardHSMCrypto.prototype.decrypt = function(key, mech, data, iv) { 2166 if (key instanceof SmartCardHSMKey) { 2167 return key.decrypt(mech, data); 2168 } else { 2169 return this.crypto.decrypt(key, mech, data, iv); 2170 } 2171 } 2172 2173 2174 2175 /** 2176 * Verify a message using the defined mechanism and key 2177 * 2178 * @param {Key} key the public key 2179 * @param {Number} mech the mechanism (e.g. Crypto.ECDSA) 2180 * @param {ByteString} message the message to be signed 2181 * @param {ByteString} signature the signature to verify 2182 * @type Boolean 2183 * @return true if signature is valid 2184 */ 2185 SmartCardHSMCrypto.prototype.verify = function(key, mech, message, signature) { 2186 return this.crypto.verify(key, mech, message, signature); 2187 } 2188 2189 2190 2191 /** 2192 * Create a key access object 2193 * 2194 * @class Class implementing key access 2195 * @param {SmartCardHSM} sc the card access object 2196 * @param {Number} id the key identifier 2197 */ 2198 function SmartCardHSMKey(sc, id) { 2199 this.sc = sc; 2200 this.id = id; 2201 if (this.sc.useExternalHashInECDSA) { 2202 this.crypto = new Crypto(); 2203 } 2204 } 2205 2206 exports.SmartCardHSMKey = SmartCardHSMKey; 2207 2208 2209 /** 2210 * Set the PKCS#15 private key description 2211 * 2212 * @param {ASN1} desc the description 2213 */ 2214 SmartCardHSMKey.prototype.setDescription = function(desc) { 2215 this.desc = desc; 2216 } 2217 2218 2219 2220 /** 2221 * Return the key identifier 2222 * 2223 * @type Number 2224 * @return the key identifier 2225 */ 2226 SmartCardHSMKey.prototype.getId = function() { 2227 return this.id; 2228 } 2229 2230 2231 2232 /** 2233 * Return the key label as encoded in the PKCS#15 structure 2234 * 2235 * @type String 2236 * @return the key label 2237 */ 2238 SmartCardHSMKey.prototype.getLabel = function() { 2239 if (this.desc == undefined) { 2240 return undefined; 2241 } 2242 if ((this.desc.get(0).elements == 0) || this.desc.get(0).get(0).tag != 0x0C) { 2243 return undefined; 2244 } 2245 2246 return this.desc.get(0).get(0).value.toString(UTF8); 2247 } 2248 2249 2250 2251 /** 2252 * Return the key id as encoded in the PKCS#15 structure 2253 * 2254 * @type ByteString 2255 * @return the key identifier 2256 */ 2257 SmartCardHSMKey.prototype.getPKCS15Id = function() { 2258 if (this.desc == undefined) { 2259 return undefined; 2260 } 2261 return this.desc.get(1).get(0).value; 2262 } 2263 2264 2265 2266 /** 2267 * Return the key size in bits 2268 * 2269 * @type Number 2270 * @return the key size in bits 2271 */ 2272 SmartCardHSMKey.prototype.getSize = function() { 2273 if (this.desc == undefined) { 2274 return undefined; 2275 } 2276 // GPSystem.trace(this.desc); 2277 if (this.desc.get(2).elements > 1) { // Fix a bug from early versions 2278 return this.desc.get(2).get(1).value.toUnsigned(); 2279 } else { 2280 return this.desc.get(2).get(0).get(1).value.toUnsigned(); 2281 } 2282 } 2283 2284 2285 2286 /** 2287 * Return the key size in bits 2288 * 2289 * @type Number 2290 * @return the key size in bits 2291 */ 2292 SmartCardHSMKey.prototype.getType = function() { 2293 if (this.desc == undefined) { 2294 return undefined; 2295 } 2296 2297 if (this.desc.tag == 0xA0) { 2298 return "EC"; 2299 } else if (this.desc.tag == 0x30) { 2300 return "RSA"; 2301 } else if (this.desc.tag == 0xA8) { 2302 return "AES"; 2303 } 2304 2305 return undefined; 2306 } 2307 2308 2309 2310 /** 2311 * Sign data using a key in the SmartCard-HSM 2312 * 2313 * @param {Number} mech the signing mechanism 2314 * @param {ByteString} data to be signed 2315 * @type ByteString 2316 * @return the signature 2317 */ 2318 SmartCardHSMKey.prototype.sign = function(mech, data) { 2319 var algo; 2320 if (mech) { 2321 switch(mech) { 2322 case Crypto.RSA: 2323 algo = 0x20; 2324 break; 2325 case Crypto.RSA_SHA1: 2326 algo = 0x31; 2327 break; 2328 case Crypto.RSA_SHA256: 2329 algo = 0x33; 2330 break; 2331 case Crypto.RSA_PKCS1: 2332 algo = 0x20; 2333 var keysize = this.getSize(); 2334 if (!keysize) { 2335 throw new GPError(module.id, GPError.INVALID_DATA, 0, "Can't determine key size"); 2336 } 2337 data = PKCS1.encode_EMSA_V15(keysize, data); 2338 break; 2339 // case Crypto.RSA_PSS: 2340 case 0x80: 2341 algo = 0x40; 2342 break; 2343 case Crypto.RSA_PSS_SHA1: 2344 algo = 0x41; 2345 break; 2346 case Crypto.RSA_PSS_SHA256: 2347 algo = 0x43; 2348 break; 2349 case Crypto.ECDSA: 2350 algo = 0x70; 2351 break; 2352 case Crypto.ECDSA_SHA1: 2353 if (this.sc.useExternalHashInECDSA) { 2354 algo = 0x70; 2355 var data = this.crypto.digest(Crypto.SHA_1, data); 2356 } else { 2357 algo = 0x71; 2358 } 2359 break; 2360 case Crypto.ECDSA_SHA224: 2361 if (this.sc.useExternalHashInECDSA) { 2362 algo = 0x70; 2363 var data = this.crypto.digest(Crypto.SHA_224, data); 2364 } else { 2365 algo = 0x72; 2366 } 2367 break; 2368 case Crypto.ECDSA_SHA256: 2369 if (this.sc.useExternalHashInECDSA) { 2370 algo = 0x70; 2371 var data = this.crypto.digest(Crypto.SHA_256, data); 2372 } else { 2373 algo = 0x73; 2374 } 2375 break; 2376 case Crypto.AES_CMAC: 2377 return this.sc.deriveSymmetricKey(this.id, SmartCardHSM.ALG_CMAC, data); 2378 default: 2379 throw new GPError("SmartCardHSMKey", GPError.INVALID_DATA, mech, "Unsupported crypto mechanism"); 2380 } 2381 } 2382 2383 return this.sc.sign(this.id, algo, data); 2384 } 2385 2386 2387 2388 /** 2389 * Decrypt data using a key in the SmartCard-HSM 2390 * 2391 * @param {Number} mech the decipher mechanism 2392 * @param {ByteString} data to be deciphered 2393 * @type ByteString 2394 * @return the plain message 2395 */ 2396 SmartCardHSMKey.prototype.decrypt = function(mech, data) { 2397 var algo; 2398 if (mech) { 2399 switch(mech) { 2400 case Crypto.RSA: 2401 break; 2402 case Crypto.RSA_PKCS1: 2403 break; 2404 case Crypto.RSA_OAEP_SHA224: 2405 algo = Crypto.SHA_224; 2406 break; 2407 case Crypto.RSA_OAEP_SHA256: 2408 algo = Crypto.SHA_256; 2409 break; 2410 case Crypto.RSA_OAEP_SHA384: 2411 algo = Crypto.SHA_384; 2412 break; 2413 case Crypto.RSA_OAEP_SHA512: 2414 algo = Crypto.SHA_512; 2415 break; 2416 default: 2417 throw new GPError("SmartCardHSMKey", GPError.INVALID_DATA, mech, "Unsupported crypto mechanism"); 2418 } 2419 } 2420 2421 var em = this.sc.decipher(this.id, 0x21, data); 2422 2423 var plain = em; 2424 2425 if (mech != Crypto.RSA) { 2426 if (mech == Crypto.RSA_PKCS1) { 2427 var plain = PKCS1.decode_EME_V15(em); 2428 } else { 2429 var crypto = this.sc.getCrypto().crypto; 2430 2431 var plain = PKCS1.decode_EME_OAEP(crypto, null, algo, em); 2432 } 2433 2434 if (!plain) { 2435 throw new GPError("SmartCardHSMKey", GPError.CRYPTO_FAILED, mech, "Decryption failed"); 2436 } 2437 } 2438 2439 return plain; 2440 } 2441 2442 2443 2444 /** 2445 * Return human readable string 2446 */ 2447 SmartCardHSMKey.prototype.toString = function() { 2448 return "SmartCardHSMKey(id=" + this.id + ")"; 2449 } 2450 2451 2452 2453 /** 2454 * Initialize SmartCard-HSM 2455 * 2456 * @class Class implementing the device initialization methods 2457 * @param {Card} card the card object 2458 */ 2459 function SmartCardHSMInitializer(card) { 2460 this.card = card; 2461 this.initializationCode = new ByteString("57621880", ASCII); 2462 this.userPIN = new ByteString("648219", ASCII); 2463 this.userPINSet = false; 2464 this.useDefaultUserPIN = true; 2465 this.retryCounterInitial = 3; 2466 this.options = 0x0001; 2467 this.keyshares = -1; 2468 this.keyDomains = -1; 2469 this.numberOfPublicKeys = 0; 2470 this.requiredPublicKeysForAuthentication = 0; 2471 this.bioslot = []; 2472 this.label = undefined; 2473 } 2474 2475 exports.SmartCardHSMInitializer = SmartCardHSMInitializer; 2476 2477 2478 2479 /** 2480 * Set the initialization code 2481 * 2482 * @param {ByteString} initializationCode an 8 byte code 2483 */ 2484 SmartCardHSMInitializer.prototype.setInitializationCode = function(initializationCode) { 2485 if (!(initializationCode instanceof ByteString)) { 2486 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "initializationCode must be a ByteString"); 2487 } 2488 if (initializationCode.length != 8) { 2489 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "initializationCode must have 8 bytes"); 2490 } 2491 2492 this.initializationCode = initializationCode; 2493 } 2494 2495 2496 2497 /** 2498 * Set the User PIN 2499 * 2500 * @param {ByteString} userPIN a 6 to 16 byte code 2501 */ 2502 SmartCardHSMInitializer.prototype.setUserPIN = function(userPIN) { 2503 if (!(userPIN instanceof ByteString)) { 2504 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "userPIN must be a ByteString"); 2505 } 2506 if ((userPIN.length < 6) || (userPIN.length > 16)) { 2507 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "userPIN must be between 6 and 16 bytes"); 2508 } 2509 2510 this.userPIN = userPIN; 2511 this.userPINSet = true; 2512 this.useDefaultUserPIN = false; 2513 } 2514 2515 2516 2517 /** 2518 * Set the retry counter 2519 * 2520 * The SmartCard-HSM enforces a retry counter <= 3 for PIN length 6 2521 * The SmartCard-HSM enforces a retry counter <= 5 for PIN length 7 2522 * The SmartCard-HSM enforces a retry counter <= 10 for PIN length larger than 7 2523 * 2524 * @param {Number} retryCounterInitial in the range 1 to 10. 2525 */ 2526 SmartCardHSMInitializer.prototype.setRetryCounterInitial = function(retryCounterInitial) { 2527 if (typeof(retryCounterInitial) != "number") { 2528 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "retryCounterInitial must be a number"); 2529 } 2530 if ((retryCounterInitial < 1) || (retryCounterInitial > 10)) { 2531 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "retryCounterInitial must be between 1 and 10"); 2532 } 2533 this.retryCounterInitial = retryCounterInitial; 2534 } 2535 2536 2537 2538 /** 2539 * Set the number of DKEK shares 2540 * 2541 * @param {Number} keyshares number of DKEK shares in the range 0 to 255 2542 */ 2543 SmartCardHSMInitializer.prototype.setDKEKShares = function(keyshares) { 2544 if (typeof(keyshares) != "number") { 2545 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyshares must be a number"); 2546 } 2547 if ((keyshares < 0) || (keyshares > 255)) { 2548 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyshares must be between 0 and 255"); 2549 } 2550 this.keyshares = keyshares; 2551 this.keyDomains = -1; 2552 } 2553 2554 2555 2556 /** 2557 * Set the number of key domains 2558 * 2559 * @param {Number} keyDomains number of key domains 2560 */ 2561 SmartCardHSMInitializer.prototype.setKeyDomains = function(keyDomains) { 2562 if (typeof(keyDomains) != "number") { 2563 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyDomains must be a number"); 2564 } 2565 2566 this.keyDomains = keyDomains; 2567 this.keyshares = -1; 2568 } 2569 2570 2571 2572 /** 2573 * Enable or disable RESET RETRY COUNTER command 2574 * 2575 * @param {Boolean} enable true (default) to allow RESET RETRY COUNTER command to reset user PIN using the initialization code 2576 */ 2577 SmartCardHSMInitializer.prototype.setResetRetryCounterMode = function(enable) { 2578 if (typeof(enable) == "undefined") { 2579 var enable = false; 2580 } 2581 2582 this.options = (this.options & 0xFFFE) + (enable ? 1 : 0); 2583 } 2584 2585 2586 2587 /** 2588 * Enable or disable transport PIN mode 2589 * 2590 * @param {Boolean} enable true (non-default) to set user PIN to transport state 2591 */ 2592 SmartCardHSMInitializer.prototype.setTransportPINMode = function(enable) { 2593 if (typeof(enable) == "undefined") { 2594 var enable = true; 2595 } 2596 2597 this.options = (this.options & 0xFFFD) + (enable ? 2 : 0); 2598 } 2599 2600 2601 2602 /** 2603 * Enable or disable session PIN mode 2604 * 2605 * @param {Number} 0 - disable, 1 - enable with clear-on-reset 3 - enable with explicit clearing 2606 */ 2607 SmartCardHSMInitializer.prototype.setSessionPINMode = function(mode) { 2608 assert(typeof(mode) == "number", "Argument mode must be number"); 2609 assert(mode >= 0 && mode <= 3 && mode != 2, "Argument mode must be 0, 1 or 3"); 2610 2611 this.options = (this.options & 0xFFF3) + (mode << 2); 2612 } 2613 2614 2615 2616 /** 2617 * Enable or disable replacing of a PKA key 2618 * 2619 * @param {Boolean} enable true (non-default) to allow replacing of a PKA key 2620 */ 2621 SmartCardHSMInitializer.prototype.setReplacePKAKeyMode = function(enable) { 2622 if (typeof(enable) == "undefined") { 2623 var enable = false; 2624 } 2625 2626 this.options = (this.options & 0xFFF7) + (enable ? 8 : 0); 2627 } 2628 2629 2630 2631 /** 2632 * Enable the combined authentication mode of user pin and public key authentication. 2633 * 2634 * @param {Boolean} enable true (non-default) to require public key authentication and user authentication 2635 */ 2636 SmartCardHSMInitializer.prototype.setCombinedAuthenticationMode = function(enable) { 2637 if (typeof(enable) == "undefined") { 2638 var enable = false; 2639 } 2640 2641 this.options = (this.options & 0xFFEF) + (enable ? 16 : 0); 2642 } 2643 2644 2645 2646 /** 2647 * If enabled RESET RETRY COUNTER only resets the error counter. 2648 * Otherwise RRC allows changing the PIN 2649 * 2650 * @param {Boolean} resetOnly true to only reset the error counter, false otherwise (default) 2651 */ 2652 SmartCardHSMInitializer.prototype.setResetRetryCounterResetOnlyMode = function(resetOnly) { 2653 if (typeof(resetOnly) == "undefined") { 2654 var resetOnly = false; 2655 } 2656 2657 this.options = (this.options & 0xFFDF) + (resetOnly ? 32 : 0); 2658 } 2659 2660 2661 2662 /** 2663 * Set parameter for public key authentication with n-of-m scheme, namely the values for n and m 2664 * 2665 * @param {Number} requiredPublicKeysForAuthentication number of key that must be authenticated for access 2666 * @param {Number} numberOfPublicKeys to register 2667 */ 2668 SmartCardHSMInitializer.prototype.setPublicKeyAuthenticationParameter = function(requiredPublicKeysForAuthentication, numberOfPublicKeys) { 2669 if ((numberOfPublicKeys < 1) || (numberOfPublicKeys > 90)) { 2670 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "numberOfPublicKeys must be between 1 and 90"); 2671 } 2672 if ((requiredPublicKeysForAuthentication < 1) || (requiredPublicKeysForAuthentication > numberOfPublicKeys)) { 2673 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 2, "requiredPublicKeysForAuthentication must be between 1 and " + numberOfPublicKeys); 2674 } 2675 this.numberOfPublicKeys = numberOfPublicKeys; 2676 this.requiredPublicKeysForAuthentication = requiredPublicKeysForAuthentication; 2677 this.useDefaultUserPIN = false; 2678 } 2679 2680 2681 2682 /** 2683 * Select the biometric matching server for a one of the biometric templates 2684 * 2685 * @param {Number} slot either 0 or 1 for first or second template 2686 * @param {ByteString} aid the application identifier of the on-card biometric server 2687 * @param {Number} param one byte parameter passed to the server during initialization 2688 */ 2689 SmartCardHSMInitializer.prototype.setBioTemplate = function(slot, aid, param) { 2690 assert(typeof(slot) == "number", "slot must be a number"); 2691 assert(slot >= 0 && slot <= 1, "slot must be either 0 or 1"); 2692 assert(aid instanceof ByteString, "aid must be a ByteString"); 2693 assert(typeof(param) == "number", "param must be a number"); 2694 assert(param >= 0 && param <= 255, "param must be between 0 and 255"); 2695 2696 this.bioslot[slot] = { aid: aid, param: param }; 2697 this.useDefaultUserPIN = false; 2698 } 2699 2700 2701 2702 /** 2703 * Set the label to be written to a minimal CIAInfo in EF 2F03 2704 * 2705 * @param {String} label the label 2706 */ 2707 SmartCardHSMInitializer.prototype.setLabel = function(label) { 2708 this.label = label; 2709 } 2710 2711 2712 2713 /** 2714 * Set the provisioning URL to be written to fixed parameter in CB00. 2715 * 2716 * @param {String} provisioningURL the URL at which this SE will be provisioned 2717 */ 2718 SmartCardHSMInitializer.prototype.setProvisioningURL = function(provisioningURL) { 2719 this.provisioningURL = provisioningURL; 2720 } 2721 2722 2723 2724 /** 2725 * Set the key check value of the token management key and the optional salt 2726 * used for SO-PIN derivation 2727 * 2728 * @param {ByteString} kcv the key check value of the token management key 2729 * @param {ByteString} salt the salt used to derive the SO-PIN 2730 */ 2731 SmartCardHSMInitializer.prototype.setTokenManagementKey = function(kcv, salt) { 2732 this.tokenManagementKeyKCV = kcv; 2733 this.tokenManagementKeySalt = salt; 2734 } 2735 2736 2737 2738 /** 2739 * Perform Initialization 2740 */ 2741 SmartCardHSMInitializer.prototype.initialize = function() { 2742 var s = new ASN1(0x30, new ASN1(0x80, ByteString.valueOf(this.options, 2))); 2743 2744 if (this.userPINSet || this.useDefaultUserPIN) { 2745 s.add(new ASN1(0x81, this.userPIN)); 2746 } 2747 2748 s.add(new ASN1(0x82, this.initializationCode)); 2749 2750 if (this.userPINSet || this.useDefaultUserPIN) { 2751 s.add(new ASN1(0x91, ByteString.valueOf(this.retryCounterInitial))); 2752 } 2753 2754 if (this.keyshares != -1) { 2755 s.add(new ASN1(0x92, ByteString.valueOf(this.keyshares))); 2756 } 2757 2758 if (this.keyDomains != -1) { 2759 s.add(new ASN1(0x97, ByteString.valueOf(this.keyDomains))); 2760 } 2761 2762 if (this.numberOfPublicKeys > 0) { 2763 s.add(new ASN1(0x93, ByteString.valueOf(this.numberOfPublicKeys).concat(ByteString.valueOf(this.requiredPublicKeysForAuthentication)))); 2764 } 2765 2766 if (this.bioslot[0]) { 2767 var o = this.bioslot[0]; 2768 s.add(new ASN1(0x95, ByteString.valueOf(o.param).concat(o.aid))); 2769 } 2770 2771 if (this.bioslot[1]) { 2772 var o = this.bioslot[1]; 2773 s.add(new ASN1(0x96, ByteString.valueOf(o.param).concat(o.aid))); 2774 } 2775 2776 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000, 0x6A84]); 2777 2778 if (this.card.SW == 0x6A84) { 2779 // Due to the nature of the JCRE, a first call to initialize may run out of memory, 2780 // as the garbage collector for the removed objects is only run during the next 2781 // APDU invocation. 2782 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000]); 2783 } 2784 2785 if (this.label) { 2786 var a = new ASN1(0x30, 2787 new ASN1(0x54, new ByteString("0000", HEX)), 2788 new ASN1(0x53, 2789 new ASN1(0x30, 2790 new ASN1(0x02, new ByteString("00", HEX)), 2791 new ASN1(0x80, new ByteString(this.label, UTF8)), 2792 new ASN1(0x03, new ByteString("0500", HEX))) 2793 ) 2794 ); 2795 2796 var p1 = SmartCardHSM.EF_TokenInfo.byteAt(0); 2797 var p2 = SmartCardHSM.EF_TokenInfo.byteAt(1); 2798 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, p1, p2, a.value, [0x9000]); 2799 } 2800 2801 if (this.provisioningURL || this.tokenManagementKeyKCV || this.tokenManagementKeySalt) { 2802 var l = new ASN1(ASN1.SEQUENCE); 2803 if (this.provisioningURL) { 2804 l.add(new ASN1(0x80, new ByteString(this.provisioningURL, UTF8))); 2805 } 2806 if (this.tokenManagementKeyKCV) { 2807 l.add(new ASN1(0x81, this.tokenManagementKeyKCV)); 2808 } 2809 if (this.tokenManagementKeySalt) { 2810 l.add(new ASN1(0x82, this.tokenManagementKeySalt)); 2811 } 2812 2813 var a = new ASN1(0x30, 2814 new ASN1(0x54, new ByteString("0000", HEX)), 2815 new ASN1(0x53, l) 2816 ); 2817 2818 var p1 = SmartCardHSM.EF_StaticTokenInfo.byteAt(0); 2819 var p2 = SmartCardHSM.EF_StaticTokenInfo.byteAt(1); 2820 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, p1, p2, a.value, [0x9000]); 2821 } 2822 } 2823 2824 2825 2826 /** 2827 * Create a key specification generator instance 2828 * 2829 * @class Class implementing an encoder for the C-Data required in GENERATE ASYMMETRIC KEY PAIR 2830 * @param {Number} keytype must be either Crypto.RSA, Crypto.EC or Crypto.AES 2831 * @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 2832 */ 2833 function SmartCardHSMKeySpecGenerator(keytype, keysizeOrDP) { 2834 this.keytype = keytype; 2835 2836 switch(keytype) { 2837 case Crypto.RSA: 2838 if (typeof(keysizeOrDP) != "number") { 2839 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be of a number for RSA keys"); 2840 } 2841 this.keysize = keysizeOrDP; 2842 this.defaultAlgo = new ByteString("id-TA-RSA-v1-5-SHA-256", OID); 2843 break; 2844 case Crypto.EC: 2845 if ((typeof(keysizeOrDP) != "object") || !(keysizeOrDP instanceof Key)) { 2846 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be a Key instance"); 2847 } 2848 this.domainParameter = keysizeOrDP; 2849 this.defaultAlgo = new ByteString("id-TA-ECDSA-SHA-256", OID); 2850 break; 2851 case Crypto.AES: 2852 if (typeof(keysizeOrDP) != "number") { 2853 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be of a number for AES keys"); 2854 } 2855 this.keysize = keysizeOrDP; 2856 break; 2857 default: 2858 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keytype must be Crypto.RSA or Crypto.EC"); 2859 } 2860 this.CHR = new PublicKeyReference("UTDUMMY00001"); 2861 this.innerCAR = new PublicKeyReference("UTDUMMY00001"); 2862 } 2863 2864 exports.SmartCardHSMKeySpecGenerator = SmartCardHSMKeySpecGenerator; 2865 2866 2867 2868 /** 2869 * Set key use counter for key 2870 * 2871 * @param {keyUseCounter} keyUseCounter in the range 1 to 2^64 - 2 2872 */ 2873 SmartCardHSMKeySpecGenerator.prototype.setKeyUseCounter = function(keyUseCounter) { 2874 if ((keyUseCounter < 0) || (keyUseCounter >= 0xFFFFFFFF)) { 2875 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 1, "keyUseCounter must be between 0 and 0xFFFFFFFF"); 2876 } 2877 this.keyUseCounter = keyUseCounter; 2878 } 2879 2880 2881 2882 /** 2883 * Set key domain 2884 * 2885 * @param {Number} keyDomain the key domain to which the key shall be added 2886 */ 2887 SmartCardHSMKeySpecGenerator.prototype.setKeyDomain = function(keyDomain) { 2888 this.keyDomain = keyDomain; 2889 } 2890 2891 2892 2893 /** 2894 * Set wrapping key 2895 * 2896 * @param {Number} wrappingKey the key to used for wrapping a newly generated symmetric key 2897 */ 2898 SmartCardHSMKeySpecGenerator.prototype.setWrappingKey = function(wrappingKey) { 2899 this.wrappingKey = wrappingKey; 2900 } 2901 2902 2903 2904 /** 2905 * Set algorithm list 2906 * 2907 * @param {ByteString} algorithms the list of algorithms allowed for this key 2908 */ 2909 SmartCardHSMKeySpecGenerator.prototype.setAlgorithms = function(algorithms) { 2910 this.algorithms = algorithms; 2911 } 2912 2913 2914 2915 /** 2916 * Set certificate holder reference for key 2917 * 2918 * @param {PublicKeyReference} CHR certificate holder reference 2919 */ 2920 SmartCardHSMKeySpecGenerator.prototype.setCHR = function(CHR) { 2921 this.CHR = CHR; 2922 } 2923 2924 2925 2926 /** 2927 * Set certificate holder reference of CA this request shall be sent to 2928 * 2929 * @param {PublicKeyReference} CAR certificate holder reference 2930 */ 2931 SmartCardHSMKeySpecGenerator.prototype.setInnerCAR = function(CAR) { 2932 this.innerCAR = CAR; 2933 } 2934 2935 2936 2937 /** 2938 * Set holder reference of the key signing this request 2939 * 2940 * @param {PublicKeyReference} CAR certificate holder reference 2941 */ 2942 SmartCardHSMKeySpecGenerator.prototype.setOuterCAR = function(CAR) { 2943 this.outerCAR = CAR; 2944 } 2945 2946 2947 2948 /** 2949 * @private 2950 */ 2951 SmartCardHSMKeySpecGenerator.prototype.encodeRSAKeySpec = function() { 2952 var p = new ASN1("Public Key", 0x7F49, 2953 new ASN1("Object Identifier", 0x06, this.defaultAlgo), 2954 new ASN1("Public Key Exponent", 0x82, ByteString.valueOf(65537)), 2955 new ASN1("Key Size", 0x02, ByteString.valueOf(this.keysize)) 2956 ); 2957 return p; 2958 } 2959 2960 2961 2962 /** 2963 * @private 2964 */ 2965 SmartCardHSMKeySpecGenerator.prototype.encodeECKeySpec = function() { 2966 // Encode G 2967 var bb = new ByteBuffer(); 2968 // uncompressed encoding 2969 bb.append(new ByteString("04", HEX)); 2970 bb.append(this.domainParameter.getComponent(Key.ECC_GX)); 2971 bb.append(this.domainParameter.getComponent(Key.ECC_GY)); 2972 var G = bb.toByteString(); 2973 2974 var p = new ASN1("Public Key", 0x7F49, 2975 new ASN1("Object Identifier", 0x06, this.defaultAlgo), 2976 new ASN1("Prime Modulus", 0x81, this.domainParameter.getComponent(Key.ECC_P)), 2977 new ASN1("First coefficient a", 0x82, this.domainParameter.getComponent(Key.ECC_A)), 2978 new ASN1("Second coefficient b", 0x83, this.domainParameter.getComponent(Key.ECC_B)), 2979 new ASN1("Base Point G", 0x84, G), 2980 new ASN1("Order of the base point", 0x85, this.domainParameter.getComponent(Key.ECC_N)), 2981 new ASN1("Cofactor f", 0x87, SmartCardHSM.stripLeadingZeros(this.domainParameter.getComponent(Key.ECC_H))) 2982 ); 2983 return p; 2984 } 2985 2986 2987 2988 /** 2989 * @private 2990 */ 2991 SmartCardHSMKeySpecGenerator.prototype.encodeKeySpec = function() { 2992 if (this.keytype == Crypto.RSA) { 2993 return this.encodeRSAKeySpec(); 2994 } else { 2995 return this.encodeECKeySpec(); 2996 } 2997 } 2998 2999 3000 3001 /** 3002 * Return the encoded key specification 3003 * 3004 * @type ByteString 3005 * @return the encoded C-Data for GENERATE ASYMMETRIC KEY PAIR 3006 */ 3007 SmartCardHSMKeySpecGenerator.prototype.encode = function() { 3008 var t = new ASN1(0x30); 3009 3010 if (this.keytype != Crypto.AES) { 3011 t.add(new ASN1("CPI", 0x5F29, new ByteString("00", HEX))); 3012 3013 if ((typeof(this.innerCAR) != "undefined") && (this.innerCAR)) { 3014 t.add(new ASN1("CAR", 0x42, this.innerCAR.getBytes())); 3015 } 3016 3017 t.add(this.encodeKeySpec()); 3018 t.add(new ASN1("CHR", 0x5F20, this.CHR.getBytes())); 3019 3020 if (typeof(this.outerCAR) != "undefined") { 3021 t.add(new ASN1("OuterCAR", 0x45, this.outerCAR.getBytes())); 3022 } 3023 } 3024 3025 if (typeof(this.keyUseCounter) != "undefined") { 3026 t.add(new ASN1("Key use counter", 0x90, ByteString.valueOf(this.keyUseCounter, 4))); 3027 } 3028 3029 if (typeof(this.algorithms) != "undefined") { 3030 t.add(new ASN1("Algorithms", 0x91, this.algorithms)); 3031 } 3032 3033 if (typeof(this.keyDomain) != "undefined") { 3034 t.add(new ASN1("KeyDomain", 0x92, ByteString.valueOf(this.keyDomain))); 3035 } 3036 3037 if (typeof(this.wrappingKey) != "undefined") { 3038 t.add(new ASN1("Wrapping Key", 0x93, ByteString.valueOf(this.wrappingKey))); 3039 } 3040 3041 return t.value; 3042 } 3043 3044 3045 3046 /** 3047 * Create a key specification generator instance for AES keys 3048 * 3049 * @class Class implementing an encoder for the C-Data required in Generate Symmetric Key 3050 * @param {ByteString} allowedAlgorithms the list of allowed algorithm identifier 3051 */ 3052 function SmartCardHSMSymmetricKeySpecGenerator(allowedAlgorithms) { 3053 this.algorithms = allowedAlgorithms; 3054 } 3055 3056 exports.SmartCardHSMSymmetricKeySpecGenerator = SmartCardHSMSymmetricKeySpecGenerator; 3057 3058 3059 3060 /** 3061 * Set key domain 3062 * 3063 * @param {Number} keyDomain the key domain to which the key shall be added 3064 */ 3065 SmartCardHSMSymmetricKeySpecGenerator.prototype.setKeyDomain = function(keyDomain) { 3066 this.keyDomain = keyDomain; 3067 } 3068 3069 3070 3071 /** 3072 * Return the encoded AES key specification 3073 * 3074 * @type ByteString 3075 * @return the encoded C-Data for Generate Symmetric Key 3076 */ 3077 SmartCardHSMSymmetricKeySpecGenerator.prototype.encode = function() { 3078 var t = new ASN1(0x30); 3079 3080 t.add(new ASN1("Algorithms", 0x91, this.algorithms)); 3081 3082 if (typeof(this.keyUseCounter) != "undefined") { 3083 t.add(new ASN1("Key use counter", 0x90, ByteString.valueOf(this.keyUseCounter, 4))); 3084 } 3085 3086 if (typeof(this.keyDomain) != "undefined") { 3087 t.add(new ASN1("Key Domain", 0x92, ByteString.valueOf(this.keyDomain))); 3088 } 3089 3090 if (typeof(this.wrappingKey) != "undefined") { 3091 t.add(new ASN1("Wrapping Key", 0x93, this.wrappingKey)); 3092 } 3093 3094 return t.value; 3095 } 3096 3097 3098 3099 SmartCardHSM.test = function() { 3100 var crypto = new Crypto(); 3101 var card = new Card(_scsh3.reader); 3102 var sc = new SmartCardHSM(card); 3103 3104 var sci = new SmartCardHSMInitializer(card); 3105 sci.initialize(); 3106 3107 var pubKey = sc.validateCertificateChain(crypto); 3108 sc.openSecureChannel(crypto, pubKey); 3109 3110 sc.verifyUserPIN(sci.userPIN); 3111 3112 var kg = new SmartCardHSMKeySpecGenerator(Crypto.RSA, 1024); 3113 sc.generateAsymmetricKeyPair(1, 0, kg.encode()); 3114 3115 var dp = new Key(); 3116 dp.setComponent(Key.ECC_CURVE_OID, new ByteString("brainpoolP256r1", OID)); 3117 3118 var kg = new SmartCardHSMKeySpecGenerator(Crypto.EC, dp); 3119 sc.generateAsymmetricKeyPair(2, 0, kg.encode()); 3120 3121 var list = sc.enumerateKeys(); 3122 GPSystem.trace("Keys on device: " + list); 3123 3124 var crypto = sc.getCrypto(); 3125 var message = new ByteString("Hello World", ASCII); 3126 3127 var key = sc.getKey(1); 3128 var signature = crypto.sign(key, Crypto.RSA_SHA256, message); 3129 GPSystem.trace("Signature: " + signature); 3130 3131 var key = sc.getKey(2); 3132 var signature = crypto.sign(key, Crypto.ECDSA, message); 3133 GPSystem.trace("Signature: " + signature); 3134 } 3135