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