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