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 if (typeof(this.caids) == "undefined") { 1840 this.enumerateCACertificates(); 1841 } 1842 1843 if (this.caids.length == 0) { 1844 return 0; 1845 } 1846 1847 var id = Math.max.apply(null, this.caids) + 1; 1848 if (id > 256) { 1849 return -1; 1850 } 1851 return id; 1852 } 1853 1854 1855 1856 /** 1857 * Add a new CA certificate to the map 1858 * 1859 * @param {X509} cert the CA certificate 1860 * @param {Number} id the corresponding id 1861 * @param {String} label the corresponding label 1862 */ 1863 SmartCardHSM.prototype.addCACertificateToMap = function(cert, id, label) { 1864 if (!this.caidmap[label]) { 1865 // new id 1866 this.caids.push(id); 1867 this.caidmap[label] = id; 1868 } 1869 this.canamemap[label] = cert; 1870 } 1871 1872 1873 1874 /** 1875 * Enumerate key objects in the SmartCard-HSM and build the map of keys 1876 * 1877 * @type String[] 1878 * @return the list of key labels 1879 */ 1880 SmartCardHSM.prototype.enumerateKeys = function() { 1881 this.namemap = []; 1882 this.idmap = []; 1883 this.idlist = []; 1884 this.p15idmap = []; 1885 1886 var fobs = this.enumerateObjects(); 1887 1888 // Process keys 1889 for (var i = 0; i < fobs.length; i += 2) { 1890 if ((fobs.byteAt(i) == SmartCardHSM.KEYPREFIX) || (fobs.byteAt(i) == 0xFF)) { 1891 var kid = fobs.byteAt(i + 1); 1892 if (kid > 0) { 1893 // GPSystem.trace("Found key: " + kid); 1894 var key = new SmartCardHSMKey(this, kid); 1895 this.idmap[kid] = key; 1896 this.idlist.push(kid); 1897 this.updateKey(key); 1898 } 1899 } 1900 } 1901 1902 var keylist = []; 1903 // Process PKCS#15 private key descriptions 1904 for (var i = 0; i < fobs.length; i += 2) { 1905 if (fobs.byteAt(i) == SmartCardHSM.PRKDPREFIX) { 1906 var kid = fobs.byteAt(i + 1); 1907 var descbin = this.readBinary(fobs.bytes(i, 2)); 1908 if (descbin.length > 2) { 1909 try { 1910 var desc = new ASN1(descbin); 1911 if (desc.elements < 3) { 1912 continue; 1913 } 1914 } 1915 catch(e) { 1916 continue; 1917 } 1918 var key = this.idmap[kid]; 1919 if (key) { 1920 key.setDescription(desc); 1921 var label = key.getLabel(); 1922 // GPSystem.trace(key.getId() + " - " + label); 1923 if (label) { 1924 keylist.push(label); 1925 this.namemap[label] = key; 1926 } 1927 var p15id = key.getPKCS15Id(); 1928 this.p15idmap[p15id.toString(HEX)] = key; 1929 } 1930 } 1931 } 1932 } 1933 1934 return keylist; 1935 } 1936 1937 1938 1939 /** 1940 * Get key ids 1941 * 1942 * @type Number[] 1943 * @return a list of key identifier 1944 */ 1945 SmartCardHSM.prototype.getKeyIds = function() { 1946 if (typeof(this.idlist) == "undefined") { 1947 this.enumerateKeys(); 1948 } 1949 return this.idlist; 1950 } 1951 1952 1953 1954 /** 1955 * Determine an unused key identifier 1956 * 1957 * @type Number 1958 * @return a free key identifier or -1 if all key identifier in use 1959 */ 1960 SmartCardHSM.prototype.determineFreeKeyId = function() { 1961 if (typeof(this.idlist) == "undefined") { 1962 this.enumerateKeys(); 1963 } 1964 for (var i = 1; i < 256; i++) { 1965 if (this.idmap[i] == undefined) { 1966 return i; 1967 } 1968 } 1969 throw new GPError("SmartCardHSM", GPError.OUT_OF_MEMORY, 1, "Key idx exhausted"); 1970 } 1971 1972 1973 1974 /** 1975 * Update key attributes, in particular the use counter 1976 * 1977 * @param {HSMKey} key the HSM key 1978 */ 1979 SmartCardHSM.prototype.updateKey = function(key) { 1980 var fid = ByteString.valueOf((SmartCardHSM.KEYPREFIX << 8) + key.getId()); 1981 try { 1982 var fcp = this.selectFile(fid); 1983 } 1984 catch(e) { 1985 return; 1986 } 1987 var a = new ASN1(fcp); 1988 var pi = a.find(0xA5); 1989 if (!pi) { 1990 return; 1991 } 1992 var kc = pi.find(0x90); 1993 if (kc) { 1994 var c = kc.value.toUnsigned(); 1995 1996 if (c != 0xFFFFFFFF) { 1997 key.useCounter = c; 1998 } 1999 } 2000 2001 var kd = pi.find(0x91); 2002 if (kd) { 2003 key.algorithms = kd.value; 2004 } 2005 2006 var kd = pi.find(0x92); 2007 if (kd) { 2008 key.keyDomain = kd.value.toUnsigned(); 2009 } 2010 } 2011 2012 2013 2014 /** 2015 * Add a new key to the map of keys 2016 * 2017 * @param {HSMKey} key the HSM key 2018 */ 2019 SmartCardHSM.prototype.addKeyToMap = function(key) { 2020 var id = key.getId(); 2021 this.idmap[id] = key; 2022 2023 var label = key.getLabel(); 2024 if (label) { 2025 this.namemap[label] = key; 2026 } 2027 2028 var p15id = key.getPKCS15Id(); 2029 if (p15id) { 2030 this.p15idmap[p15id.toString(HEX)] = key; 2031 } 2032 } 2033 2034 2035 2036 /** 2037 * Get a key reference object 2038 * 2039 * @param {String/Number/ByteString} labelOrId label or id of key 2040 * @returns the key or null if not found 2041 * @type Key 2042 */ 2043 SmartCardHSM.prototype.getKey = function(labelOrId) { 2044 if (typeof(this.idlist) == "undefined") { 2045 this.enumerateKeys(); 2046 } 2047 2048 if (typeof(labelOrId) == "number") { 2049 var key = this.idmap[labelOrId]; 2050 } else if (typeof(labelOrId) == "string") { 2051 var key = this.namemap[labelOrId]; 2052 } else { 2053 var key = this.p15idmap[labelOrId.toString(HEX)]; 2054 } 2055 2056 if (key == undefined) { 2057 return null; 2058 } 2059 return key; 2060 } 2061 2062 2063 2064 /** 2065 * Return a list of key objects 2066 * 2067 * @type SmartCardHSMKey[] 2068 * @return the list of keys 2069 */ 2070 SmartCardHSM.prototype.getKeys = function() { 2071 if (typeof(this.idlist) == "undefined") { 2072 this.enumerateKeys(); 2073 } 2074 2075 var keylist = []; 2076 for (var i in this.idmap) { 2077 keylist.push(this.idmap[i]); 2078 } 2079 return keylist; 2080 } 2081 2082 2083 2084 /** 2085 * Determine a free id in the list of FID for the given prefix. 2086 * 2087 * @param {Number} the prefix to look at 2088 * @param {ByteString} the list of FID as returned from the device 2089 * @type Number 2090 * @return a free id for the given prefix or -1 if range is exhausted. 2091 */ 2092 SmartCardHSM.determineFreeId = function(prefix, fobs) { 2093 var map = new Bitmap(256); 2094 2095 for (var i = 0; i < fobs.length; i+= 2) { 2096 if (fobs.byteAt(i) == prefix) { 2097 map.toggle(fobs.byteAt(i + 1)); 2098 } 2099 } 2100 2101 return map.determineFirstUnset(); 2102 } 2103 2104 2105 2106 /** 2107 * Determine a free FID in the list of FID for the given prefix. 2108 * 2109 * @param {Number} the prefix to look at 2110 * @param {ByteString} the list of FID as returned from the device 2111 * @type ByteString 2112 * @return a free two byte file identifier (FID) for the given prefix or null if range is exhausted. 2113 */ 2114 SmartCardHSM.determineFreeFid = function(prefix, fobs) { 2115 var id = SmartCardHSM.determineFreeId(prefix, fobs); 2116 if (id < 0) { 2117 return null; 2118 } 2119 return ByteString.valueOf((prefix << 8) + id); 2120 } 2121 2122 2123 2124 /** 2125 * Enumerate Data Objects 2126 * 2127 * @type String[] 2128 * @return the list of data object labels 2129 */ 2130 SmartCardHSM.prototype.enumerateDataObjects = function() { 2131 this.donamemap = []; 2132 var dolist = []; 2133 2134 var fobs = this.enumerateObjects(); 2135 2136 // Process PKCS#15 data object descriptions 2137 for (var i = 0; i < fobs.length; i+= 2) { 2138 if (fobs.byteAt(i) == SmartCardHSM.DODPREFIX) { 2139 var descfid = fobs.bytes(i, 2); 2140 var descbin = this.readBinary(descfid); 2141 var asn = new ASN1(descbin); 2142 // print(asn); 2143 var coa = asn.get(0); 2144 if (coa.elements > 0) { 2145 var label = coa.get(0).value.toString(ASCII); 2146 } else { 2147 var label = "No label (" + i + ")"; 2148 } 2149 var taga1 = asn.find(0xA1); 2150 if (taga1) { 2151 var datafid = taga1.get(0).get(0).value; 2152 this.donamemap[label] = { datafid: datafid, descfid: descfid }; 2153 dolist.push(label); 2154 } 2155 } 2156 } 2157 2158 return dolist; 2159 } 2160 2161 2162 2163 /** 2164 * Check if the data object is present 2165 * 2166 * @param {String} label the label 2167 * @type boolean 2168 * @return true if the data object exists 2169 */ 2170 SmartCardHSM.prototype.hasDataObject = function(label) { 2171 if (typeof(this.donamemap) == "undefined"){ 2172 this.enumerateDataObjects(); 2173 } 2174 return (this.donamemap[label] != undefined); 2175 } 2176 2177 2178 2179 /** 2180 * Return the file identifier containing the data object. 2181 * 2182 * @param {String} label the label. 2183 * @type ByteString 2184 * @return the two byte file identifier 2185 */ 2186 SmartCardHSM.prototype.getDataObjectFileIdentifier = function(label) { 2187 if (typeof(this.donamemap) == "undefined"){ 2188 this.enumerateDataObjects(); 2189 } 2190 var e = this.donamemap[label]; 2191 if (e == undefined) { 2192 throw new GPError(module.id, GPError.INVALID_DATA, 0, "Data object " + label + " not found"); 2193 } 2194 return e.datafid; 2195 } 2196 2197 2198 2199 /** 2200 * Import a data object 2201 * 2202 * @param {String} label the unique label to reference the new data object 2203 * @param {Boolean} privObj true to store the data object with read protection 2204 * @param {ByteString} data the data blob to store 2205 */ 2206 SmartCardHSM.prototype.importDataObject = function(label, privObj, data) { 2207 var fobs = this.enumerateObjects(); 2208 2209 var e = this.donamemap[label]; 2210 if (e != undefined) { 2211 throw new GPError(module.id, GPError.INVALID_DATA, 0, "Data object " + label + " does already exist"); 2212 } 2213 2214 if (privObj) { 2215 var datafid = SmartCardHSM.determineFreeFid(SmartCardHSM.CONFIDENTIALDATAPREFIX, fobs); 2216 } else { 2217 var datafid = SmartCardHSM.determineFreeFid(SmartCardHSM.PUBLICDATAPREFIX, fobs); 2218 } 2219 2220 if (datafid == null) { 2221 throw new GPError(module.id, GPError.INVALID_DATA, 0, "Out of space for data objects"); 2222 } 2223 2224 var desc = SmartCardHSM.buildDataObjectDescription(label, undefined, datafid, "KeyManager"); 2225 2226 var descfid = SmartCardHSM.determineFreeFid(SmartCardHSM.DODPREFIX, fobs); 2227 2228 if (descfid == null) { 2229 throw new GPError(module.id, GPError.INVALID_DATA, 0, "Out of space for data objects descriptor"); 2230 } 2231 2232 this.updateBinary(datafid, 0, data); 2233 this.updateBinary(descfid, 0, desc.getBytes()); 2234 this.donamemap[label] = { datafid: datafid, descfid: descfid }; 2235 } 2236 2237 2238 2239 /** 2240 * Delete the data object references by the label. 2241 * 2242 * @param {String} label the label of the data object 2243 */ 2244 SmartCardHSM.prototype.deleteDataObject = function(label) { 2245 if (typeof(this.donamemap) == "undefined"){ 2246 this.enumerateDataObjects(); 2247 } 2248 var e = this.donamemap[label]; 2249 if (e == undefined) { 2250 throw new GPError(module.id, GPError.INVALID_DATA, 0, "Data object " + label + " not found"); 2251 } 2252 this.deleteFile(e.descfid); 2253 this.deleteFile(e.datafid); 2254 delete this.donamemap[label]; 2255 } 2256 2257 2258 2259 /** 2260 * Get crypto object 2261 * 2262 * @type HSMCrypto 2263 * @return the HSMCrypto object 2264 */ 2265 SmartCardHSM.prototype.getCrypto = function() { 2266 if (this.crypto == undefined) { 2267 this.crypto = new SmartCardHSMCrypto(new Crypto()); 2268 } 2269 return this.crypto; 2270 } 2271 2272 2273 2274 /** 2275 * @private 2276 */ 2277 SmartCardHSM.prototype.getTokenInfo = function() { 2278 if (this.tokenInfo != undefined) { 2279 return this.tokenInfo; 2280 } 2281 2282 if (!this.hasFile(SmartCardHSM.EF_TokenInfo)) { 2283 return; 2284 } 2285 2286 var bin = this.readBinary(SmartCardHSM.EF_TokenInfo); 2287 this.tokenInfo = new ASN1(bin); 2288 return this.tokenInfo; 2289 } 2290 2291 2292 2293 /** 2294 * Get Token Label 2295 * 2296 * @type String 2297 * @return the token label from CIAInfo 2298 */ 2299 SmartCardHSM.prototype.getLabel = function() { 2300 var ti = this.getTokenInfo(); 2301 if (!ti) { 2302 return; 2303 } 2304 2305 var a = ti.find(0x80); 2306 if (!a) { 2307 return; 2308 } 2309 return a.value.toString(UTF8); 2310 } 2311 2312 2313 2314 /** 2315 * @private 2316 */ 2317 SmartCardHSM.prototype.getStaticTokenInfo = function() { 2318 if (this.staticTokenInfo != undefined) { 2319 return this.staticTokenInfo; 2320 } 2321 2322 if (!this.hasFile(SmartCardHSM.EF_StaticTokenInfo)) { 2323 return; 2324 } 2325 2326 var bin = this.readBinary(SmartCardHSM.EF_StaticTokenInfo); 2327 this.staticTokenInfo = new ASN1(bin); 2328 return this.staticTokenInfo; 2329 } 2330 2331 2332 2333 /** 2334 * Get ProvisioningURL 2335 * 2336 * @type String 2337 * @return the configured ProvisioningURL or undefined 2338 */ 2339 SmartCardHSM.prototype.getProvisioningURL = function() { 2340 var ti = this.getStaticTokenInfo(); 2341 if (!ti) { 2342 return; 2343 } 2344 2345 var a = ti.find(0x80); 2346 if (!a) { 2347 return; 2348 } 2349 return a.value.toString(UTF8); 2350 } 2351 2352 2353 2354 /** 2355 * Get Key Check Value of Token Management Key 2356 * 2357 * @type ByteString 2358 * @return the configured KCV of the Token Management Key or undefined 2359 */ 2360 SmartCardHSM.prototype.getTokenManagementKeyKCV = function() { 2361 var ti = this.getStaticTokenInfo(); 2362 if (!ti) { 2363 return; 2364 } 2365 2366 var a = ti.find(0x81); 2367 if (!a) { 2368 return; 2369 } 2370 return a.value; 2371 } 2372 2373 2374 2375 /** 2376 * Get salt for SO-PIN derivation using the Token Management Key 2377 * 2378 * @type ByteString 2379 * @return the configured salt 2380 */ 2381 SmartCardHSM.prototype.getTokenManagementKeySalt = function() { 2382 var ti = this.getStaticTokenInfo(); 2383 if (!ti) { 2384 return; 2385 } 2386 2387 var a = ti.find(0x82); 2388 if (!a) { 2389 return; 2390 } 2391 return a.value; 2392 } 2393 2394 2395 2396 /** 2397 * Create crypto object implementing access to the SmartCard-HSM 2398 * 2399 * @class Wrapper to provide Crypto interface to SmartCard-HSM 2400 * @constructor 2401 * @param {Crypto} crypto the backend crypto provider 2402 */ 2403 function SmartCardHSMCrypto(crypto) { 2404 this.crypto = crypto; 2405 } 2406 2407 2408 2409 /** 2410 * Sign a message using the defined mechanism and key 2411 * 2412 * @param {HSMKey} key the private key 2413 * @param {Number} mech the mechanism (e.g. Crypto.ECDSA) 2414 * @param {ByteString} message the message to be signed 2415 * @type ByteString 2416 * @return the signature 2417 */ 2418 SmartCardHSMCrypto.prototype.sign = function(key, mech, message) { 2419 if (key instanceof SmartCardHSMKey) { 2420 return key.sign(mech, message); 2421 } else { 2422 return this.crypto.sign(key, mech, message); 2423 } 2424 } 2425 2426 2427 2428 /** 2429 * Decrypt a message using the defined mechanism and key 2430 * 2431 * @param {HSMKey} key the private key 2432 * @param {Number} mech the mechanism (e.g. Crypto.RSA_PKCS1) 2433 * @param {ByteString} data the cryptogram 2434 * @param {ByteString} iv the initialization vector for symmetric ciphers 2435 * @type ByteString 2436 * @return the plain text 2437 */ 2438 SmartCardHSMCrypto.prototype.decrypt = function(key, mech, data, iv) { 2439 if (key instanceof SmartCardHSMKey) { 2440 return key.decrypt(mech, data); 2441 } else { 2442 return this.crypto.decrypt(key, mech, data, iv); 2443 } 2444 } 2445 2446 2447 2448 /** 2449 * Verify a message using the defined mechanism and key 2450 * 2451 * @param {Key} key the public key 2452 * @param {Number} mech the mechanism (e.g. Crypto.ECDSA) 2453 * @param {ByteString} message the message to be signed 2454 * @param {ByteString} signature the signature to verify 2455 * @type Boolean 2456 * @return true if signature is valid 2457 */ 2458 SmartCardHSMCrypto.prototype.verify = function(key, mech, message, signature) { 2459 return this.crypto.verify(key, mech, message, signature); 2460 } 2461 2462 2463 2464 /** 2465 * Create a key access object 2466 * 2467 * @class Class implementing key access 2468 * @param {SmartCardHSM} sc the card access object 2469 * @param {Number} id the key identifier 2470 */ 2471 function SmartCardHSMKey(sc, id) { 2472 this.sc = sc; 2473 this.id = id; 2474 if (this.sc.useExternalHashInECDSA) { 2475 this.crypto = new Crypto(); 2476 } 2477 } 2478 2479 exports.SmartCardHSMKey = SmartCardHSMKey; 2480 2481 2482 /** 2483 * Set the PKCS#15 private key description 2484 * 2485 * @param {ASN1} desc the description 2486 */ 2487 SmartCardHSMKey.prototype.setDescription = function(desc) { 2488 this.desc = desc; 2489 } 2490 2491 2492 2493 /** 2494 * Return the key identifier 2495 * 2496 * @type Number 2497 * @return the key identifier 2498 */ 2499 SmartCardHSMKey.prototype.getId = function() { 2500 return this.id; 2501 } 2502 2503 2504 2505 /** 2506 * Return the key label as encoded in the PKCS#15 structure 2507 * 2508 * @type String 2509 * @return the key label 2510 */ 2511 SmartCardHSMKey.prototype.getLabel = function() { 2512 if (this.desc == undefined) { 2513 return undefined; 2514 } 2515 if ((this.desc.get(0).elements == 0) || this.desc.get(0).get(0).tag != 0x0C) { 2516 return undefined; 2517 } 2518 2519 return this.desc.get(0).get(0).value.toString(UTF8); 2520 } 2521 2522 2523 2524 /** 2525 * Return the key id as encoded in the PKCS#15 structure 2526 * 2527 * @type ByteString 2528 * @return the key identifier 2529 */ 2530 SmartCardHSMKey.prototype.getPKCS15Id = function() { 2531 if (this.desc == undefined) { 2532 return undefined; 2533 } 2534 return this.desc.get(1).get(0).value; 2535 } 2536 2537 2538 2539 /** 2540 * Return the key size in bits 2541 * 2542 * @type Number 2543 * @return the key size in bits 2544 */ 2545 SmartCardHSMKey.prototype.getSize = function() { 2546 if (this.desc == undefined) { 2547 return undefined; 2548 } 2549 // GPSystem.trace(this.desc); 2550 if (this.desc.get(2).elements > 1) { // Fix a bug from early versions 2551 return this.desc.get(2).get(1).value.toUnsigned(); 2552 } 2553 2554 if (this.desc.tag == 0xA8) { 2555 var size = this.desc.get(2).get(0).get(0).value.toUnsigned(); 2556 } else { 2557 var a1 = this.desc.find(0xA1); 2558 var size = a1.get(0).get(1).value.toUnsigned(); 2559 2560 if (size == 528) { 2561 size = 521; // Fix bug in OpenSCDP returning the wrong key size for secp521 keys 2562 } 2563 } 2564 2565 return size; 2566 } 2567 2568 2569 2570 /** 2571 * Return the key type 2572 * 2573 * @type String 2574 * @return the key type 2575 */ 2576 SmartCardHSMKey.prototype.getType = function() { 2577 if (this.desc == undefined) { 2578 return undefined; 2579 } 2580 2581 if (this.desc.tag == 0xA0) { 2582 return "EC"; 2583 } else if (this.desc.tag == 0x30) { 2584 return "RSA"; 2585 } else if (this.desc.tag == 0xA8) { 2586 return "AES"; 2587 } 2588 2589 return undefined; 2590 } 2591 2592 2593 2594 /** 2595 * Sign data using a key in the SmartCard-HSM 2596 * 2597 * @param {Number} mech the signing mechanism 2598 * @param {ByteString} data to be signed 2599 * @type ByteString 2600 * @return the signature 2601 */ 2602 SmartCardHSMKey.prototype.sign = function(mech, data) { 2603 var algo; 2604 if (mech) { 2605 switch(mech) { 2606 case Crypto.RSA: 2607 algo = 0x20; 2608 break; 2609 case Crypto.RSA_SHA1: 2610 algo = 0x31; 2611 break; 2612 case Crypto.RSA_SHA224: 2613 algo = 0x32; 2614 break; 2615 case Crypto.RSA_SHA256: 2616 algo = 0x33; 2617 break; 2618 case Crypto.RSA_SHA384: 2619 algo = 0x34; 2620 break; 2621 case Crypto.RSA_SHA512: 2622 algo = 0x35; 2623 break; 2624 case Crypto.RSA_PKCS1: 2625 if (this.sc.major && this.sc.major >= 4) { 2626 algo = 0x30; 2627 } else { 2628 algo = 0x20; 2629 var keysize = this.getSize(); 2630 if (!keysize) { 2631 throw new GPError(module.id, GPError.INVALID_DATA, 0, "Can't determine key size"); 2632 } 2633 data = PKCS1.encode_EMSA_V15(keysize, data); 2634 } 2635 break; 2636 case Crypto.RSA_PSS: 2637 case 0x80: 2638 algo = 0x40; 2639 break; 2640 case Crypto.RSA_PSS_SHA1: 2641 algo = 0x41; 2642 break; 2643 case Crypto.RSA_PSS_SHA224: 2644 algo = 0x42; 2645 break; 2646 case Crypto.RSA_PSS_SHA256: 2647 algo = 0x43; 2648 break; 2649 case Crypto.RSA_PSS_SHA384: 2650 algo = 0x44; 2651 break; 2652 case Crypto.RSA_PSS_SHA512: 2653 algo = 0x45; 2654 break; 2655 case Crypto.ECDSA: 2656 algo = 0x70; 2657 break; 2658 case Crypto.ECDSA_SHA1: 2659 if (this.sc.useExternalHashInECDSA) { 2660 algo = 0x70; 2661 var data = this.crypto.digest(Crypto.SHA_1, data); 2662 } else { 2663 algo = 0x71; 2664 } 2665 break; 2666 case Crypto.ECDSA_SHA224: 2667 if (this.sc.useExternalHashInECDSA) { 2668 algo = 0x70; 2669 var data = this.crypto.digest(Crypto.SHA_224, data); 2670 } else { 2671 algo = 0x72; 2672 } 2673 break; 2674 case Crypto.ECDSA_SHA256: 2675 if (this.sc.useExternalHashInECDSA) { 2676 algo = 0x70; 2677 var data = this.crypto.digest(Crypto.SHA_256, data); 2678 } else { 2679 algo = 0x73; 2680 } 2681 break; 2682 case Crypto.ECDSA_SHA384: 2683 if (this.sc.useExternalHashInECDSA) { 2684 algo = 0x70; 2685 var data = this.crypto.digest(Crypto.SHA_384, data); 2686 } else { 2687 algo = 0x74; 2688 } 2689 break; 2690 case Crypto.ECDSA_SHA512: 2691 if (this.sc.useExternalHashInECDSA) { 2692 algo = 0x70; 2693 var data = this.crypto.digest(Crypto.SHA_512, data); 2694 } else { 2695 algo = 0x75; 2696 } 2697 break; 2698 case Crypto.AES_CMAC: 2699 return this.sc.deriveSymmetricKey(this.id, SmartCardHSM.ALG_CMAC, data); 2700 default: 2701 throw new GPError("SmartCardHSMKey", GPError.INVALID_DATA, mech, "Unsupported crypto mechanism"); 2702 } 2703 } 2704 2705 return this.sc.sign(this.id, algo, data); 2706 } 2707 2708 2709 2710 /** 2711 * Decrypt data using a key in the SmartCard-HSM 2712 * 2713 * @param {Number} mech the decipher mechanism 2714 * @param {ByteString} data to be deciphered 2715 * @type ByteString 2716 * @return the plain message 2717 */ 2718 SmartCardHSMKey.prototype.decrypt = function(mech, data) { 2719 var algo; 2720 if (mech) { 2721 switch(mech) { 2722 case Crypto.RSA: 2723 break; 2724 case Crypto.RSA_PKCS1: 2725 break; 2726 case Crypto.RSA_OAEP_SHA224: 2727 algo = Crypto.SHA_224; 2728 break; 2729 case Crypto.RSA_OAEP_SHA256: 2730 algo = Crypto.SHA_256; 2731 break; 2732 case Crypto.RSA_OAEP_SHA384: 2733 algo = Crypto.SHA_384; 2734 break; 2735 case Crypto.RSA_OAEP_SHA512: 2736 algo = Crypto.SHA_512; 2737 break; 2738 default: 2739 throw new GPError("SmartCardHSMKey", GPError.INVALID_DATA, mech, "Unsupported crypto mechanism"); 2740 } 2741 } 2742 2743 var em = this.sc.decipher(this.id, 0x21, data); 2744 2745 var plain = em; 2746 2747 if (mech != Crypto.RSA) { 2748 if (mech == Crypto.RSA_PKCS1) { 2749 var plain = PKCS1.decode_EME_V15(em); 2750 } else { 2751 var crypto = this.sc.getCrypto().crypto; 2752 2753 var plain = PKCS1.decode_EME_OAEP(crypto, null, algo, em); 2754 } 2755 2756 if (!plain) { 2757 throw new GPError("SmartCardHSMKey", GPError.CRYPTO_FAILED, mech, "Decryption failed"); 2758 } 2759 } 2760 2761 return plain; 2762 } 2763 2764 2765 2766 /** 2767 * Return human readable string 2768 */ 2769 SmartCardHSMKey.prototype.toString = function() { 2770 return "SmartCardHSMKey(id=" + this.id + ")"; 2771 } 2772 2773 2774 2775 /** 2776 * Initialize SmartCard-HSM 2777 * 2778 * @class Class implementing the device initialization methods 2779 * @param {Card} card the card object 2780 */ 2781 function SmartCardHSMInitializer(card) { 2782 this.card = card; 2783 this.initializationCode = new ByteString("57621880", ASCII); 2784 this.userPIN = new ByteString("648219", ASCII); 2785 this.userPINSet = false; 2786 this.useDefaultUserPIN = true; 2787 this.retryCounterInitial = 3; 2788 this.options = 0x0001; 2789 this.keyshares = -1; 2790 this.keyDomains = -1; 2791 this.numberOfPublicKeys = 0; 2792 this.requiredPublicKeysForAuthentication = 0; 2793 this.bioslot = []; 2794 this.label = undefined; 2795 } 2796 2797 exports.SmartCardHSMInitializer = SmartCardHSMInitializer; 2798 2799 2800 2801 /** 2802 * Set the initialization code 2803 * 2804 * @param {ByteString} initializationCode an 8 byte code 2805 */ 2806 SmartCardHSMInitializer.prototype.setInitializationCode = function(initializationCode) { 2807 if (!(initializationCode instanceof ByteString)) { 2808 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "initializationCode must be a ByteString"); 2809 } 2810 if (initializationCode.length != 8) { 2811 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "initializationCode must have 8 bytes"); 2812 } 2813 2814 this.initializationCode = initializationCode; 2815 } 2816 2817 2818 2819 /** 2820 * Set the User PIN 2821 * 2822 * @param {ByteString} userPIN a 6 to 16 byte code 2823 */ 2824 SmartCardHSMInitializer.prototype.setUserPIN = function(userPIN) { 2825 if (!(userPIN instanceof ByteString)) { 2826 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "userPIN must be a ByteString"); 2827 } 2828 if ((userPIN.length < 6) || (userPIN.length > 16)) { 2829 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "userPIN must be between 6 and 16 bytes"); 2830 } 2831 2832 this.userPIN = userPIN; 2833 this.userPINSet = true; 2834 this.useDefaultUserPIN = false; 2835 } 2836 2837 2838 2839 /** 2840 * Set the retry counter 2841 * 2842 * The SmartCard-HSM enforces a retry counter <= 3 for PIN length 6 2843 * The SmartCard-HSM enforces a retry counter <= 5 for PIN length 7 2844 * The SmartCard-HSM enforces a retry counter <= 10 for PIN length larger than 7 2845 * 2846 * @param {Number} retryCounterInitial in the range 1 to 10. 2847 */ 2848 SmartCardHSMInitializer.prototype.setRetryCounterInitial = function(retryCounterInitial) { 2849 if (typeof(retryCounterInitial) != "number") { 2850 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "retryCounterInitial must be a number"); 2851 } 2852 if ((retryCounterInitial < 1) || (retryCounterInitial > 10)) { 2853 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "retryCounterInitial must be between 1 and 10"); 2854 } 2855 this.retryCounterInitial = retryCounterInitial; 2856 } 2857 2858 2859 2860 /** 2861 * Set the number of DKEK shares 2862 * 2863 * @param {Number} keyshares number of DKEK shares in the range 0 to 255 2864 */ 2865 SmartCardHSMInitializer.prototype.setDKEKShares = function(keyshares) { 2866 if (typeof(keyshares) != "number") { 2867 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyshares must be a number"); 2868 } 2869 if ((keyshares < 0) || (keyshares > 255)) { 2870 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyshares must be between 0 and 255"); 2871 } 2872 this.keyshares = keyshares; 2873 this.keyDomains = -1; 2874 } 2875 2876 2877 2878 /** 2879 * Set the number of key domains 2880 * 2881 * @param {Number} keyDomains number of key domains 2882 */ 2883 SmartCardHSMInitializer.prototype.setKeyDomains = function(keyDomains) { 2884 if (typeof(keyDomains) != "number") { 2885 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyDomains must be a number"); 2886 } 2887 2888 this.keyDomains = keyDomains; 2889 this.keyshares = -1; 2890 } 2891 2892 2893 2894 /** 2895 * Enable or disable RESET RETRY COUNTER command 2896 * 2897 * @param {Boolean} enable true (default) to allow RESET RETRY COUNTER command to reset user PIN using the initialization code 2898 */ 2899 SmartCardHSMInitializer.prototype.setResetRetryCounterMode = function(enable) { 2900 if (typeof(enable) == "undefined") { 2901 var enable = false; 2902 } 2903 2904 this.options = (this.options & 0xFFFE) + (enable ? 1 : 0); 2905 } 2906 2907 2908 2909 /** 2910 * Enable or disable transport PIN mode 2911 * 2912 * @param {Boolean} enable true (non-default) to set user PIN to transport state 2913 */ 2914 SmartCardHSMInitializer.prototype.setTransportPINMode = function(enable) { 2915 if (typeof(enable) == "undefined") { 2916 var enable = true; 2917 } 2918 2919 this.options = (this.options & 0xFFFD) + (enable ? 2 : 0); 2920 } 2921 2922 2923 2924 /** 2925 * Enable or disable session PIN mode 2926 * 2927 * @param {Number} 0 - disable, 1 - enable with clear-on-reset 3 - enable with explicit clearing 2928 */ 2929 SmartCardHSMInitializer.prototype.setSessionPINMode = function(mode) { 2930 assert(typeof(mode) == "number", "Argument mode must be number"); 2931 assert(mode >= 0 && mode <= 3 && mode != 2, "Argument mode must be 0, 1 or 3"); 2932 2933 this.options = (this.options & 0xFFF3) + (mode << 2); 2934 } 2935 2936 2937 2938 /** 2939 * Enable or disable replacing of a PKA key 2940 * 2941 * @param {Boolean} enable true (non-default) to allow replacing of a PKA key 2942 */ 2943 SmartCardHSMInitializer.prototype.setReplacePKAKeyMode = function(enable) { 2944 if (typeof(enable) == "undefined") { 2945 var enable = false; 2946 } 2947 2948 this.options = (this.options & 0xFFF7) + (enable ? 8 : 0); 2949 } 2950 2951 2952 2953 /** 2954 * Enable the combined authentication mode of user pin and public key authentication. 2955 * 2956 * @param {Boolean} enable true (non-default) to require public key authentication and user authentication 2957 */ 2958 SmartCardHSMInitializer.prototype.setCombinedAuthenticationMode = function(enable) { 2959 if (typeof(enable) == "undefined") { 2960 var enable = false; 2961 } 2962 2963 this.options = (this.options & 0xFFEF) + (enable ? 16 : 0); 2964 } 2965 2966 2967 2968 /** 2969 * If enabled RESET RETRY COUNTER only resets the error counter. 2970 * Otherwise RRC allows changing the PIN 2971 * 2972 * @param {Boolean} resetOnly true to only reset the error counter, false otherwise (default) 2973 */ 2974 SmartCardHSMInitializer.prototype.setResetRetryCounterResetOnlyMode = function(resetOnly) { 2975 if (typeof(resetOnly) == "undefined") { 2976 var resetOnly = false; 2977 } 2978 2979 this.options = (this.options & 0xFFDF) + (resetOnly ? 32 : 0); 2980 } 2981 2982 2983 2984 /** 2985 * Set parameter for public key authentication with n-of-m scheme, namely the values for n and m 2986 * 2987 * @param {Number} requiredPublicKeysForAuthentication number of key that must be authenticated for access 2988 * @param {Number} numberOfPublicKeys to register 2989 */ 2990 SmartCardHSMInitializer.prototype.setPublicKeyAuthenticationParameter = function(requiredPublicKeysForAuthentication, numberOfPublicKeys) { 2991 if ((numberOfPublicKeys < 1) || (numberOfPublicKeys > 90)) { 2992 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "numberOfPublicKeys must be between 1 and 90"); 2993 } 2994 if ((requiredPublicKeysForAuthentication < 1) || (requiredPublicKeysForAuthentication > numberOfPublicKeys)) { 2995 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 2, "requiredPublicKeysForAuthentication must be between 1 and " + numberOfPublicKeys); 2996 } 2997 this.numberOfPublicKeys = numberOfPublicKeys; 2998 this.requiredPublicKeysForAuthentication = requiredPublicKeysForAuthentication; 2999 this.useDefaultUserPIN = false; 3000 } 3001 3002 3003 3004 /** 3005 * Select the biometric matching server for a one of the biometric templates 3006 * 3007 * @param {Number} slot either 0 or 1 for first or second template 3008 * @param {ByteString} aid the application identifier of the on-card biometric server 3009 * @param {Number} param one byte parameter passed to the server during initialization 3010 */ 3011 SmartCardHSMInitializer.prototype.setBioTemplate = function(slot, aid, param) { 3012 assert(typeof(slot) == "number", "slot must be a number"); 3013 assert(slot >= 0 && slot <= 1, "slot must be either 0 or 1"); 3014 assert(aid instanceof ByteString, "aid must be a ByteString"); 3015 assert(typeof(param) == "number", "param must be a number"); 3016 assert(param >= 0 && param <= 255, "param must be between 0 and 255"); 3017 3018 this.bioslot[slot] = { aid: aid, param: param }; 3019 this.useDefaultUserPIN = false; 3020 } 3021 3022 3023 3024 /** 3025 * Set the label to be written to a minimal CIAInfo in EF 2F03 3026 * 3027 * @param {String} label the label 3028 */ 3029 SmartCardHSMInitializer.prototype.setLabel = function(label) { 3030 this.label = label; 3031 } 3032 3033 3034 3035 /** 3036 * Set the provisioning URL to be written to fixed parameter in CB00. 3037 * 3038 * @param {String} provisioningURL the URL at which this SE will be provisioned 3039 */ 3040 SmartCardHSMInitializer.prototype.setProvisioningURL = function(provisioningURL) { 3041 this.provisioningURL = provisioningURL; 3042 } 3043 3044 3045 3046 /** 3047 * Set the key check value of the token management key and the optional salt 3048 * used for SO-PIN derivation 3049 * 3050 * @param {ByteString} kcv the key check value of the token management key 3051 * @param {ByteString} salt the salt used to derive the SO-PIN 3052 */ 3053 SmartCardHSMInitializer.prototype.setTokenManagementKey = function(kcv, salt) { 3054 this.tokenManagementKeyKCV = kcv; 3055 this.tokenManagementKeySalt = salt; 3056 } 3057 3058 3059 3060 /** 3061 * Perform Initialization 3062 */ 3063 SmartCardHSMInitializer.prototype.initialize = function() { 3064 var s = new ASN1(0x30, new ASN1(0x80, ByteString.valueOf(this.options, 2))); 3065 3066 if (this.userPINSet || this.useDefaultUserPIN) { 3067 s.add(new ASN1(0x81, this.userPIN)); 3068 } 3069 3070 s.add(new ASN1(0x82, this.initializationCode)); 3071 3072 if (this.userPINSet || this.useDefaultUserPIN) { 3073 s.add(new ASN1(0x91, ByteString.valueOf(this.retryCounterInitial))); 3074 } 3075 3076 if (this.keyshares != -1) { 3077 s.add(new ASN1(0x92, ByteString.valueOf(this.keyshares))); 3078 } 3079 3080 if (this.keyDomains != -1) { 3081 s.add(new ASN1(0x97, ByteString.valueOf(this.keyDomains))); 3082 } 3083 3084 if (this.numberOfPublicKeys > 0) { 3085 s.add(new ASN1(0x93, ByteString.valueOf(this.numberOfPublicKeys).concat(ByteString.valueOf(this.requiredPublicKeysForAuthentication)))); 3086 } 3087 3088 if (this.bioslot[0]) { 3089 var o = this.bioslot[0]; 3090 s.add(new ASN1(0x95, ByteString.valueOf(o.param).concat(o.aid))); 3091 } 3092 3093 if (this.bioslot[1]) { 3094 var o = this.bioslot[1]; 3095 s.add(new ASN1(0x96, ByteString.valueOf(o.param).concat(o.aid))); 3096 } 3097 3098 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000, 0x6A84]); 3099 3100 if (this.card.SW == 0x6A84) { 3101 // Due to the nature of the JCRE, a first call to initialize may run out of memory, 3102 // as the garbage collector for the removed objects is only run during the next 3103 // APDU invocation. 3104 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000]); 3105 } 3106 3107 if (this.label) { 3108 var a = new ASN1(0x30, 3109 new ASN1(0x54, new ByteString("0000", HEX)), 3110 new ASN1(0x53, 3111 new ASN1(0x30, 3112 new ASN1(0x02, new ByteString("00", HEX)), 3113 new ASN1(0x80, new ByteString(this.label, UTF8)), 3114 new ASN1(0x03, new ByteString("0500", HEX))) 3115 ) 3116 ); 3117 3118 var p1 = SmartCardHSM.EF_TokenInfo.byteAt(0); 3119 var p2 = SmartCardHSM.EF_TokenInfo.byteAt(1); 3120 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, p1, p2, a.value, [0x9000]); 3121 } 3122 3123 if (this.provisioningURL || this.tokenManagementKeyKCV || this.tokenManagementKeySalt) { 3124 var l = new ASN1(ASN1.SEQUENCE); 3125 if (this.provisioningURL) { 3126 l.add(new ASN1(0x80, new ByteString(this.provisioningURL, UTF8))); 3127 } 3128 if (this.tokenManagementKeyKCV) { 3129 l.add(new ASN1(0x81, this.tokenManagementKeyKCV)); 3130 } 3131 if (this.tokenManagementKeySalt) { 3132 l.add(new ASN1(0x82, this.tokenManagementKeySalt)); 3133 } 3134 3135 var a = new ASN1(0x30, 3136 new ASN1(0x54, new ByteString("0000", HEX)), 3137 new ASN1(0x53, l) 3138 ); 3139 3140 var p1 = SmartCardHSM.EF_StaticTokenInfo.byteAt(0); 3141 var p2 = SmartCardHSM.EF_StaticTokenInfo.byteAt(1); 3142 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, p1, p2, a.value, [0x9000]); 3143 } 3144 } 3145 3146 3147 3148 /** 3149 * Create a key specification generator instance 3150 * 3151 * @class Class implementing an encoder for the C-Data required in GENERATE ASYMMETRIC KEY PAIR 3152 * @param {Number} keytype must be either Crypto.RSA, Crypto.EC or Crypto.AES 3153 * @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 3154 */ 3155 function SmartCardHSMKeySpecGenerator(keytype, keysizeOrDP) { 3156 this.keytype = keytype; 3157 3158 switch(keytype) { 3159 case Crypto.RSA: 3160 if (typeof(keysizeOrDP) != "number") { 3161 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be of a number for RSA keys"); 3162 } 3163 this.keysize = keysizeOrDP; 3164 this.defaultAlgo = new ByteString("id-TA-RSA-v1-5-SHA-256", OID); 3165 break; 3166 case Crypto.EC: 3167 if ((typeof(keysizeOrDP) != "object") || !(keysizeOrDP instanceof Key)) { 3168 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be a Key instance"); 3169 } 3170 this.domainParameter = keysizeOrDP; 3171 this.defaultAlgo = new ByteString("id-TA-ECDSA-SHA-256", OID); 3172 break; 3173 case Crypto.AES: 3174 if (typeof(keysizeOrDP) != "number") { 3175 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be of a number for AES keys"); 3176 } 3177 this.keysize = keysizeOrDP; 3178 break; 3179 default: 3180 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keytype must be Crypto.RSA or Crypto.EC"); 3181 } 3182 this.CHR = new PublicKeyReference("UTDUMMY00001"); 3183 this.innerCAR = new PublicKeyReference("UTDUMMY00001"); 3184 } 3185 3186 exports.SmartCardHSMKeySpecGenerator = SmartCardHSMKeySpecGenerator; 3187 3188 3189 3190 /** 3191 * Set key use counter for key 3192 * 3193 * @param {keyUseCounter} keyUseCounter in the range 1 to 2^64 - 2 3194 */ 3195 SmartCardHSMKeySpecGenerator.prototype.setKeyUseCounter = function(keyUseCounter) { 3196 if ((keyUseCounter < 0) || (keyUseCounter >= 0xFFFFFFFF)) { 3197 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 1, "keyUseCounter must be between 0 and 0xFFFFFFFF"); 3198 } 3199 this.keyUseCounter = keyUseCounter; 3200 } 3201 3202 3203 3204 /** 3205 * Set key domain 3206 * 3207 * @param {Number} keyDomain the key domain to which the key shall be added 3208 */ 3209 SmartCardHSMKeySpecGenerator.prototype.setKeyDomain = function(keyDomain) { 3210 this.keyDomain = keyDomain; 3211 } 3212 3213 3214 3215 /** 3216 * Set wrapping key 3217 * 3218 * @param {Number} wrappingKey the key to used for wrapping a newly generated symmetric key 3219 */ 3220 SmartCardHSMKeySpecGenerator.prototype.setWrappingKey = function(wrappingKey) { 3221 this.wrappingKey = wrappingKey; 3222 } 3223 3224 3225 3226 /** 3227 * Set algorithm list 3228 * 3229 * @param {ByteString} algorithms the list of algorithms allowed for this key 3230 */ 3231 SmartCardHSMKeySpecGenerator.prototype.setAlgorithms = function(algorithms) { 3232 this.algorithms = algorithms; 3233 } 3234 3235 3236 3237 /** 3238 * Set certificate holder reference for key 3239 * 3240 * @param {PublicKeyReference} CHR certificate holder reference 3241 */ 3242 SmartCardHSMKeySpecGenerator.prototype.setCHR = function(CHR) { 3243 this.CHR = CHR; 3244 } 3245 3246 3247 3248 /** 3249 * Set certificate holder reference of CA this request shall be sent to 3250 * 3251 * @param {PublicKeyReference} CAR certificate holder reference 3252 */ 3253 SmartCardHSMKeySpecGenerator.prototype.setInnerCAR = function(CAR) { 3254 this.innerCAR = CAR; 3255 } 3256 3257 3258 3259 /** 3260 * Set holder reference of the key signing this request 3261 * 3262 * @param {PublicKeyReference} CAR certificate holder reference 3263 */ 3264 SmartCardHSMKeySpecGenerator.prototype.setOuterCAR = function(CAR) { 3265 this.outerCAR = CAR; 3266 } 3267 3268 3269 3270 /** 3271 * @private 3272 */ 3273 SmartCardHSMKeySpecGenerator.prototype.encodeRSAKeySpec = function() { 3274 var p = new ASN1("Public Key", 0x7F49, 3275 new ASN1("Object Identifier", 0x06, this.defaultAlgo), 3276 new ASN1("Public Key Exponent", 0x82, ByteString.valueOf(65537)), 3277 new ASN1("Key Size", 0x02, ByteString.valueOf(this.keysize)) 3278 ); 3279 return p; 3280 } 3281 3282 3283 3284 /** 3285 * @private 3286 */ 3287 SmartCardHSMKeySpecGenerator.prototype.encodeECKeySpec = function() { 3288 // Encode G 3289 var bb = new ByteBuffer(); 3290 // uncompressed encoding 3291 bb.append(new ByteString("04", HEX)); 3292 bb.append(this.domainParameter.getComponent(Key.ECC_GX)); 3293 bb.append(this.domainParameter.getComponent(Key.ECC_GY)); 3294 var G = bb.toByteString(); 3295 3296 var p = new ASN1("Public Key", 0x7F49, 3297 new ASN1("Object Identifier", 0x06, this.defaultAlgo), 3298 new ASN1("Prime Modulus", 0x81, this.domainParameter.getComponent(Key.ECC_P)), 3299 new ASN1("First coefficient a", 0x82, this.domainParameter.getComponent(Key.ECC_A)), 3300 new ASN1("Second coefficient b", 0x83, this.domainParameter.getComponent(Key.ECC_B)), 3301 new ASN1("Base Point G", 0x84, G), 3302 new ASN1("Order of the base point", 0x85, this.domainParameter.getComponent(Key.ECC_N)), 3303 new ASN1("Cofactor f", 0x87, SmartCardHSM.stripLeadingZeros(this.domainParameter.getComponent(Key.ECC_H))) 3304 ); 3305 return p; 3306 } 3307 3308 3309 3310 /** 3311 * @private 3312 */ 3313 SmartCardHSMKeySpecGenerator.prototype.encodeKeySpec = function() { 3314 if (this.keytype == Crypto.RSA) { 3315 return this.encodeRSAKeySpec(); 3316 } else { 3317 return this.encodeECKeySpec(); 3318 } 3319 } 3320 3321 3322 3323 /** 3324 * Return the encoded key specification 3325 * 3326 * @type ByteString 3327 * @return the encoded C-Data for GENERATE ASYMMETRIC KEY PAIR 3328 */ 3329 SmartCardHSMKeySpecGenerator.prototype.encode = function() { 3330 var t = new ASN1(0x30); 3331 3332 if (this.keytype != Crypto.AES) { 3333 t.add(new ASN1("CPI", 0x5F29, new ByteString("00", HEX))); 3334 3335 if ((typeof(this.innerCAR) != "undefined") && (this.innerCAR)) { 3336 t.add(new ASN1("CAR", 0x42, this.innerCAR.getBytes())); 3337 } 3338 3339 t.add(this.encodeKeySpec()); 3340 t.add(new ASN1("CHR", 0x5F20, this.CHR.getBytes())); 3341 3342 if (typeof(this.outerCAR) != "undefined") { 3343 t.add(new ASN1("OuterCAR", 0x45, this.outerCAR.getBytes())); 3344 } 3345 } 3346 3347 if (typeof(this.keyUseCounter) != "undefined") { 3348 t.add(new ASN1("Key use counter", 0x90, ByteString.valueOf(this.keyUseCounter, 4))); 3349 } 3350 3351 if (typeof(this.algorithms) != "undefined") { 3352 t.add(new ASN1("Algorithms", 0x91, this.algorithms)); 3353 } 3354 3355 if (typeof(this.keyDomain) != "undefined") { 3356 t.add(new ASN1("KeyDomain", 0x92, ByteString.valueOf(this.keyDomain))); 3357 } 3358 3359 if (typeof(this.wrappingKey) != "undefined") { 3360 t.add(new ASN1("Wrapping Key", 0x93, ByteString.valueOf(this.wrappingKey))); 3361 } 3362 3363 return t.value; 3364 } 3365 3366 3367 3368 /** 3369 * Create a key specification generator instance for AES keys 3370 * 3371 * @class Class implementing an encoder for the C-Data required in Generate Symmetric Key 3372 * @param {ByteString} allowedAlgorithms the list of allowed algorithm identifier 3373 */ 3374 function SmartCardHSMSymmetricKeySpecGenerator(allowedAlgorithms) { 3375 this.algorithms = allowedAlgorithms; 3376 } 3377 3378 exports.SmartCardHSMSymmetricKeySpecGenerator = SmartCardHSMSymmetricKeySpecGenerator; 3379 3380 3381 3382 /** 3383 * Set key domain 3384 * 3385 * @param {Number} keyDomain the key domain to which the key shall be added 3386 */ 3387 SmartCardHSMSymmetricKeySpecGenerator.prototype.setKeyDomain = function(keyDomain) { 3388 this.keyDomain = keyDomain; 3389 } 3390 3391 3392 3393 /** 3394 * Return the encoded AES key specification 3395 * 3396 * @type ByteString 3397 * @return the encoded C-Data for Generate Symmetric Key 3398 */ 3399 SmartCardHSMSymmetricKeySpecGenerator.prototype.encode = function() { 3400 var t = new ASN1(0x30); 3401 3402 t.add(new ASN1("Algorithms", 0x91, this.algorithms)); 3403 3404 if (typeof(this.keyUseCounter) != "undefined") { 3405 t.add(new ASN1("Key use counter", 0x90, ByteString.valueOf(this.keyUseCounter, 4))); 3406 } 3407 3408 if (typeof(this.keyDomain) != "undefined") { 3409 t.add(new ASN1("Key Domain", 0x92, ByteString.valueOf(this.keyDomain))); 3410 } 3411 3412 if (typeof(this.wrappingKey) != "undefined") { 3413 t.add(new ASN1("Wrapping Key", 0x93, this.wrappingKey)); 3414 } 3415 3416 return t.value; 3417 } 3418 3419 3420 3421 SmartCardHSM.test = function() { 3422 var crypto = new Crypto(); 3423 var card = new Card(_scsh3.reader); 3424 var sc = new SmartCardHSM(card); 3425 3426 var sci = new SmartCardHSMInitializer(card); 3427 sci.initialize(); 3428 3429 var pubKey = sc.validateCertificateChain(crypto); 3430 sc.openSecureChannel(crypto, pubKey); 3431 3432 sc.verifyUserPIN(sci.userPIN); 3433 3434 var kg = new SmartCardHSMKeySpecGenerator(Crypto.RSA, 1024); 3435 sc.generateAsymmetricKeyPair(1, 0, kg.encode()); 3436 3437 var dp = new Key(); 3438 dp.setComponent(Key.ECC_CURVE_OID, new ByteString("brainpoolP256r1", OID)); 3439 3440 var kg = new SmartCardHSMKeySpecGenerator(Crypto.EC, dp); 3441 sc.generateAsymmetricKeyPair(2, 0, kg.encode()); 3442 3443 var list = sc.enumerateKeys(); 3444 GPSystem.trace("Keys on device: " + list); 3445 3446 var crypto = sc.getCrypto(); 3447 var message = new ByteString("Hello World", ASCII); 3448 3449 var key = sc.getKey(1); 3450 var signature = crypto.sign(key, Crypto.RSA_SHA256, message); 3451 GPSystem.trace("Signature: " + signature); 3452 3453 var key = sc.getKey(2); 3454 var signature = crypto.sign(key, Crypto.ECDSA, message); 3455 GPSystem.trace("Signature: " + signature); 3456 } 3457