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