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