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