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