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.trace("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.trace("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.trace("Device certificate DECA00001 disabled"); 323 return null; 324 } 325 if (!cvc.verifyWith(crypto, SmartCardHSM.devAutPuk)) { 326 GPSystem.trace("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.trace("Device Issuer CA : " + dica); 338 339 if (typeof(SmartCardHSM.rootCerts[dica.getCAR()]) == "undefined") { 340 GPSystem.trace("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.trace("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.trace("DICA certificate not verified"); 353 return null; 354 } 355 356 var dicapuk = dica.getPublicKey(srcapuk); 357 if (!cvc.verifyWith(crypto, dicapuk, oid)) { 358 GPSystem.trace("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.trace(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.trace("Encoded CA public key: " + enc); 566 ca.performKeyAgreement(enc, nonce); 567 var result = ca.verifyAuthenticationToken(authToken); 568 569 if (!result) { 570 GPSystem.trace("Authentication token invalid"); 571 throw new Error("Authentication token invalid"); 572 } 573 GPSystem.trace("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.trace(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.trace(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.trace(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.trace(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.trace(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.trace(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.trace("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.trace(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 * Decrypt a message using the defined mechanism and key 2504 * 2505 * @param {HSMKey} key the private 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.decrypt = function(key, mech, data, iv) { 2513 if (key instanceof SmartCardHSMKey) { 2514 return key.decrypt(mech, data); 2515 } else { 2516 return this.crypto.decrypt(key, mech, data, iv); 2517 } 2518 } 2519 2520 2521 2522 /** 2523 * Verify a message using the defined mechanism and key 2524 * 2525 * @param {Key} key the public key 2526 * @param {Number} mech the mechanism (e.g. Crypto.ECDSA) 2527 * @param {ByteString} message the message to be signed 2528 * @param {ByteString} signature the signature to verify 2529 * @type Boolean 2530 * @return true if signature is valid 2531 */ 2532 SmartCardHSMCrypto.prototype.verify = function(key, mech, message, signature) { 2533 return this.crypto.verify(key, mech, message, signature); 2534 } 2535 2536 2537 2538 /** 2539 * Create a key access object 2540 * 2541 * @class Class implementing key access 2542 * @param {SmartCardHSM} sc the card access object 2543 * @param {Number} id the key identifier 2544 */ 2545 function SmartCardHSMKey(sc, id) { 2546 this.sc = sc; 2547 this.id = id; 2548 if (this.sc.useExternalHashInECDSA) { 2549 this.crypto = new Crypto(); 2550 } 2551 } 2552 2553 exports.SmartCardHSMKey = SmartCardHSMKey; 2554 2555 2556 /** 2557 * Set the PKCS#15 private key description 2558 * 2559 * @param {ASN1} desc the description 2560 */ 2561 SmartCardHSMKey.prototype.setDescription = function(desc) { 2562 this.desc = desc; 2563 } 2564 2565 2566 2567 /** 2568 * Return the key identifier 2569 * 2570 * @type Number 2571 * @return the key identifier 2572 */ 2573 SmartCardHSMKey.prototype.getId = function() { 2574 return this.id; 2575 } 2576 2577 2578 2579 /** 2580 * Return the key label as encoded in the PKCS#15 structure 2581 * 2582 * @type String 2583 * @return the key label 2584 */ 2585 SmartCardHSMKey.prototype.getLabel = function() { 2586 if (this.desc == undefined) { 2587 return undefined; 2588 } 2589 if ((this.desc.get(0).elements == 0) || this.desc.get(0).get(0).tag != 0x0C) { 2590 return undefined; 2591 } 2592 2593 return this.desc.get(0).get(0).value.toString(UTF8); 2594 } 2595 2596 2597 2598 /** 2599 * Return the key id as encoded in the PKCS#15 structure 2600 * 2601 * @type ByteString 2602 * @return the key identifier 2603 */ 2604 SmartCardHSMKey.prototype.getPKCS15Id = function() { 2605 if (this.desc == undefined) { 2606 return undefined; 2607 } 2608 return this.desc.get(1).get(0).value; 2609 } 2610 2611 2612 2613 /** 2614 * Return the key size in bits 2615 * 2616 * @type Number 2617 * @return the key size in bits 2618 */ 2619 SmartCardHSMKey.prototype.getSize = function() { 2620 if (this.desc == undefined) { 2621 return undefined; 2622 } 2623 // GPSystem.trace(this.desc); 2624 if (this.desc.get(2).elements > 1) { // Fix a bug from early versions 2625 return this.desc.get(2).get(1).value.toUnsigned(); 2626 } 2627 2628 if (this.desc.tag == 0xA8) { 2629 var size = this.desc.get(2).get(0).get(0).value.toUnsigned(); 2630 } else { 2631 var a1 = this.desc.find(0xA1); 2632 var size = a1.get(0).get(1).value.toUnsigned(); 2633 2634 if (size == 528) { 2635 size = 521; // Fix bug in OpenSCDP returning the wrong key size for secp521 keys 2636 } 2637 } 2638 2639 return size; 2640 } 2641 2642 2643 2644 /** 2645 * Return the key type 2646 * 2647 * @type String 2648 * @return the key type 2649 */ 2650 SmartCardHSMKey.prototype.getType = function() { 2651 if (this.desc == undefined) { 2652 return undefined; 2653 } 2654 2655 if (this.desc.tag == 0xA0) { 2656 return "EC"; 2657 } else if (this.desc.tag == 0x30) { 2658 return "RSA"; 2659 } else if (this.desc.tag == 0xA8) { 2660 return "AES"; 2661 } 2662 2663 return undefined; 2664 } 2665 2666 2667 2668 /** 2669 * Sign data using a key in the SmartCard-HSM 2670 * 2671 * @param {Number} mech the signing mechanism 2672 * @param {ByteString} data to be signed 2673 * @type ByteString 2674 * @return the signature 2675 */ 2676 SmartCardHSMKey.prototype.sign = function(mech, data) { 2677 var algo; 2678 if (mech) { 2679 switch(mech) { 2680 case Crypto.RSA: 2681 algo = 0x20; 2682 break; 2683 case Crypto.RSA_SHA1: 2684 algo = 0x31; 2685 break; 2686 case Crypto.RSA_SHA224: 2687 algo = 0x32; 2688 break; 2689 case Crypto.RSA_SHA256: 2690 algo = 0x33; 2691 break; 2692 case Crypto.RSA_SHA384: 2693 algo = 0x34; 2694 break; 2695 case Crypto.RSA_SHA512: 2696 algo = 0x35; 2697 break; 2698 case Crypto.RSA_PKCS1: 2699 if (this.sc.major && this.sc.major >= 4) { 2700 algo = 0x30; 2701 } else { 2702 algo = 0x20; 2703 var keysize = this.getSize(); 2704 if (!keysize) { 2705 throw new GPError(module.id, GPError.INVALID_DATA, 0, "Can't determine key size"); 2706 } 2707 data = PKCS1.encode_EMSA_V15(keysize, data); 2708 } 2709 break; 2710 case Crypto.RSA_PSS: 2711 case 0x80: 2712 algo = 0x40; 2713 break; 2714 case Crypto.RSA_PSS_SHA1: 2715 algo = 0x41; 2716 break; 2717 case Crypto.RSA_PSS_SHA224: 2718 algo = 0x42; 2719 break; 2720 case Crypto.RSA_PSS_SHA256: 2721 algo = 0x43; 2722 break; 2723 case Crypto.RSA_PSS_SHA384: 2724 algo = 0x44; 2725 break; 2726 case Crypto.RSA_PSS_SHA512: 2727 algo = 0x45; 2728 break; 2729 case Crypto.ECDSA: 2730 algo = 0x70; 2731 break; 2732 case Crypto.ECDSA_SHA1: 2733 if (this.sc.useExternalHashInECDSA) { 2734 algo = 0x70; 2735 var data = this.crypto.digest(Crypto.SHA_1, data); 2736 } else { 2737 algo = 0x71; 2738 } 2739 break; 2740 case Crypto.ECDSA_SHA224: 2741 if (this.sc.useExternalHashInECDSA) { 2742 algo = 0x70; 2743 var data = this.crypto.digest(Crypto.SHA_224, data); 2744 } else { 2745 algo = 0x72; 2746 } 2747 break; 2748 case Crypto.ECDSA_SHA256: 2749 if (this.sc.useExternalHashInECDSA) { 2750 algo = 0x70; 2751 var data = this.crypto.digest(Crypto.SHA_256, data); 2752 } else { 2753 algo = 0x73; 2754 } 2755 break; 2756 case Crypto.ECDSA_SHA384: 2757 if (this.sc.useExternalHashInECDSA) { 2758 algo = 0x70; 2759 var data = this.crypto.digest(Crypto.SHA_384, data); 2760 } else { 2761 algo = 0x74; 2762 } 2763 break; 2764 case Crypto.ECDSA_SHA512: 2765 if (this.sc.useExternalHashInECDSA) { 2766 algo = 0x70; 2767 var data = this.crypto.digest(Crypto.SHA_512, data); 2768 } else { 2769 algo = 0x75; 2770 } 2771 break; 2772 case Crypto.AES_CMAC: 2773 return this.sc.deriveSymmetricKey(this.id, SmartCardHSM.ALG_CMAC, data); 2774 default: 2775 throw new GPError("SmartCardHSMKey", GPError.INVALID_DATA, mech, "Unsupported crypto mechanism"); 2776 } 2777 } 2778 2779 return this.sc.sign(this.id, algo, data); 2780 } 2781 2782 2783 2784 /** 2785 * Decrypt data using a key in the SmartCard-HSM 2786 * 2787 * @param {Number} mech the decipher mechanism 2788 * @param {ByteString} data to be deciphered 2789 * @type ByteString 2790 * @return the plain message 2791 */ 2792 SmartCardHSMKey.prototype.decrypt = function(mech, data) { 2793 var algo; 2794 if (mech) { 2795 switch(mech) { 2796 case Crypto.RSA: 2797 break; 2798 case Crypto.RSA_PKCS1: 2799 break; 2800 case Crypto.RSA_OAEP_SHA224: 2801 algo = Crypto.SHA_224; 2802 break; 2803 case Crypto.RSA_OAEP_SHA256: 2804 algo = Crypto.SHA_256; 2805 break; 2806 case Crypto.RSA_OAEP_SHA384: 2807 algo = Crypto.SHA_384; 2808 break; 2809 case Crypto.RSA_OAEP_SHA512: 2810 algo = Crypto.SHA_512; 2811 break; 2812 default: 2813 throw new GPError("SmartCardHSMKey", GPError.INVALID_DATA, mech, "Unsupported crypto mechanism"); 2814 } 2815 } 2816 2817 var em = this.sc.decipher(this.id, 0x21, data); 2818 2819 var plain = em; 2820 2821 if (mech != Crypto.RSA) { 2822 if (mech == Crypto.RSA_PKCS1) { 2823 var plain = PKCS1.decode_EME_V15(em); 2824 } else { 2825 var crypto = this.sc.getCrypto().crypto; 2826 2827 var plain = PKCS1.decode_EME_OAEP(crypto, null, algo, em); 2828 } 2829 2830 if (!plain) { 2831 throw new GPError("SmartCardHSMKey", GPError.CRYPTO_FAILED, mech, "Decryption failed"); 2832 } 2833 } 2834 2835 return plain; 2836 } 2837 2838 2839 2840 /** 2841 * Return human readable string 2842 */ 2843 SmartCardHSMKey.prototype.toString = function() { 2844 return "SmartCardHSMKey(id=" + this.id + ")"; 2845 } 2846 2847 2848 2849 /** 2850 * Initialize SmartCard-HSM 2851 * 2852 * @class Class implementing the device initialization methods 2853 * @param {Card} card the card object 2854 */ 2855 function SmartCardHSMInitializer(card) { 2856 this.card = card; 2857 this.initializationCode = new ByteString("57621880", ASCII); 2858 this.userPIN = new ByteString("648219", ASCII); 2859 this.userPINSet = false; 2860 this.useDefaultUserPIN = true; 2861 this.retryCounterInitial = 3; 2862 this.options = 0x0001; 2863 this.keyshares = -1; 2864 this.keyDomains = -1; 2865 this.numberOfPublicKeys = 0; 2866 this.requiredPublicKeysForAuthentication = 0; 2867 this.bioslot = []; 2868 this.label = undefined; 2869 } 2870 2871 exports.SmartCardHSMInitializer = SmartCardHSMInitializer; 2872 2873 2874 2875 /** 2876 * Set the initialization code 2877 * 2878 * @param {ByteString} initializationCode an 8 byte code 2879 */ 2880 SmartCardHSMInitializer.prototype.setInitializationCode = function(initializationCode) { 2881 if (!(initializationCode instanceof ByteString)) { 2882 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "initializationCode must be a ByteString"); 2883 } 2884 if (initializationCode.length != 8) { 2885 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "initializationCode must have 8 bytes"); 2886 } 2887 2888 this.initializationCode = initializationCode; 2889 } 2890 2891 2892 2893 /** 2894 * Set the User PIN 2895 * 2896 * @param {ByteString} userPIN a 6 to 16 byte code 2897 */ 2898 SmartCardHSMInitializer.prototype.setUserPIN = function(userPIN) { 2899 if (!(userPIN instanceof ByteString)) { 2900 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "userPIN must be a ByteString"); 2901 } 2902 if ((userPIN.length < 6) || (userPIN.length > 16)) { 2903 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "userPIN must be between 6 and 16 bytes"); 2904 } 2905 2906 this.userPIN = userPIN; 2907 this.userPINSet = true; 2908 this.useDefaultUserPIN = false; 2909 } 2910 2911 2912 2913 /** 2914 * Set the retry counter 2915 * 2916 * The SmartCard-HSM enforces a retry counter <= 3 for PIN length 6 2917 * The SmartCard-HSM enforces a retry counter <= 5 for PIN length 7 2918 * The SmartCard-HSM enforces a retry counter <= 10 for PIN length larger than 7 2919 * 2920 * @param {Number} retryCounterInitial in the range 1 to 10. 2921 */ 2922 SmartCardHSMInitializer.prototype.setRetryCounterInitial = function(retryCounterInitial) { 2923 if (typeof(retryCounterInitial) != "number") { 2924 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "retryCounterInitial must be a number"); 2925 } 2926 if ((retryCounterInitial < 1) || (retryCounterInitial > 10)) { 2927 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "retryCounterInitial must be between 1 and 10"); 2928 } 2929 this.retryCounterInitial = retryCounterInitial; 2930 } 2931 2932 2933 2934 /** 2935 * Set the number of DKEK shares 2936 * 2937 * @param {Number} keyshares number of DKEK shares in the range 0 to 255 2938 */ 2939 SmartCardHSMInitializer.prototype.setDKEKShares = function(keyshares) { 2940 if (typeof(keyshares) != "number") { 2941 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyshares must be a number"); 2942 } 2943 if ((keyshares < 0) || (keyshares > 255)) { 2944 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyshares must be between 0 and 255"); 2945 } 2946 this.keyshares = keyshares; 2947 this.keyDomains = -1; 2948 } 2949 2950 2951 2952 /** 2953 * Set the number of key domains 2954 * 2955 * @param {Number} keyDomains number of key domains 2956 */ 2957 SmartCardHSMInitializer.prototype.setKeyDomains = function(keyDomains) { 2958 if (typeof(keyDomains) != "number") { 2959 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyDomains must be a number"); 2960 } 2961 2962 this.keyDomains = keyDomains; 2963 this.keyshares = -1; 2964 } 2965 2966 2967 2968 /** 2969 * Enable or disable RESET RETRY COUNTER command 2970 * 2971 * @param {Boolean} enable true (default) to allow RESET RETRY COUNTER command to reset user PIN using the initialization code 2972 */ 2973 SmartCardHSMInitializer.prototype.setResetRetryCounterMode = function(enable) { 2974 if (typeof(enable) == "undefined") { 2975 var enable = false; 2976 } 2977 2978 this.options = (this.options & 0xFFFE) + (enable ? 1 : 0); 2979 } 2980 2981 2982 2983 /** 2984 * Enable or disable transport PIN mode 2985 * 2986 * @param {Boolean} enable true (non-default) to set user PIN to transport state 2987 */ 2988 SmartCardHSMInitializer.prototype.setTransportPINMode = function(enable) { 2989 if (typeof(enable) == "undefined") { 2990 var enable = true; 2991 } 2992 2993 this.options = (this.options & 0xFFFD) + (enable ? 2 : 0); 2994 } 2995 2996 2997 2998 /** 2999 * Enable or disable session PIN mode 3000 * 3001 * @param {Number} 0 - disable, 1 - enable with clear-on-reset 3 - enable with explicit clearing 3002 */ 3003 SmartCardHSMInitializer.prototype.setSessionPINMode = function(mode) { 3004 assert(typeof(mode) == "number", "Argument mode must be number"); 3005 assert(mode >= 0 && mode <= 3 && mode != 2, "Argument mode must be 0, 1 or 3"); 3006 3007 this.options = (this.options & 0xFFF3) + (mode << 2); 3008 } 3009 3010 3011 3012 /** 3013 * Enable or disable replacing of a PKA key 3014 * 3015 * @param {Boolean} enable true (non-default) to allow replacing of a PKA key 3016 */ 3017 SmartCardHSMInitializer.prototype.setReplacePKAKeyMode = function(enable) { 3018 if (typeof(enable) == "undefined") { 3019 var enable = false; 3020 } 3021 3022 this.options = (this.options & 0xFFF7) + (enable ? 8 : 0); 3023 } 3024 3025 3026 3027 /** 3028 * Enable the combined authentication mode of user pin and public key authentication. 3029 * 3030 * @param {Boolean} enable true (non-default) to require public key authentication and user authentication 3031 */ 3032 SmartCardHSMInitializer.prototype.setCombinedAuthenticationMode = function(enable) { 3033 if (typeof(enable) == "undefined") { 3034 var enable = false; 3035 } 3036 3037 this.options = (this.options & 0xFFEF) + (enable ? 16 : 0); 3038 } 3039 3040 3041 3042 /** 3043 * If enabled RESET RETRY COUNTER only resets the error counter. 3044 * Otherwise RRC allows changing the PIN 3045 * 3046 * @param {Boolean} resetOnly true to only reset the error counter, false otherwise (default) 3047 */ 3048 SmartCardHSMInitializer.prototype.setResetRetryCounterResetOnlyMode = function(resetOnly) { 3049 if (typeof(resetOnly) == "undefined") { 3050 var resetOnly = false; 3051 } 3052 3053 this.options = (this.options & 0xFFDF) + (resetOnly ? 32 : 0); 3054 } 3055 3056 3057 3058 /** 3059 * Set parameter for public key authentication with n-of-m scheme, namely the values for n and m 3060 * 3061 * @param {Number} requiredPublicKeysForAuthentication number of key that must be authenticated for access 3062 * @param {Number} numberOfPublicKeys to register 3063 */ 3064 SmartCardHSMInitializer.prototype.setPublicKeyAuthenticationParameter = function(requiredPublicKeysForAuthentication, numberOfPublicKeys) { 3065 if ((numberOfPublicKeys < 1) || (numberOfPublicKeys > 90)) { 3066 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "numberOfPublicKeys must be between 1 and 90"); 3067 } 3068 if ((requiredPublicKeysForAuthentication < 1) || (requiredPublicKeysForAuthentication > numberOfPublicKeys)) { 3069 throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 2, "requiredPublicKeysForAuthentication must be between 1 and " + numberOfPublicKeys); 3070 } 3071 this.numberOfPublicKeys = numberOfPublicKeys; 3072 this.requiredPublicKeysForAuthentication = requiredPublicKeysForAuthentication; 3073 this.useDefaultUserPIN = false; 3074 } 3075 3076 3077 3078 /** 3079 * Select the biometric matching server for a one of the biometric templates 3080 * 3081 * @param {Number} slot either 0 or 1 for first or second template 3082 * @param {ByteString} aid the application identifier of the on-card biometric server 3083 * @param {Number} param one byte parameter passed to the server during initialization 3084 */ 3085 SmartCardHSMInitializer.prototype.setBioTemplate = function(slot, aid, param) { 3086 assert(typeof(slot) == "number", "slot must be a number"); 3087 assert(slot >= 0 && slot <= 1, "slot must be either 0 or 1"); 3088 assert(aid instanceof ByteString, "aid must be a ByteString"); 3089 assert(typeof(param) == "number", "param must be a number"); 3090 assert(param >= 0 && param <= 255, "param must be between 0 and 255"); 3091 3092 this.bioslot[slot] = { aid: aid, param: param }; 3093 this.useDefaultUserPIN = false; 3094 } 3095 3096 3097 3098 /** 3099 * Set the label to be written to a minimal CIAInfo in EF 2F03 3100 * 3101 * @param {String} label the label 3102 */ 3103 SmartCardHSMInitializer.prototype.setLabel = function(label) { 3104 this.label = label; 3105 } 3106 3107 3108 3109 /** 3110 * Set the provisioning URL to be written to fixed parameter in CB00. 3111 * 3112 * @param {String} provisioningURL the URL at which this SE will be provisioned 3113 */ 3114 SmartCardHSMInitializer.prototype.setProvisioningURL = function(provisioningURL) { 3115 this.provisioningURL = provisioningURL; 3116 } 3117 3118 3119 3120 /** 3121 * Set the key check value of the token management key and the optional salt 3122 * used for SO-PIN derivation 3123 * 3124 * @param {ByteString} kcv the key check value of the token management key 3125 * @param {ByteString} salt the salt used to derive the SO-PIN 3126 */ 3127 SmartCardHSMInitializer.prototype.setTokenManagementKey = function(kcv, salt) { 3128 this.tokenManagementKeyKCV = kcv; 3129 this.tokenManagementKeySalt = salt; 3130 } 3131 3132 3133 3134 /** 3135 * Perform Initialization 3136 */ 3137 SmartCardHSMInitializer.prototype.initialize = function() { 3138 var s = new ASN1(0x30, new ASN1(0x80, ByteString.valueOf(this.options, 2))); 3139 3140 if (this.userPINSet || this.useDefaultUserPIN) { 3141 s.add(new ASN1(0x81, this.userPIN)); 3142 } 3143 3144 s.add(new ASN1(0x82, this.initializationCode)); 3145 3146 if (this.userPINSet || this.useDefaultUserPIN) { 3147 s.add(new ASN1(0x91, ByteString.valueOf(this.retryCounterInitial))); 3148 } 3149 3150 if (this.keyshares != -1) { 3151 s.add(new ASN1(0x92, ByteString.valueOf(this.keyshares))); 3152 } 3153 3154 if (this.keyDomains != -1) { 3155 s.add(new ASN1(0x97, ByteString.valueOf(this.keyDomains))); 3156 } 3157 3158 if (this.numberOfPublicKeys > 0) { 3159 s.add(new ASN1(0x93, ByteString.valueOf(this.numberOfPublicKeys).concat(ByteString.valueOf(this.requiredPublicKeysForAuthentication)))); 3160 } 3161 3162 if (this.bioslot[0]) { 3163 var o = this.bioslot[0]; 3164 s.add(new ASN1(0x95, ByteString.valueOf(o.param).concat(o.aid))); 3165 } 3166 3167 if (this.bioslot[1]) { 3168 var o = this.bioslot[1]; 3169 s.add(new ASN1(0x96, ByteString.valueOf(o.param).concat(o.aid))); 3170 } 3171 3172 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000, 0x6A84]); 3173 3174 if (this.card.SW == 0x6A84) { 3175 // Due to the nature of the JCRE, a first call to initialize may run out of memory, 3176 // as the garbage collector for the removed objects is only run during the next 3177 // APDU invocation. 3178 this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000]); 3179 } 3180 3181 if (this.label) { 3182 var a = new ASN1(0x30, 3183 new ASN1(0x54, new ByteString("0000", HEX)), 3184 new ASN1(0x53, 3185 new ASN1(0x30, 3186 new ASN1(0x02, new ByteString("00", HEX)), 3187 new ASN1(0x80, new ByteString(this.label, UTF8)), 3188 new ASN1(0x03, new ByteString("0500", HEX))) 3189 ) 3190 ); 3191 3192 var p1 = SmartCardHSM.EF_TokenInfo.byteAt(0); 3193 var p2 = SmartCardHSM.EF_TokenInfo.byteAt(1); 3194 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, p1, p2, a.value, [0x9000]); 3195 } 3196 3197 if (this.provisioningURL || this.tokenManagementKeyKCV || this.tokenManagementKeySalt) { 3198 var l = new ASN1(ASN1.SEQUENCE); 3199 if (this.provisioningURL) { 3200 l.add(new ASN1(0x80, new ByteString(this.provisioningURL, UTF8))); 3201 } 3202 if (this.tokenManagementKeyKCV) { 3203 l.add(new ASN1(0x81, this.tokenManagementKeyKCV)); 3204 } 3205 if (this.tokenManagementKeySalt) { 3206 l.add(new ASN1(0x82, this.tokenManagementKeySalt)); 3207 } 3208 3209 var a = new ASN1(0x30, 3210 new ASN1(0x54, new ByteString("0000", HEX)), 3211 new ASN1(0x53, l) 3212 ); 3213 3214 var p1 = SmartCardHSM.EF_StaticTokenInfo.byteAt(0); 3215 var p2 = SmartCardHSM.EF_StaticTokenInfo.byteAt(1); 3216 this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, p1, p2, a.value, [0x9000]); 3217 } 3218 } 3219 3220 3221 3222 /** 3223 * Create a key specification generator instance 3224 * 3225 * @class Class implementing an encoder for the C-Data required in GENERATE ASYMMETRIC KEY PAIR 3226 * @param {Number} keytype must be either Crypto.RSA, Crypto.EC or Crypto.AES 3227 * @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 3228 */ 3229 function SmartCardHSMKeySpecGenerator(keytype, keysizeOrDP) { 3230 this.keytype = keytype; 3231 3232 switch(keytype) { 3233 case Crypto.RSA: 3234 if (typeof(keysizeOrDP) != "number") { 3235 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be of a number for RSA keys"); 3236 } 3237 this.keysize = keysizeOrDP; 3238 this.defaultAlgo = new ByteString("id-TA-RSA-v1-5-SHA-256", OID); 3239 break; 3240 case Crypto.EC: 3241 if ((typeof(keysizeOrDP) != "object") || !(keysizeOrDP instanceof Key)) { 3242 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be a Key instance"); 3243 } 3244 this.domainParameter = keysizeOrDP; 3245 this.defaultAlgo = new ByteString("id-TA-ECDSA-SHA-256", OID); 3246 break; 3247 case Crypto.AES: 3248 if (typeof(keysizeOrDP) != "number") { 3249 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be of a number for AES keys"); 3250 } 3251 this.keysize = keysizeOrDP; 3252 break; 3253 default: 3254 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keytype must be Crypto.RSA or Crypto.EC"); 3255 } 3256 this.CHR = new PublicKeyReference("UTDUMMY00001"); 3257 this.innerCAR = new PublicKeyReference("UTDUMMY00001"); 3258 } 3259 3260 exports.SmartCardHSMKeySpecGenerator = SmartCardHSMKeySpecGenerator; 3261 3262 3263 3264 /** 3265 * Set key use counter for key 3266 * 3267 * @param {keyUseCounter} keyUseCounter in the range 1 to 2^64 - 2 3268 */ 3269 SmartCardHSMKeySpecGenerator.prototype.setKeyUseCounter = function(keyUseCounter) { 3270 if ((keyUseCounter < 0) || (keyUseCounter >= 0xFFFFFFFF)) { 3271 throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 1, "keyUseCounter must be between 0 and 0xFFFFFFFF"); 3272 } 3273 this.keyUseCounter = keyUseCounter; 3274 } 3275 3276 3277 3278 /** 3279 * Set key domain 3280 * 3281 * @param {Number} keyDomain the key domain to which the key shall be added 3282 */ 3283 SmartCardHSMKeySpecGenerator.prototype.setKeyDomain = function(keyDomain) { 3284 this.keyDomain = keyDomain; 3285 } 3286 3287 3288 3289 /** 3290 * Set wrapping key 3291 * 3292 * @param {Number} wrappingKey the key to used for wrapping a newly generated symmetric key 3293 */ 3294 SmartCardHSMKeySpecGenerator.prototype.setWrappingKey = function(wrappingKey) { 3295 this.wrappingKey = wrappingKey; 3296 } 3297 3298 3299 3300 /** 3301 * Set algorithm list 3302 * 3303 * @param {ByteString} algorithms the list of algorithms allowed for this key 3304 */ 3305 SmartCardHSMKeySpecGenerator.prototype.setAlgorithms = function(algorithms) { 3306 this.algorithms = algorithms; 3307 } 3308 3309 3310 3311 /** 3312 * Set certificate holder reference for key 3313 * 3314 * @param {PublicKeyReference} CHR certificate holder reference 3315 */ 3316 SmartCardHSMKeySpecGenerator.prototype.setCHR = function(CHR) { 3317 this.CHR = CHR; 3318 } 3319 3320 3321 3322 /** 3323 * Set certificate holder reference of CA this request shall be sent to 3324 * 3325 * @param {PublicKeyReference} CAR certificate holder reference 3326 */ 3327 SmartCardHSMKeySpecGenerator.prototype.setInnerCAR = function(CAR) { 3328 this.innerCAR = CAR; 3329 } 3330 3331 3332 3333 /** 3334 * Set holder reference of the key signing this request 3335 * 3336 * @param {PublicKeyReference} CAR certificate holder reference 3337 */ 3338 SmartCardHSMKeySpecGenerator.prototype.setOuterCAR = function(CAR) { 3339 this.outerCAR = CAR; 3340 } 3341 3342 3343 3344 /** 3345 * @private 3346 */ 3347 SmartCardHSMKeySpecGenerator.prototype.encodeRSAKeySpec = function() { 3348 var p = new ASN1("Public Key", 0x7F49, 3349 new ASN1("Object Identifier", 0x06, this.defaultAlgo), 3350 new ASN1("Public Key Exponent", 0x82, ByteString.valueOf(65537)), 3351 new ASN1("Key Size", 0x02, ByteString.valueOf(this.keysize)) 3352 ); 3353 return p; 3354 } 3355 3356 3357 3358 /** 3359 * @private 3360 */ 3361 SmartCardHSMKeySpecGenerator.prototype.encodeECKeySpec = function() { 3362 // Encode G 3363 var bb = new ByteBuffer(); 3364 // uncompressed encoding 3365 bb.append(new ByteString("04", HEX)); 3366 bb.append(this.domainParameter.getComponent(Key.ECC_GX)); 3367 bb.append(this.domainParameter.getComponent(Key.ECC_GY)); 3368 var G = bb.toByteString(); 3369 3370 var p = new ASN1("Public Key", 0x7F49, 3371 new ASN1("Object Identifier", 0x06, this.defaultAlgo), 3372 new ASN1("Prime Modulus", 0x81, this.domainParameter.getComponent(Key.ECC_P)), 3373 new ASN1("First coefficient a", 0x82, this.domainParameter.getComponent(Key.ECC_A)), 3374 new ASN1("Second coefficient b", 0x83, this.domainParameter.getComponent(Key.ECC_B)), 3375 new ASN1("Base Point G", 0x84, G), 3376 new ASN1("Order of the base point", 0x85, this.domainParameter.getComponent(Key.ECC_N)), 3377 new ASN1("Cofactor f", 0x87, SmartCardHSM.stripLeadingZeros(this.domainParameter.getComponent(Key.ECC_H))) 3378 ); 3379 return p; 3380 } 3381 3382 3383 3384 /** 3385 * @private 3386 */ 3387 SmartCardHSMKeySpecGenerator.prototype.encodeKeySpec = function() { 3388 if (this.keytype == Crypto.RSA) { 3389 return this.encodeRSAKeySpec(); 3390 } else { 3391 return this.encodeECKeySpec(); 3392 } 3393 } 3394 3395 3396 3397 /** 3398 * Return the encoded key specification 3399 * 3400 * @type ByteString 3401 * @return the encoded C-Data for GENERATE ASYMMETRIC KEY PAIR 3402 */ 3403 SmartCardHSMKeySpecGenerator.prototype.encode = function() { 3404 var t = new ASN1(0x30); 3405 3406 if (this.keytype != Crypto.AES) { 3407 t.add(new ASN1("CPI", 0x5F29, new ByteString("00", HEX))); 3408 3409 if ((typeof(this.innerCAR) != "undefined") && (this.innerCAR)) { 3410 t.add(new ASN1("CAR", 0x42, this.innerCAR.getBytes())); 3411 } 3412 3413 t.add(this.encodeKeySpec()); 3414 t.add(new ASN1("CHR", 0x5F20, this.CHR.getBytes())); 3415 3416 if (typeof(this.outerCAR) != "undefined") { 3417 t.add(new ASN1("OuterCAR", 0x45, this.outerCAR.getBytes())); 3418 } 3419 } 3420 3421 if (typeof(this.keyUseCounter) != "undefined") { 3422 t.add(new ASN1("Key use counter", 0x90, ByteString.valueOf(this.keyUseCounter, 4))); 3423 } 3424 3425 if (typeof(this.algorithms) != "undefined") { 3426 t.add(new ASN1("Algorithms", 0x91, this.algorithms)); 3427 } 3428 3429 if (typeof(this.keyDomain) != "undefined") { 3430 t.add(new ASN1("KeyDomain", 0x92, ByteString.valueOf(this.keyDomain))); 3431 } 3432 3433 if (typeof(this.wrappingKey) != "undefined") { 3434 t.add(new ASN1("Wrapping Key", 0x93, ByteString.valueOf(this.wrappingKey))); 3435 } 3436 3437 return t.value; 3438 } 3439 3440 3441 3442 /** 3443 * Create a key specification generator instance for AES keys 3444 * 3445 * @class Class implementing an encoder for the C-Data required in Generate Symmetric Key 3446 * @param {ByteString} allowedAlgorithms the list of allowed algorithm identifier 3447 */ 3448 function SmartCardHSMSymmetricKeySpecGenerator(allowedAlgorithms) { 3449 this.algorithms = allowedAlgorithms; 3450 } 3451 3452 exports.SmartCardHSMSymmetricKeySpecGenerator = SmartCardHSMSymmetricKeySpecGenerator; 3453 3454 3455 3456 /** 3457 * Set key domain 3458 * 3459 * @param {Number} keyDomain the key domain to which the key shall be added 3460 */ 3461 SmartCardHSMSymmetricKeySpecGenerator.prototype.setKeyDomain = function(keyDomain) { 3462 this.keyDomain = keyDomain; 3463 } 3464 3465 3466 3467 /** 3468 * Return the encoded AES key specification 3469 * 3470 * @type ByteString 3471 * @return the encoded C-Data for Generate Symmetric Key 3472 */ 3473 SmartCardHSMSymmetricKeySpecGenerator.prototype.encode = function() { 3474 var t = new ASN1(0x30); 3475 3476 t.add(new ASN1("Algorithms", 0x91, this.algorithms)); 3477 3478 if (typeof(this.keyUseCounter) != "undefined") { 3479 t.add(new ASN1("Key use counter", 0x90, ByteString.valueOf(this.keyUseCounter, 4))); 3480 } 3481 3482 if (typeof(this.keyDomain) != "undefined") { 3483 t.add(new ASN1("Key Domain", 0x92, ByteString.valueOf(this.keyDomain))); 3484 } 3485 3486 if (typeof(this.wrappingKey) != "undefined") { 3487 t.add(new ASN1("Wrapping Key", 0x93, this.wrappingKey)); 3488 } 3489 3490 return t.value; 3491 } 3492 3493 3494 3495 SmartCardHSM.test = function() { 3496 var crypto = new Crypto(); 3497 var card = new Card(_scsh3.reader); 3498 var sc = new SmartCardHSM(card); 3499 3500 var sci = new SmartCardHSMInitializer(card); 3501 sci.initialize(); 3502 3503 var pubKey = sc.validateCertificateChain(crypto); 3504 sc.openSecureChannel(crypto, pubKey); 3505 3506 sc.verifyUserPIN(sci.userPIN); 3507 3508 var kg = new SmartCardHSMKeySpecGenerator(Crypto.RSA, 1024); 3509 sc.generateAsymmetricKeyPair(1, 0, kg.encode()); 3510 3511 var dp = new Key(); 3512 dp.setComponent(Key.ECC_CURVE_OID, new ByteString("brainpoolP256r1", OID)); 3513 3514 var kg = new SmartCardHSMKeySpecGenerator(Crypto.EC, dp); 3515 sc.generateAsymmetricKeyPair(2, 0, kg.encode()); 3516 3517 var list = sc.enumerateKeys(); 3518 GPSystem.trace("Keys on device: " + list); 3519 3520 var crypto = sc.getCrypto(); 3521 var message = new ByteString("Hello World", ASCII); 3522 3523 var key = sc.getKey(1); 3524 var signature = crypto.sign(key, Crypto.RSA_SHA256, message); 3525 GPSystem.trace("Signature: " + signature); 3526 3527 var key = sc.getKey(2); 3528 var signature = crypto.sign(key, Crypto.ECDSA, message); 3529 GPSystem.trace("Signature: " + signature); 3530 } 3531