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