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