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