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