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