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 label = asn.get(0).get(0).value.toString(ASCII);
1680 			var cert = this.readBinary(fid);
1681 			certlist.push(label);
1682 			this.canamemap[label] = cert;
1683 			cert.id = id;
1684 			this.caidmap[label] = id;
1685 		}
1686 	}
1687 
1688 	return certlist;
1689 }
1690 
1691 
1692 
1693 /**
1694  * Return CA certificate with label
1695  *
1696  * @param {String} label the certificate label
1697  * @type ByteString
1698  * @return the encoded certificate
1699  */
1700 SmartCardHSM.prototype.getCACertificate = function(label) {
1701 	return this.canamemap[label];
1702 }
1703 
1704 
1705 
1706 /**
1707  * Determine an unused CA certificate identifier
1708  *
1709  * @type Number
1710  * @return a free CA certificate identifier or -1 if all identifier in use
1711  */
1712 SmartCardHSM.prototype.determineFreeCAId = function() {
1713 	if (typeof(this.caids) == "undefined") {
1714 		this.enumerateCACertificates();
1715 	}
1716 
1717 	if (this.caids.length == 0) {
1718 		return 0;
1719 	}
1720 
1721 	var id = Math.max.apply(null, this.caids) + 1;
1722 	if (id > 256) {
1723 		return -1;
1724 	}
1725 	return id;
1726 }
1727 
1728 
1729 
1730 /**
1731  * Add a new CA certificate to the map
1732  *
1733  * @param {X509} cert the CA certificate
1734  * @param {Number} id the corresponding id
1735  * @param {String} label the corresponding label
1736  */
1737 SmartCardHSM.prototype.addCACertificateToMap = function(cert, id, label) {
1738 	if (!this.caidmap[label]) {
1739 		// new id
1740 		this.caids.push(id);
1741 		this.caidmap[label] = id;
1742 	}
1743 	this.canamemap[label] = cert;
1744 }
1745 
1746 
1747 
1748 /**
1749  * Enumerate key objects in the SmartCard-HSM and build the map of keys
1750  *
1751  * @type String[]
1752  * @return the list of key labels
1753  */
1754 SmartCardHSM.prototype.enumerateKeys = function() {
1755 	this.namemap = [];
1756 	this.idmap = [];
1757 	this.idlist = [];
1758 	this.p15idmap = [];
1759 
1760 	var fobs = this.enumerateObjects();
1761 
1762 	// Process keys
1763 	for (var i = 0; i < fobs.length; i += 2) {
1764 		if ((fobs.byteAt(i) == SmartCardHSM.KEYPREFIX) || (fobs.byteAt(i) == 0xFF)) {
1765 			var kid = fobs.byteAt(i + 1);
1766 			if (kid > 0) {
1767 //				GPSystem.trace("Found key: " + kid);
1768 				var key = new SmartCardHSMKey(this, kid);
1769 				this.idmap[kid] = key;
1770 				this.idlist.push(kid);
1771 				this.updateKey(key);
1772 			}
1773 		}
1774 	}
1775 
1776 	var keylist = [];
1777 	// Process PKCS#15 private key descriptions
1778 	for (var i = 0; i < fobs.length; i += 2) {
1779 		if (fobs.byteAt(i) == SmartCardHSM.PRKDPREFIX) {
1780 			var kid = fobs.byteAt(i + 1);
1781 			var descbin = this.readBinary(fobs.bytes(i, 2));
1782 			if (descbin.length > 2) {
1783 				try {
1784 					var desc = new ASN1(descbin);
1785 					if (desc.elements < 3) {
1786 						continue;
1787 					}
1788 				}
1789 				catch(e) {
1790 					continue;
1791 				}
1792 				var key = this.idmap[kid];
1793 				if (key) {
1794 					key.setDescription(desc);
1795 					var label = key.getLabel();
1796 //					GPSystem.trace(key.getId() + " - " + label);
1797 					if (label) {
1798 						keylist.push(label);
1799 						this.namemap[label] = key;
1800 					}
1801 					var p15id = key.getPKCS15Id();
1802 					this.p15idmap[p15id.toString(HEX)] = key;
1803 				}
1804 			}
1805 		}
1806 	}
1807 
1808 	return keylist;
1809 }
1810 
1811 
1812 
1813 /**
1814  * Get key ids
1815  *
1816  * @type Number[]
1817  * @return a list of key identifier
1818  */
1819 SmartCardHSM.prototype.getKeyIds = function() {
1820 	if (typeof(this.idlist) == "undefined") {
1821 		this.enumerateKeys();
1822 	}
1823 	return this.idlist;
1824 }
1825 
1826 
1827 
1828 /**
1829  * Determine an unused key identifier
1830  *
1831  * @type Number
1832  * @return a free key identifier or -1 if all key identifier in use
1833  */
1834 SmartCardHSM.prototype.determineFreeKeyId = function() {
1835 	if (typeof(this.idlist) == "undefined") {
1836 		this.enumerateKeys();
1837 	}
1838 	for (var i = 1; i < 256; i++) {
1839 		if (this.idmap[i] == undefined) {
1840 			return i;
1841 		}
1842 	}
1843 	throw new GPError("SmartCardHSM", GPError.OUT_OF_MEMORY, 1, "Key idx exhausted");
1844 }
1845 
1846 
1847 
1848 /**
1849  * Update key attributes, in particular the use counter
1850  *
1851  * @param {HSMKey} key the HSM key
1852  */
1853 SmartCardHSM.prototype.updateKey = function(key) {
1854 	var fid = ByteString.valueOf((SmartCardHSM.KEYPREFIX << 8) + key.getId());
1855 	try	{
1856 		var fcp = this.selectFile(fid);
1857 	}
1858 	catch(e) {
1859 		return;
1860 	}
1861 	var a = new ASN1(fcp);
1862 	var pi = a.find(0xA5);
1863 	if (!pi) {
1864 		return;
1865 	}
1866 	var kc = pi.find(0x90);
1867 	if (kc) {
1868 		var c = kc.value.toUnsigned();
1869 
1870 		if (c != 0xFFFFFFFF) {
1871 			key.useCounter = c;
1872 		}
1873 	}
1874 
1875 	var kd = pi.find(0x91);
1876 	if (kd) {
1877 		key.algorithms = kd.value;
1878 	}
1879 
1880 	var kd = pi.find(0x92);
1881 	if (kd) {
1882 		key.keyDomain = kd.value.toUnsigned();
1883 	}
1884 }
1885 
1886 
1887 
1888 /**
1889  * Add a new key to the map of keys
1890  *
1891  * @param {HSMKey} key the HSM key
1892  */
1893 SmartCardHSM.prototype.addKeyToMap = function(key) {
1894 	var id = key.getId();
1895 	this.idmap[id] = key;
1896 
1897 	var label = key.getLabel();
1898 	if (label) {
1899 		this.namemap[label] = key;
1900 	}
1901 
1902 	var p15id = key.getPKCS15Id();
1903 	if (p15id) {
1904 		this.p15idmap[p15id.toString(HEX)] = key;
1905 	}
1906 }
1907 
1908 
1909 
1910 /**
1911  * Get a key reference object
1912  *
1913  * @param {String/Number/ByteString} labelOrId label or id of key
1914  * @returns the key or null if not found
1915  * @type Key
1916  */
1917 SmartCardHSM.prototype.getKey = function(labelOrId) {
1918 	if (typeof(this.idlist) == "undefined") {
1919 		this.enumerateKeys();
1920 	}
1921 
1922 	if (typeof(labelOrId) == "number") {
1923 		var key = this.idmap[labelOrId];
1924 	} else if (typeof(labelOrId) == "string") {
1925 		var key = this.namemap[labelOrId];
1926 	} else {
1927 		var key = this.p15idmap[labelOrId.toString(HEX)];
1928 	}
1929 
1930 	if (key == undefined) {
1931 		return null;
1932 	}
1933 	return key;
1934 }
1935 
1936 
1937 
1938 /**
1939  * Return a list of key objects
1940  *
1941  * @type SmartCardHSMKey[]
1942  * @return the list of keys
1943  */
1944 SmartCardHSM.prototype.getKeys = function() {
1945 	if (typeof(this.idlist) == "undefined") {
1946 		this.enumerateKeys();
1947 	}
1948 
1949 	var keylist = [];
1950 	for (var i in this.idmap) {
1951 		keylist.push(this.idmap[i]);
1952 	}
1953 	return keylist;
1954 }
1955 
1956 
1957 
1958 /**
1959  * Get crypto object
1960  *
1961  * @type HSMCrypto
1962  * @return the HSMCrypto object
1963  */
1964 SmartCardHSM.prototype.getCrypto = function() {
1965 	if (this.crypto == undefined) {
1966 		this.crypto = new SmartCardHSMCrypto(new Crypto());
1967 	}
1968 	return this.crypto;
1969 }
1970 
1971 
1972 
1973 /**
1974  * @private
1975  */
1976 SmartCardHSM.prototype.getStaticTokenInfo = function() {
1977 	if (this.staticTokenInfo != undefined) {
1978 		return this.staticTokenInfo;
1979 	}
1980 
1981 	if (!this.hasFile(SmartCardHSM.EF_StaticTokenInfo)) {
1982 		return;
1983 	}
1984 
1985 	var bin = this.readBinary(SmartCardHSM.EF_StaticTokenInfo);
1986 	this.staticTokenInfo = new ASN1(bin);
1987 	return this.staticTokenInfo;
1988 }
1989 
1990 
1991 
1992 /**
1993  * Get ProvisioningURL
1994  *
1995  * @type String
1996  * @return the configured ProvisioningURL or undefined
1997  */
1998 SmartCardHSM.prototype.getProvisioningURL = function() {
1999 	var ti = this.getStaticTokenInfo();
2000 	if (!ti) {
2001 		return;
2002 	}
2003 
2004 	return ti.get(0).value.toString(UTF8);
2005 }
2006 
2007 
2008 
2009 /**
2010  * Create crypto object implementing access to the SmartCard-HSM
2011  *
2012  * @class Wrapper to provide Crypto interface to SmartCard-HSM
2013  * @constructor
2014  * @param {Crypto} crypto the backend crypto provider
2015  */
2016 function SmartCardHSMCrypto(crypto) {
2017 	this.crypto = crypto;
2018 }
2019 
2020 
2021 
2022 /**
2023  * Sign a message using the defined mechanism and key
2024  *
2025  * @param {HSMKey} key the private key
2026  * @param {Number} mech the mechanism (e.g. Crypto.ECDSA)
2027  * @param {ByteString} message the message to be signed
2028  * @type ByteString
2029  * @return the signature
2030  */
2031 SmartCardHSMCrypto.prototype.sign = function(key, mech, message) {
2032 	if (key instanceof SmartCardHSMKey) {
2033 		return key.sign(mech, message);
2034 	} else {
2035 		return this.crypto.sign(key, mech, message);
2036 	}
2037 }
2038 
2039 
2040 
2041 /**
2042  * Decrypt a message using the defined mechanism and key
2043  *
2044  * @param {HSMKey} key the private key
2045  * @param {Number} mech the mechanism (e.g. Crypto.RSA_PKCS1)
2046  * @param {ByteString} data the cryptogram
2047  * @param {ByteString} iv the initialization vector for symmetric ciphers
2048  * @type ByteString
2049  * @return the plain text
2050  */
2051 SmartCardHSMCrypto.prototype.decrypt = function(key, mech, data, iv) {
2052 	if (key instanceof SmartCardHSMKey) {
2053 		return key.decrypt(mech, data);
2054 	} else {
2055 		return this.crypto.decrypt(key, mech, data, iv);
2056 	}
2057 }
2058 
2059 
2060 
2061 /**
2062  * Verify a message using the defined mechanism and key
2063  *
2064  * @param {Key} key the public key
2065  * @param {Number} mech the mechanism (e.g. Crypto.ECDSA)
2066  * @param {ByteString} message the message to be signed
2067  * @param {ByteString} signature the signature to verify
2068  * @type Boolean
2069  * @return true if signature is valid
2070  */
2071 SmartCardHSMCrypto.prototype.verify = function(key, mech, message, signature) {
2072 	return this.crypto.verify(key, mech, message, signature);
2073 }
2074 
2075 
2076 
2077 /**
2078  * Create a key access object
2079  *
2080  * @class Class implementing key access
2081  * @param {SmartCardHSM} sc the card access object
2082  * @param {Number} id the key identifier
2083  */
2084 function SmartCardHSMKey(sc, id) {
2085 	this.sc = sc;
2086 	this.id = id;
2087 	if (this.sc.useExternalHashInECDSA) {
2088 		this.crypto = new Crypto();
2089 	}
2090 }
2091 
2092 exports.SmartCardHSMKey = SmartCardHSMKey;
2093 
2094 
2095 /**
2096  * Set the PKCS#15 private key description
2097  *
2098  * @param {ASN1} desc the description
2099  */
2100 SmartCardHSMKey.prototype.setDescription = function(desc) {
2101 	this.desc = desc;
2102 }
2103 
2104 
2105 
2106 /**
2107  * Return the key identifier
2108  *
2109  * @type Number
2110  * @return the key identifier
2111  */
2112 SmartCardHSMKey.prototype.getId = function() {
2113 	return this.id;
2114 }
2115 
2116 
2117 
2118 /**
2119  * Return the key label as encoded in the PKCS#15 structure
2120  *
2121  * @type String
2122  * @return the key label
2123  */
2124 SmartCardHSMKey.prototype.getLabel = function() {
2125 	if (this.desc == undefined) {
2126 		return undefined;
2127 	}
2128 	if ((this.desc.get(0).elements == 0) || this.desc.get(0).get(0).tag != 0x0C) {
2129 		return undefined;
2130 	}
2131 
2132 	return this.desc.get(0).get(0).value.toString(UTF8);
2133 }
2134 
2135 
2136 
2137 /**
2138  * Return the key id as encoded in the PKCS#15 structure
2139  *
2140  * @type ByteString
2141  * @return the key identifier
2142  */
2143 SmartCardHSMKey.prototype.getPKCS15Id = function() {
2144 	if (this.desc == undefined) {
2145 		return undefined;
2146 	}
2147 	return this.desc.get(1).get(0).value;
2148 }
2149 
2150 
2151 
2152 /**
2153  * Return the key size in bits
2154  *
2155  * @type Number
2156  * @return the key size in bits
2157  */
2158 SmartCardHSMKey.prototype.getSize = function() {
2159 	if (this.desc == undefined) {
2160 		return undefined;
2161 	}
2162 //	GPSystem.trace(this.desc);
2163 	if (this.desc.get(2).elements > 1) {	// Fix a bug from early versions
2164 		return this.desc.get(2).get(1).value.toUnsigned();
2165 	} else {
2166 		return this.desc.get(2).get(0).get(1).value.toUnsigned();
2167 	}
2168 }
2169 
2170 
2171 
2172 /**
2173  * Return the key size in bits
2174  *
2175  * @type Number
2176  * @return the key size in bits
2177  */
2178 SmartCardHSMKey.prototype.getType = function() {
2179 	if (this.desc == undefined) {
2180 		return undefined;
2181 	}
2182 
2183 	if (this.desc.tag == 0xA0) {
2184 		return "EC";
2185 	} else if (this.desc.tag == 0x30) {
2186 		return "RSA";
2187 	} else if (this.desc.tag == 0xA8) {
2188 		return "AES";
2189 	}
2190 
2191 	return undefined;
2192 }
2193 
2194 
2195 
2196 /**
2197  * Sign data using a key in the SmartCard-HSM
2198  *
2199  * @param {Number} mech the signing mechanism
2200  * @param {ByteString} data to be signed
2201  * @type ByteString
2202  * @return the signature
2203  */
2204 SmartCardHSMKey.prototype.sign = function(mech, data) {
2205 	var algo;
2206 	if (mech) {
2207 		switch(mech) {
2208 		case Crypto.RSA:
2209 			algo = 0x20;
2210 			break;
2211 		case Crypto.RSA_SHA1:
2212 			algo = 0x31;
2213 			break;
2214 		case Crypto.RSA_SHA256:
2215 			algo = 0x33;
2216 			break;
2217 		case Crypto.RSA_PKCS1:
2218 			algo = 0x20;
2219 			var keysize = this.getSize();
2220 			if (!keysize) {
2221 				throw new GPError(module.id, GPError.INVALID_DATA, 0, "Can't determine key size");
2222 			}
2223 			data = PKCS1.encode_EMSA_V15(keysize, data);
2224 			break;
2225 //		case Crypto.RSA_PSS:
2226 		case 0x80:
2227 			algo = 0x40;
2228 			break;
2229 		case Crypto.RSA_PSS_SHA1:
2230 			algo = 0x41;
2231 			break;
2232 		case Crypto.RSA_PSS_SHA256:
2233 			algo = 0x43;
2234 			break;
2235 		case Crypto.ECDSA:
2236 			algo = 0x70;
2237 			break;
2238 		case Crypto.ECDSA_SHA1:
2239 			if (this.sc.useExternalHashInECDSA) {
2240 				algo = 0x70;
2241 				var data = this.crypto.digest(Crypto.SHA_1, data);
2242 			} else {
2243 				algo = 0x71;
2244 			}
2245 			break;
2246 		case Crypto.ECDSA_SHA224:
2247 			if (this.sc.useExternalHashInECDSA) {
2248 				algo = 0x70;
2249 				var data = this.crypto.digest(Crypto.SHA_224, data);
2250 			} else {
2251 				algo = 0x72;
2252 			}
2253 			break;
2254 		case Crypto.ECDSA_SHA256:
2255 			if (this.sc.useExternalHashInECDSA) {
2256 				algo = 0x70;
2257 				var data = this.crypto.digest(Crypto.SHA_256, data);
2258 			} else {
2259 				algo = 0x73;
2260 			}
2261 			break;
2262 		case Crypto.AES_CMAC:
2263 			return this.sc.deriveSymmetricKey(this.id, SmartCardHSM.ALG_CMAC, data);
2264 		default:
2265 			throw new GPError("SmartCardHSMKey", GPError.INVALID_DATA, mech, "Unsupported crypto mechanism");
2266 		}
2267 	}
2268 
2269 	return this.sc.sign(this.id, algo, data);
2270 }
2271 
2272 
2273 
2274 /**
2275  * Decrypt data using a key in the SmartCard-HSM
2276  *
2277  * @param {Number} mech the decipher mechanism
2278  * @param {ByteString} data to be deciphered
2279  * @type ByteString
2280  * @return the plain message
2281  */
2282 SmartCardHSMKey.prototype.decrypt = function(mech, data) {
2283 	var algo;
2284 	if (mech) {
2285 		switch(mech) {
2286 		case Crypto.RSA:
2287 			break;
2288 		case Crypto.RSA_PKCS1:
2289 			break;
2290 		case Crypto.RSA_OAEP_SHA224:
2291 			algo = Crypto.SHA_224;
2292 			break;
2293 		case Crypto.RSA_OAEP_SHA256:
2294 			algo = Crypto.SHA_256;
2295 			break;
2296 		case Crypto.RSA_OAEP_SHA384:
2297 			algo = Crypto.SHA_384;
2298 			break;
2299 		case Crypto.RSA_OAEP_SHA512:
2300 			algo = Crypto.SHA_512;
2301 			break;
2302 		default:
2303 			throw new GPError("SmartCardHSMKey", GPError.INVALID_DATA, mech, "Unsupported crypto mechanism");
2304 		}
2305 	}
2306 
2307 	var em = this.sc.decipher(this.id, 0x21, data);
2308 
2309 	var plain = em;
2310 
2311 	if (mech != Crypto.RSA) {
2312 		if (mech == Crypto.RSA_PKCS1) {
2313 			var plain = PKCS1.decode_EME_V15(em);
2314 		} else {
2315 			var crypto = this.sc.getCrypto().crypto;
2316 
2317 			var plain = PKCS1.decode_EME_OAEP(crypto, null, algo, em);
2318 		}
2319 
2320 		if (!plain) {
2321 			throw new GPError("SmartCardHSMKey", GPError.CRYPTO_FAILED, mech, "Decryption failed");
2322 		}
2323 	}
2324 
2325 	return plain;
2326 }
2327 
2328 
2329 
2330 /**
2331  * Return human readable string
2332  */
2333 SmartCardHSMKey.prototype.toString = function() {
2334 	return "SmartCardHSMKey(id=" + this.id + ")";
2335 }
2336 
2337 
2338 
2339 /**
2340  * Initialize SmartCard-HSM
2341  *
2342  * @class Class implementing the device initialization methods
2343  * @param {Card} card the card object
2344  */
2345 function SmartCardHSMInitializer(card) {
2346 	this.card = card;
2347 	this.initializationCode = new ByteString("57621880", ASCII);
2348 	this.userPIN = new ByteString("648219", ASCII);
2349 	this.userPINSet = false;
2350 	this.useDefaultUserPIN = true;
2351 	this.retryCounterInitial = 3;
2352 	this.options = 0x0001;
2353 	this.keyshares = -1;
2354 	this.keyDomains = -1;
2355 	this.numberOfPublicKeys = 0;
2356 	this.requiredPublicKeysForAuthentication = 0;
2357 	this.bioslot = [];
2358 	this.label = undefined;
2359 }
2360 
2361 exports.SmartCardHSMInitializer = SmartCardHSMInitializer;
2362 
2363 
2364 
2365 /**
2366  * Set the initialization code
2367  *
2368  * @param {ByteString} initializationCode an 8 byte code
2369  */
2370 SmartCardHSMInitializer.prototype.setInitializationCode = function(initializationCode) {
2371 	if (!(initializationCode instanceof ByteString)) {
2372 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "initializationCode must be a ByteString");
2373 	}
2374 	if (initializationCode.length != 8) {
2375 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "initializationCode must have 8 bytes");
2376 	}
2377 
2378 	this.initializationCode = initializationCode;
2379 }
2380 
2381 
2382 
2383 /**
2384  * Set the User PIN
2385  *
2386  * @param {ByteString} userPIN a 6 to 16 byte code
2387  */
2388 SmartCardHSMInitializer.prototype.setUserPIN = function(userPIN) {
2389 	if (!(userPIN instanceof ByteString)) {
2390 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "userPIN must be a ByteString");
2391 	}
2392 	if ((userPIN.length < 6) || (userPIN.length > 16)) {
2393 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "userPIN must be between 6 and 16 bytes");
2394 	}
2395 
2396 	this.userPIN = userPIN;
2397 	this.userPINSet = true;
2398 	this.useDefaultUserPIN = false;
2399 }
2400 
2401 
2402 
2403 /**
2404  * Set the retry counter
2405  *
2406  * The SmartCard-HSM enforces a retry counter <= 3 for PIN length 6
2407  * The SmartCard-HSM enforces a retry counter <= 5 for PIN length 7
2408  * The SmartCard-HSM enforces a retry counter <= 10 for PIN length larger than 7
2409  *
2410  * @param {Number} retryCounterInitial in the range 1 to 10.
2411  */
2412 SmartCardHSMInitializer.prototype.setRetryCounterInitial = function(retryCounterInitial) {
2413 	if (typeof(retryCounterInitial) != "number") {
2414 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "retryCounterInitial must be a number");
2415 	}
2416 	if ((retryCounterInitial < 1) || (retryCounterInitial > 10)) {
2417 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "retryCounterInitial must be between 1 and 10");
2418 	}
2419 	this.retryCounterInitial = retryCounterInitial;
2420 }
2421 
2422 
2423 
2424 /**
2425  * Set the number of DKEK shares
2426  *
2427  * @param {Number} keyshares number of DKEK shares in the range 0 to 255
2428  */
2429 SmartCardHSMInitializer.prototype.setDKEKShares = function(keyshares) {
2430 	if (typeof(keyshares) != "number") {
2431 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyshares must be a number");
2432 	}
2433 	if ((keyshares < 0) || (keyshares > 255)) {
2434 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyshares must be between 0 and 255");
2435 	}
2436 	this.keyshares = keyshares;
2437 	this.keyDomains = -1;
2438 }
2439 
2440 
2441 
2442 /**
2443  * Set the number of key domains
2444  *
2445  * @param {Number} keyDomains number of key domains
2446  */
2447 SmartCardHSMInitializer.prototype.setKeyDomains = function(keyDomains) {
2448 	if (typeof(keyDomains) != "number") {
2449 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyDomains must be a number");
2450 	}
2451 
2452 	this.keyDomains = keyDomains;
2453 	this.keyshares = -1;
2454 }
2455 
2456 
2457 
2458 /**
2459  * Enable or disable RESET RETRY COUNTER command
2460  *
2461  * @param {Boolean} enable true (default) to allow RESET RETRY COUNTER command to reset user PIN using the initialization code
2462  */
2463 SmartCardHSMInitializer.prototype.setResetRetryCounterMode = function(enable) {
2464 	if (typeof(enable) == "undefined") {
2465 		var enable = false;
2466 	}
2467 
2468 	this.options = (this.options & 0xFFFE) + (enable ? 1 : 0);
2469 }
2470 
2471 
2472 
2473 /**
2474  * Enable or disable transport PIN mode
2475  *
2476  * @param {Boolean} enable true (non-default) to set user PIN to transport state
2477  */
2478 SmartCardHSMInitializer.prototype.setTransportPINMode = function(enable) {
2479 	if (typeof(enable) == "undefined") {
2480 		var enable = true;
2481 	}
2482 
2483 	this.options = (this.options & 0xFFFD) + (enable ? 2 : 0);
2484 }
2485 
2486 
2487 
2488 /**
2489  * Enable or disable session PIN mode
2490  *
2491  * @param {Number} 0 - disable, 1 - enable with clear-on-reset 3 - enable with explicit clearing
2492  */
2493 SmartCardHSMInitializer.prototype.setSessionPINMode = function(mode) {
2494 	assert(typeof(mode) == "number", "Argument mode must be number");
2495 	assert(mode >= 0 && mode <= 3 && mode != 2, "Argument mode must be 0, 1 or 3");
2496 
2497 	this.options = (this.options & 0xFFF3) + (mode << 2);
2498 }
2499 
2500 
2501 
2502 /**
2503  * Enable or disable replacing of a PKA key
2504  *
2505  * @param {Boolean} enable true (non-default) to allow replacing of a PKA key
2506  */
2507 SmartCardHSMInitializer.prototype.setReplacePKAKeyMode = function(enable) {
2508 	if (typeof(enable) == "undefined") {
2509 		var enable = false;
2510 	}
2511 
2512 	this.options = (this.options & 0xFFF7) + (enable ? 8 : 0);
2513 }
2514 
2515 
2516 
2517 /**
2518  * Enable the combined authentication mode of user pin and public key authentication.
2519  *
2520  * @param {Boolean} enable true (non-default) to require public key authentication and user authentication
2521  */
2522 SmartCardHSMInitializer.prototype.setCombinedAuthenticationMode = function(enable) {
2523 	if (typeof(enable) == "undefined") {
2524 		var enable = false;
2525 	}
2526 
2527 	this.options = (this.options & 0xFFEF) + (enable ? 16 : 0);
2528 }
2529 
2530 
2531 
2532 /**
2533  * If enabled RESET RETRY COUNTER only resets the error counter.
2534  * Otherwise  RRC allows changing the PIN
2535  *
2536  * @param {Boolean} resetOnly true to only reset the error counter, false otherwise (default)
2537  */
2538 SmartCardHSMInitializer.prototype.setResetRetryCounterResetOnlyMode = function(resetOnly) {
2539 	if (typeof(resetOnly) == "undefined") {
2540 		var resetOnly = false;
2541 	}
2542 
2543 	this.options = (this.options & 0xFFDF) + (resetOnly ? 32 : 0);
2544 }
2545 
2546 
2547 
2548 /**
2549  * Set parameter for public key authentication with n-of-m scheme, namely the values for n and m
2550  *
2551  * @param {Number} requiredPublicKeysForAuthentication number of key that must be authenticated for access
2552  * @param {Number} numberOfPublicKeys to register
2553  */
2554 SmartCardHSMInitializer.prototype.setPublicKeyAuthenticationParameter = function(requiredPublicKeysForAuthentication, numberOfPublicKeys) {
2555 	if ((numberOfPublicKeys < 1) || (numberOfPublicKeys > 90)) {
2556 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "numberOfPublicKeys must be between 1 and 90");
2557 	}
2558 	if ((requiredPublicKeysForAuthentication < 1) || (requiredPublicKeysForAuthentication > numberOfPublicKeys)) {
2559 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 2, "requiredPublicKeysForAuthentication must be between 1 and " + numberOfPublicKeys);
2560 	}
2561 	this.numberOfPublicKeys = numberOfPublicKeys;
2562 	this.requiredPublicKeysForAuthentication = requiredPublicKeysForAuthentication;
2563 	this.useDefaultUserPIN = false;
2564 }
2565 
2566 
2567 
2568 /**
2569  * Select the biometric matching server for a one of the biometric templates
2570  *
2571  * @param {Number} slot either 0 or 1 for first or second template
2572  * @param {ByteString} aid the application identifier of the on-card biometric server
2573  * @param {Number} param one byte parameter passed to the server during initialization
2574  */
2575 SmartCardHSMInitializer.prototype.setBioTemplate = function(slot, aid, param) {
2576 	assert(typeof(slot) == "number", "slot must be a number");
2577 	assert(slot >= 0 && slot <= 1, "slot must be either 0 or 1");
2578 	assert(aid instanceof ByteString, "aid must be a ByteString");
2579 	assert(typeof(param) == "number", "param must be a number");
2580 	assert(param >= 0 && param <= 255, "param must be between 0 and 255");
2581 
2582 	this.bioslot[slot] = { aid: aid, param: param };
2583 	this.useDefaultUserPIN = false;
2584 }
2585 
2586 
2587 
2588 /**
2589  * Set the label to be written to a minimal CIAInfo in EF 2F03
2590  *
2591  * @param {String} label the label
2592  */
2593 SmartCardHSMInitializer.prototype.setLabel = function(label) {
2594 	this.label = label;
2595 }
2596 
2597 
2598 
2599 /**
2600  * Set the provisioning URL to be written to fixed parameter in CB00.
2601  *
2602  * @param {String} provisioningURL the URL at which this SE will be provisioned
2603  */
2604 SmartCardHSMInitializer.prototype.setProvisioningURL = function(provisioningURL) {
2605 	this.provisioningURL = provisioningURL;
2606 }
2607 
2608 
2609 
2610 /**
2611  * Perform Initialization
2612  */
2613 SmartCardHSMInitializer.prototype.initialize = function() {
2614 	var s = new ASN1(0x30,	new ASN1(0x80, ByteString.valueOf(this.options, 2)));
2615 
2616 	if (this.userPINSet || this.useDefaultUserPIN) {
2617 		s.add(new ASN1(0x81, this.userPIN));
2618 	}
2619 
2620 	s.add(new ASN1(0x82, this.initializationCode));
2621 
2622 	if (this.userPINSet || this.useDefaultUserPIN) {
2623 		s.add(new ASN1(0x91, ByteString.valueOf(this.retryCounterInitial)));
2624 	}
2625 
2626 	if (this.keyshares != -1) {
2627 		s.add(new ASN1(0x92, ByteString.valueOf(this.keyshares)));
2628 	}
2629 
2630 	if (this.keyDomains != -1) {
2631 		s.add(new ASN1(0x97, ByteString.valueOf(this.keyDomains)));
2632 	}
2633 
2634 	if (this.numberOfPublicKeys > 0) {
2635 		s.add(new ASN1(0x93, ByteString.valueOf(this.numberOfPublicKeys).concat(ByteString.valueOf(this.requiredPublicKeysForAuthentication))));
2636 	}
2637 
2638 	if (this.bioslot[0]) {
2639 		var o = this.bioslot[0];
2640 		s.add(new ASN1(0x95, ByteString.valueOf(o.param).concat(o.aid)));
2641 	}
2642 
2643 	if (this.bioslot[1]) {
2644 		var o = this.bioslot[1];
2645 		s.add(new ASN1(0x96, ByteString.valueOf(o.param).concat(o.aid)));
2646 	}
2647 
2648 	this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000, 0x6A84]);
2649 
2650 	if (this.card.SW == 0x6A84) {
2651 		// Due to the nature of the JCRE, a first call to initialize may run out of memory,
2652 		// as the garbage collector for the removed objects is only run during the next
2653 		// APDU invocation.
2654 		this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000]);
2655 	}
2656 
2657 	if (this.label) {
2658 		var a = new ASN1(0x30,
2659 				new ASN1(0x54, new ByteString("0000", HEX)),
2660 				new ASN1(0x53,
2661 					new ASN1(0x30,
2662 						new ASN1(0x02, new ByteString("00", HEX)),
2663 						new ASN1(0x80, new ByteString(this.label, UTF8)),
2664 						new ASN1(0x03, new ByteString("0500", HEX)))
2665 				)
2666 			);
2667 
2668 		var p1 = SmartCardHSM.EF_TokenInfo.byteAt(0);
2669 		var p2 = SmartCardHSM.EF_TokenInfo.byteAt(1);
2670 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, p1, p2, a.value, [0x9000]);
2671 	}
2672 
2673 	if (this.provisioningURL) {
2674 		var a = new ASN1(0x30,
2675 				new ASN1(0x54, new ByteString("0000", HEX)),
2676 				new ASN1(0x53,
2677 					new ASN1(0x30,
2678 						new ASN1(0x80, new ByteString(this.provisioningURL, UTF8)))
2679 				)
2680 			);
2681 
2682 		var p1 = SmartCardHSM.EF_StaticTokenInfo.byteAt(0);
2683 		var p2 = SmartCardHSM.EF_StaticTokenInfo.byteAt(1);
2684 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, p1, p2, a.value, [0x9000]);
2685 	}
2686 }
2687 
2688 
2689 
2690 /**
2691  * Create a key specification generator instance
2692  *
2693  * @class Class implementing an encoder for the C-Data required in GENERATE ASYMMETRIC KEY PAIR
2694  * @param {Number} keytype must be either Crypto.RSA, Crypto.EC or Crypto.AES
2695  * @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
2696  */
2697 function SmartCardHSMKeySpecGenerator(keytype, keysizeOrDP) {
2698 	this.keytype = keytype;
2699 
2700 	switch(keytype) {
2701 		case Crypto.RSA:
2702 			if (typeof(keysizeOrDP) != "number") {
2703 				throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be of a number for RSA keys");
2704 			}
2705 			this.keysize = keysizeOrDP;
2706 			this.defaultAlgo = new ByteString("id-TA-RSA-v1-5-SHA-256", OID);
2707 			break;
2708 		case Crypto.EC:
2709 			if ((typeof(keysizeOrDP) != "object") || !(keysizeOrDP instanceof Key)) {
2710 				throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be a Key instance");
2711 			}
2712 			this.domainParameter = keysizeOrDP;
2713 			this.defaultAlgo = new ByteString("id-TA-ECDSA-SHA-256", OID);
2714 			break;
2715 		case Crypto.AES:
2716 			if (typeof(keysizeOrDP) != "number") {
2717 				throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be of a number for AES keys");
2718 			}
2719 			this.keysize = keysizeOrDP;
2720 			break;
2721 		default:
2722 			throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keytype must be Crypto.RSA or Crypto.EC");
2723 	}
2724 	this.CHR = new PublicKeyReference("UTDUMMY00001");
2725 	this.innerCAR = new PublicKeyReference("UTDUMMY00001");
2726 }
2727 
2728 exports.SmartCardHSMKeySpecGenerator = SmartCardHSMKeySpecGenerator;
2729 
2730 
2731 
2732 /**
2733  * Set key use counter for key
2734  *
2735  * @param {keyUseCounter} keyUseCounter in the range 1 to 2^64 - 2
2736  */
2737 SmartCardHSMKeySpecGenerator.prototype.setKeyUseCounter = function(keyUseCounter) {
2738 	if ((keyUseCounter < 0) || (keyUseCounter >= 0xFFFFFFFF)) {
2739 		throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 1, "keyUseCounter must be between 0 and 0xFFFFFFFF");
2740 	}
2741 	this.keyUseCounter = keyUseCounter;
2742 }
2743 
2744 
2745 
2746 /**
2747  * Set key domain
2748  *
2749  * @param {Number} keyDomain the key domain to which the key shall be added
2750  */
2751 SmartCardHSMKeySpecGenerator.prototype.setKeyDomain = function(keyDomain) {
2752 	this.keyDomain = keyDomain;
2753 }
2754 
2755 
2756 
2757 /**
2758  * Set wrapping key
2759  *
2760  * @param {Number} wrappingKey the key to used for wrapping a newly generated symmetric key
2761  */
2762 SmartCardHSMKeySpecGenerator.prototype.setWrappingKey = function(wrappingKey) {
2763 	this.wrappingKey = wrappingKey;
2764 }
2765 
2766 
2767 
2768 /**
2769  * Set algorithm list
2770  *
2771  * @param {ByteString} algorithms the list of algorithms allowed for this key
2772  */
2773 SmartCardHSMKeySpecGenerator.prototype.setAlgorithms = function(algorithms) {
2774 	this.algorithms = algorithms;
2775 }
2776 
2777 
2778 
2779 /**
2780  * Set certificate holder reference for key
2781  *
2782  * @param {PublicKeyReference} CHR certificate holder reference
2783  */
2784 SmartCardHSMKeySpecGenerator.prototype.setCHR = function(CHR) {
2785 	this.CHR = CHR;
2786 }
2787 
2788 
2789 
2790 /**
2791  * Set certificate holder reference of CA this request shall be sent to
2792  *
2793  * @param {PublicKeyReference} CAR certificate holder reference
2794  */
2795 SmartCardHSMKeySpecGenerator.prototype.setInnerCAR = function(CAR) {
2796 	this.innerCAR = CAR;
2797 }
2798 
2799 
2800 
2801 /**
2802  * Set holder reference of the key signing this request
2803  *
2804  * @param {PublicKeyReference} CAR certificate holder reference
2805  */
2806 SmartCardHSMKeySpecGenerator.prototype.setOuterCAR = function(CAR) {
2807 	this.outerCAR = CAR;
2808 }
2809 
2810 
2811 
2812 /**
2813  * @private
2814  */
2815 SmartCardHSMKeySpecGenerator.prototype.encodeRSAKeySpec = function() {
2816 	var p = new ASN1("Public Key", 0x7F49,
2817 			new ASN1("Object Identifier", 0x06, this.defaultAlgo),
2818 			new ASN1("Public Key Exponent", 0x82, ByteString.valueOf(65537)),
2819 			new ASN1("Key Size", 0x02, ByteString.valueOf(this.keysize))
2820 		);
2821 	return p;
2822 }
2823 
2824 
2825 
2826 /**
2827  * @private
2828  */
2829 SmartCardHSMKeySpecGenerator.prototype.encodeECKeySpec = function() {
2830 	// Encode G
2831 	var bb = new ByteBuffer();
2832 	// uncompressed encoding
2833 	bb.append(new ByteString("04", HEX));
2834 	bb.append(this.domainParameter.getComponent(Key.ECC_GX));
2835 	bb.append(this.domainParameter.getComponent(Key.ECC_GY));
2836 	var G = bb.toByteString();
2837 
2838 	var p = new ASN1("Public Key", 0x7F49,
2839 			new ASN1("Object Identifier", 0x06, this.defaultAlgo),
2840 			new ASN1("Prime Modulus", 0x81, this.domainParameter.getComponent(Key.ECC_P)),
2841 			new ASN1("First coefficient a", 0x82, this.domainParameter.getComponent(Key.ECC_A)),
2842 			new ASN1("Second coefficient b", 0x83, this.domainParameter.getComponent(Key.ECC_B)),
2843 			new ASN1("Base Point G", 0x84, G),
2844 			new ASN1("Order of the base point", 0x85, this.domainParameter.getComponent(Key.ECC_N)),
2845 			new ASN1("Cofactor f", 0x87, SmartCardHSM.stripLeadingZeros(this.domainParameter.getComponent(Key.ECC_H)))
2846 		);
2847 	return p;
2848 }
2849 
2850 
2851 
2852 /**
2853  * @private
2854  */
2855 SmartCardHSMKeySpecGenerator.prototype.encodeKeySpec = function() {
2856 	if (this.keytype == Crypto.RSA) {
2857 		return this.encodeRSAKeySpec();
2858 	} else {
2859 		return this.encodeECKeySpec();
2860 	}
2861 }
2862 
2863 
2864 
2865 /**
2866  * Return the encoded key specification
2867  *
2868  * @type ByteString
2869  * @return the encoded C-Data for GENERATE ASYMMETRIC KEY PAIR
2870  */
2871 SmartCardHSMKeySpecGenerator.prototype.encode = function() {
2872 	var t = new ASN1(0x30);
2873 
2874 	if (this.keytype != Crypto.AES) {
2875 		t.add(new ASN1("CPI", 0x5F29, new ByteString("00", HEX)));
2876 
2877 		if ((typeof(this.innerCAR) != "undefined") && (this.innerCAR)) {
2878 			t.add(new ASN1("CAR", 0x42, this.innerCAR.getBytes()));
2879 		}
2880 
2881 		t.add(this.encodeKeySpec());
2882 		t.add(new ASN1("CHR", 0x5F20, this.CHR.getBytes()));
2883 
2884 		if (typeof(this.outerCAR) != "undefined") {
2885 			t.add(new ASN1("OuterCAR", 0x45, this.outerCAR.getBytes()));
2886 		}
2887 	}
2888 
2889 	if (typeof(this.keyUseCounter) != "undefined") {
2890 		t.add(new ASN1("Key use counter", 0x90, ByteString.valueOf(this.keyUseCounter, 4)));
2891 	}
2892 
2893 	if (typeof(this.algorithms) != "undefined") {
2894 		t.add(new ASN1("Algorithms", 0x91, this.algorithms));
2895 	}
2896 
2897 	if (typeof(this.keyDomain) != "undefined") {
2898 		t.add(new ASN1("KeyDomain", 0x92, ByteString.valueOf(this.keyDomain)));
2899 	}
2900 
2901 	if (typeof(this.wrappingKey) != "undefined") {
2902 		t.add(new ASN1("Wrapping Key", 0x93, ByteString.valueOf(this.wrappingKey)));
2903 	}
2904 
2905 	return t.value;
2906 }
2907 
2908 
2909 
2910 /**
2911  * Create a key specification generator instance for AES keys
2912  *
2913  * @class Class implementing an encoder for the C-Data required in Generate Symmetric Key
2914  * @param {ByteString} allowedAlgorithms the list of allowed algorithm identifier
2915  */
2916 function SmartCardHSMSymmetricKeySpecGenerator(allowedAlgorithms) {
2917 	this.algorithms = allowedAlgorithms;
2918 }
2919 
2920 exports.SmartCardHSMSymmetricKeySpecGenerator = SmartCardHSMSymmetricKeySpecGenerator;
2921 
2922 
2923 
2924 /**
2925  * Set key domain
2926  *
2927  * @param {Number} keyDomain the key domain to which the key shall be added
2928  */
2929 SmartCardHSMSymmetricKeySpecGenerator.prototype.setKeyDomain = function(keyDomain) {
2930 	this.keyDomain = keyDomain;
2931 }
2932 
2933 
2934 
2935 /**
2936  * Return the encoded AES key specification
2937  *
2938  * @type ByteString
2939  * @return the encoded C-Data for Generate Symmetric Key
2940  */
2941 SmartCardHSMSymmetricKeySpecGenerator.prototype.encode = function() {
2942 	var t = new ASN1(0x30);
2943 
2944 	t.add(new ASN1("Algorithms", 0x91, this.algorithms));
2945 
2946 	if (typeof(this.keyUseCounter) != "undefined") {
2947 		t.add(new ASN1("Key use counter", 0x90, ByteString.valueOf(this.keyUseCounter, 4)));
2948 	}
2949 
2950 	if (typeof(this.keyDomain) != "undefined") {
2951 		t.add(new ASN1("Key Domain", 0x92, ByteString.valueOf(this.keyDomain)));
2952 	}
2953 
2954 	if (typeof(this.wrappingKey) != "undefined") {
2955 		t.add(new ASN1("Wrapping Key", 0x93, this.wrappingKey));
2956 	}
2957 
2958 	return t.value;
2959 }
2960 
2961 
2962 
2963 SmartCardHSM.test = function() {
2964 	var crypto = new Crypto();
2965 	var card = new Card(_scsh3.reader);
2966 	var sc = new SmartCardHSM(card);
2967 
2968 	var sci = new SmartCardHSMInitializer(card);
2969 	sci.initialize();
2970 
2971 	var pubKey = sc.validateCertificateChain(crypto);
2972 	sc.openSecureChannel(crypto, pubKey);
2973 
2974 	sc.verifyUserPIN(sci.userPIN);
2975 
2976 	var kg = new SmartCardHSMKeySpecGenerator(Crypto.RSA, 1024);
2977 	sc.generateAsymmetricKeyPair(1, 0, kg.encode());
2978 
2979 	var dp = new Key();
2980 	dp.setComponent(Key.ECC_CURVE_OID, new ByteString("brainpoolP256r1", OID));
2981 
2982 	var kg = new SmartCardHSMKeySpecGenerator(Crypto.EC, dp);
2983 	sc.generateAsymmetricKeyPair(2, 0, kg.encode());
2984 
2985 	var list = sc.enumerateKeys();
2986 	GPSystem.trace("Keys on device: " + list);
2987 
2988 	var crypto = sc.getCrypto();
2989 	var message = new ByteString("Hello World", ASCII);
2990 
2991 	var key = sc.getKey(1);
2992 	var signature = crypto.sign(key, Crypto.RSA_SHA256, message);
2993 	GPSystem.trace("Signature: " + signature);
2994 
2995 	var key = sc.getKey(2);
2996 	var signature = crypto.sign(key, Crypto.ECDSA, message);
2997 	GPSystem.trace("Signature: " + signature);
2998 }
2999