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