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