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