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