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 	this.smactive = true;
543 	return sm;
544 }
545 
546 
547 
548 /**
549  * Update transparent EF referenced by file identifier
550  *
551  * @param {ByteString} fid the two byte file identifier
552  * @param {Number} offset the offset into the EF
553  * @param {ByteString} data the data to write
554  */
555 SmartCardHSM.prototype.updateBinary = function(fid, offset, data) {
556 	if (typeof(offset) == "undefined") {
557 		offset = 0;
558 	}
559 
560 	var bytesLeft = data.length;
561 	var sent = 0;
562 
563 	// 8 bytes are required for T54(4) and T53(4)
564 	var blksize = this.maxCData - 8;
565 
566 	while (bytesLeft > 0) {
567 		var toSend = bytesLeft >= blksize ? blksize : bytesLeft;
568 
569 		var t54 = new ASN1(0x54, ByteString.valueOf(offset, 2));
570 		var t53 = new ASN1(0x53, data.bytes(sent, toSend));
571 
572 		var cdata = t54.getBytes().concat(t53.getBytes());
573 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, fid.byteAt(0), fid.byteAt(1), cdata, [0x9000]);
574 
575 		bytesLeft -= toSend;
576 		offset += toSend;
577 		sent += toSend;
578 	}
579 }
580 
581 
582 
583 /**
584  * Read transparent EF referenced by file identifier
585  *
586  * @param {ByteString} fid the two byte file identifier (optional - use currently selected EF if absent)
587  * @param {Number} offset the offset into the EF (optional)
588  * @param {Number} length the number of byte to read (optional)
589  * @type ByteString
590  * @return the data read from the EF
591  */
592 SmartCardHSM.prototype.readBinary = function(fid, offset, length) {
593 	if (typeof(offset) == "undefined") {
594 		offset = 0;
595 	}
596 	if (typeof(fid) == "undefined") {
597 		fid = new ByteString("0000", HEX);
598 	}
599 
600 	var rsp = new ByteBuffer();
601 	do	{
602 		var t54 = new ASN1(0x54, ByteString.valueOf(offset, 2));
603 
604 		if (length || this.limitedAPDUTransport || this.smactive) {				// Is a length defined ?
605 			var le = (!length || (length > this.maxRData)) ? this.maxRData: length;		// Truncate if larger than maximum APDU size ?
606 		} else {
607 			var le = this.maxRAPDU <= 256 ? 0 : 65536;					// Get all with Le=0 in either short or extended APDU mode
608 		}
609 
610 		var data = this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xB1, fid.byteAt(0), fid.byteAt(1), t54.getBytes(), le, [0x9000, 0x6282]);
611 
612 		if (data.length == 0) {
613 			break;
614 		}
615 
616 		rsp.append(data);
617 		offset += data.length;
618 
619 		if (length) {					// Length was defined, see if we already got everything
620 			length -= data.length;
621 			if (length <= 0) {
622 				break;
623 			}
624 		}
625 	} while ((this.card.SW == 0x9000) || (this.card.SW == 0x6282));
626 
627 	return rsp.toByteString();
628 }
629 
630 
631 
632 /**
633  * Select the file or key an return the FCP
634  *
635  * @param {ByteString} fid the two byte file object identifier
636  */
637 SmartCardHSM.prototype.selectFile = function(fid) {
638 	var fcp = this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xA4, 0x00, 0x04, fid, 0, [0x9000]);
639 	return fcp;
640 }
641 
642 
643 
644 /**
645  * Try selecting the file to see if is present
646  *
647  * @param {ByteString} fid the two byte file object identifier
648  */
649 SmartCardHSM.prototype.hasFile = function(fid) {
650 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xA4, 0x00, 0x04, fid, 0);
651 	return this.card.SW == 0x9000;
652 }
653 
654 
655 
656 /**
657  * Delete file system object (EF or key)
658  *
659  * @param {ByteString} fid the two byte file object identifier
660  */
661 SmartCardHSM.prototype.deleteFile = function(fid) {
662 	return this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xE4, 0x02, 0x00, fid, [0x9000]);
663 }
664 
665 
666 
667 /**
668  * Strips leading zeros of a ByteString
669  *
670  * @param {ByteString} value the ByteString value
671  * @return the stripped ByteString object, may be an empty ByteString
672  * @type ByteString
673  */
674 SmartCardHSM.stripLeadingZeros = function(value) {
675 	var i = 0;
676 	for (; (i < value.length) && (value.byteAt(i) == 0); i++);
677 
678 	return value.right(value.length - i);
679 }
680 
681 
682 
683 /**
684  * Build input for Generate Asymmetric Key Pair command for generating an ECC key pair
685  *
686  * @param {PublicKeyReference} innerCAR the CA the request shall be directed to
687  * @param {ByteString} algo the public key algorithm
688  * @param {PublicKeyReference} chr the certificate holder reference associated with this key
689  * @param {Key} dp the domain parameter for the key
690  * @param {PublicKeyReference} outerCAR the certificate holder reference of the public key for verifying the outer signature
691  * @param {Key} privateKey optional parameter to supply a private key value for import. This only works with the development version
692  *              of the SmartCard-HSM.
693  * @type ByteString
694  * @return the encoded C-Data for GENERATE ASYMMETRIC KEY PAIR
695  */
696 SmartCardHSM.buildGAKPwithECC = function(innerCAR, algo, chr, dp, outerCAR, priKey) {
697 
698 	// Encode G
699 	var bb = new ByteBuffer();
700 	// uncompressed encoding
701 	bb.append(new ByteString("04", HEX));
702 	bb.append(dp.getComponent(Key.ECC_GX));
703 	bb.append(dp.getComponent(Key.ECC_GY));
704 	var G = bb.toByteString();
705 
706 	var t = new ASN1(0x30,
707 				new ASN1("CPI", 0x5F29, new ByteString("00", HEX)),
708 				new ASN1("CAR", 0x42, innerCAR.getBytes()),
709 				new ASN1("Public Key", 0x7F49,
710 					new ASN1("Object Identifier", 0x06, algo),
711 					new ASN1("Prime Modulus", 0x81, dp.getComponent(Key.ECC_P)),
712 					new ASN1("First coefficient a", 0x82, dp.getComponent(Key.ECC_A)),
713 					new ASN1("Second coefficient b", 0x83, dp.getComponent(Key.ECC_B)),
714 					new ASN1("Base Point G", 0x84, G),
715 					new ASN1("Order of the base point", 0x85, dp.getComponent(Key.ECC_N)),
716 					new ASN1("Cofactor f", 0x87, SmartCardHSM.stripLeadingZeros(dp.getComponent(Key.ECC_H)))
717 				),
718 				new ASN1("CHR", 0x5F20, chr.getBytes())
719 			);
720 
721 	if (typeof(outerCAR) != "undefined") {
722 		t.add(new ASN1("OuterCAR", 0x45, outerCAR.getBytes()));
723 	}
724 
725 	if (priKey != undefined) {
726 		var d = new ASN1("Private Key", 0x8A, priKey.getComponent(Key.ECC_D));
727 		t.get(2).add(d);
728 //		GPSystem.trace(t);
729 	}
730 	return t.value;
731 }
732 
733 
734 
735 /**
736  * Build input for Generate Asymmetric Key Pair command for generating a RSA key pair
737  *
738  * @param {PublicKeyReference} innerCAR the CA the request shall be directed to
739  * @param {ByteString} algo the public key algorithm
740  * @param {PublicKeyReference} chr the certificate holder reference associated with this key
741  * @param {Number} keysize the module size in bits (1024, 1536 or 2048)
742  * @param {PublicKeyReference} outerCAR the certificate holder reference of the public key for verifying the outer signature
743  * @type ByteString
744  * @return the encoded C-Data for GENERATE ASYMMETRIC KEY PAIR
745  */
746 SmartCardHSM.buildGAKPwithRSA = function(innerCAR, algo, chr, keysize, outerCAR) {
747 
748 	var t = new ASN1(0x30,
749 				new ASN1("CPI", 0x5F29, new ByteString("00", HEX)),
750 				new ASN1("CAR", 0x42, innerCAR.getBytes()),
751 				new ASN1("Public Key", 0x7F49,
752 					new ASN1("Object Identifier", 0x06, algo),
753 					new ASN1("Public Key Exponent", 0x82, ByteString.valueOf(65537)),
754 					new ASN1("Key Size", 0x02, ByteString.valueOf(keysize))
755 				),
756 				new ASN1("CHR", 0x5F20, chr.getBytes())
757 			);
758 
759 	if (typeof(outerCAR) != "undefined") {
760 		t.add(new ASN1("OuterCAR", 0x45, outerCAR.getBytes()));
761 	}
762 	return t.value;
763 }
764 
765 
766 
767 /**
768  * Create a PKCS#15 PrivateECCKey description
769  *
770  * @param {Number/ByteString} keyid the key identifier
771  * @param {String} label the key label
772  * @type ASN1
773  * @return the PrivateECCKey description
774  */
775 SmartCardHSM.buildPrkDforECC = function(keyid, label, keysize) {
776 	if (typeof(keyid) == "number") {
777 		keyid = ByteString.valueOf(keyid);
778 	}
779 
780 	var prkd = 	new ASN1(0xA0,
781 					new ASN1(ASN1.SEQUENCE,
782 						new ASN1(ASN1.UTF8String, new ByteString(label, UTF8))
783 //						new ASN1(ASN1.BIT_STRING, new ByteString("0780", HEX)),
784 //						new ASN1(ASN1.OCTET_STRING, new ByteString("01", HEX))
785 					),
786 					new ASN1(ASN1.SEQUENCE,
787 						new ASN1(ASN1.OCTET_STRING, keyid),
788 						new ASN1(ASN1.BIT_STRING, new ByteString("072080", HEX))
789 					),
790 					new ASN1(0xA1,
791 						new ASN1(ASN1.SEQUENCE,
792 							new ASN1(ASN1.SEQUENCE,
793 								new ASN1(ASN1.OCTET_STRING, new ByteString("", HEX))
794 							)
795 						)
796 					)
797 				);
798 
799 	if (keysize != undefined) {
800 		assert(keysize > 0, "Key size must be > 0");
801 		var tlvint = ByteString.valueOf(keysize);
802 		if (tlvint.byteAt(0) >= 0x80) {
803 			tlvint = (new ByteString("00", HEX)).concat(tlvint);
804 		}
805 		prkd.get(2).get(0).add(new ASN1(ASN1.INTEGER, tlvint));
806 	}
807 
808 //	GPSystem.trace(prkd);
809 	return prkd;
810 }
811 
812 
813 
814 /**
815  * Create a PKCS#15 PrivateRSAKey description
816  *
817  * @param {Number/ByteString} keyid the key identifier
818  * @param {String} label the key label
819  * @param {Number} modulussize
820  * @type ASN1
821  * @return the PrivateECCKey description
822  */
823 SmartCardHSM.buildPrkDforRSA = function(keyid, label, modulussize) {
824 	if (typeof(keyid) == "number") {
825 		keyid = ByteString.valueOf(keyid);
826 	}
827 
828 	var prkd = 	new ASN1(0x30,
829 					new ASN1(ASN1.SEQUENCE,
830 						new ASN1(ASN1.UTF8String, new ByteString(label, UTF8))
831 //						new ASN1(ASN1.BIT_STRING, new ByteString("0780", HEX)),
832 //						new ASN1(ASN1.OCTET_STRING, new ByteString("01", HEX))
833 					),
834 					new ASN1(ASN1.SEQUENCE,
835 						new ASN1(ASN1.OCTET_STRING, keyid),
836 						new ASN1(ASN1.BIT_STRING, new ByteString("0274", HEX))
837 					),
838 					new ASN1(0xA1,
839 						new ASN1(ASN1.SEQUENCE,
840 							new ASN1(ASN1.SEQUENCE,
841 								new ASN1(ASN1.OCTET_STRING, new ByteString("", HEX))
842 							),
843 							new ASN1(ASN1.INTEGER, ByteString.valueOf(modulussize))
844 						)
845 					)
846 				);
847 //	GPSystem.trace(prkd);
848 	return prkd;
849 }
850 
851 
852 
853 /**
854  * Create a PKCS#15 SecretKey description
855  *
856  * @param {Number/ByteString} keyid the key identifier
857  * @param {String} label the key label
858  * @param {Number} keysize
859  * @type ASN1
860  * @return the secret key description
861  */
862 SmartCardHSM.buildSKDforAES = function(keyid, label, keysize) {
863 	if (typeof(keyid) == "number") {
864 		keyid = ByteString.valueOf(keyid);
865 	}
866 
867 	var skd =
868 		new ASN1(0xA8,
869 			// CommonObjectAttributes
870 			new ASN1(ASN1.SEQUENCE,
871 				new ASN1(ASN1.UTF8String, new ByteString(label, UTF8))
872 				//						new ASN1(ASN1.BIT_STRING, new ByteString("0780", HEX)),
873 				//						new ASN1(ASN1.OCTET_STRING, new ByteString("01", HEX))
874 			),
875 			// ClassAttributes: CommonKeyAttributes
876 			new ASN1(ASN1.SEQUENCE,
877 				new ASN1(ASN1.OCTET_STRING, keyid),
878 				new ASN1(ASN1.BIT_STRING, new ByteString("07C010", HEX))
879 			),
880 			// SubClassAttribute: CommonSecretKeyAttributes
881 			new ASN1(0xA0,
882 				new ASN1(ASN1.SEQUENCE,
883 					new ASN1(ASN1.INTEGER, ByteString.valueOf(keysize, 2))
884 				)
885 			),
886 			new ASN1(0xA1,
887 				new ASN1(ASN1.SEQUENCE,
888 					new ASN1(ASN1.SEQUENCE,
889 						new ASN1(ASN1.OCTET_STRING, new ByteString("", HEX))
890 					)
891 				)
892 			)
893 
894 		);
895 //	GPSystem.trace(skd);
896 	return skd;
897 }
898 
899 
900 
901 /**
902  * Create a PKCS#15 certificate description
903  *
904  * @param {ByteString} commonObjectFlags default value is '0640'
905  * @param {String} label the key label
906  * @param {Key} pubKey the public key
907  * @param {ByteString} certFID the file identifier of the certificate
908  * @type ASN1
909  * @return the PrivateECCKey description
910  */
911 SmartCardHSM.buildCertDescription = function(label, commonObjectFlags, pubKey, certFID) {
912 	if (!commonObjectFlags) {
913 		commonObjectFlags = new ByteString("0x0640", HEX);
914 	}
915 
916 	// generate subject key id
917 	var qx = pubKey.getComponent(Key.ECC_QX)
918 	if (qx) {
919 	  var enc = qx;
920 	} else {
921 	  var enc = pubKey.getComponent(Key.MODULUS);
922 	}
923 	var crypto = new Crypto();
924 	var subjectKeyID = crypto.digest(Crypto.SHA_1, enc);
925 
926 	var desc = 	new ASN1(ASN1.SEQUENCE,
927 				new ASN1(ASN1.SEQUENCE,			// common object attributes
928 					new ASN1(ASN1.UTF8String, new ByteString(label, UTF8)),
929 					new ASN1(ASN1.BIT_STRING, commonObjectFlags)
930 				),
931 				new ASN1(ASN1.SEQUENCE,			// common certificate attributes
932 					  new ASN1(ASN1.OCTET_STRING, subjectKeyID)
933 				),
934 				new ASN1(0xA1,					// type attributes
935 					new ASN1(ASN1.SEQUENCE,			// x.509 certificate attributes
936 						new ASN1(ASN1.SEQUENCE,			// path
937 							new ASN1(ASN1.OCTET_STRING, certFID)
938 						)
939 					)
940 				)
941 			);
942 	return desc;
943 }
944 
945 
946 
947 /**
948  * Dump C-Data of Generate Asymmetric Key Pair command
949  *
950  * @param {ByteString} keydata the content of C-Data
951  */
952 SmartCardHSM.dumpKeyData = function(keydata) {
953 	GPSystem.trace(keydata);
954 	var a = new ASN1(0x30, keydata);
955 	var a = new ASN1(a.getBytes());
956 	for (var i = 0; i < a.elements; i++) {
957 		GPSystem.trace(a.get(i));
958 	}
959 }
960 
961 
962 
963 /**
964  * Generate an asymmetric key pair
965  *
966  * @param {Number} newkid key identifier for new key
967  * @param {Number} signkid key identifier for signing the new public key
968  * @param {ByteString} keydata the key data template
969  * @type ByteString
970  * @return the certificate signing request containing the new public key
971  */
972 SmartCardHSM.prototype.generateAsymmetricKeyPair = function(newkid, signkid, keydata) {
973 
974 	if (!this.limitedAPDUTransport) { // Use extended length
975 		var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x46, newkid, signkid, keydata, 65536, [0x9000]);
976 	} else {
977 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x46, newkid, signkid, keydata, [0x9000]);
978 		var rsp = this.readBinary(ByteString.valueOf(0xCE00 + newkid), 0);
979 	}
980 
981 	return rsp;
982 }
983 
984 
985 
986 /**
987  * Generate a symmetric key
988  *
989  * @param {Number} newkid key identifier for new key
990  * @param {Number} algo key generation algorithm
991  * @param {ByteString} keydata the key data template
992  * @type ByteString
993  * @return
994  */
995 SmartCardHSM.prototype.generateSymmetricKey = function(newkid, algo, keydata) {
996 
997 	var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x48, newkid, algo, keydata, 0, [0x9000]);
998 	return rsp;
999 }
1000 
1001 
1002 
1003 /**
1004  * Return true is SmartCard-HSM is initialized
1005  *
1006  * @type Boolean
1007  * @return true if initialized
1008  */
1009 SmartCardHSM.prototype.isInitialized = function() {
1010 	var sw = this.queryUserPINStatus();
1011 	if ((sw == 0x6984) || (sw == 0x6A88)) {		// V1.2: Not initialized / V2.0: Transport PIN
1012 		var sw = this.queryInitializationCodeStatus();
1013 		if (sw == 0x6A88) {
1014 			return false;
1015 		}
1016 	}
1017 	return true;
1018 }
1019 
1020 
1021 
1022 /**
1023  * Initialize device and clear all keys and files
1024  *
1025  * @param {ByteString} options two byte option mask
1026  * @param {ByteString} initialPIN initial user PIN value
1027  * @param {ByteString} initializationCode secret code for device initialization (set during first use)
1028  * @param {Number} retryCounterInitial retry counter for user PIN
1029  * @param {Number} keyshares number of device key encryption key shares (optional)
1030  */
1031 SmartCardHSM.prototype.initDevice = function(options, initialPIN, initializationCode, retryCounterInitial, keyshares) {
1032 	var s = new ASN1(0x30,
1033 				new ASN1(0x80, options),
1034 				new ASN1(0x81, initialPIN),
1035 				new ASN1(0x82, initializationCode),
1036 				new ASN1(0x91, ByteString.valueOf(retryCounterInitial))
1037 				);
1038 
1039 	if (typeof(keyshares) != "undefined") {
1040 		s.add(new ASN1(0x92, ByteString.valueOf(keyshares)));
1041 	}
1042 	this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000]);
1043 }
1044 
1045 
1046 
1047 /**
1048  * Determine free memory
1049  *
1050  * @type Number
1051  * @return the number of available bytes (this values is capped to 32767 on JCOP 2.4.1)
1052  */
1053 SmartCardHSM.prototype.getFreeMemory = function() {
1054 	var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, 0, [0x9000, 0x6700]);
1055 
1056 	if (this.card.SW != 0x9000) {
1057 		return -1;
1058 	}
1059 
1060 	this.major = rsp.byteAt(rsp.length - 2);
1061 	this.minor = rsp.byteAt(rsp.length - 1);
1062 	this.platform = rsp.byteAt(rsp.length - 3);
1063 	return rsp.bytes(rsp.length - 7, 4).toUnsigned();
1064 }
1065 
1066 
1067 
1068 /**
1069  * Parse the key domain status returned from the device
1070  *
1071  * @param {ByteString} status the R-DATA from the MANAGE KEY DOMAIN command
1072  * @type object
1073  * @return the decoded status Info
1074  */
1075 SmartCardHSM.prototype.parseKeyDomainStatus = function(status) {
1076 	if (status.length == 0) {
1077 		return { sw: this.card.SW };
1078 	}
1079 
1080 	var statusObject = {
1081 		sw: this.card.SW,
1082 		shares: status.byteAt(0),
1083 		outstanding: status.byteAt(1),
1084 		kcv: status.bytes(2, 8)
1085 	}
1086 
1087 	if (status.length > 10) {
1088 		statusObject.keyDomain = status.bytes(10);
1089 	}
1090 
1091 	return statusObject;
1092 }
1093 
1094 
1095 
1096 /*
1097  * Create DKEK Key Domain
1098  *
1099  * @param {Number} keyDomain number of key domain in the range 0 to the maximum defined in the INITIALIZE DEVICE command
1100  * @param {Number} shares the number of DKEK shares to import
1101  * @type Object
1102  * @return object with properties sw{Number}, shares{Number}, outstanding{Number} and kcv{ByteString}
1103  */
1104 SmartCardHSM.prototype.createDKEKKeyDomain = function(keyDomain, shares) {
1105 	if (typeof(keyDomain) != "number") {
1106 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be a number");
1107 	}
1108 	if (typeof(shares) != "number") {
1109 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "shares must be a number");
1110 	}
1111 
1112 	var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x01, keyDomain, ByteString.valueOf(shares), 0);
1113 
1114 	return this.parseKeyDomainStatus(status);
1115 }
1116 
1117 
1118 
1119 /**
1120  * Create XKEK Key Domain
1121  *
1122  * @param {Number} keyDomain number of key domain in the range 0 to the maximum defined in the INITIALIZE DEVICE command
1123  * @param {ByteString} keyDomainMembership either a 64 byte signature (old format) or a encoded TLV object with tag 54 or 55
1124  * @return object with properties sw{Number}, shares{Number}, outstanding{Number}, kcv{ByteString} and the key domain UID{ByteString}
1125  * @type Object
1126  */
1127 SmartCardHSM.prototype.createXKEKKeyDomain = function(keyDomain, groupSignerPublicKey, keyDomainMembership) {
1128 	if (typeof(keyDomain) != "number") {
1129 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be a number");
1130 	}
1131 	if ((keyDomain < 0) || (keyDomain > 0xFF)) {
1132 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be between 0 and 255");
1133 	}
1134 	if (!(groupSignerPublicKey instanceof CVC)) {
1135 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "groupSignerPublicKey must be a CVC instance");
1136 	}
1137 	if (!(keyDomainMembership instanceof ByteString)) {
1138 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomainMembership must be a ByteString");
1139 	}
1140 
1141 	var car = groupSignerPublicKey.getOuterCAR().getBytes();
1142 
1143 	var pukrefdo = new ASN1(0x83, car);
1144 	var pukref = pukrefdo.getBytes();
1145 
1146 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000]);
1147 
1148 	if (keyDomainMembership.length == 64) {
1149 		keyDomainMembership = new ASN1(0x53, keyDomainMembership).getBytes();
1150 	}
1151 	var cdata = groupSignerPublicKey.getASN1().value.concat(keyDomainMembership);
1152 
1153 	if (cdata.length <= this.maxCData) {
1154 		var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x02, keyDomain, cdata, 0);
1155 	} else {
1156 		this.updateBinary(ByteString.valueOf(0x2F10), 0, cdata);
1157 		var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x02, keyDomain, 0);
1158 	}
1159 
1160 	return this.parseKeyDomainStatus(status);
1161 }
1162 
1163 
1164 
1165 /**
1166  * Associate XKEK Key Domain
1167  *
1168  * @param {Number} keyDomain number of key domain in the range 0 to the maximum defined in the INITIALIZE DEVICE command
1169  * @param {ByteString} keyDomainUID a encoded TLV object with tag 51 containing the key domain uid of the associated domain
1170  * @param {ByteString} keyDomainAssociation a encoded TLV object with tag 56 or 57
1171  * @return object with properties sw{Number}, shares{Number}, outstanding{Number}, kcv{ByteString} and the key domain UID{ByteString}
1172  * @type Object
1173  */
1174 SmartCardHSM.prototype.associateXKEKKeyDomain = function(keyDomain, groupSignerPublicKey, keyDomainUID, keyDomainAssociation) {
1175 	if (typeof(keyDomain) != "number") {
1176 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be a number");
1177 	}
1178 	if ((keyDomain < 0) || (keyDomain > 0xFF)) {
1179 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be between 0 and 255");
1180 	}
1181 	if (!(groupSignerPublicKey instanceof CVC)) {
1182 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "groupSignerPublicKey must be a ByteString");
1183 	}
1184 	if (!(keyDomainUID instanceof ByteString)) {
1185 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomainUID must be a ByteString");
1186 	}
1187 	if (!(keyDomainAssociation instanceof ByteString)) {
1188 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomainAssociation must be a ByteString");
1189 	}
1190 
1191 	var car = groupSignerPublicKey.getOuterCAR().getBytes();
1192 
1193 	var pukrefdo = new ASN1(0x83, car);
1194 	var pukref = pukrefdo.getBytes();
1195 
1196 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000]);
1197 
1198 	var cdata = groupSignerPublicKey.getASN1().value.concat(keyDomainUID).concat(keyDomainAssociation);
1199 
1200 	if (cdata.length <= this.maxCData) {
1201 		var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x05, keyDomain, cdata, 0);
1202 	} else {
1203 		this.updateBinary(ByteString.valueOf(0x2F10), 0, cdata);
1204 		var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x05, keyDomain, 0);
1205 	}
1206 
1207 	return this.parseKeyDomainStatus(status);
1208 }
1209 
1210 
1211 
1212 /**
1213  * Derive XKEK
1214  *
1215  * @param {Number} keyDomain number of key domain in the range 0 to the maximum defined in the INITIALIZE DEVICE command
1216  * @param {ByteString} derivationParam
1217  * @return object with properties sw{Number}, shares{Number}, outstanding{Number}, kcv{ByteString} and the key domain UID{ByteString}
1218  * @type Object
1219  */
1220 SmartCardHSM.prototype.deriveXKEK = function(keyid, peerPublicKey, derivationParam) {
1221 	if (typeof(keyid) != "number") {
1222 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyid must be a number");
1223 	}
1224 	if ((keyid < 1) || (keyid > 0xFF)) {
1225 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyid must be between 1 and 255");
1226 	}
1227 	if (!(peerPublicKey instanceof CVC)) {
1228 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "peerPublicKey must be a CVC");
1229 	}
1230 	if (!(derivationParam instanceof ByteString)) {
1231 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "derivationParam must be a ByteString");
1232 	}
1233 
1234 	var car = peerPublicKey.getOuterCAR().getBytes();
1235 
1236 	var pukrefdo = new ASN1(0x83, car);
1237 	var pukref = pukrefdo.getBytes();
1238 
1239 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000]);
1240 
1241 	var kdp = new ASN1(0x50, derivationParam).getBytes();
1242 	var cdata = peerPublicKey.getASN1().value.concat(kdp);
1243 
1244 	if (cdata.length <= this.maxCData) {
1245 		// Le is usually not required, but versions 3.1 to 3.3 fail without Le (#178)
1246 		this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x62, keyid, 0x84, cdata, 0, [0x9000]);
1247 	} else {
1248 		this.updateBinary(ByteString.valueOf(0x2F10), 0, cdata);
1249 		this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x62, keyid, 0x84, [0x9000]);
1250 	}
1251 }
1252 
1253 
1254 
1255 /**
1256  * Query the status of the key domain
1257  *
1258  * @param {Number} keyDomain the number of the key domain which will be queried, default is 0
1259  * @type Object
1260  * @return object with properties sw{Number}, shares{Number}, outstanding{Number}, kcv{ByteString} and for a XKEK key domain the key domain UID{ByteString}
1261  */
1262 SmartCardHSM.prototype.queryKeyDomainStatus = function(keyDomain) {
1263 	if (!keyDomain) {
1264 		keyDomain = 0;
1265 	}
1266 
1267 	var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x00, keyDomain, 0);
1268 
1269 	return this.parseKeyDomainStatus(status);
1270 }
1271 
1272 
1273 
1274 /**
1275  * Delete the key encryption key in a key domain
1276  *
1277  * @param {Number} keyDomain the number of the key domain
1278  */
1279 SmartCardHSM.prototype.deleteKEK = function(keyDomain) {
1280 	var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x04, keyDomain, [0x9000]);
1281 
1282 	return this.parseKeyDomainStatus(status);
1283 }
1284 
1285 
1286 
1287 /**
1288  * Delete the empty key domain
1289  *
1290  * @param {Number} keyDomain the number of the key domain
1291  */
1292 SmartCardHSM.prototype.deleteKeyDomain = function(keyDomain) {
1293 	this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x03, keyDomain, [0x9000]);
1294 }
1295 
1296 
1297 
1298 /**
1299  * Import DKEK share or query status
1300  *
1301  * @param {Number} keyDomain the number of the key domain
1302  * @param {ByteString} keyshare 32 byte key share
1303  * @type Object
1304  * @return object with properties sw{Number}, shares{Number}, outstanding{Number} and kcv{ByteString}
1305  */
1306 SmartCardHSM.prototype.importKeyShare = function(keyDomain, keyshare) {
1307 	if (typeof(keyDomain) != "number") {
1308 		keyshare = keyDomain;
1309 		keyDomain = 0;
1310 	}
1311 	if (typeof(keyshare) != "undefined") {
1312 		var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x00, keyDomain, keyshare, 0, [0x9000]);
1313 	} else {
1314 		var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x00, keyDomain, 0);
1315 	}
1316 	if (status.length == 0) {
1317 		return { sw: this.card.SW };
1318 	}
1319 
1320 	var statusObject = {
1321 		sw: this.card.SW,
1322 		shares: status.byteAt(0),
1323 		outstanding: status.byteAt(1),
1324 		kcv: status.bytes(2, 8)
1325 	}
1326 
1327 	if (status.length > 10) {
1328 		statusObject.keyDomain = status.bytes(10);
1329 	}
1330 
1331 	return statusObject;
1332 }
1333 
1334 
1335 
1336 /**
1337  * Decrypt and import a DKEK share
1338  *
1339  * @param {ByteString} keyshare the encrypted key share as read from the .pbe file
1340  * @param {ByteString} password the password
1341  * @param {Number} keyDomain the number of the key domain
1342  * @return object with properties sw{Number}, shares{Number}, outstanding{Number} and kcv{ByteString}
1343  */
1344 SmartCardHSM.prototype.importEncryptedKeyShare = function(keyshare, password, keyDomain) {
1345 	if (typeof(keyDomain) == "undefined") {
1346 		keyDomain = 0;
1347 	}
1348 
1349 	var dkek = DKEK.decryptKeyShare(keyshare, password);
1350 //	print("Importing into SmartCard-HSM");
1351 	var r = this.importKeyShare(keyDomain, dkek);
1352 	dkek.clear();
1353 	return r;
1354 }
1355 
1356 
1357 
1358 /**
1359  * Wrap key under DKEK
1360  *
1361  * @param {Number} id key id
1362  * @type ByteString
1363  * @return key blob with encrypted key value
1364  */
1365 SmartCardHSM.prototype.wrapKey = function(id) {
1366 	var keyblob = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x72, id, 0x92, 65536, [0x9000]);
1367 	return keyblob;
1368 }
1369 
1370 
1371 
1372 /**
1373  * Unwrap key with DKEK
1374  *
1375  * @param {Number} id key id
1376  * @param {ByteString} keyblob the wrapped key
1377  */
1378 SmartCardHSM.prototype.unwrapKey = function(id, keyblob) {
1379 	if (keyblob.length < this.maxCData) {
1380 		this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x74, id, 0x93, keyblob, [0x9000]);
1381 	} else {
1382 		this.updateBinary(ByteString.valueOf(0x2F10), 0, keyblob);
1383 		this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x74, id, 0x93, [0x9000]);
1384 	}
1385 }
1386 
1387 
1388 
1389 /**
1390  * Replace symmetric key value encrypted under current key
1391  *
1392  * @param {Number} id key id
1393  * @param {ByteString} keyblob the wrapped key
1394  */
1395 SmartCardHSM.prototype.unwrapAndReplaceKey = function(id, keyblob) {
1396 	this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x74, id, 0x94, keyblob, [0x9000]);
1397 }
1398 
1399 
1400 
1401 /**
1402  * Derive Symmetric Key
1403  *
1404  * @param {Number} id key id
1405  * @param {Number} algo algorithm id (one of ALG_CBC_ENC, ALG_CBC_DEC, ALG_CMAC or ALG_DERIVE_SP800_56C)
1406  * @param {ByteString} derivationParam the derivation parameter
1407  * @type ByteString
1408  * @return derived key value
1409  */
1410 SmartCardHSM.prototype.deriveSymmetricKey = function(id, algo, derivationParam) {
1411 	var derivedKeyValue = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x78, id, algo, derivationParam, 0, [0x9000]);
1412 	return derivedKeyValue;
1413 }
1414 
1415 
1416 
1417 /**
1418  * Verify User PIN
1419  *
1420  * @param {ByteString} userPIN user PIN value
1421  * @return the status word SW1/SW2 returned by the device
1422  */
1423 SmartCardHSM.prototype.verifyUserPIN = function(userPIN) {
1424 	if (userPIN) {
1425 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x20, 0x00, 0x81, userPIN);
1426 		return this.card.SW;
1427 	} else {
1428 		var cs = this.getNativeCardService();
1429 		cs.verifyPassword();
1430 		return this.queryUserPINStatus();
1431 	}
1432 }
1433 
1434 
1435 
1436 /**
1437  * Logout
1438  *
1439  */
1440 SmartCardHSM.prototype.logout = function() {
1441 	this.card.clearCredential();
1442 	var fcp = this.card.sendApdu(0x00, 0xA4, 0x04, 0x04, new ByteString("E82B0601040181C31F0201", HEX), 0, [0x9000]);
1443 	var a = new ASN1(fcp);
1444 	var v = a.find(0x85).value;
1445 	this.options = v.bytes(0, 2).toUnsigned();
1446 	this.major = v.byteAt(v.length - 2);
1447 	this.minor = v.byteAt(v.length - 1);
1448 	if (v.length >= 5) {
1449 		this.platform = v.byteAt(v.length - 3);
1450 	}
1451 }
1452 
1453 
1454 
1455 /**
1456  * Change User PIN
1457  *
1458  * @param {ByteString} currentPIN current user PIN value
1459  * @param {ByteString} newPIN new user PIN value
1460  */
1461 SmartCardHSM.prototype.changeUserPIN = function(currentPIN, newPIN) {
1462 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x24, 0x00, 0x81, currentPIN.concat(newPIN), [0x9000]);
1463 }
1464 
1465 
1466 
1467 /**
1468  * Unblock and set User PIN
1469  *
1470  * @param {ByteString} initializationCode the initialization code
1471  * @param {ByteString} newPIN new user PIN value (optional)
1472  */
1473 SmartCardHSM.prototype.unblockUserPIN = function(initializationCode, newPIN) {
1474 	if (newPIN) {
1475 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x2C, 0x00, 0x81, initializationCode.concat(newPIN), [0x9000]);
1476 	} else {
1477 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x2C, 0x01, 0x81, initializationCode, [0x9000]);
1478 	}
1479 }
1480 
1481 
1482 
1483 /**
1484  * Change InitializationCode
1485  *
1486  * @param {ByteString} initializationCode current initialization code
1487  * @param {ByteString} newInitializationCode new initialization code
1488  */
1489 SmartCardHSM.prototype.changeInitializationCode = function(initializationCode, newInitializationCode) {
1490 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x24, 0x00, 0x88, initializationCode.concat(newInitializationCode), [0x9000]);
1491 }
1492 
1493 
1494 
1495 SmartCardHSM.describePINStatus = function(sw, name) {
1496 	var str;
1497 	switch(sw) {
1498 	case 0x9000:
1499 		str = name + " authenticated";
1500 		break;
1501 	case 0x6984:
1502 		str = name + " in transport mode or device not initialized";
1503 		break;
1504 	case 0x6A88:
1505 		str = name + " not initialized";
1506 		break;
1507 	case 0x6983:
1508 		str = name + " blocked";
1509 		break;
1510 	case 0x6300:
1511 		str = name + " not authenticated";
1512 		break;
1513 	default:
1514 		str = name + " not verified, " + (sw & 0xF) + " tries remaining";
1515 		break;
1516 	}
1517 	return str + " (" + ByteString.valueOf(sw).toString(HEX) + ")";
1518 }
1519 
1520 
1521 
1522 /**
1523  * Request PIN Status Information
1524  *
1525  * @param {Number} p2 the PIN object id
1526  * @type Number
1527  * @return the status word SW1/SW2 returned by the device
1528  */
1529 SmartCardHSM.prototype.queryPINStatus = function(p2) {
1530 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x20, 0x00, p2, 0);
1531 	return this.card.SW;
1532 }
1533 
1534 
1535 
1536 /**
1537  * Request PIN Status Information
1538  *
1539  * @type Number
1540  * @return the status word SW1/SW2 returned by the device
1541  */
1542 SmartCardHSM.prototype.queryUserPINStatus = function() {
1543 	return this.queryPINStatus(0x81);
1544 }
1545 
1546 
1547 
1548 /**
1549  * Request Initialization Code Status
1550  *
1551  * @type Number
1552  * @return the status word SW1/SW2 returned by the device
1553  */
1554 SmartCardHSM.prototype.queryInitializationCodeStatus = function() {
1555 	return this.queryPINStatus(0x88);
1556 }
1557 
1558 
1559 
1560 /**
1561  * Enumerate Objects
1562  *
1563  * @return the enumeration
1564  */
1565 SmartCardHSM.prototype.enumerateObjects = function() {
1566 	var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x58, 0x00, 0x00, 65536, [0x9000]);
1567 	return rsp;
1568 }
1569 
1570 
1571 
1572 /**
1573  * Generate random data
1574  *
1575  * @param {Number} length number of bytes
1576  * @return the random bytes
1577  */
1578 SmartCardHSM.prototype.generateRandom = function(length) {
1579 	var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x84, 0x00, 0x00, length, [0x9000]);
1580 	return rsp;
1581 }
1582 
1583 
1584 
1585 /**
1586  * Sign data using referenced key
1587  *
1588  * @param {Number} keyid the key identifier for signing
1589  * @param {algo} algo the algorithm identifier
1590  * @param {ByteString} data the data to be signed
1591  * @return the signature value
1592  */
1593 SmartCardHSM.prototype.sign = function(keyid, algo, data) {
1594 	if (data.length <= this.maxCData) {
1595 		var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x68, keyid, algo, data, 0x10000, [0x9000]);
1596 	} else {
1597 		this.updateBinary(ByteString.valueOf(0x2F10), 0, data);
1598 		var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x68, keyid, algo, 0x10000, [0x9000]);
1599 	}
1600 
1601 	return rsp;
1602 }
1603 
1604 
1605 
1606 /**
1607  * Decipher cryptogram or agree shared secret using Diffie-Hellman
1608  *
1609  * @param {Number} keyid the key identifier
1610  * @param {Number} algo the algorithm identifier
1611  * @param {ByteString} data the the cryptogram or concatenation of x || y of ECC public key
1612  * @return the plain output
1613  */
1614 SmartCardHSM.prototype.decipher = function(keyid, algo, data) {
1615 	var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x62, keyid, algo, data, 0x00, [0x9000]);
1616 	return rsp;
1617 }
1618 
1619 
1620 
1621 /**
1622  * Verify card verifiable certificate
1623  *
1624  * @param {CVC} cvc the card verifiable certificate
1625  **/
1626 SmartCardHSM.prototype.verifyCertificate = function(cvc) {
1627 
1628 	// Check if public key is already known
1629 	var chr = cvc.getCHR().getBytes();
1630 
1631 	var pukrefdo = new ASN1(0x83, chr);
1632 	var pukref = pukrefdo.getBytes();
1633 
1634 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000, 0x6A88]);
1635 
1636 	if (this.card.SW == 0x9000) {
1637 		return;
1638 	}
1639 
1640 	// Select public key for verification
1641 	var car = cvc.getCAR().getBytes();
1642 
1643 	var pukrefdo = new ASN1(0x83, car);
1644 	var pukref = pukrefdo.getBytes();
1645 
1646 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000]);
1647 
1648 	// Extract value of 7F21
1649 	var tl = new TLVList(cvc.getBytes(), TLV.EMV);
1650 	var t = tl.index(0);
1651 	var v = t.getValue();
1652 
1653 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x2A, 0x00, 0xBE, v, [0x9000]);
1654 }
1655 
1656 
1657 
1658 /**
1659  * Enumerate CA certificates
1660  *
1661  * @type String[]
1662  * @return the list of certificate labels
1663  */
1664 SmartCardHSM.prototype.enumerateCACertificates = function() {
1665 	this.canamemap = [];
1666 	this.caidmap = []
1667 	this.caids = [];
1668 	var certlist = [];
1669 
1670 	var fobs = this.enumerateObjects();
1671 
1672 	// Process PKCS#15 certificate descriptions
1673 	for (var i = 0; i < fobs.length; i+= 2) {
1674 		if (fobs.byteAt(i) == SmartCardHSM.CERTDPREFIX) {
1675 			var id = fobs.byteAt(i + 1);
1676 			this.caids.push(id);
1677 			var fid = ByteString.valueOf((SmartCardHSM.CACERTIFICATEPREFIX << 8) + id);
1678 			var descbin = this.readBinary(fobs.bytes(i, 2));
1679 			var asn = new ASN1(descbin);
1680 			var coa = asn.get(0);
1681 			if (coa.elements > 0) {
1682 				var label = coa.get(0).value.toString(ASCII);
1683 			} else {
1684 				var label = "No label (" + i + ")";
1685 			}
1686 			var cert = this.readBinary(fid);
1687 			certlist.push(label);
1688 			this.canamemap[label] = cert;
1689 			cert.id = id;
1690 			this.caidmap[label] = id;
1691 		}
1692 	}
1693 
1694 	return certlist;
1695 }
1696 
1697 
1698 
1699 /**
1700  * Return CA certificate with label
1701  *
1702  * @param {String} label the certificate label
1703  * @type ByteString
1704  * @return the encoded certificate
1705  */
1706 SmartCardHSM.prototype.getCACertificate = function(label) {
1707 	if (typeof(this.caids) == "undefined") {
1708 		this.enumerateCACertificates();
1709 	}
1710 
1711 	return this.canamemap[label];
1712 }
1713 
1714 
1715 
1716 /**
1717  * Determine an unused CA certificate identifier
1718  *
1719  * @type Number
1720  * @return a free CA certificate identifier or -1 if all identifier in use
1721  */
1722 SmartCardHSM.prototype.determineFreeCAId = function() {
1723 	if (typeof(this.caids) == "undefined") {
1724 		this.enumerateCACertificates();
1725 	}
1726 
1727 	if (this.caids.length == 0) {
1728 		return 0;
1729 	}
1730 
1731 	var id = Math.max.apply(null, this.caids) + 1;
1732 	if (id > 256) {
1733 		return -1;
1734 	}
1735 	return id;
1736 }
1737 
1738 
1739 
1740 /**
1741  * Add a new CA certificate to the map
1742  *
1743  * @param {X509} cert the CA certificate
1744  * @param {Number} id the corresponding id
1745  * @param {String} label the corresponding label
1746  */
1747 SmartCardHSM.prototype.addCACertificateToMap = function(cert, id, label) {
1748 	if (!this.caidmap[label]) {
1749 		// new id
1750 		this.caids.push(id);
1751 		this.caidmap[label] = id;
1752 	}
1753 	this.canamemap[label] = cert;
1754 }
1755 
1756 
1757 
1758 /**
1759  * Enumerate key objects in the SmartCard-HSM and build the map of keys
1760  *
1761  * @type String[]
1762  * @return the list of key labels
1763  */
1764 SmartCardHSM.prototype.enumerateKeys = function() {
1765 	this.namemap = [];
1766 	this.idmap = [];
1767 	this.idlist = [];
1768 	this.p15idmap = [];
1769 
1770 	var fobs = this.enumerateObjects();
1771 
1772 	// Process keys
1773 	for (var i = 0; i < fobs.length; i += 2) {
1774 		if ((fobs.byteAt(i) == SmartCardHSM.KEYPREFIX) || (fobs.byteAt(i) == 0xFF)) {
1775 			var kid = fobs.byteAt(i + 1);
1776 			if (kid > 0) {
1777 //				GPSystem.trace("Found key: " + kid);
1778 				var key = new SmartCardHSMKey(this, kid);
1779 				this.idmap[kid] = key;
1780 				this.idlist.push(kid);
1781 				this.updateKey(key);
1782 			}
1783 		}
1784 	}
1785 
1786 	var keylist = [];
1787 	// Process PKCS#15 private key descriptions
1788 	for (var i = 0; i < fobs.length; i += 2) {
1789 		if (fobs.byteAt(i) == SmartCardHSM.PRKDPREFIX) {
1790 			var kid = fobs.byteAt(i + 1);
1791 			var descbin = this.readBinary(fobs.bytes(i, 2));
1792 			if (descbin.length > 2) {
1793 				try {
1794 					var desc = new ASN1(descbin);
1795 					if (desc.elements < 3) {
1796 						continue;
1797 					}
1798 				}
1799 				catch(e) {
1800 					continue;
1801 				}
1802 				var key = this.idmap[kid];
1803 				if (key) {
1804 					key.setDescription(desc);
1805 					var label = key.getLabel();
1806 //					GPSystem.trace(key.getId() + " - " + label);
1807 					if (label) {
1808 						keylist.push(label);
1809 						this.namemap[label] = key;
1810 					}
1811 					var p15id = key.getPKCS15Id();
1812 					this.p15idmap[p15id.toString(HEX)] = key;
1813 				}
1814 			}
1815 		}
1816 	}
1817 
1818 	return keylist;
1819 }
1820 
1821 
1822 
1823 /**
1824  * Get key ids
1825  *
1826  * @type Number[]
1827  * @return a list of key identifier
1828  */
1829 SmartCardHSM.prototype.getKeyIds = function() {
1830 	if (typeof(this.idlist) == "undefined") {
1831 		this.enumerateKeys();
1832 	}
1833 	return this.idlist;
1834 }
1835 
1836 
1837 
1838 /**
1839  * Determine an unused key identifier
1840  *
1841  * @type Number
1842  * @return a free key identifier or -1 if all key identifier in use
1843  */
1844 SmartCardHSM.prototype.determineFreeKeyId = function() {
1845 	if (typeof(this.idlist) == "undefined") {
1846 		this.enumerateKeys();
1847 	}
1848 	for (var i = 1; i < 256; i++) {
1849 		if (this.idmap[i] == undefined) {
1850 			return i;
1851 		}
1852 	}
1853 	throw new GPError("SmartCardHSM", GPError.OUT_OF_MEMORY, 1, "Key idx exhausted");
1854 }
1855 
1856 
1857 
1858 /**
1859  * Update key attributes, in particular the use counter
1860  *
1861  * @param {HSMKey} key the HSM key
1862  */
1863 SmartCardHSM.prototype.updateKey = function(key) {
1864 	var fid = ByteString.valueOf((SmartCardHSM.KEYPREFIX << 8) + key.getId());
1865 	try	{
1866 		var fcp = this.selectFile(fid);
1867 	}
1868 	catch(e) {
1869 		return;
1870 	}
1871 	var a = new ASN1(fcp);
1872 	var pi = a.find(0xA5);
1873 	if (!pi) {
1874 		return;
1875 	}
1876 	var kc = pi.find(0x90);
1877 	if (kc) {
1878 		var c = kc.value.toUnsigned();
1879 
1880 		if (c != 0xFFFFFFFF) {
1881 			key.useCounter = c;
1882 		}
1883 	}
1884 
1885 	var kd = pi.find(0x91);
1886 	if (kd) {
1887 		key.algorithms = kd.value;
1888 	}
1889 
1890 	var kd = pi.find(0x92);
1891 	if (kd) {
1892 		key.keyDomain = kd.value.toUnsigned();
1893 	}
1894 }
1895 
1896 
1897 
1898 /**
1899  * Add a new key to the map of keys
1900  *
1901  * @param {HSMKey} key the HSM key
1902  */
1903 SmartCardHSM.prototype.addKeyToMap = function(key) {
1904 	var id = key.getId();
1905 	this.idmap[id] = key;
1906 
1907 	var label = key.getLabel();
1908 	if (label) {
1909 		this.namemap[label] = key;
1910 	}
1911 
1912 	var p15id = key.getPKCS15Id();
1913 	if (p15id) {
1914 		this.p15idmap[p15id.toString(HEX)] = key;
1915 	}
1916 }
1917 
1918 
1919 
1920 /**
1921  * Get a key reference object
1922  *
1923  * @param {String/Number/ByteString} labelOrId label or id of key
1924  * @returns the key or null if not found
1925  * @type Key
1926  */
1927 SmartCardHSM.prototype.getKey = function(labelOrId) {
1928 	if (typeof(this.idlist) == "undefined") {
1929 		this.enumerateKeys();
1930 	}
1931 
1932 	if (typeof(labelOrId) == "number") {
1933 		var key = this.idmap[labelOrId];
1934 	} else if (typeof(labelOrId) == "string") {
1935 		var key = this.namemap[labelOrId];
1936 	} else {
1937 		var key = this.p15idmap[labelOrId.toString(HEX)];
1938 	}
1939 
1940 	if (key == undefined) {
1941 		return null;
1942 	}
1943 	return key;
1944 }
1945 
1946 
1947 
1948 /**
1949  * Return a list of key objects
1950  *
1951  * @type SmartCardHSMKey[]
1952  * @return the list of keys
1953  */
1954 SmartCardHSM.prototype.getKeys = function() {
1955 	if (typeof(this.idlist) == "undefined") {
1956 		this.enumerateKeys();
1957 	}
1958 
1959 	var keylist = [];
1960 	for (var i in this.idmap) {
1961 		keylist.push(this.idmap[i]);
1962 	}
1963 	return keylist;
1964 }
1965 
1966 
1967 
1968 /**
1969  * Get crypto object
1970  *
1971  * @type HSMCrypto
1972  * @return the HSMCrypto object
1973  */
1974 SmartCardHSM.prototype.getCrypto = function() {
1975 	if (this.crypto == undefined) {
1976 		this.crypto = new SmartCardHSMCrypto(new Crypto());
1977 	}
1978 	return this.crypto;
1979 }
1980 
1981 
1982 
1983 /**
1984  * @private
1985  */
1986 SmartCardHSM.prototype.getTokenInfo = function() {
1987 	if (this.tokenInfo != undefined) {
1988 		return this.tokenInfo;
1989 	}
1990 
1991 	if (!this.hasFile(SmartCardHSM.EF_TokenInfo)) {
1992 		return;
1993 	}
1994 
1995 	var bin = this.readBinary(SmartCardHSM.EF_TokenInfo);
1996 	this.tokenInfo = new ASN1(bin);
1997 	return this.tokenInfo;
1998 }
1999 
2000 
2001 
2002 /**
2003  * Get Token Label
2004  *
2005  * @type String
2006  * @return the token label from CIAInfo
2007  */
2008 SmartCardHSM.prototype.getLabel = function() {
2009 	var ti = this.getTokenInfo();
2010 	if (!ti) {
2011 		return;
2012 	}
2013 
2014 	var a = ti.find(0x80);
2015 	if (!a) {
2016 		return;
2017 	}
2018 	return a.value.toString(UTF8);
2019 }
2020 
2021 
2022 
2023 /**
2024  * @private
2025  */
2026 SmartCardHSM.prototype.getStaticTokenInfo = function() {
2027 	if (this.staticTokenInfo != undefined) {
2028 		return this.staticTokenInfo;
2029 	}
2030 
2031 	if (!this.hasFile(SmartCardHSM.EF_StaticTokenInfo)) {
2032 		return;
2033 	}
2034 
2035 	var bin = this.readBinary(SmartCardHSM.EF_StaticTokenInfo);
2036 	this.staticTokenInfo = new ASN1(bin);
2037 	return this.staticTokenInfo;
2038 }
2039 
2040 
2041 
2042 /**
2043  * Get ProvisioningURL
2044  *
2045  * @type String
2046  * @return the configured ProvisioningURL or undefined
2047  */
2048 SmartCardHSM.prototype.getProvisioningURL = function() {
2049 	var ti = this.getStaticTokenInfo();
2050 	if (!ti) {
2051 		return;
2052 	}
2053 
2054 	var a = ti.find(0x80);
2055 	if (!a) {
2056 		return;
2057 	}
2058 	return a.value.toString(UTF8);
2059 }
2060 
2061 
2062 
2063 /**
2064  * Get Key Check Value of Token Management Key
2065  *
2066  * @type ByteString
2067  * @return the configured KCV of the Token Management Key or undefined
2068  */
2069 SmartCardHSM.prototype.getTokenManagementKeyKCV = function() {
2070 	var ti = this.getStaticTokenInfo();
2071 	if (!ti) {
2072 		return;
2073 	}
2074 
2075 	var a = ti.find(0x81);
2076 	if (!a) {
2077 		return;
2078 	}
2079 	return a.value;
2080 }
2081 
2082 
2083 
2084 /**
2085  * Get salt for SO-PIN derivation using  the Token Management Key
2086  *
2087  * @type ByteString
2088  * @return the configured salt
2089  */
2090 SmartCardHSM.prototype.getTokenManagementKeySalt = function() {
2091 	var ti = this.getStaticTokenInfo();
2092 	if (!ti) {
2093 		return;
2094 	}
2095 
2096 	var a = ti.find(0x82);
2097 	if (!a) {
2098 		return;
2099 	}
2100 	return a.value;
2101 }
2102 
2103 
2104 
2105 /**
2106  * Create crypto object implementing access to the SmartCard-HSM
2107  *
2108  * @class Wrapper to provide Crypto interface to SmartCard-HSM
2109  * @constructor
2110  * @param {Crypto} crypto the backend crypto provider
2111  */
2112 function SmartCardHSMCrypto(crypto) {
2113 	this.crypto = crypto;
2114 }
2115 
2116 
2117 
2118 /**
2119  * Sign a message using the defined mechanism and key
2120  *
2121  * @param {HSMKey} key the private key
2122  * @param {Number} mech the mechanism (e.g. Crypto.ECDSA)
2123  * @param {ByteString} message the message to be signed
2124  * @type ByteString
2125  * @return the signature
2126  */
2127 SmartCardHSMCrypto.prototype.sign = function(key, mech, message) {
2128 	if (key instanceof SmartCardHSMKey) {
2129 		return key.sign(mech, message);
2130 	} else {
2131 		return this.crypto.sign(key, mech, message);
2132 	}
2133 }
2134 
2135 
2136 
2137 /**
2138  * Decrypt a message using the defined mechanism and key
2139  *
2140  * @param {HSMKey} key the private key
2141  * @param {Number} mech the mechanism (e.g. Crypto.RSA_PKCS1)
2142  * @param {ByteString} data the cryptogram
2143  * @param {ByteString} iv the initialization vector for symmetric ciphers
2144  * @type ByteString
2145  * @return the plain text
2146  */
2147 SmartCardHSMCrypto.prototype.decrypt = function(key, mech, data, iv) {
2148 	if (key instanceof SmartCardHSMKey) {
2149 		return key.decrypt(mech, data);
2150 	} else {
2151 		return this.crypto.decrypt(key, mech, data, iv);
2152 	}
2153 }
2154 
2155 
2156 
2157 /**
2158  * Verify a message using the defined mechanism and key
2159  *
2160  * @param {Key} key the public key
2161  * @param {Number} mech the mechanism (e.g. Crypto.ECDSA)
2162  * @param {ByteString} message the message to be signed
2163  * @param {ByteString} signature the signature to verify
2164  * @type Boolean
2165  * @return true if signature is valid
2166  */
2167 SmartCardHSMCrypto.prototype.verify = function(key, mech, message, signature) {
2168 	return this.crypto.verify(key, mech, message, signature);
2169 }
2170 
2171 
2172 
2173 /**
2174  * Create a key access object
2175  *
2176  * @class Class implementing key access
2177  * @param {SmartCardHSM} sc the card access object
2178  * @param {Number} id the key identifier
2179  */
2180 function SmartCardHSMKey(sc, id) {
2181 	this.sc = sc;
2182 	this.id = id;
2183 	if (this.sc.useExternalHashInECDSA) {
2184 		this.crypto = new Crypto();
2185 	}
2186 }
2187 
2188 exports.SmartCardHSMKey = SmartCardHSMKey;
2189 
2190 
2191 /**
2192  * Set the PKCS#15 private key description
2193  *
2194  * @param {ASN1} desc the description
2195  */
2196 SmartCardHSMKey.prototype.setDescription = function(desc) {
2197 	this.desc = desc;
2198 }
2199 
2200 
2201 
2202 /**
2203  * Return the key identifier
2204  *
2205  * @type Number
2206  * @return the key identifier
2207  */
2208 SmartCardHSMKey.prototype.getId = function() {
2209 	return this.id;
2210 }
2211 
2212 
2213 
2214 /**
2215  * Return the key label as encoded in the PKCS#15 structure
2216  *
2217  * @type String
2218  * @return the key label
2219  */
2220 SmartCardHSMKey.prototype.getLabel = function() {
2221 	if (this.desc == undefined) {
2222 		return undefined;
2223 	}
2224 	if ((this.desc.get(0).elements == 0) || this.desc.get(0).get(0).tag != 0x0C) {
2225 		return undefined;
2226 	}
2227 
2228 	return this.desc.get(0).get(0).value.toString(UTF8);
2229 }
2230 
2231 
2232 
2233 /**
2234  * Return the key id as encoded in the PKCS#15 structure
2235  *
2236  * @type ByteString
2237  * @return the key identifier
2238  */
2239 SmartCardHSMKey.prototype.getPKCS15Id = function() {
2240 	if (this.desc == undefined) {
2241 		return undefined;
2242 	}
2243 	return this.desc.get(1).get(0).value;
2244 }
2245 
2246 
2247 
2248 /**
2249  * Return the key size in bits
2250  *
2251  * @type Number
2252  * @return the key size in bits
2253  */
2254 SmartCardHSMKey.prototype.getSize = function() {
2255 	if (this.desc == undefined) {
2256 		return undefined;
2257 	}
2258 //	GPSystem.trace(this.desc);
2259 	if (this.desc.get(2).elements > 1) {	// Fix a bug from early versions
2260 		return this.desc.get(2).get(1).value.toUnsigned();
2261 	} else {
2262 		return this.desc.get(2).get(0).get(1).value.toUnsigned();
2263 	}
2264 }
2265 
2266 
2267 
2268 /**
2269  * Return the key size in bits
2270  *
2271  * @type Number
2272  * @return the key size in bits
2273  */
2274 SmartCardHSMKey.prototype.getType = function() {
2275 	if (this.desc == undefined) {
2276 		return undefined;
2277 	}
2278 
2279 	if (this.desc.tag == 0xA0) {
2280 		return "EC";
2281 	} else if (this.desc.tag == 0x30) {
2282 		return "RSA";
2283 	} else if (this.desc.tag == 0xA8) {
2284 		return "AES";
2285 	}
2286 
2287 	return undefined;
2288 }
2289 
2290 
2291 
2292 /**
2293  * Sign data using a key in the SmartCard-HSM
2294  *
2295  * @param {Number} mech the signing mechanism
2296  * @param {ByteString} data to be signed
2297  * @type ByteString
2298  * @return the signature
2299  */
2300 SmartCardHSMKey.prototype.sign = function(mech, data) {
2301 	var algo;
2302 	if (mech) {
2303 		switch(mech) {
2304 		case Crypto.RSA:
2305 			algo = 0x20;
2306 			break;
2307 		case Crypto.RSA_SHA1:
2308 			algo = 0x31;
2309 			break;
2310 		case Crypto.RSA_SHA256:
2311 			algo = 0x33;
2312 			break;
2313 		case Crypto.RSA_PKCS1:
2314 			algo = 0x20;
2315 			var keysize = this.getSize();
2316 			if (!keysize) {
2317 				throw new GPError(module.id, GPError.INVALID_DATA, 0, "Can't determine key size");
2318 			}
2319 			data = PKCS1.encode_EMSA_V15(keysize, data);
2320 			break;
2321 //		case Crypto.RSA_PSS:
2322 		case 0x80:
2323 			algo = 0x40;
2324 			break;
2325 		case Crypto.RSA_PSS_SHA1:
2326 			algo = 0x41;
2327 			break;
2328 		case Crypto.RSA_PSS_SHA256:
2329 			algo = 0x43;
2330 			break;
2331 		case Crypto.ECDSA:
2332 			algo = 0x70;
2333 			break;
2334 		case Crypto.ECDSA_SHA1:
2335 			if (this.sc.useExternalHashInECDSA) {
2336 				algo = 0x70;
2337 				var data = this.crypto.digest(Crypto.SHA_1, data);
2338 			} else {
2339 				algo = 0x71;
2340 			}
2341 			break;
2342 		case Crypto.ECDSA_SHA224:
2343 			if (this.sc.useExternalHashInECDSA) {
2344 				algo = 0x70;
2345 				var data = this.crypto.digest(Crypto.SHA_224, data);
2346 			} else {
2347 				algo = 0x72;
2348 			}
2349 			break;
2350 		case Crypto.ECDSA_SHA256:
2351 			if (this.sc.useExternalHashInECDSA) {
2352 				algo = 0x70;
2353 				var data = this.crypto.digest(Crypto.SHA_256, data);
2354 			} else {
2355 				algo = 0x73;
2356 			}
2357 			break;
2358 		case Crypto.AES_CMAC:
2359 			return this.sc.deriveSymmetricKey(this.id, SmartCardHSM.ALG_CMAC, data);
2360 		default:
2361 			throw new GPError("SmartCardHSMKey", GPError.INVALID_DATA, mech, "Unsupported crypto mechanism");
2362 		}
2363 	}
2364 
2365 	return this.sc.sign(this.id, algo, data);
2366 }
2367 
2368 
2369 
2370 /**
2371  * Decrypt data using a key in the SmartCard-HSM
2372  *
2373  * @param {Number} mech the decipher mechanism
2374  * @param {ByteString} data to be deciphered
2375  * @type ByteString
2376  * @return the plain message
2377  */
2378 SmartCardHSMKey.prototype.decrypt = function(mech, data) {
2379 	var algo;
2380 	if (mech) {
2381 		switch(mech) {
2382 		case Crypto.RSA:
2383 			break;
2384 		case Crypto.RSA_PKCS1:
2385 			break;
2386 		case Crypto.RSA_OAEP_SHA224:
2387 			algo = Crypto.SHA_224;
2388 			break;
2389 		case Crypto.RSA_OAEP_SHA256:
2390 			algo = Crypto.SHA_256;
2391 			break;
2392 		case Crypto.RSA_OAEP_SHA384:
2393 			algo = Crypto.SHA_384;
2394 			break;
2395 		case Crypto.RSA_OAEP_SHA512:
2396 			algo = Crypto.SHA_512;
2397 			break;
2398 		default:
2399 			throw new GPError("SmartCardHSMKey", GPError.INVALID_DATA, mech, "Unsupported crypto mechanism");
2400 		}
2401 	}
2402 
2403 	var em = this.sc.decipher(this.id, 0x21, data);
2404 
2405 	var plain = em;
2406 
2407 	if (mech != Crypto.RSA) {
2408 		if (mech == Crypto.RSA_PKCS1) {
2409 			var plain = PKCS1.decode_EME_V15(em);
2410 		} else {
2411 			var crypto = this.sc.getCrypto().crypto;
2412 
2413 			var plain = PKCS1.decode_EME_OAEP(crypto, null, algo, em);
2414 		}
2415 
2416 		if (!plain) {
2417 			throw new GPError("SmartCardHSMKey", GPError.CRYPTO_FAILED, mech, "Decryption failed");
2418 		}
2419 	}
2420 
2421 	return plain;
2422 }
2423 
2424 
2425 
2426 /**
2427  * Return human readable string
2428  */
2429 SmartCardHSMKey.prototype.toString = function() {
2430 	return "SmartCardHSMKey(id=" + this.id + ")";
2431 }
2432 
2433 
2434 
2435 /**
2436  * Initialize SmartCard-HSM
2437  *
2438  * @class Class implementing the device initialization methods
2439  * @param {Card} card the card object
2440  */
2441 function SmartCardHSMInitializer(card) {
2442 	this.card = card;
2443 	this.initializationCode = new ByteString("57621880", ASCII);
2444 	this.userPIN = new ByteString("648219", ASCII);
2445 	this.userPINSet = false;
2446 	this.useDefaultUserPIN = true;
2447 	this.retryCounterInitial = 3;
2448 	this.options = 0x0001;
2449 	this.keyshares = -1;
2450 	this.keyDomains = -1;
2451 	this.numberOfPublicKeys = 0;
2452 	this.requiredPublicKeysForAuthentication = 0;
2453 	this.bioslot = [];
2454 	this.label = undefined;
2455 }
2456 
2457 exports.SmartCardHSMInitializer = SmartCardHSMInitializer;
2458 
2459 
2460 
2461 /**
2462  * Set the initialization code
2463  *
2464  * @param {ByteString} initializationCode an 8 byte code
2465  */
2466 SmartCardHSMInitializer.prototype.setInitializationCode = function(initializationCode) {
2467 	if (!(initializationCode instanceof ByteString)) {
2468 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "initializationCode must be a ByteString");
2469 	}
2470 	if (initializationCode.length != 8) {
2471 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "initializationCode must have 8 bytes");
2472 	}
2473 
2474 	this.initializationCode = initializationCode;
2475 }
2476 
2477 
2478 
2479 /**
2480  * Set the User PIN
2481  *
2482  * @param {ByteString} userPIN a 6 to 16 byte code
2483  */
2484 SmartCardHSMInitializer.prototype.setUserPIN = function(userPIN) {
2485 	if (!(userPIN instanceof ByteString)) {
2486 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "userPIN must be a ByteString");
2487 	}
2488 	if ((userPIN.length < 6) || (userPIN.length > 16)) {
2489 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "userPIN must be between 6 and 16 bytes");
2490 	}
2491 
2492 	this.userPIN = userPIN;
2493 	this.userPINSet = true;
2494 	this.useDefaultUserPIN = false;
2495 }
2496 
2497 
2498 
2499 /**
2500  * Set the retry counter
2501  *
2502  * The SmartCard-HSM enforces a retry counter <= 3 for PIN length 6
2503  * The SmartCard-HSM enforces a retry counter <= 5 for PIN length 7
2504  * The SmartCard-HSM enforces a retry counter <= 10 for PIN length larger than 7
2505  *
2506  * @param {Number} retryCounterInitial in the range 1 to 10.
2507  */
2508 SmartCardHSMInitializer.prototype.setRetryCounterInitial = function(retryCounterInitial) {
2509 	if (typeof(retryCounterInitial) != "number") {
2510 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "retryCounterInitial must be a number");
2511 	}
2512 	if ((retryCounterInitial < 1) || (retryCounterInitial > 10)) {
2513 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "retryCounterInitial must be between 1 and 10");
2514 	}
2515 	this.retryCounterInitial = retryCounterInitial;
2516 }
2517 
2518 
2519 
2520 /**
2521  * Set the number of DKEK shares
2522  *
2523  * @param {Number} keyshares number of DKEK shares in the range 0 to 255
2524  */
2525 SmartCardHSMInitializer.prototype.setDKEKShares = function(keyshares) {
2526 	if (typeof(keyshares) != "number") {
2527 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyshares must be a number");
2528 	}
2529 	if ((keyshares < 0) || (keyshares > 255)) {
2530 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyshares must be between 0 and 255");
2531 	}
2532 	this.keyshares = keyshares;
2533 	this.keyDomains = -1;
2534 }
2535 
2536 
2537 
2538 /**
2539  * Set the number of key domains
2540  *
2541  * @param {Number} keyDomains number of key domains
2542  */
2543 SmartCardHSMInitializer.prototype.setKeyDomains = function(keyDomains) {
2544 	if (typeof(keyDomains) != "number") {
2545 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyDomains must be a number");
2546 	}
2547 
2548 	this.keyDomains = keyDomains;
2549 	this.keyshares = -1;
2550 }
2551 
2552 
2553 
2554 /**
2555  * Enable or disable RESET RETRY COUNTER command
2556  *
2557  * @param {Boolean} enable true (default) to allow RESET RETRY COUNTER command to reset user PIN using the initialization code
2558  */
2559 SmartCardHSMInitializer.prototype.setResetRetryCounterMode = function(enable) {
2560 	if (typeof(enable) == "undefined") {
2561 		var enable = false;
2562 	}
2563 
2564 	this.options = (this.options & 0xFFFE) + (enable ? 1 : 0);
2565 }
2566 
2567 
2568 
2569 /**
2570  * Enable or disable transport PIN mode
2571  *
2572  * @param {Boolean} enable true (non-default) to set user PIN to transport state
2573  */
2574 SmartCardHSMInitializer.prototype.setTransportPINMode = function(enable) {
2575 	if (typeof(enable) == "undefined") {
2576 		var enable = true;
2577 	}
2578 
2579 	this.options = (this.options & 0xFFFD) + (enable ? 2 : 0);
2580 }
2581 
2582 
2583 
2584 /**
2585  * Enable or disable session PIN mode
2586  *
2587  * @param {Number} 0 - disable, 1 - enable with clear-on-reset 3 - enable with explicit clearing
2588  */
2589 SmartCardHSMInitializer.prototype.setSessionPINMode = function(mode) {
2590 	assert(typeof(mode) == "number", "Argument mode must be number");
2591 	assert(mode >= 0 && mode <= 3 && mode != 2, "Argument mode must be 0, 1 or 3");
2592 
2593 	this.options = (this.options & 0xFFF3) + (mode << 2);
2594 }
2595 
2596 
2597 
2598 /**
2599  * Enable or disable replacing of a PKA key
2600  *
2601  * @param {Boolean} enable true (non-default) to allow replacing of a PKA key
2602  */
2603 SmartCardHSMInitializer.prototype.setReplacePKAKeyMode = function(enable) {
2604 	if (typeof(enable) == "undefined") {
2605 		var enable = false;
2606 	}
2607 
2608 	this.options = (this.options & 0xFFF7) + (enable ? 8 : 0);
2609 }
2610 
2611 
2612 
2613 /**
2614  * Enable the combined authentication mode of user pin and public key authentication.
2615  *
2616  * @param {Boolean} enable true (non-default) to require public key authentication and user authentication
2617  */
2618 SmartCardHSMInitializer.prototype.setCombinedAuthenticationMode = function(enable) {
2619 	if (typeof(enable) == "undefined") {
2620 		var enable = false;
2621 	}
2622 
2623 	this.options = (this.options & 0xFFEF) + (enable ? 16 : 0);
2624 }
2625 
2626 
2627 
2628 /**
2629  * If enabled RESET RETRY COUNTER only resets the error counter.
2630  * Otherwise  RRC allows changing the PIN
2631  *
2632  * @param {Boolean} resetOnly true to only reset the error counter, false otherwise (default)
2633  */
2634 SmartCardHSMInitializer.prototype.setResetRetryCounterResetOnlyMode = function(resetOnly) {
2635 	if (typeof(resetOnly) == "undefined") {
2636 		var resetOnly = false;
2637 	}
2638 
2639 	this.options = (this.options & 0xFFDF) + (resetOnly ? 32 : 0);
2640 }
2641 
2642 
2643 
2644 /**
2645  * Set parameter for public key authentication with n-of-m scheme, namely the values for n and m
2646  *
2647  * @param {Number} requiredPublicKeysForAuthentication number of key that must be authenticated for access
2648  * @param {Number} numberOfPublicKeys to register
2649  */
2650 SmartCardHSMInitializer.prototype.setPublicKeyAuthenticationParameter = function(requiredPublicKeysForAuthentication, numberOfPublicKeys) {
2651 	if ((numberOfPublicKeys < 1) || (numberOfPublicKeys > 90)) {
2652 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "numberOfPublicKeys must be between 1 and 90");
2653 	}
2654 	if ((requiredPublicKeysForAuthentication < 1) || (requiredPublicKeysForAuthentication > numberOfPublicKeys)) {
2655 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 2, "requiredPublicKeysForAuthentication must be between 1 and " + numberOfPublicKeys);
2656 	}
2657 	this.numberOfPublicKeys = numberOfPublicKeys;
2658 	this.requiredPublicKeysForAuthentication = requiredPublicKeysForAuthentication;
2659 	this.useDefaultUserPIN = false;
2660 }
2661 
2662 
2663 
2664 /**
2665  * Select the biometric matching server for a one of the biometric templates
2666  *
2667  * @param {Number} slot either 0 or 1 for first or second template
2668  * @param {ByteString} aid the application identifier of the on-card biometric server
2669  * @param {Number} param one byte parameter passed to the server during initialization
2670  */
2671 SmartCardHSMInitializer.prototype.setBioTemplate = function(slot, aid, param) {
2672 	assert(typeof(slot) == "number", "slot must be a number");
2673 	assert(slot >= 0 && slot <= 1, "slot must be either 0 or 1");
2674 	assert(aid instanceof ByteString, "aid must be a ByteString");
2675 	assert(typeof(param) == "number", "param must be a number");
2676 	assert(param >= 0 && param <= 255, "param must be between 0 and 255");
2677 
2678 	this.bioslot[slot] = { aid: aid, param: param };
2679 	this.useDefaultUserPIN = false;
2680 }
2681 
2682 
2683 
2684 /**
2685  * Set the label to be written to a minimal CIAInfo in EF 2F03
2686  *
2687  * @param {String} label the label
2688  */
2689 SmartCardHSMInitializer.prototype.setLabel = function(label) {
2690 	this.label = label;
2691 }
2692 
2693 
2694 
2695 /**
2696  * Set the provisioning URL to be written to fixed parameter in CB00.
2697  *
2698  * @param {String} provisioningURL the URL at which this SE will be provisioned
2699  */
2700 SmartCardHSMInitializer.prototype.setProvisioningURL = function(provisioningURL) {
2701 	this.provisioningURL = provisioningURL;
2702 }
2703 
2704 
2705 
2706 /**
2707  * Set the key check value of the token management key and the optional salt
2708  * used for SO-PIN derivation
2709  *
2710  * @param {ByteString} kcv the key check value of the token management key
2711  * @param {ByteString} salt the salt used to derive the SO-PIN
2712  */
2713 SmartCardHSMInitializer.prototype.setTokenManagementKey = function(kcv, salt) {
2714 	this.tokenManagementKeyKCV = kcv;
2715 	this.tokenManagementKeySalt = salt;
2716 }
2717 
2718 
2719 
2720 /**
2721  * Perform Initialization
2722  */
2723 SmartCardHSMInitializer.prototype.initialize = function() {
2724 	var s = new ASN1(0x30,	new ASN1(0x80, ByteString.valueOf(this.options, 2)));
2725 
2726 	if (this.userPINSet || this.useDefaultUserPIN) {
2727 		s.add(new ASN1(0x81, this.userPIN));
2728 	}
2729 
2730 	s.add(new ASN1(0x82, this.initializationCode));
2731 
2732 	if (this.userPINSet || this.useDefaultUserPIN) {
2733 		s.add(new ASN1(0x91, ByteString.valueOf(this.retryCounterInitial)));
2734 	}
2735 
2736 	if (this.keyshares != -1) {
2737 		s.add(new ASN1(0x92, ByteString.valueOf(this.keyshares)));
2738 	}
2739 
2740 	if (this.keyDomains != -1) {
2741 		s.add(new ASN1(0x97, ByteString.valueOf(this.keyDomains)));
2742 	}
2743 
2744 	if (this.numberOfPublicKeys > 0) {
2745 		s.add(new ASN1(0x93, ByteString.valueOf(this.numberOfPublicKeys).concat(ByteString.valueOf(this.requiredPublicKeysForAuthentication))));
2746 	}
2747 
2748 	if (this.bioslot[0]) {
2749 		var o = this.bioslot[0];
2750 		s.add(new ASN1(0x95, ByteString.valueOf(o.param).concat(o.aid)));
2751 	}
2752 
2753 	if (this.bioslot[1]) {
2754 		var o = this.bioslot[1];
2755 		s.add(new ASN1(0x96, ByteString.valueOf(o.param).concat(o.aid)));
2756 	}
2757 
2758 	this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000, 0x6A84]);
2759 
2760 	if (this.card.SW == 0x6A84) {
2761 		// Due to the nature of the JCRE, a first call to initialize may run out of memory,
2762 		// as the garbage collector for the removed objects is only run during the next
2763 		// APDU invocation.
2764 		this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000]);
2765 	}
2766 
2767 	if (this.label) {
2768 		var a = new ASN1(0x30,
2769 				new ASN1(0x54, new ByteString("0000", HEX)),
2770 				new ASN1(0x53,
2771 					new ASN1(0x30,
2772 						new ASN1(0x02, new ByteString("00", HEX)),
2773 						new ASN1(0x80, new ByteString(this.label, UTF8)),
2774 						new ASN1(0x03, new ByteString("0500", HEX)))
2775 				)
2776 			);
2777 
2778 		var p1 = SmartCardHSM.EF_TokenInfo.byteAt(0);
2779 		var p2 = SmartCardHSM.EF_TokenInfo.byteAt(1);
2780 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, p1, p2, a.value, [0x9000]);
2781 	}
2782 
2783 	if (this.provisioningURL || this.tokenManagementKeyKCV || this.tokenManagementKeySalt) {
2784 		var l = new ASN1(ASN1.SEQUENCE);
2785 		if (this.provisioningURL) {
2786 			l.add(new ASN1(0x80, new ByteString(this.provisioningURL, UTF8)));
2787 		}
2788 		if (this.tokenManagementKeyKCV) {
2789 			l.add(new ASN1(0x81, this.tokenManagementKeyKCV));
2790 		}
2791 		if (this.tokenManagementKeySalt) {
2792 			l.add(new ASN1(0x82, this.tokenManagementKeySalt));
2793 		}
2794 
2795 		var a = new ASN1(0x30,
2796 				new ASN1(0x54, new ByteString("0000", HEX)),
2797 				new ASN1(0x53, l)
2798 			);
2799 
2800 		var p1 = SmartCardHSM.EF_StaticTokenInfo.byteAt(0);
2801 		var p2 = SmartCardHSM.EF_StaticTokenInfo.byteAt(1);
2802 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, p1, p2, a.value, [0x9000]);
2803 	}
2804 }
2805 
2806 
2807 
2808 /**
2809  * Create a key specification generator instance
2810  *
2811  * @class Class implementing an encoder for the C-Data required in GENERATE ASYMMETRIC KEY PAIR
2812  * @param {Number} keytype must be either Crypto.RSA, Crypto.EC or Crypto.AES
2813  * @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
2814  */
2815 function SmartCardHSMKeySpecGenerator(keytype, keysizeOrDP) {
2816 	this.keytype = keytype;
2817 
2818 	switch(keytype) {
2819 		case Crypto.RSA:
2820 			if (typeof(keysizeOrDP) != "number") {
2821 				throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be of a number for RSA keys");
2822 			}
2823 			this.keysize = keysizeOrDP;
2824 			this.defaultAlgo = new ByteString("id-TA-RSA-v1-5-SHA-256", OID);
2825 			break;
2826 		case Crypto.EC:
2827 			if ((typeof(keysizeOrDP) != "object") || !(keysizeOrDP instanceof Key)) {
2828 				throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be a Key instance");
2829 			}
2830 			this.domainParameter = keysizeOrDP;
2831 			this.defaultAlgo = new ByteString("id-TA-ECDSA-SHA-256", OID);
2832 			break;
2833 		case Crypto.AES:
2834 			if (typeof(keysizeOrDP) != "number") {
2835 				throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be of a number for AES keys");
2836 			}
2837 			this.keysize = keysizeOrDP;
2838 			break;
2839 		default:
2840 			throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keytype must be Crypto.RSA or Crypto.EC");
2841 	}
2842 	this.CHR = new PublicKeyReference("UTDUMMY00001");
2843 	this.innerCAR = new PublicKeyReference("UTDUMMY00001");
2844 }
2845 
2846 exports.SmartCardHSMKeySpecGenerator = SmartCardHSMKeySpecGenerator;
2847 
2848 
2849 
2850 /**
2851  * Set key use counter for key
2852  *
2853  * @param {keyUseCounter} keyUseCounter in the range 1 to 2^64 - 2
2854  */
2855 SmartCardHSMKeySpecGenerator.prototype.setKeyUseCounter = function(keyUseCounter) {
2856 	if ((keyUseCounter < 0) || (keyUseCounter >= 0xFFFFFFFF)) {
2857 		throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 1, "keyUseCounter must be between 0 and 0xFFFFFFFF");
2858 	}
2859 	this.keyUseCounter = keyUseCounter;
2860 }
2861 
2862 
2863 
2864 /**
2865  * Set key domain
2866  *
2867  * @param {Number} keyDomain the key domain to which the key shall be added
2868  */
2869 SmartCardHSMKeySpecGenerator.prototype.setKeyDomain = function(keyDomain) {
2870 	this.keyDomain = keyDomain;
2871 }
2872 
2873 
2874 
2875 /**
2876  * Set wrapping key
2877  *
2878  * @param {Number} wrappingKey the key to used for wrapping a newly generated symmetric key
2879  */
2880 SmartCardHSMKeySpecGenerator.prototype.setWrappingKey = function(wrappingKey) {
2881 	this.wrappingKey = wrappingKey;
2882 }
2883 
2884 
2885 
2886 /**
2887  * Set algorithm list
2888  *
2889  * @param {ByteString} algorithms the list of algorithms allowed for this key
2890  */
2891 SmartCardHSMKeySpecGenerator.prototype.setAlgorithms = function(algorithms) {
2892 	this.algorithms = algorithms;
2893 }
2894 
2895 
2896 
2897 /**
2898  * Set certificate holder reference for key
2899  *
2900  * @param {PublicKeyReference} CHR certificate holder reference
2901  */
2902 SmartCardHSMKeySpecGenerator.prototype.setCHR = function(CHR) {
2903 	this.CHR = CHR;
2904 }
2905 
2906 
2907 
2908 /**
2909  * Set certificate holder reference of CA this request shall be sent to
2910  *
2911  * @param {PublicKeyReference} CAR certificate holder reference
2912  */
2913 SmartCardHSMKeySpecGenerator.prototype.setInnerCAR = function(CAR) {
2914 	this.innerCAR = CAR;
2915 }
2916 
2917 
2918 
2919 /**
2920  * Set holder reference of the key signing this request
2921  *
2922  * @param {PublicKeyReference} CAR certificate holder reference
2923  */
2924 SmartCardHSMKeySpecGenerator.prototype.setOuterCAR = function(CAR) {
2925 	this.outerCAR = CAR;
2926 }
2927 
2928 
2929 
2930 /**
2931  * @private
2932  */
2933 SmartCardHSMKeySpecGenerator.prototype.encodeRSAKeySpec = function() {
2934 	var p = new ASN1("Public Key", 0x7F49,
2935 			new ASN1("Object Identifier", 0x06, this.defaultAlgo),
2936 			new ASN1("Public Key Exponent", 0x82, ByteString.valueOf(65537)),
2937 			new ASN1("Key Size", 0x02, ByteString.valueOf(this.keysize))
2938 		);
2939 	return p;
2940 }
2941 
2942 
2943 
2944 /**
2945  * @private
2946  */
2947 SmartCardHSMKeySpecGenerator.prototype.encodeECKeySpec = function() {
2948 	// Encode G
2949 	var bb = new ByteBuffer();
2950 	// uncompressed encoding
2951 	bb.append(new ByteString("04", HEX));
2952 	bb.append(this.domainParameter.getComponent(Key.ECC_GX));
2953 	bb.append(this.domainParameter.getComponent(Key.ECC_GY));
2954 	var G = bb.toByteString();
2955 
2956 	var p = new ASN1("Public Key", 0x7F49,
2957 			new ASN1("Object Identifier", 0x06, this.defaultAlgo),
2958 			new ASN1("Prime Modulus", 0x81, this.domainParameter.getComponent(Key.ECC_P)),
2959 			new ASN1("First coefficient a", 0x82, this.domainParameter.getComponent(Key.ECC_A)),
2960 			new ASN1("Second coefficient b", 0x83, this.domainParameter.getComponent(Key.ECC_B)),
2961 			new ASN1("Base Point G", 0x84, G),
2962 			new ASN1("Order of the base point", 0x85, this.domainParameter.getComponent(Key.ECC_N)),
2963 			new ASN1("Cofactor f", 0x87, SmartCardHSM.stripLeadingZeros(this.domainParameter.getComponent(Key.ECC_H)))
2964 		);
2965 	return p;
2966 }
2967 
2968 
2969 
2970 /**
2971  * @private
2972  */
2973 SmartCardHSMKeySpecGenerator.prototype.encodeKeySpec = function() {
2974 	if (this.keytype == Crypto.RSA) {
2975 		return this.encodeRSAKeySpec();
2976 	} else {
2977 		return this.encodeECKeySpec();
2978 	}
2979 }
2980 
2981 
2982 
2983 /**
2984  * Return the encoded key specification
2985  *
2986  * @type ByteString
2987  * @return the encoded C-Data for GENERATE ASYMMETRIC KEY PAIR
2988  */
2989 SmartCardHSMKeySpecGenerator.prototype.encode = function() {
2990 	var t = new ASN1(0x30);
2991 
2992 	if (this.keytype != Crypto.AES) {
2993 		t.add(new ASN1("CPI", 0x5F29, new ByteString("00", HEX)));
2994 
2995 		if ((typeof(this.innerCAR) != "undefined") && (this.innerCAR)) {
2996 			t.add(new ASN1("CAR", 0x42, this.innerCAR.getBytes()));
2997 		}
2998 
2999 		t.add(this.encodeKeySpec());
3000 		t.add(new ASN1("CHR", 0x5F20, this.CHR.getBytes()));
3001 
3002 		if (typeof(this.outerCAR) != "undefined") {
3003 			t.add(new ASN1("OuterCAR", 0x45, this.outerCAR.getBytes()));
3004 		}
3005 	}
3006 
3007 	if (typeof(this.keyUseCounter) != "undefined") {
3008 		t.add(new ASN1("Key use counter", 0x90, ByteString.valueOf(this.keyUseCounter, 4)));
3009 	}
3010 
3011 	if (typeof(this.algorithms) != "undefined") {
3012 		t.add(new ASN1("Algorithms", 0x91, this.algorithms));
3013 	}
3014 
3015 	if (typeof(this.keyDomain) != "undefined") {
3016 		t.add(new ASN1("KeyDomain", 0x92, ByteString.valueOf(this.keyDomain)));
3017 	}
3018 
3019 	if (typeof(this.wrappingKey) != "undefined") {
3020 		t.add(new ASN1("Wrapping Key", 0x93, ByteString.valueOf(this.wrappingKey)));
3021 	}
3022 
3023 	return t.value;
3024 }
3025 
3026 
3027 
3028 /**
3029  * Create a key specification generator instance for AES keys
3030  *
3031  * @class Class implementing an encoder for the C-Data required in Generate Symmetric Key
3032  * @param {ByteString} allowedAlgorithms the list of allowed algorithm identifier
3033  */
3034 function SmartCardHSMSymmetricKeySpecGenerator(allowedAlgorithms) {
3035 	this.algorithms = allowedAlgorithms;
3036 }
3037 
3038 exports.SmartCardHSMSymmetricKeySpecGenerator = SmartCardHSMSymmetricKeySpecGenerator;
3039 
3040 
3041 
3042 /**
3043  * Set key domain
3044  *
3045  * @param {Number} keyDomain the key domain to which the key shall be added
3046  */
3047 SmartCardHSMSymmetricKeySpecGenerator.prototype.setKeyDomain = function(keyDomain) {
3048 	this.keyDomain = keyDomain;
3049 }
3050 
3051 
3052 
3053 /**
3054  * Return the encoded AES key specification
3055  *
3056  * @type ByteString
3057  * @return the encoded C-Data for Generate Symmetric Key
3058  */
3059 SmartCardHSMSymmetricKeySpecGenerator.prototype.encode = function() {
3060 	var t = new ASN1(0x30);
3061 
3062 	t.add(new ASN1("Algorithms", 0x91, this.algorithms));
3063 
3064 	if (typeof(this.keyUseCounter) != "undefined") {
3065 		t.add(new ASN1("Key use counter", 0x90, ByteString.valueOf(this.keyUseCounter, 4)));
3066 	}
3067 
3068 	if (typeof(this.keyDomain) != "undefined") {
3069 		t.add(new ASN1("Key Domain", 0x92, ByteString.valueOf(this.keyDomain)));
3070 	}
3071 
3072 	if (typeof(this.wrappingKey) != "undefined") {
3073 		t.add(new ASN1("Wrapping Key", 0x93, this.wrappingKey));
3074 	}
3075 
3076 	return t.value;
3077 }
3078 
3079 
3080 
3081 SmartCardHSM.test = function() {
3082 	var crypto = new Crypto();
3083 	var card = new Card(_scsh3.reader);
3084 	var sc = new SmartCardHSM(card);
3085 
3086 	var sci = new SmartCardHSMInitializer(card);
3087 	sci.initialize();
3088 
3089 	var pubKey = sc.validateCertificateChain(crypto);
3090 	sc.openSecureChannel(crypto, pubKey);
3091 
3092 	sc.verifyUserPIN(sci.userPIN);
3093 
3094 	var kg = new SmartCardHSMKeySpecGenerator(Crypto.RSA, 1024);
3095 	sc.generateAsymmetricKeyPair(1, 0, kg.encode());
3096 
3097 	var dp = new Key();
3098 	dp.setComponent(Key.ECC_CURVE_OID, new ByteString("brainpoolP256r1", OID));
3099 
3100 	var kg = new SmartCardHSMKeySpecGenerator(Crypto.EC, dp);
3101 	sc.generateAsymmetricKeyPair(2, 0, kg.encode());
3102 
3103 	var list = sc.enumerateKeys();
3104 	GPSystem.trace("Keys on device: " + list);
3105 
3106 	var crypto = sc.getCrypto();
3107 	var message = new ByteString("Hello World", ASCII);
3108 
3109 	var key = sc.getKey(1);
3110 	var signature = crypto.sign(key, Crypto.RSA_SHA256, message);
3111 	GPSystem.trace("Signature: " + signature);
3112 
3113 	var key = sc.getKey(2);
3114 	var signature = crypto.sign(key, Crypto.ECDSA, message);
3115 	GPSystem.trace("Signature: " + signature);
3116 }
3117