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