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