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.trace("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.trace("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.trace("Device certificate DECA00001 disabled");
323 			return null;
324 		}
325 		if (!cvc.verifyWith(crypto, SmartCardHSM.devAutPuk)) {
326 			GPSystem.trace("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.trace("Device Issuer CA      : " + dica);
338 
339 	if (typeof(SmartCardHSM.rootCerts[dica.getCAR()]) == "undefined") {
340 		GPSystem.trace("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.trace("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.trace("DICA certificate not verified");
353 		return null;
354 	}
355 
356 	var dicapuk = dica.getPublicKey(srcapuk);
357 	if (!cvc.verifyWith(crypto, dicapuk, oid)) {
358 		GPSystem.trace("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.trace(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.trace("Encoded CA public key: " + enc);
566 	ca.performKeyAgreement(enc, nonce);
567 	var result = ca.verifyAuthenticationToken(authToken);
568 
569 	if (!result) {
570 		GPSystem.trace("Authentication token invalid");
571 		throw new Error("Authentication token invalid");
572 	}
573 	GPSystem.trace("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.trace(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.trace(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.trace(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.trace(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.trace(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.trace(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.trace("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.trace(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  * Decrypt a message using the defined mechanism and key
2504  *
2505  * @param {HSMKey} key the private 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.decrypt = function(key, mech, data, iv) {
2513 	if (key instanceof SmartCardHSMKey) {
2514 		return key.decrypt(mech, data);
2515 	} else {
2516 		return this.crypto.decrypt(key, mech, data, iv);
2517 	}
2518 }
2519 
2520 
2521 
2522 /**
2523  * Verify a message using the defined mechanism and key
2524  *
2525  * @param {Key} key the public key
2526  * @param {Number} mech the mechanism (e.g. Crypto.ECDSA)
2527  * @param {ByteString} message the message to be signed
2528  * @param {ByteString} signature the signature to verify
2529  * @type Boolean
2530  * @return true if signature is valid
2531  */
2532 SmartCardHSMCrypto.prototype.verify = function(key, mech, message, signature) {
2533 	return this.crypto.verify(key, mech, message, signature);
2534 }
2535 
2536 
2537 
2538 /**
2539  * Create a key access object
2540  *
2541  * @class Class implementing key access
2542  * @param {SmartCardHSM} sc the card access object
2543  * @param {Number} id the key identifier
2544  */
2545 function SmartCardHSMKey(sc, id) {
2546 	this.sc = sc;
2547 	this.id = id;
2548 	if (this.sc.useExternalHashInECDSA) {
2549 		this.crypto = new Crypto();
2550 	}
2551 }
2552 
2553 exports.SmartCardHSMKey = SmartCardHSMKey;
2554 
2555 
2556 /**
2557  * Set the PKCS#15 private key description
2558  *
2559  * @param {ASN1} desc the description
2560  */
2561 SmartCardHSMKey.prototype.setDescription = function(desc) {
2562 	this.desc = desc;
2563 }
2564 
2565 
2566 
2567 /**
2568  * Return the key identifier
2569  *
2570  * @type Number
2571  * @return the key identifier
2572  */
2573 SmartCardHSMKey.prototype.getId = function() {
2574 	return this.id;
2575 }
2576 
2577 
2578 
2579 /**
2580  * Return the key label as encoded in the PKCS#15 structure
2581  *
2582  * @type String
2583  * @return the key label
2584  */
2585 SmartCardHSMKey.prototype.getLabel = function() {
2586 	if (this.desc == undefined) {
2587 		return undefined;
2588 	}
2589 	if ((this.desc.get(0).elements == 0) || this.desc.get(0).get(0).tag != 0x0C) {
2590 		return undefined;
2591 	}
2592 
2593 	return this.desc.get(0).get(0).value.toString(UTF8);
2594 }
2595 
2596 
2597 
2598 /**
2599  * Return the key id as encoded in the PKCS#15 structure
2600  *
2601  * @type ByteString
2602  * @return the key identifier
2603  */
2604 SmartCardHSMKey.prototype.getPKCS15Id = function() {
2605 	if (this.desc == undefined) {
2606 		return undefined;
2607 	}
2608 	return this.desc.get(1).get(0).value;
2609 }
2610 
2611 
2612 
2613 /**
2614  * Return the key size in bits
2615  *
2616  * @type Number
2617  * @return the key size in bits
2618  */
2619 SmartCardHSMKey.prototype.getSize = function() {
2620 	if (this.desc == undefined) {
2621 		return undefined;
2622 	}
2623 //	GPSystem.trace(this.desc);
2624 	if (this.desc.get(2).elements > 1) {	// Fix a bug from early versions
2625 		return this.desc.get(2).get(1).value.toUnsigned();
2626 	}
2627 
2628 	if (this.desc.tag == 0xA8) {
2629 		var size = this.desc.get(2).get(0).get(0).value.toUnsigned();
2630 	} else {
2631 		var a1 = this.desc.find(0xA1);
2632 		var size = a1.get(0).get(1).value.toUnsigned();
2633 
2634 		if (size == 528) {
2635 			size = 521;		// Fix bug in OpenSCDP returning the wrong key size for secp521 keys
2636 		}
2637 	}
2638 
2639 	return size;
2640 }
2641 
2642 
2643 
2644 /**
2645  * Return the key type
2646  *
2647  * @type String
2648  * @return the key type
2649  */
2650 SmartCardHSMKey.prototype.getType = function() {
2651 	if (this.desc == undefined) {
2652 		return undefined;
2653 	}
2654 
2655 	if (this.desc.tag == 0xA0) {
2656 		return "EC";
2657 	} else if (this.desc.tag == 0x30) {
2658 		return "RSA";
2659 	} else if (this.desc.tag == 0xA8) {
2660 		return "AES";
2661 	}
2662 
2663 	return undefined;
2664 }
2665 
2666 
2667 
2668 /**
2669  * Sign data using a key in the SmartCard-HSM
2670  *
2671  * @param {Number} mech the signing mechanism
2672  * @param {ByteString} data to be signed
2673  * @type ByteString
2674  * @return the signature
2675  */
2676 SmartCardHSMKey.prototype.sign = function(mech, data) {
2677 	var algo;
2678 	if (mech) {
2679 		switch(mech) {
2680 		case Crypto.RSA:
2681 			algo = 0x20;
2682 			break;
2683 		case Crypto.RSA_SHA1:
2684 			algo = 0x31;
2685 			break;
2686 		case Crypto.RSA_SHA224:
2687 			algo = 0x32;
2688 			break;
2689 		case Crypto.RSA_SHA256:
2690 			algo = 0x33;
2691 			break;
2692 		case Crypto.RSA_SHA384:
2693 			algo = 0x34;
2694 			break;
2695 		case Crypto.RSA_SHA512:
2696 			algo = 0x35;
2697 			break;
2698 		case Crypto.RSA_PKCS1:
2699 			if (this.sc.major && this.sc.major >= 4) {
2700 				algo = 0x30;
2701 			} else {
2702 				algo = 0x20;
2703 				var keysize = this.getSize();
2704 				if (!keysize) {
2705 					throw new GPError(module.id, GPError.INVALID_DATA, 0, "Can't determine key size");
2706 				}
2707 				data = PKCS1.encode_EMSA_V15(keysize, data);
2708 			}
2709 			break;
2710 		case Crypto.RSA_PSS:
2711 		case 0x80:
2712 			algo = 0x40;
2713 			break;
2714 		case Crypto.RSA_PSS_SHA1:
2715 			algo = 0x41;
2716 			break;
2717 		case Crypto.RSA_PSS_SHA224:
2718 			algo = 0x42;
2719 			break;
2720 		case Crypto.RSA_PSS_SHA256:
2721 			algo = 0x43;
2722 			break;
2723 		case Crypto.RSA_PSS_SHA384:
2724 			algo = 0x44;
2725 			break;
2726 		case Crypto.RSA_PSS_SHA512:
2727 			algo = 0x45;
2728 			break;
2729 		case Crypto.ECDSA:
2730 			algo = 0x70;
2731 			break;
2732 		case Crypto.ECDSA_SHA1:
2733 			if (this.sc.useExternalHashInECDSA) {
2734 				algo = 0x70;
2735 				var data = this.crypto.digest(Crypto.SHA_1, data);
2736 			} else {
2737 				algo = 0x71;
2738 			}
2739 			break;
2740 		case Crypto.ECDSA_SHA224:
2741 			if (this.sc.useExternalHashInECDSA) {
2742 				algo = 0x70;
2743 				var data = this.crypto.digest(Crypto.SHA_224, data);
2744 			} else {
2745 				algo = 0x72;
2746 			}
2747 			break;
2748 		case Crypto.ECDSA_SHA256:
2749 			if (this.sc.useExternalHashInECDSA) {
2750 				algo = 0x70;
2751 				var data = this.crypto.digest(Crypto.SHA_256, data);
2752 			} else {
2753 				algo = 0x73;
2754 			}
2755 			break;
2756 		case Crypto.ECDSA_SHA384:
2757 			if (this.sc.useExternalHashInECDSA) {
2758 				algo = 0x70;
2759 				var data = this.crypto.digest(Crypto.SHA_384, data);
2760 			} else {
2761 				algo = 0x74;
2762 			}
2763 			break;
2764 		case Crypto.ECDSA_SHA512:
2765 			if (this.sc.useExternalHashInECDSA) {
2766 				algo = 0x70;
2767 				var data = this.crypto.digest(Crypto.SHA_512, data);
2768 			} else {
2769 				algo = 0x75;
2770 			}
2771 			break;
2772 		case Crypto.AES_CMAC:
2773 			return this.sc.deriveSymmetricKey(this.id, SmartCardHSM.ALG_CMAC, data);
2774 		default:
2775 			throw new GPError("SmartCardHSMKey", GPError.INVALID_DATA, mech, "Unsupported crypto mechanism");
2776 		}
2777 	}
2778 
2779 	return this.sc.sign(this.id, algo, data);
2780 }
2781 
2782 
2783 
2784 /**
2785  * Decrypt data using a key in the SmartCard-HSM
2786  *
2787  * @param {Number} mech the decipher mechanism
2788  * @param {ByteString} data to be deciphered
2789  * @type ByteString
2790  * @return the plain message
2791  */
2792 SmartCardHSMKey.prototype.decrypt = function(mech, data) {
2793 	var algo;
2794 	if (mech) {
2795 		switch(mech) {
2796 		case Crypto.RSA:
2797 			break;
2798 		case Crypto.RSA_PKCS1:
2799 			break;
2800 		case Crypto.RSA_OAEP_SHA224:
2801 			algo = Crypto.SHA_224;
2802 			break;
2803 		case Crypto.RSA_OAEP_SHA256:
2804 			algo = Crypto.SHA_256;
2805 			break;
2806 		case Crypto.RSA_OAEP_SHA384:
2807 			algo = Crypto.SHA_384;
2808 			break;
2809 		case Crypto.RSA_OAEP_SHA512:
2810 			algo = Crypto.SHA_512;
2811 			break;
2812 		default:
2813 			throw new GPError("SmartCardHSMKey", GPError.INVALID_DATA, mech, "Unsupported crypto mechanism");
2814 		}
2815 	}
2816 
2817 	var em = this.sc.decipher(this.id, 0x21, data);
2818 
2819 	var plain = em;
2820 
2821 	if (mech != Crypto.RSA) {
2822 		if (mech == Crypto.RSA_PKCS1) {
2823 			var plain = PKCS1.decode_EME_V15(em);
2824 		} else {
2825 			var crypto = this.sc.getCrypto().crypto;
2826 
2827 			var plain = PKCS1.decode_EME_OAEP(crypto, null, algo, em);
2828 		}
2829 
2830 		if (!plain) {
2831 			throw new GPError("SmartCardHSMKey", GPError.CRYPTO_FAILED, mech, "Decryption failed");
2832 		}
2833 	}
2834 
2835 	return plain;
2836 }
2837 
2838 
2839 
2840 /**
2841  * Return human readable string
2842  */
2843 SmartCardHSMKey.prototype.toString = function() {
2844 	return "SmartCardHSMKey(id=" + this.id + ")";
2845 }
2846 
2847 
2848 
2849 /**
2850  * Initialize SmartCard-HSM
2851  *
2852  * @class Class implementing the device initialization methods
2853  * @param {Card} card the card object
2854  */
2855 function SmartCardHSMInitializer(card) {
2856 	this.card = card;
2857 	this.initializationCode = new ByteString("57621880", ASCII);
2858 	this.userPIN = new ByteString("648219", ASCII);
2859 	this.userPINSet = false;
2860 	this.useDefaultUserPIN = true;
2861 	this.retryCounterInitial = 3;
2862 	this.options = 0x0001;
2863 	this.keyshares = -1;
2864 	this.keyDomains = -1;
2865 	this.numberOfPublicKeys = 0;
2866 	this.requiredPublicKeysForAuthentication = 0;
2867 	this.bioslot = [];
2868 	this.label = undefined;
2869 }
2870 
2871 exports.SmartCardHSMInitializer = SmartCardHSMInitializer;
2872 
2873 
2874 
2875 /**
2876  * Set the initialization code
2877  *
2878  * @param {ByteString} initializationCode an 8 byte code
2879  */
2880 SmartCardHSMInitializer.prototype.setInitializationCode = function(initializationCode) {
2881 	if (!(initializationCode instanceof ByteString)) {
2882 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "initializationCode must be a ByteString");
2883 	}
2884 	if (initializationCode.length != 8) {
2885 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "initializationCode must have 8 bytes");
2886 	}
2887 
2888 	this.initializationCode = initializationCode;
2889 }
2890 
2891 
2892 
2893 /**
2894  * Set the User PIN
2895  *
2896  * @param {ByteString} userPIN a 6 to 16 byte code
2897  */
2898 SmartCardHSMInitializer.prototype.setUserPIN = function(userPIN) {
2899 	if (!(userPIN instanceof ByteString)) {
2900 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "userPIN must be a ByteString");
2901 	}
2902 	if ((userPIN.length < 6) || (userPIN.length > 16)) {
2903 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "userPIN must be between 6 and 16 bytes");
2904 	}
2905 
2906 	this.userPIN = userPIN;
2907 	this.userPINSet = true;
2908 	this.useDefaultUserPIN = false;
2909 }
2910 
2911 
2912 
2913 /**
2914  * Set the retry counter
2915  *
2916  * The SmartCard-HSM enforces a retry counter <= 3 for PIN length 6
2917  * The SmartCard-HSM enforces a retry counter <= 5 for PIN length 7
2918  * The SmartCard-HSM enforces a retry counter <= 10 for PIN length larger than 7
2919  *
2920  * @param {Number} retryCounterInitial in the range 1 to 10.
2921  */
2922 SmartCardHSMInitializer.prototype.setRetryCounterInitial = function(retryCounterInitial) {
2923 	if (typeof(retryCounterInitial) != "number") {
2924 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "retryCounterInitial must be a number");
2925 	}
2926 	if ((retryCounterInitial < 1) || (retryCounterInitial > 10)) {
2927 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "retryCounterInitial must be between 1 and 10");
2928 	}
2929 	this.retryCounterInitial = retryCounterInitial;
2930 }
2931 
2932 
2933 
2934 /**
2935  * Set the number of DKEK shares
2936  *
2937  * @param {Number} keyshares number of DKEK shares in the range 0 to 255
2938  */
2939 SmartCardHSMInitializer.prototype.setDKEKShares = function(keyshares) {
2940 	if (typeof(keyshares) != "number") {
2941 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyshares must be a number");
2942 	}
2943 	if ((keyshares < 0) || (keyshares > 255)) {
2944 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyshares must be between 0 and 255");
2945 	}
2946 	this.keyshares = keyshares;
2947 	this.keyDomains = -1;
2948 }
2949 
2950 
2951 
2952 /**
2953  * Set the number of key domains
2954  *
2955  * @param {Number} keyDomains number of key domains
2956  */
2957 SmartCardHSMInitializer.prototype.setKeyDomains = function(keyDomains) {
2958 	if (typeof(keyDomains) != "number") {
2959 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyDomains must be a number");
2960 	}
2961 
2962 	this.keyDomains = keyDomains;
2963 	this.keyshares = -1;
2964 }
2965 
2966 
2967 
2968 /**
2969  * Enable or disable RESET RETRY COUNTER command
2970  *
2971  * @param {Boolean} enable true (default) to allow RESET RETRY COUNTER command to reset user PIN using the initialization code
2972  */
2973 SmartCardHSMInitializer.prototype.setResetRetryCounterMode = function(enable) {
2974 	if (typeof(enable) == "undefined") {
2975 		var enable = false;
2976 	}
2977 
2978 	this.options = (this.options & 0xFFFE) + (enable ? 1 : 0);
2979 }
2980 
2981 
2982 
2983 /**
2984  * Enable or disable transport PIN mode
2985  *
2986  * @param {Boolean} enable true (non-default) to set user PIN to transport state
2987  */
2988 SmartCardHSMInitializer.prototype.setTransportPINMode = function(enable) {
2989 	if (typeof(enable) == "undefined") {
2990 		var enable = true;
2991 	}
2992 
2993 	this.options = (this.options & 0xFFFD) + (enable ? 2 : 0);
2994 }
2995 
2996 
2997 
2998 /**
2999  * Enable or disable session PIN mode
3000  *
3001  * @param {Number} 0 - disable, 1 - enable with clear-on-reset 3 - enable with explicit clearing
3002  */
3003 SmartCardHSMInitializer.prototype.setSessionPINMode = function(mode) {
3004 	assert(typeof(mode) == "number", "Argument mode must be number");
3005 	assert(mode >= 0 && mode <= 3 && mode != 2, "Argument mode must be 0, 1 or 3");
3006 
3007 	this.options = (this.options & 0xFFF3) + (mode << 2);
3008 }
3009 
3010 
3011 
3012 /**
3013  * Enable or disable replacing of a PKA key
3014  *
3015  * @param {Boolean} enable true (non-default) to allow replacing of a PKA key
3016  */
3017 SmartCardHSMInitializer.prototype.setReplacePKAKeyMode = function(enable) {
3018 	if (typeof(enable) == "undefined") {
3019 		var enable = false;
3020 	}
3021 
3022 	this.options = (this.options & 0xFFF7) + (enable ? 8 : 0);
3023 }
3024 
3025 
3026 
3027 /**
3028  * Enable the combined authentication mode of user pin and public key authentication.
3029  *
3030  * @param {Boolean} enable true (non-default) to require public key authentication and user authentication
3031  */
3032 SmartCardHSMInitializer.prototype.setCombinedAuthenticationMode = function(enable) {
3033 	if (typeof(enable) == "undefined") {
3034 		var enable = false;
3035 	}
3036 
3037 	this.options = (this.options & 0xFFEF) + (enable ? 16 : 0);
3038 }
3039 
3040 
3041 
3042 /**
3043  * If enabled RESET RETRY COUNTER only resets the error counter.
3044  * Otherwise  RRC allows changing the PIN
3045  *
3046  * @param {Boolean} resetOnly true to only reset the error counter, false otherwise (default)
3047  */
3048 SmartCardHSMInitializer.prototype.setResetRetryCounterResetOnlyMode = function(resetOnly) {
3049 	if (typeof(resetOnly) == "undefined") {
3050 		var resetOnly = false;
3051 	}
3052 
3053 	this.options = (this.options & 0xFFDF) + (resetOnly ? 32 : 0);
3054 }
3055 
3056 
3057 
3058 /**
3059  * Set parameter for public key authentication with n-of-m scheme, namely the values for n and m
3060  *
3061  * @param {Number} requiredPublicKeysForAuthentication number of key that must be authenticated for access
3062  * @param {Number} numberOfPublicKeys to register
3063  */
3064 SmartCardHSMInitializer.prototype.setPublicKeyAuthenticationParameter = function(requiredPublicKeysForAuthentication, numberOfPublicKeys) {
3065 	if ((numberOfPublicKeys < 1) || (numberOfPublicKeys > 90)) {
3066 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "numberOfPublicKeys must be between 1 and 90");
3067 	}
3068 	if ((requiredPublicKeysForAuthentication < 1) || (requiredPublicKeysForAuthentication > numberOfPublicKeys)) {
3069 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 2, "requiredPublicKeysForAuthentication must be between 1 and " + numberOfPublicKeys);
3070 	}
3071 	this.numberOfPublicKeys = numberOfPublicKeys;
3072 	this.requiredPublicKeysForAuthentication = requiredPublicKeysForAuthentication;
3073 	this.useDefaultUserPIN = false;
3074 }
3075 
3076 
3077 
3078 /**
3079  * Select the biometric matching server for a one of the biometric templates
3080  *
3081  * @param {Number} slot either 0 or 1 for first or second template
3082  * @param {ByteString} aid the application identifier of the on-card biometric server
3083  * @param {Number} param one byte parameter passed to the server during initialization
3084  */
3085 SmartCardHSMInitializer.prototype.setBioTemplate = function(slot, aid, param) {
3086 	assert(typeof(slot) == "number", "slot must be a number");
3087 	assert(slot >= 0 && slot <= 1, "slot must be either 0 or 1");
3088 	assert(aid instanceof ByteString, "aid must be a ByteString");
3089 	assert(typeof(param) == "number", "param must be a number");
3090 	assert(param >= 0 && param <= 255, "param must be between 0 and 255");
3091 
3092 	this.bioslot[slot] = { aid: aid, param: param };
3093 	this.useDefaultUserPIN = false;
3094 }
3095 
3096 
3097 
3098 /**
3099  * Set the label to be written to a minimal CIAInfo in EF 2F03
3100  *
3101  * @param {String} label the label
3102  */
3103 SmartCardHSMInitializer.prototype.setLabel = function(label) {
3104 	this.label = label;
3105 }
3106 
3107 
3108 
3109 /**
3110  * Set the provisioning URL to be written to fixed parameter in CB00.
3111  *
3112  * @param {String} provisioningURL the URL at which this SE will be provisioned
3113  */
3114 SmartCardHSMInitializer.prototype.setProvisioningURL = function(provisioningURL) {
3115 	this.provisioningURL = provisioningURL;
3116 }
3117 
3118 
3119 
3120 /**
3121  * Set the key check value of the token management key and the optional salt
3122  * used for SO-PIN derivation
3123  *
3124  * @param {ByteString} kcv the key check value of the token management key
3125  * @param {ByteString} salt the salt used to derive the SO-PIN
3126  */
3127 SmartCardHSMInitializer.prototype.setTokenManagementKey = function(kcv, salt) {
3128 	this.tokenManagementKeyKCV = kcv;
3129 	this.tokenManagementKeySalt = salt;
3130 }
3131 
3132 
3133 
3134 /**
3135  * Perform Initialization
3136  */
3137 SmartCardHSMInitializer.prototype.initialize = function() {
3138 	var s = new ASN1(0x30,	new ASN1(0x80, ByteString.valueOf(this.options, 2)));
3139 
3140 	if (this.userPINSet || this.useDefaultUserPIN) {
3141 		s.add(new ASN1(0x81, this.userPIN));
3142 	}
3143 
3144 	s.add(new ASN1(0x82, this.initializationCode));
3145 
3146 	if (this.userPINSet || this.useDefaultUserPIN) {
3147 		s.add(new ASN1(0x91, ByteString.valueOf(this.retryCounterInitial)));
3148 	}
3149 
3150 	if (this.keyshares != -1) {
3151 		s.add(new ASN1(0x92, ByteString.valueOf(this.keyshares)));
3152 	}
3153 
3154 	if (this.keyDomains != -1) {
3155 		s.add(new ASN1(0x97, ByteString.valueOf(this.keyDomains)));
3156 	}
3157 
3158 	if (this.numberOfPublicKeys > 0) {
3159 		s.add(new ASN1(0x93, ByteString.valueOf(this.numberOfPublicKeys).concat(ByteString.valueOf(this.requiredPublicKeysForAuthentication))));
3160 	}
3161 
3162 	if (this.bioslot[0]) {
3163 		var o = this.bioslot[0];
3164 		s.add(new ASN1(0x95, ByteString.valueOf(o.param).concat(o.aid)));
3165 	}
3166 
3167 	if (this.bioslot[1]) {
3168 		var o = this.bioslot[1];
3169 		s.add(new ASN1(0x96, ByteString.valueOf(o.param).concat(o.aid)));
3170 	}
3171 
3172 	this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000, 0x6A84]);
3173 
3174 	if (this.card.SW == 0x6A84) {
3175 		// Due to the nature of the JCRE, a first call to initialize may run out of memory,
3176 		// as the garbage collector for the removed objects is only run during the next
3177 		// APDU invocation.
3178 		this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000]);
3179 	}
3180 
3181 	if (this.label) {
3182 		var a = new ASN1(0x30,
3183 				new ASN1(0x54, new ByteString("0000", HEX)),
3184 				new ASN1(0x53,
3185 					new ASN1(0x30,
3186 						new ASN1(0x02, new ByteString("00", HEX)),
3187 						new ASN1(0x80, new ByteString(this.label, UTF8)),
3188 						new ASN1(0x03, new ByteString("0500", HEX)))
3189 				)
3190 			);
3191 
3192 		var p1 = SmartCardHSM.EF_TokenInfo.byteAt(0);
3193 		var p2 = SmartCardHSM.EF_TokenInfo.byteAt(1);
3194 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, p1, p2, a.value, [0x9000]);
3195 	}
3196 
3197 	if (this.provisioningURL || this.tokenManagementKeyKCV || this.tokenManagementKeySalt) {
3198 		var l = new ASN1(ASN1.SEQUENCE);
3199 		if (this.provisioningURL) {
3200 			l.add(new ASN1(0x80, new ByteString(this.provisioningURL, UTF8)));
3201 		}
3202 		if (this.tokenManagementKeyKCV) {
3203 			l.add(new ASN1(0x81, this.tokenManagementKeyKCV));
3204 		}
3205 		if (this.tokenManagementKeySalt) {
3206 			l.add(new ASN1(0x82, this.tokenManagementKeySalt));
3207 		}
3208 
3209 		var a = new ASN1(0x30,
3210 				new ASN1(0x54, new ByteString("0000", HEX)),
3211 				new ASN1(0x53, l)
3212 			);
3213 
3214 		var p1 = SmartCardHSM.EF_StaticTokenInfo.byteAt(0);
3215 		var p2 = SmartCardHSM.EF_StaticTokenInfo.byteAt(1);
3216 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, p1, p2, a.value, [0x9000]);
3217 	}
3218 }
3219 
3220 
3221 
3222 /**
3223  * Create a key specification generator instance
3224  *
3225  * @class Class implementing an encoder for the C-Data required in GENERATE ASYMMETRIC KEY PAIR
3226  * @param {Number} keytype must be either Crypto.RSA, Crypto.EC or Crypto.AES
3227  * @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
3228  */
3229 function SmartCardHSMKeySpecGenerator(keytype, keysizeOrDP) {
3230 	this.keytype = keytype;
3231 
3232 	switch(keytype) {
3233 		case Crypto.RSA:
3234 			if (typeof(keysizeOrDP) != "number") {
3235 				throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be of a number for RSA keys");
3236 			}
3237 			this.keysize = keysizeOrDP;
3238 			this.defaultAlgo = new ByteString("id-TA-RSA-v1-5-SHA-256", OID);
3239 			break;
3240 		case Crypto.EC:
3241 			if ((typeof(keysizeOrDP) != "object") || !(keysizeOrDP instanceof Key)) {
3242 				throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be a Key instance");
3243 			}
3244 			this.domainParameter = keysizeOrDP;
3245 			this.defaultAlgo = new ByteString("id-TA-ECDSA-SHA-256", OID);
3246 			break;
3247 		case Crypto.AES:
3248 			if (typeof(keysizeOrDP) != "number") {
3249 				throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be of a number for AES keys");
3250 			}
3251 			this.keysize = keysizeOrDP;
3252 			break;
3253 		default:
3254 			throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keytype must be Crypto.RSA or Crypto.EC");
3255 	}
3256 	this.CHR = new PublicKeyReference("UTDUMMY00001");
3257 	this.innerCAR = new PublicKeyReference("UTDUMMY00001");
3258 }
3259 
3260 exports.SmartCardHSMKeySpecGenerator = SmartCardHSMKeySpecGenerator;
3261 
3262 
3263 
3264 /**
3265  * Set key use counter for key
3266  *
3267  * @param {keyUseCounter} keyUseCounter in the range 1 to 2^64 - 2
3268  */
3269 SmartCardHSMKeySpecGenerator.prototype.setKeyUseCounter = function(keyUseCounter) {
3270 	if ((keyUseCounter < 0) || (keyUseCounter >= 0xFFFFFFFF)) {
3271 		throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 1, "keyUseCounter must be between 0 and 0xFFFFFFFF");
3272 	}
3273 	this.keyUseCounter = keyUseCounter;
3274 }
3275 
3276 
3277 
3278 /**
3279  * Set key domain
3280  *
3281  * @param {Number} keyDomain the key domain to which the key shall be added
3282  */
3283 SmartCardHSMKeySpecGenerator.prototype.setKeyDomain = function(keyDomain) {
3284 	this.keyDomain = keyDomain;
3285 }
3286 
3287 
3288 
3289 /**
3290  * Set wrapping key
3291  *
3292  * @param {Number} wrappingKey the key to used for wrapping a newly generated symmetric key
3293  */
3294 SmartCardHSMKeySpecGenerator.prototype.setWrappingKey = function(wrappingKey) {
3295 	this.wrappingKey = wrappingKey;
3296 }
3297 
3298 
3299 
3300 /**
3301  * Set algorithm list
3302  *
3303  * @param {ByteString} algorithms the list of algorithms allowed for this key
3304  */
3305 SmartCardHSMKeySpecGenerator.prototype.setAlgorithms = function(algorithms) {
3306 	this.algorithms = algorithms;
3307 }
3308 
3309 
3310 
3311 /**
3312  * Set certificate holder reference for key
3313  *
3314  * @param {PublicKeyReference} CHR certificate holder reference
3315  */
3316 SmartCardHSMKeySpecGenerator.prototype.setCHR = function(CHR) {
3317 	this.CHR = CHR;
3318 }
3319 
3320 
3321 
3322 /**
3323  * Set certificate holder reference of CA this request shall be sent to
3324  *
3325  * @param {PublicKeyReference} CAR certificate holder reference
3326  */
3327 SmartCardHSMKeySpecGenerator.prototype.setInnerCAR = function(CAR) {
3328 	this.innerCAR = CAR;
3329 }
3330 
3331 
3332 
3333 /**
3334  * Set holder reference of the key signing this request
3335  *
3336  * @param {PublicKeyReference} CAR certificate holder reference
3337  */
3338 SmartCardHSMKeySpecGenerator.prototype.setOuterCAR = function(CAR) {
3339 	this.outerCAR = CAR;
3340 }
3341 
3342 
3343 
3344 /**
3345  * @private
3346  */
3347 SmartCardHSMKeySpecGenerator.prototype.encodeRSAKeySpec = function() {
3348 	var p = new ASN1("Public Key", 0x7F49,
3349 			new ASN1("Object Identifier", 0x06, this.defaultAlgo),
3350 			new ASN1("Public Key Exponent", 0x82, ByteString.valueOf(65537)),
3351 			new ASN1("Key Size", 0x02, ByteString.valueOf(this.keysize))
3352 		);
3353 	return p;
3354 }
3355 
3356 
3357 
3358 /**
3359  * @private
3360  */
3361 SmartCardHSMKeySpecGenerator.prototype.encodeECKeySpec = function() {
3362 	// Encode G
3363 	var bb = new ByteBuffer();
3364 	// uncompressed encoding
3365 	bb.append(new ByteString("04", HEX));
3366 	bb.append(this.domainParameter.getComponent(Key.ECC_GX));
3367 	bb.append(this.domainParameter.getComponent(Key.ECC_GY));
3368 	var G = bb.toByteString();
3369 
3370 	var p = new ASN1("Public Key", 0x7F49,
3371 			new ASN1("Object Identifier", 0x06, this.defaultAlgo),
3372 			new ASN1("Prime Modulus", 0x81, this.domainParameter.getComponent(Key.ECC_P)),
3373 			new ASN1("First coefficient a", 0x82, this.domainParameter.getComponent(Key.ECC_A)),
3374 			new ASN1("Second coefficient b", 0x83, this.domainParameter.getComponent(Key.ECC_B)),
3375 			new ASN1("Base Point G", 0x84, G),
3376 			new ASN1("Order of the base point", 0x85, this.domainParameter.getComponent(Key.ECC_N)),
3377 			new ASN1("Cofactor f", 0x87, SmartCardHSM.stripLeadingZeros(this.domainParameter.getComponent(Key.ECC_H)))
3378 		);
3379 	return p;
3380 }
3381 
3382 
3383 
3384 /**
3385  * @private
3386  */
3387 SmartCardHSMKeySpecGenerator.prototype.encodeKeySpec = function() {
3388 	if (this.keytype == Crypto.RSA) {
3389 		return this.encodeRSAKeySpec();
3390 	} else {
3391 		return this.encodeECKeySpec();
3392 	}
3393 }
3394 
3395 
3396 
3397 /**
3398  * Return the encoded key specification
3399  *
3400  * @type ByteString
3401  * @return the encoded C-Data for GENERATE ASYMMETRIC KEY PAIR
3402  */
3403 SmartCardHSMKeySpecGenerator.prototype.encode = function() {
3404 	var t = new ASN1(0x30);
3405 
3406 	if (this.keytype != Crypto.AES) {
3407 		t.add(new ASN1("CPI", 0x5F29, new ByteString("00", HEX)));
3408 
3409 		if ((typeof(this.innerCAR) != "undefined") && (this.innerCAR)) {
3410 			t.add(new ASN1("CAR", 0x42, this.innerCAR.getBytes()));
3411 		}
3412 
3413 		t.add(this.encodeKeySpec());
3414 		t.add(new ASN1("CHR", 0x5F20, this.CHR.getBytes()));
3415 
3416 		if (typeof(this.outerCAR) != "undefined") {
3417 			t.add(new ASN1("OuterCAR", 0x45, this.outerCAR.getBytes()));
3418 		}
3419 	}
3420 
3421 	if (typeof(this.keyUseCounter) != "undefined") {
3422 		t.add(new ASN1("Key use counter", 0x90, ByteString.valueOf(this.keyUseCounter, 4)));
3423 	}
3424 
3425 	if (typeof(this.algorithms) != "undefined") {
3426 		t.add(new ASN1("Algorithms", 0x91, this.algorithms));
3427 	}
3428 
3429 	if (typeof(this.keyDomain) != "undefined") {
3430 		t.add(new ASN1("KeyDomain", 0x92, ByteString.valueOf(this.keyDomain)));
3431 	}
3432 
3433 	if (typeof(this.wrappingKey) != "undefined") {
3434 		t.add(new ASN1("Wrapping Key", 0x93, ByteString.valueOf(this.wrappingKey)));
3435 	}
3436 
3437 	return t.value;
3438 }
3439 
3440 
3441 
3442 /**
3443  * Create a key specification generator instance for AES keys
3444  *
3445  * @class Class implementing an encoder for the C-Data required in Generate Symmetric Key
3446  * @param {ByteString} allowedAlgorithms the list of allowed algorithm identifier
3447  */
3448 function SmartCardHSMSymmetricKeySpecGenerator(allowedAlgorithms) {
3449 	this.algorithms = allowedAlgorithms;
3450 }
3451 
3452 exports.SmartCardHSMSymmetricKeySpecGenerator = SmartCardHSMSymmetricKeySpecGenerator;
3453 
3454 
3455 
3456 /**
3457  * Set key domain
3458  *
3459  * @param {Number} keyDomain the key domain to which the key shall be added
3460  */
3461 SmartCardHSMSymmetricKeySpecGenerator.prototype.setKeyDomain = function(keyDomain) {
3462 	this.keyDomain = keyDomain;
3463 }
3464 
3465 
3466 
3467 /**
3468  * Return the encoded AES key specification
3469  *
3470  * @type ByteString
3471  * @return the encoded C-Data for Generate Symmetric Key
3472  */
3473 SmartCardHSMSymmetricKeySpecGenerator.prototype.encode = function() {
3474 	var t = new ASN1(0x30);
3475 
3476 	t.add(new ASN1("Algorithms", 0x91, this.algorithms));
3477 
3478 	if (typeof(this.keyUseCounter) != "undefined") {
3479 		t.add(new ASN1("Key use counter", 0x90, ByteString.valueOf(this.keyUseCounter, 4)));
3480 	}
3481 
3482 	if (typeof(this.keyDomain) != "undefined") {
3483 		t.add(new ASN1("Key Domain", 0x92, ByteString.valueOf(this.keyDomain)));
3484 	}
3485 
3486 	if (typeof(this.wrappingKey) != "undefined") {
3487 		t.add(new ASN1("Wrapping Key", 0x93, this.wrappingKey));
3488 	}
3489 
3490 	return t.value;
3491 }
3492 
3493 
3494 
3495 SmartCardHSM.test = function() {
3496 	var crypto = new Crypto();
3497 	var card = new Card(_scsh3.reader);
3498 	var sc = new SmartCardHSM(card);
3499 
3500 	var sci = new SmartCardHSMInitializer(card);
3501 	sci.initialize();
3502 
3503 	var pubKey = sc.validateCertificateChain(crypto);
3504 	sc.openSecureChannel(crypto, pubKey);
3505 
3506 	sc.verifyUserPIN(sci.userPIN);
3507 
3508 	var kg = new SmartCardHSMKeySpecGenerator(Crypto.RSA, 1024);
3509 	sc.generateAsymmetricKeyPair(1, 0, kg.encode());
3510 
3511 	var dp = new Key();
3512 	dp.setComponent(Key.ECC_CURVE_OID, new ByteString("brainpoolP256r1", OID));
3513 
3514 	var kg = new SmartCardHSMKeySpecGenerator(Crypto.EC, dp);
3515 	sc.generateAsymmetricKeyPair(2, 0, kg.encode());
3516 
3517 	var list = sc.enumerateKeys();
3518 	GPSystem.trace("Keys on device: " + list);
3519 
3520 	var crypto = sc.getCrypto();
3521 	var message = new ByteString("Hello World", ASCII);
3522 
3523 	var key = sc.getKey(1);
3524 	var signature = crypto.sign(key, Crypto.RSA_SHA256, message);
3525 	GPSystem.trace("Signature: " + signature);
3526 
3527 	var key = sc.getKey(2);
3528 	var signature = crypto.sign(key, Crypto.ECDSA, message);
3529 	GPSystem.trace("Signature: " + signature);
3530 }
3531