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