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 	if (typeof(this.caids) == "undefined") {
1840 		this.enumerateCACertificates();
1841 	}
1842 
1843 	if (this.caids.length == 0) {
1844 		return 0;
1845 	}
1846 
1847 	var id = Math.max.apply(null, this.caids) + 1;
1848 	if (id > 256) {
1849 		return -1;
1850 	}
1851 	return id;
1852 }
1853 
1854 
1855 
1856 /**
1857  * Add a new CA certificate to the map
1858  *
1859  * @param {X509} cert the CA certificate
1860  * @param {Number} id the corresponding id
1861  * @param {String} label the corresponding label
1862  */
1863 SmartCardHSM.prototype.addCACertificateToMap = function(cert, id, label) {
1864 	if (!this.caidmap[label]) {
1865 		// new id
1866 		this.caids.push(id);
1867 		this.caidmap[label] = id;
1868 	}
1869 	this.canamemap[label] = cert;
1870 }
1871 
1872 
1873 
1874 /**
1875  * Enumerate key objects in the SmartCard-HSM and build the map of keys
1876  *
1877  * @type String[]
1878  * @return the list of key labels
1879  */
1880 SmartCardHSM.prototype.enumerateKeys = function() {
1881 	this.namemap = [];
1882 	this.idmap = [];
1883 	this.idlist = [];
1884 	this.p15idmap = [];
1885 
1886 	var fobs = this.enumerateObjects();
1887 
1888 	// Process keys
1889 	for (var i = 0; i < fobs.length; i += 2) {
1890 		if ((fobs.byteAt(i) == SmartCardHSM.KEYPREFIX) || (fobs.byteAt(i) == 0xFF)) {
1891 			var kid = fobs.byteAt(i + 1);
1892 			if (kid > 0) {
1893 //				GPSystem.trace("Found key: " + kid);
1894 				var key = new SmartCardHSMKey(this, kid);
1895 				this.idmap[kid] = key;
1896 				this.idlist.push(kid);
1897 				this.updateKey(key);
1898 			}
1899 		}
1900 	}
1901 
1902 	var keylist = [];
1903 	// Process PKCS#15 private key descriptions
1904 	for (var i = 0; i < fobs.length; i += 2) {
1905 		if (fobs.byteAt(i) == SmartCardHSM.PRKDPREFIX) {
1906 			var kid = fobs.byteAt(i + 1);
1907 			var descbin = this.readBinary(fobs.bytes(i, 2));
1908 			if (descbin.length > 2) {
1909 				try {
1910 					var desc = new ASN1(descbin);
1911 					if (desc.elements < 3) {
1912 						continue;
1913 					}
1914 				}
1915 				catch(e) {
1916 					continue;
1917 				}
1918 				var key = this.idmap[kid];
1919 				if (key) {
1920 					key.setDescription(desc);
1921 					var label = key.getLabel();
1922 //					GPSystem.trace(key.getId() + " - " + label);
1923 					if (label) {
1924 						keylist.push(label);
1925 						this.namemap[label] = key;
1926 					}
1927 					var p15id = key.getPKCS15Id();
1928 					this.p15idmap[p15id.toString(HEX)] = key;
1929 				}
1930 			}
1931 		}
1932 	}
1933 
1934 	return keylist;
1935 }
1936 
1937 
1938 
1939 /**
1940  * Get key ids
1941  *
1942  * @type Number[]
1943  * @return a list of key identifier
1944  */
1945 SmartCardHSM.prototype.getKeyIds = function() {
1946 	if (typeof(this.idlist) == "undefined") {
1947 		this.enumerateKeys();
1948 	}
1949 	return this.idlist;
1950 }
1951 
1952 
1953 
1954 /**
1955  * Determine an unused key identifier
1956  *
1957  * @type Number
1958  * @return a free key identifier or -1 if all key identifier in use
1959  */
1960 SmartCardHSM.prototype.determineFreeKeyId = function() {
1961 	if (typeof(this.idlist) == "undefined") {
1962 		this.enumerateKeys();
1963 	}
1964 	for (var i = 1; i < 256; i++) {
1965 		if (this.idmap[i] == undefined) {
1966 			return i;
1967 		}
1968 	}
1969 	throw new GPError("SmartCardHSM", GPError.OUT_OF_MEMORY, 1, "Key idx exhausted");
1970 }
1971 
1972 
1973 
1974 /**
1975  * Update key attributes, in particular the use counter
1976  *
1977  * @param {HSMKey} key the HSM key
1978  */
1979 SmartCardHSM.prototype.updateKey = function(key) {
1980 	var fid = ByteString.valueOf((SmartCardHSM.KEYPREFIX << 8) + key.getId());
1981 	try	{
1982 		var fcp = this.selectFile(fid);
1983 	}
1984 	catch(e) {
1985 		return;
1986 	}
1987 	var a = new ASN1(fcp);
1988 	var pi = a.find(0xA5);
1989 	if (!pi) {
1990 		return;
1991 	}
1992 	var kc = pi.find(0x90);
1993 	if (kc) {
1994 		var c = kc.value.toUnsigned();
1995 
1996 		if (c != 0xFFFFFFFF) {
1997 			key.useCounter = c;
1998 		}
1999 	}
2000 
2001 	var kd = pi.find(0x91);
2002 	if (kd) {
2003 		key.algorithms = kd.value;
2004 	}
2005 
2006 	var kd = pi.find(0x92);
2007 	if (kd) {
2008 		key.keyDomain = kd.value.toUnsigned();
2009 	}
2010 }
2011 
2012 
2013 
2014 /**
2015  * Add a new key to the map of keys
2016  *
2017  * @param {HSMKey} key the HSM key
2018  */
2019 SmartCardHSM.prototype.addKeyToMap = function(key) {
2020 	var id = key.getId();
2021 	this.idmap[id] = key;
2022 
2023 	var label = key.getLabel();
2024 	if (label) {
2025 		this.namemap[label] = key;
2026 	}
2027 
2028 	var p15id = key.getPKCS15Id();
2029 	if (p15id) {
2030 		this.p15idmap[p15id.toString(HEX)] = key;
2031 	}
2032 }
2033 
2034 
2035 
2036 /**
2037  * Get a key reference object
2038  *
2039  * @param {String/Number/ByteString} labelOrId label or id of key
2040  * @returns the key or null if not found
2041  * @type Key
2042  */
2043 SmartCardHSM.prototype.getKey = function(labelOrId) {
2044 	if (typeof(this.idlist) == "undefined") {
2045 		this.enumerateKeys();
2046 	}
2047 
2048 	if (typeof(labelOrId) == "number") {
2049 		var key = this.idmap[labelOrId];
2050 	} else if (typeof(labelOrId) == "string") {
2051 		var key = this.namemap[labelOrId];
2052 	} else {
2053 		var key = this.p15idmap[labelOrId.toString(HEX)];
2054 	}
2055 
2056 	if (key == undefined) {
2057 		return null;
2058 	}
2059 	return key;
2060 }
2061 
2062 
2063 
2064 /**
2065  * Return a list of key objects
2066  *
2067  * @type SmartCardHSMKey[]
2068  * @return the list of keys
2069  */
2070 SmartCardHSM.prototype.getKeys = function() {
2071 	if (typeof(this.idlist) == "undefined") {
2072 		this.enumerateKeys();
2073 	}
2074 
2075 	var keylist = [];
2076 	for (var i in this.idmap) {
2077 		keylist.push(this.idmap[i]);
2078 	}
2079 	return keylist;
2080 }
2081 
2082 
2083 
2084 /**
2085  * Determine a free id in the list of FID for the given prefix.
2086  *
2087  * @param {Number} the prefix to look at
2088  * @param {ByteString} the list of FID as returned from the device
2089  * @type Number
2090  * @return a free id for the given prefix or -1 if range is exhausted.
2091  */
2092 SmartCardHSM.determineFreeId = function(prefix, fobs) {
2093 	var map = new Bitmap(256);
2094 
2095 	for (var i = 0; i < fobs.length; i+= 2) {
2096 		if (fobs.byteAt(i) == prefix) {
2097 			map.toggle(fobs.byteAt(i + 1));
2098 		}
2099 	}
2100 
2101 	return map.determineFirstUnset();
2102 }
2103 
2104 
2105 
2106 /**
2107  * Determine a free FID in the list of FID for the given prefix.
2108  *
2109  * @param {Number} the prefix to look at
2110  * @param {ByteString} the list of FID as returned from the device
2111  * @type ByteString
2112  * @return a free two byte file identifier (FID) for the given prefix or null if range is exhausted.
2113  */
2114 SmartCardHSM.determineFreeFid = function(prefix, fobs) {
2115 	var id = SmartCardHSM.determineFreeId(prefix, fobs);
2116 	if (id < 0) {
2117 		return null;
2118 	}
2119 	return ByteString.valueOf((prefix << 8) + id);
2120 }
2121 
2122 
2123 
2124 /**
2125  * Enumerate Data Objects
2126  *
2127  * @type String[]
2128  * @return the list of data object labels
2129  */
2130 SmartCardHSM.prototype.enumerateDataObjects = function() {
2131 	this.donamemap = [];
2132 	var dolist = [];
2133 
2134 	var fobs = this.enumerateObjects();
2135 
2136 	// Process PKCS#15 data object descriptions
2137 	for (var i = 0; i < fobs.length; i+= 2) {
2138 		if (fobs.byteAt(i) == SmartCardHSM.DODPREFIX) {
2139 			var descfid = fobs.bytes(i, 2);
2140 			var descbin = this.readBinary(descfid);
2141 			var asn = new ASN1(descbin);
2142 //			print(asn);
2143 			var coa = asn.get(0);
2144 			if (coa.elements > 0) {
2145 				var label = coa.get(0).value.toString(ASCII);
2146 			} else {
2147 				var label = "No label (" + i + ")";
2148 			}
2149 			var taga1 = asn.find(0xA1);
2150 			if (taga1) {
2151 				var datafid = taga1.get(0).get(0).value;
2152 				this.donamemap[label] = { datafid: datafid, descfid: descfid };
2153 				dolist.push(label);
2154 			}
2155 		}
2156 	}
2157 
2158 	return dolist;
2159 }
2160 
2161 
2162 
2163 /**
2164  * Check if the data object is present
2165  *
2166  * @param {String} label the label
2167  * @type boolean
2168  * @return true if the data object exists
2169  */
2170 SmartCardHSM.prototype.hasDataObject = function(label) {
2171 	if (typeof(this.donamemap) == "undefined"){
2172 		this.enumerateDataObjects();
2173 	}
2174 	return (this.donamemap[label] != undefined);
2175 }
2176 
2177 
2178 
2179 /**
2180  * Return the file identifier containing the data object.
2181  *
2182  * @param {String} label the label.
2183  * @type ByteString
2184  * @return the two byte file identifier
2185  */
2186 SmartCardHSM.prototype.getDataObjectFileIdentifier = function(label) {
2187 	if (typeof(this.donamemap) == "undefined"){
2188 		this.enumerateDataObjects();
2189 	}
2190 	var e = this.donamemap[label];
2191 	if (e == undefined) {
2192 		throw new GPError(module.id, GPError.INVALID_DATA, 0, "Data object " + label + " not found");
2193 	}
2194 	return e.datafid;
2195 }
2196 
2197 
2198 
2199 /**
2200  * Import a data object
2201  *
2202  * @param {String} label the unique label to reference the new data object
2203  * @param {Boolean} privObj true to store the data object with read protection
2204  * @param {ByteString} data the data blob to store
2205  */
2206 SmartCardHSM.prototype.importDataObject = function(label, privObj, data) {
2207 	var fobs = this.enumerateObjects();
2208 
2209 	var e = this.donamemap[label];
2210 	if (e != undefined) {
2211 		throw new GPError(module.id, GPError.INVALID_DATA, 0, "Data object " + label + " does already exist");
2212 	}
2213 
2214 	if (privObj) {
2215 		var datafid = SmartCardHSM.determineFreeFid(SmartCardHSM.CONFIDENTIALDATAPREFIX, fobs);
2216 	} else {
2217 		var datafid = SmartCardHSM.determineFreeFid(SmartCardHSM.PUBLICDATAPREFIX, fobs);
2218 	}
2219 
2220 	if (datafid == null) {
2221 		throw new GPError(module.id, GPError.INVALID_DATA, 0, "Out of space for data objects");
2222 	}
2223 
2224 	var desc = SmartCardHSM.buildDataObjectDescription(label, undefined, datafid, "KeyManager");
2225 
2226 	var descfid = SmartCardHSM.determineFreeFid(SmartCardHSM.DODPREFIX, fobs);
2227 
2228 	if (descfid == null) {
2229 		throw new GPError(module.id, GPError.INVALID_DATA, 0, "Out of space for data objects descriptor");
2230 	}
2231 
2232 	this.updateBinary(datafid, 0, data);
2233 	this.updateBinary(descfid, 0, desc.getBytes());
2234 	this.donamemap[label] = { datafid: datafid, descfid: descfid };
2235 }
2236 
2237 
2238 
2239 /**
2240  * Delete the data object references by the label.
2241  *
2242  * @param {String} label the label of the data object
2243  */
2244 SmartCardHSM.prototype.deleteDataObject = function(label) {
2245 	if (typeof(this.donamemap) == "undefined"){
2246 		this.enumerateDataObjects();
2247 	}
2248 	var e = this.donamemap[label];
2249 	if (e == undefined) {
2250 		throw new GPError(module.id, GPError.INVALID_DATA, 0, "Data object " + label + " not found");
2251 	}
2252 	this.deleteFile(e.descfid);
2253 	this.deleteFile(e.datafid);
2254 	delete this.donamemap[label];
2255 }
2256 
2257 
2258 
2259 /**
2260  * Get crypto object
2261  *
2262  * @type HSMCrypto
2263  * @return the HSMCrypto object
2264  */
2265 SmartCardHSM.prototype.getCrypto = function() {
2266 	if (this.crypto == undefined) {
2267 		this.crypto = new SmartCardHSMCrypto(new Crypto());
2268 	}
2269 	return this.crypto;
2270 }
2271 
2272 
2273 
2274 /**
2275  * @private
2276  */
2277 SmartCardHSM.prototype.getTokenInfo = function() {
2278 	if (this.tokenInfo != undefined) {
2279 		return this.tokenInfo;
2280 	}
2281 
2282 	if (!this.hasFile(SmartCardHSM.EF_TokenInfo)) {
2283 		return;
2284 	}
2285 
2286 	var bin = this.readBinary(SmartCardHSM.EF_TokenInfo);
2287 	this.tokenInfo = new ASN1(bin);
2288 	return this.tokenInfo;
2289 }
2290 
2291 
2292 
2293 /**
2294  * Get Token Label
2295  *
2296  * @type String
2297  * @return the token label from CIAInfo
2298  */
2299 SmartCardHSM.prototype.getLabel = function() {
2300 	var ti = this.getTokenInfo();
2301 	if (!ti) {
2302 		return;
2303 	}
2304 
2305 	var a = ti.find(0x80);
2306 	if (!a) {
2307 		return;
2308 	}
2309 	return a.value.toString(UTF8);
2310 }
2311 
2312 
2313 
2314 /**
2315  * @private
2316  */
2317 SmartCardHSM.prototype.getStaticTokenInfo = function() {
2318 	if (this.staticTokenInfo != undefined) {
2319 		return this.staticTokenInfo;
2320 	}
2321 
2322 	if (!this.hasFile(SmartCardHSM.EF_StaticTokenInfo)) {
2323 		return;
2324 	}
2325 
2326 	var bin = this.readBinary(SmartCardHSM.EF_StaticTokenInfo);
2327 	this.staticTokenInfo = new ASN1(bin);
2328 	return this.staticTokenInfo;
2329 }
2330 
2331 
2332 
2333 /**
2334  * Get ProvisioningURL
2335  *
2336  * @type String
2337  * @return the configured ProvisioningURL or undefined
2338  */
2339 SmartCardHSM.prototype.getProvisioningURL = function() {
2340 	var ti = this.getStaticTokenInfo();
2341 	if (!ti) {
2342 		return;
2343 	}
2344 
2345 	var a = ti.find(0x80);
2346 	if (!a) {
2347 		return;
2348 	}
2349 	return a.value.toString(UTF8);
2350 }
2351 
2352 
2353 
2354 /**
2355  * Get Key Check Value of Token Management Key
2356  *
2357  * @type ByteString
2358  * @return the configured KCV of the Token Management Key or undefined
2359  */
2360 SmartCardHSM.prototype.getTokenManagementKeyKCV = function() {
2361 	var ti = this.getStaticTokenInfo();
2362 	if (!ti) {
2363 		return;
2364 	}
2365 
2366 	var a = ti.find(0x81);
2367 	if (!a) {
2368 		return;
2369 	}
2370 	return a.value;
2371 }
2372 
2373 
2374 
2375 /**
2376  * Get salt for SO-PIN derivation using  the Token Management Key
2377  *
2378  * @type ByteString
2379  * @return the configured salt
2380  */
2381 SmartCardHSM.prototype.getTokenManagementKeySalt = function() {
2382 	var ti = this.getStaticTokenInfo();
2383 	if (!ti) {
2384 		return;
2385 	}
2386 
2387 	var a = ti.find(0x82);
2388 	if (!a) {
2389 		return;
2390 	}
2391 	return a.value;
2392 }
2393 
2394 
2395 
2396 /**
2397  * Create crypto object implementing access to the SmartCard-HSM
2398  *
2399  * @class Wrapper to provide Crypto interface to SmartCard-HSM
2400  * @constructor
2401  * @param {Crypto} crypto the backend crypto provider
2402  */
2403 function SmartCardHSMCrypto(crypto) {
2404 	this.crypto = crypto;
2405 }
2406 
2407 
2408 
2409 /**
2410  * Sign a message using the defined mechanism and key
2411  *
2412  * @param {HSMKey} key the private key
2413  * @param {Number} mech the mechanism (e.g. Crypto.ECDSA)
2414  * @param {ByteString} message the message to be signed
2415  * @type ByteString
2416  * @return the signature
2417  */
2418 SmartCardHSMCrypto.prototype.sign = function(key, mech, message) {
2419 	if (key instanceof SmartCardHSMKey) {
2420 		return key.sign(mech, message);
2421 	} else {
2422 		return this.crypto.sign(key, mech, message);
2423 	}
2424 }
2425 
2426 
2427 
2428 /**
2429  * Decrypt a message using the defined mechanism and key
2430  *
2431  * @param {HSMKey} key the private key
2432  * @param {Number} mech the mechanism (e.g. Crypto.RSA_PKCS1)
2433  * @param {ByteString} data the cryptogram
2434  * @param {ByteString} iv the initialization vector for symmetric ciphers
2435  * @type ByteString
2436  * @return the plain text
2437  */
2438 SmartCardHSMCrypto.prototype.decrypt = function(key, mech, data, iv) {
2439 	if (key instanceof SmartCardHSMKey) {
2440 		return key.decrypt(mech, data);
2441 	} else {
2442 		return this.crypto.decrypt(key, mech, data, iv);
2443 	}
2444 }
2445 
2446 
2447 
2448 /**
2449  * Verify a message using the defined mechanism and key
2450  *
2451  * @param {Key} key the public key
2452  * @param {Number} mech the mechanism (e.g. Crypto.ECDSA)
2453  * @param {ByteString} message the message to be signed
2454  * @param {ByteString} signature the signature to verify
2455  * @type Boolean
2456  * @return true if signature is valid
2457  */
2458 SmartCardHSMCrypto.prototype.verify = function(key, mech, message, signature) {
2459 	return this.crypto.verify(key, mech, message, signature);
2460 }
2461 
2462 
2463 
2464 /**
2465  * Create a key access object
2466  *
2467  * @class Class implementing key access
2468  * @param {SmartCardHSM} sc the card access object
2469  * @param {Number} id the key identifier
2470  */
2471 function SmartCardHSMKey(sc, id) {
2472 	this.sc = sc;
2473 	this.id = id;
2474 	if (this.sc.useExternalHashInECDSA) {
2475 		this.crypto = new Crypto();
2476 	}
2477 }
2478 
2479 exports.SmartCardHSMKey = SmartCardHSMKey;
2480 
2481 
2482 /**
2483  * Set the PKCS#15 private key description
2484  *
2485  * @param {ASN1} desc the description
2486  */
2487 SmartCardHSMKey.prototype.setDescription = function(desc) {
2488 	this.desc = desc;
2489 }
2490 
2491 
2492 
2493 /**
2494  * Return the key identifier
2495  *
2496  * @type Number
2497  * @return the key identifier
2498  */
2499 SmartCardHSMKey.prototype.getId = function() {
2500 	return this.id;
2501 }
2502 
2503 
2504 
2505 /**
2506  * Return the key label as encoded in the PKCS#15 structure
2507  *
2508  * @type String
2509  * @return the key label
2510  */
2511 SmartCardHSMKey.prototype.getLabel = function() {
2512 	if (this.desc == undefined) {
2513 		return undefined;
2514 	}
2515 	if ((this.desc.get(0).elements == 0) || this.desc.get(0).get(0).tag != 0x0C) {
2516 		return undefined;
2517 	}
2518 
2519 	return this.desc.get(0).get(0).value.toString(UTF8);
2520 }
2521 
2522 
2523 
2524 /**
2525  * Return the key id as encoded in the PKCS#15 structure
2526  *
2527  * @type ByteString
2528  * @return the key identifier
2529  */
2530 SmartCardHSMKey.prototype.getPKCS15Id = function() {
2531 	if (this.desc == undefined) {
2532 		return undefined;
2533 	}
2534 	return this.desc.get(1).get(0).value;
2535 }
2536 
2537 
2538 
2539 /**
2540  * Return the key size in bits
2541  *
2542  * @type Number
2543  * @return the key size in bits
2544  */
2545 SmartCardHSMKey.prototype.getSize = function() {
2546 	if (this.desc == undefined) {
2547 		return undefined;
2548 	}
2549 //	GPSystem.trace(this.desc);
2550 	if (this.desc.get(2).elements > 1) {	// Fix a bug from early versions
2551 		return this.desc.get(2).get(1).value.toUnsigned();
2552 	}
2553 
2554 	if (this.desc.tag == 0xA8) {
2555 		var size = this.desc.get(2).get(0).get(0).value.toUnsigned();
2556 	} else {
2557 		var a1 = this.desc.find(0xA1);
2558 		var size = a1.get(0).get(1).value.toUnsigned();
2559 
2560 		if (size == 528) {
2561 			size = 521;		// Fix bug in OpenSCDP returning the wrong key size for secp521 keys
2562 		}
2563 	}
2564 
2565 	return size;
2566 }
2567 
2568 
2569 
2570 /**
2571  * Return the key type
2572  *
2573  * @type String
2574  * @return the key type
2575  */
2576 SmartCardHSMKey.prototype.getType = function() {
2577 	if (this.desc == undefined) {
2578 		return undefined;
2579 	}
2580 
2581 	if (this.desc.tag == 0xA0) {
2582 		return "EC";
2583 	} else if (this.desc.tag == 0x30) {
2584 		return "RSA";
2585 	} else if (this.desc.tag == 0xA8) {
2586 		return "AES";
2587 	}
2588 
2589 	return undefined;
2590 }
2591 
2592 
2593 
2594 /**
2595  * Sign data using a key in the SmartCard-HSM
2596  *
2597  * @param {Number} mech the signing mechanism
2598  * @param {ByteString} data to be signed
2599  * @type ByteString
2600  * @return the signature
2601  */
2602 SmartCardHSMKey.prototype.sign = function(mech, data) {
2603 	var algo;
2604 	if (mech) {
2605 		switch(mech) {
2606 		case Crypto.RSA:
2607 			algo = 0x20;
2608 			break;
2609 		case Crypto.RSA_SHA1:
2610 			algo = 0x31;
2611 			break;
2612 		case Crypto.RSA_SHA224:
2613 			algo = 0x32;
2614 			break;
2615 		case Crypto.RSA_SHA256:
2616 			algo = 0x33;
2617 			break;
2618 		case Crypto.RSA_SHA384:
2619 			algo = 0x34;
2620 			break;
2621 		case Crypto.RSA_SHA512:
2622 			algo = 0x35;
2623 			break;
2624 		case Crypto.RSA_PKCS1:
2625 			if (this.sc.major && this.sc.major >= 4) {
2626 				algo = 0x30;
2627 			} else {
2628 				algo = 0x20;
2629 				var keysize = this.getSize();
2630 				if (!keysize) {
2631 					throw new GPError(module.id, GPError.INVALID_DATA, 0, "Can't determine key size");
2632 				}
2633 				data = PKCS1.encode_EMSA_V15(keysize, data);
2634 			}
2635 			break;
2636 		case Crypto.RSA_PSS:
2637 		case 0x80:
2638 			algo = 0x40;
2639 			break;
2640 		case Crypto.RSA_PSS_SHA1:
2641 			algo = 0x41;
2642 			break;
2643 		case Crypto.RSA_PSS_SHA224:
2644 			algo = 0x42;
2645 			break;
2646 		case Crypto.RSA_PSS_SHA256:
2647 			algo = 0x43;
2648 			break;
2649 		case Crypto.RSA_PSS_SHA384:
2650 			algo = 0x44;
2651 			break;
2652 		case Crypto.RSA_PSS_SHA512:
2653 			algo = 0x45;
2654 			break;
2655 		case Crypto.ECDSA:
2656 			algo = 0x70;
2657 			break;
2658 		case Crypto.ECDSA_SHA1:
2659 			if (this.sc.useExternalHashInECDSA) {
2660 				algo = 0x70;
2661 				var data = this.crypto.digest(Crypto.SHA_1, data);
2662 			} else {
2663 				algo = 0x71;
2664 			}
2665 			break;
2666 		case Crypto.ECDSA_SHA224:
2667 			if (this.sc.useExternalHashInECDSA) {
2668 				algo = 0x70;
2669 				var data = this.crypto.digest(Crypto.SHA_224, data);
2670 			} else {
2671 				algo = 0x72;
2672 			}
2673 			break;
2674 		case Crypto.ECDSA_SHA256:
2675 			if (this.sc.useExternalHashInECDSA) {
2676 				algo = 0x70;
2677 				var data = this.crypto.digest(Crypto.SHA_256, data);
2678 			} else {
2679 				algo = 0x73;
2680 			}
2681 			break;
2682 		case Crypto.ECDSA_SHA384:
2683 			if (this.sc.useExternalHashInECDSA) {
2684 				algo = 0x70;
2685 				var data = this.crypto.digest(Crypto.SHA_384, data);
2686 			} else {
2687 				algo = 0x74;
2688 			}
2689 			break;
2690 		case Crypto.ECDSA_SHA512:
2691 			if (this.sc.useExternalHashInECDSA) {
2692 				algo = 0x70;
2693 				var data = this.crypto.digest(Crypto.SHA_512, data);
2694 			} else {
2695 				algo = 0x75;
2696 			}
2697 			break;
2698 		case Crypto.AES_CMAC:
2699 			return this.sc.deriveSymmetricKey(this.id, SmartCardHSM.ALG_CMAC, data);
2700 		default:
2701 			throw new GPError("SmartCardHSMKey", GPError.INVALID_DATA, mech, "Unsupported crypto mechanism");
2702 		}
2703 	}
2704 
2705 	return this.sc.sign(this.id, algo, data);
2706 }
2707 
2708 
2709 
2710 /**
2711  * Decrypt data using a key in the SmartCard-HSM
2712  *
2713  * @param {Number} mech the decipher mechanism
2714  * @param {ByteString} data to be deciphered
2715  * @type ByteString
2716  * @return the plain message
2717  */
2718 SmartCardHSMKey.prototype.decrypt = function(mech, data) {
2719 	var algo;
2720 	if (mech) {
2721 		switch(mech) {
2722 		case Crypto.RSA:
2723 			break;
2724 		case Crypto.RSA_PKCS1:
2725 			break;
2726 		case Crypto.RSA_OAEP_SHA224:
2727 			algo = Crypto.SHA_224;
2728 			break;
2729 		case Crypto.RSA_OAEP_SHA256:
2730 			algo = Crypto.SHA_256;
2731 			break;
2732 		case Crypto.RSA_OAEP_SHA384:
2733 			algo = Crypto.SHA_384;
2734 			break;
2735 		case Crypto.RSA_OAEP_SHA512:
2736 			algo = Crypto.SHA_512;
2737 			break;
2738 		default:
2739 			throw new GPError("SmartCardHSMKey", GPError.INVALID_DATA, mech, "Unsupported crypto mechanism");
2740 		}
2741 	}
2742 
2743 	var em = this.sc.decipher(this.id, 0x21, data);
2744 
2745 	var plain = em;
2746 
2747 	if (mech != Crypto.RSA) {
2748 		if (mech == Crypto.RSA_PKCS1) {
2749 			var plain = PKCS1.decode_EME_V15(em);
2750 		} else {
2751 			var crypto = this.sc.getCrypto().crypto;
2752 
2753 			var plain = PKCS1.decode_EME_OAEP(crypto, null, algo, em);
2754 		}
2755 
2756 		if (!plain) {
2757 			throw new GPError("SmartCardHSMKey", GPError.CRYPTO_FAILED, mech, "Decryption failed");
2758 		}
2759 	}
2760 
2761 	return plain;
2762 }
2763 
2764 
2765 
2766 /**
2767  * Return human readable string
2768  */
2769 SmartCardHSMKey.prototype.toString = function() {
2770 	return "SmartCardHSMKey(id=" + this.id + ")";
2771 }
2772 
2773 
2774 
2775 /**
2776  * Initialize SmartCard-HSM
2777  *
2778  * @class Class implementing the device initialization methods
2779  * @param {Card} card the card object
2780  */
2781 function SmartCardHSMInitializer(card) {
2782 	this.card = card;
2783 	this.initializationCode = new ByteString("57621880", ASCII);
2784 	this.userPIN = new ByteString("648219", ASCII);
2785 	this.userPINSet = false;
2786 	this.useDefaultUserPIN = true;
2787 	this.retryCounterInitial = 3;
2788 	this.options = 0x0001;
2789 	this.keyshares = -1;
2790 	this.keyDomains = -1;
2791 	this.numberOfPublicKeys = 0;
2792 	this.requiredPublicKeysForAuthentication = 0;
2793 	this.bioslot = [];
2794 	this.label = undefined;
2795 }
2796 
2797 exports.SmartCardHSMInitializer = SmartCardHSMInitializer;
2798 
2799 
2800 
2801 /**
2802  * Set the initialization code
2803  *
2804  * @param {ByteString} initializationCode an 8 byte code
2805  */
2806 SmartCardHSMInitializer.prototype.setInitializationCode = function(initializationCode) {
2807 	if (!(initializationCode instanceof ByteString)) {
2808 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "initializationCode must be a ByteString");
2809 	}
2810 	if (initializationCode.length != 8) {
2811 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "initializationCode must have 8 bytes");
2812 	}
2813 
2814 	this.initializationCode = initializationCode;
2815 }
2816 
2817 
2818 
2819 /**
2820  * Set the User PIN
2821  *
2822  * @param {ByteString} userPIN a 6 to 16 byte code
2823  */
2824 SmartCardHSMInitializer.prototype.setUserPIN = function(userPIN) {
2825 	if (!(userPIN instanceof ByteString)) {
2826 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "userPIN must be a ByteString");
2827 	}
2828 	if ((userPIN.length < 6) || (userPIN.length > 16)) {
2829 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "userPIN must be between 6 and 16 bytes");
2830 	}
2831 
2832 	this.userPIN = userPIN;
2833 	this.userPINSet = true;
2834 	this.useDefaultUserPIN = false;
2835 }
2836 
2837 
2838 
2839 /**
2840  * Set the retry counter
2841  *
2842  * The SmartCard-HSM enforces a retry counter <= 3 for PIN length 6
2843  * The SmartCard-HSM enforces a retry counter <= 5 for PIN length 7
2844  * The SmartCard-HSM enforces a retry counter <= 10 for PIN length larger than 7
2845  *
2846  * @param {Number} retryCounterInitial in the range 1 to 10.
2847  */
2848 SmartCardHSMInitializer.prototype.setRetryCounterInitial = function(retryCounterInitial) {
2849 	if (typeof(retryCounterInitial) != "number") {
2850 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "retryCounterInitial must be a number");
2851 	}
2852 	if ((retryCounterInitial < 1) || (retryCounterInitial > 10)) {
2853 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "retryCounterInitial must be between 1 and 10");
2854 	}
2855 	this.retryCounterInitial = retryCounterInitial;
2856 }
2857 
2858 
2859 
2860 /**
2861  * Set the number of DKEK shares
2862  *
2863  * @param {Number} keyshares number of DKEK shares in the range 0 to 255
2864  */
2865 SmartCardHSMInitializer.prototype.setDKEKShares = function(keyshares) {
2866 	if (typeof(keyshares) != "number") {
2867 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyshares must be a number");
2868 	}
2869 	if ((keyshares < 0) || (keyshares > 255)) {
2870 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyshares must be between 0 and 255");
2871 	}
2872 	this.keyshares = keyshares;
2873 	this.keyDomains = -1;
2874 }
2875 
2876 
2877 
2878 /**
2879  * Set the number of key domains
2880  *
2881  * @param {Number} keyDomains number of key domains
2882  */
2883 SmartCardHSMInitializer.prototype.setKeyDomains = function(keyDomains) {
2884 	if (typeof(keyDomains) != "number") {
2885 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyDomains must be a number");
2886 	}
2887 
2888 	this.keyDomains = keyDomains;
2889 	this.keyshares = -1;
2890 }
2891 
2892 
2893 
2894 /**
2895  * Enable or disable RESET RETRY COUNTER command
2896  *
2897  * @param {Boolean} enable true (default) to allow RESET RETRY COUNTER command to reset user PIN using the initialization code
2898  */
2899 SmartCardHSMInitializer.prototype.setResetRetryCounterMode = function(enable) {
2900 	if (typeof(enable) == "undefined") {
2901 		var enable = false;
2902 	}
2903 
2904 	this.options = (this.options & 0xFFFE) + (enable ? 1 : 0);
2905 }
2906 
2907 
2908 
2909 /**
2910  * Enable or disable transport PIN mode
2911  *
2912  * @param {Boolean} enable true (non-default) to set user PIN to transport state
2913  */
2914 SmartCardHSMInitializer.prototype.setTransportPINMode = function(enable) {
2915 	if (typeof(enable) == "undefined") {
2916 		var enable = true;
2917 	}
2918 
2919 	this.options = (this.options & 0xFFFD) + (enable ? 2 : 0);
2920 }
2921 
2922 
2923 
2924 /**
2925  * Enable or disable session PIN mode
2926  *
2927  * @param {Number} 0 - disable, 1 - enable with clear-on-reset 3 - enable with explicit clearing
2928  */
2929 SmartCardHSMInitializer.prototype.setSessionPINMode = function(mode) {
2930 	assert(typeof(mode) == "number", "Argument mode must be number");
2931 	assert(mode >= 0 && mode <= 3 && mode != 2, "Argument mode must be 0, 1 or 3");
2932 
2933 	this.options = (this.options & 0xFFF3) + (mode << 2);
2934 }
2935 
2936 
2937 
2938 /**
2939  * Enable or disable replacing of a PKA key
2940  *
2941  * @param {Boolean} enable true (non-default) to allow replacing of a PKA key
2942  */
2943 SmartCardHSMInitializer.prototype.setReplacePKAKeyMode = function(enable) {
2944 	if (typeof(enable) == "undefined") {
2945 		var enable = false;
2946 	}
2947 
2948 	this.options = (this.options & 0xFFF7) + (enable ? 8 : 0);
2949 }
2950 
2951 
2952 
2953 /**
2954  * Enable the combined authentication mode of user pin and public key authentication.
2955  *
2956  * @param {Boolean} enable true (non-default) to require public key authentication and user authentication
2957  */
2958 SmartCardHSMInitializer.prototype.setCombinedAuthenticationMode = function(enable) {
2959 	if (typeof(enable) == "undefined") {
2960 		var enable = false;
2961 	}
2962 
2963 	this.options = (this.options & 0xFFEF) + (enable ? 16 : 0);
2964 }
2965 
2966 
2967 
2968 /**
2969  * If enabled RESET RETRY COUNTER only resets the error counter.
2970  * Otherwise  RRC allows changing the PIN
2971  *
2972  * @param {Boolean} resetOnly true to only reset the error counter, false otherwise (default)
2973  */
2974 SmartCardHSMInitializer.prototype.setResetRetryCounterResetOnlyMode = function(resetOnly) {
2975 	if (typeof(resetOnly) == "undefined") {
2976 		var resetOnly = false;
2977 	}
2978 
2979 	this.options = (this.options & 0xFFDF) + (resetOnly ? 32 : 0);
2980 }
2981 
2982 
2983 
2984 /**
2985  * Set parameter for public key authentication with n-of-m scheme, namely the values for n and m
2986  *
2987  * @param {Number} requiredPublicKeysForAuthentication number of key that must be authenticated for access
2988  * @param {Number} numberOfPublicKeys to register
2989  */
2990 SmartCardHSMInitializer.prototype.setPublicKeyAuthenticationParameter = function(requiredPublicKeysForAuthentication, numberOfPublicKeys) {
2991 	if ((numberOfPublicKeys < 1) || (numberOfPublicKeys > 90)) {
2992 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "numberOfPublicKeys must be between 1 and 90");
2993 	}
2994 	if ((requiredPublicKeysForAuthentication < 1) || (requiredPublicKeysForAuthentication > numberOfPublicKeys)) {
2995 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 2, "requiredPublicKeysForAuthentication must be between 1 and " + numberOfPublicKeys);
2996 	}
2997 	this.numberOfPublicKeys = numberOfPublicKeys;
2998 	this.requiredPublicKeysForAuthentication = requiredPublicKeysForAuthentication;
2999 	this.useDefaultUserPIN = false;
3000 }
3001 
3002 
3003 
3004 /**
3005  * Select the biometric matching server for a one of the biometric templates
3006  *
3007  * @param {Number} slot either 0 or 1 for first or second template
3008  * @param {ByteString} aid the application identifier of the on-card biometric server
3009  * @param {Number} param one byte parameter passed to the server during initialization
3010  */
3011 SmartCardHSMInitializer.prototype.setBioTemplate = function(slot, aid, param) {
3012 	assert(typeof(slot) == "number", "slot must be a number");
3013 	assert(slot >= 0 && slot <= 1, "slot must be either 0 or 1");
3014 	assert(aid instanceof ByteString, "aid must be a ByteString");
3015 	assert(typeof(param) == "number", "param must be a number");
3016 	assert(param >= 0 && param <= 255, "param must be between 0 and 255");
3017 
3018 	this.bioslot[slot] = { aid: aid, param: param };
3019 	this.useDefaultUserPIN = false;
3020 }
3021 
3022 
3023 
3024 /**
3025  * Set the label to be written to a minimal CIAInfo in EF 2F03
3026  *
3027  * @param {String} label the label
3028  */
3029 SmartCardHSMInitializer.prototype.setLabel = function(label) {
3030 	this.label = label;
3031 }
3032 
3033 
3034 
3035 /**
3036  * Set the provisioning URL to be written to fixed parameter in CB00.
3037  *
3038  * @param {String} provisioningURL the URL at which this SE will be provisioned
3039  */
3040 SmartCardHSMInitializer.prototype.setProvisioningURL = function(provisioningURL) {
3041 	this.provisioningURL = provisioningURL;
3042 }
3043 
3044 
3045 
3046 /**
3047  * Set the key check value of the token management key and the optional salt
3048  * used for SO-PIN derivation
3049  *
3050  * @param {ByteString} kcv the key check value of the token management key
3051  * @param {ByteString} salt the salt used to derive the SO-PIN
3052  */
3053 SmartCardHSMInitializer.prototype.setTokenManagementKey = function(kcv, salt) {
3054 	this.tokenManagementKeyKCV = kcv;
3055 	this.tokenManagementKeySalt = salt;
3056 }
3057 
3058 
3059 
3060 /**
3061  * Perform Initialization
3062  */
3063 SmartCardHSMInitializer.prototype.initialize = function() {
3064 	var s = new ASN1(0x30,	new ASN1(0x80, ByteString.valueOf(this.options, 2)));
3065 
3066 	if (this.userPINSet || this.useDefaultUserPIN) {
3067 		s.add(new ASN1(0x81, this.userPIN));
3068 	}
3069 
3070 	s.add(new ASN1(0x82, this.initializationCode));
3071 
3072 	if (this.userPINSet || this.useDefaultUserPIN) {
3073 		s.add(new ASN1(0x91, ByteString.valueOf(this.retryCounterInitial)));
3074 	}
3075 
3076 	if (this.keyshares != -1) {
3077 		s.add(new ASN1(0x92, ByteString.valueOf(this.keyshares)));
3078 	}
3079 
3080 	if (this.keyDomains != -1) {
3081 		s.add(new ASN1(0x97, ByteString.valueOf(this.keyDomains)));
3082 	}
3083 
3084 	if (this.numberOfPublicKeys > 0) {
3085 		s.add(new ASN1(0x93, ByteString.valueOf(this.numberOfPublicKeys).concat(ByteString.valueOf(this.requiredPublicKeysForAuthentication))));
3086 	}
3087 
3088 	if (this.bioslot[0]) {
3089 		var o = this.bioslot[0];
3090 		s.add(new ASN1(0x95, ByteString.valueOf(o.param).concat(o.aid)));
3091 	}
3092 
3093 	if (this.bioslot[1]) {
3094 		var o = this.bioslot[1];
3095 		s.add(new ASN1(0x96, ByteString.valueOf(o.param).concat(o.aid)));
3096 	}
3097 
3098 	this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000, 0x6A84]);
3099 
3100 	if (this.card.SW == 0x6A84) {
3101 		// Due to the nature of the JCRE, a first call to initialize may run out of memory,
3102 		// as the garbage collector for the removed objects is only run during the next
3103 		// APDU invocation.
3104 		this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000]);
3105 	}
3106 
3107 	if (this.label) {
3108 		var a = new ASN1(0x30,
3109 				new ASN1(0x54, new ByteString("0000", HEX)),
3110 				new ASN1(0x53,
3111 					new ASN1(0x30,
3112 						new ASN1(0x02, new ByteString("00", HEX)),
3113 						new ASN1(0x80, new ByteString(this.label, UTF8)),
3114 						new ASN1(0x03, new ByteString("0500", HEX)))
3115 				)
3116 			);
3117 
3118 		var p1 = SmartCardHSM.EF_TokenInfo.byteAt(0);
3119 		var p2 = SmartCardHSM.EF_TokenInfo.byteAt(1);
3120 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, p1, p2, a.value, [0x9000]);
3121 	}
3122 
3123 	if (this.provisioningURL || this.tokenManagementKeyKCV || this.tokenManagementKeySalt) {
3124 		var l = new ASN1(ASN1.SEQUENCE);
3125 		if (this.provisioningURL) {
3126 			l.add(new ASN1(0x80, new ByteString(this.provisioningURL, UTF8)));
3127 		}
3128 		if (this.tokenManagementKeyKCV) {
3129 			l.add(new ASN1(0x81, this.tokenManagementKeyKCV));
3130 		}
3131 		if (this.tokenManagementKeySalt) {
3132 			l.add(new ASN1(0x82, this.tokenManagementKeySalt));
3133 		}
3134 
3135 		var a = new ASN1(0x30,
3136 				new ASN1(0x54, new ByteString("0000", HEX)),
3137 				new ASN1(0x53, l)
3138 			);
3139 
3140 		var p1 = SmartCardHSM.EF_StaticTokenInfo.byteAt(0);
3141 		var p2 = SmartCardHSM.EF_StaticTokenInfo.byteAt(1);
3142 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, p1, p2, a.value, [0x9000]);
3143 	}
3144 }
3145 
3146 
3147 
3148 /**
3149  * Create a key specification generator instance
3150  *
3151  * @class Class implementing an encoder for the C-Data required in GENERATE ASYMMETRIC KEY PAIR
3152  * @param {Number} keytype must be either Crypto.RSA, Crypto.EC or Crypto.AES
3153  * @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
3154  */
3155 function SmartCardHSMKeySpecGenerator(keytype, keysizeOrDP) {
3156 	this.keytype = keytype;
3157 
3158 	switch(keytype) {
3159 		case Crypto.RSA:
3160 			if (typeof(keysizeOrDP) != "number") {
3161 				throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be of a number for RSA keys");
3162 			}
3163 			this.keysize = keysizeOrDP;
3164 			this.defaultAlgo = new ByteString("id-TA-RSA-v1-5-SHA-256", OID);
3165 			break;
3166 		case Crypto.EC:
3167 			if ((typeof(keysizeOrDP) != "object") || !(keysizeOrDP instanceof Key)) {
3168 				throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be a Key instance");
3169 			}
3170 			this.domainParameter = keysizeOrDP;
3171 			this.defaultAlgo = new ByteString("id-TA-ECDSA-SHA-256", OID);
3172 			break;
3173 		case Crypto.AES:
3174 			if (typeof(keysizeOrDP) != "number") {
3175 				throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be of a number for AES keys");
3176 			}
3177 			this.keysize = keysizeOrDP;
3178 			break;
3179 		default:
3180 			throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keytype must be Crypto.RSA or Crypto.EC");
3181 	}
3182 	this.CHR = new PublicKeyReference("UTDUMMY00001");
3183 	this.innerCAR = new PublicKeyReference("UTDUMMY00001");
3184 }
3185 
3186 exports.SmartCardHSMKeySpecGenerator = SmartCardHSMKeySpecGenerator;
3187 
3188 
3189 
3190 /**
3191  * Set key use counter for key
3192  *
3193  * @param {keyUseCounter} keyUseCounter in the range 1 to 2^64 - 2
3194  */
3195 SmartCardHSMKeySpecGenerator.prototype.setKeyUseCounter = function(keyUseCounter) {
3196 	if ((keyUseCounter < 0) || (keyUseCounter >= 0xFFFFFFFF)) {
3197 		throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 1, "keyUseCounter must be between 0 and 0xFFFFFFFF");
3198 	}
3199 	this.keyUseCounter = keyUseCounter;
3200 }
3201 
3202 
3203 
3204 /**
3205  * Set key domain
3206  *
3207  * @param {Number} keyDomain the key domain to which the key shall be added
3208  */
3209 SmartCardHSMKeySpecGenerator.prototype.setKeyDomain = function(keyDomain) {
3210 	this.keyDomain = keyDomain;
3211 }
3212 
3213 
3214 
3215 /**
3216  * Set wrapping key
3217  *
3218  * @param {Number} wrappingKey the key to used for wrapping a newly generated symmetric key
3219  */
3220 SmartCardHSMKeySpecGenerator.prototype.setWrappingKey = function(wrappingKey) {
3221 	this.wrappingKey = wrappingKey;
3222 }
3223 
3224 
3225 
3226 /**
3227  * Set algorithm list
3228  *
3229  * @param {ByteString} algorithms the list of algorithms allowed for this key
3230  */
3231 SmartCardHSMKeySpecGenerator.prototype.setAlgorithms = function(algorithms) {
3232 	this.algorithms = algorithms;
3233 }
3234 
3235 
3236 
3237 /**
3238  * Set certificate holder reference for key
3239  *
3240  * @param {PublicKeyReference} CHR certificate holder reference
3241  */
3242 SmartCardHSMKeySpecGenerator.prototype.setCHR = function(CHR) {
3243 	this.CHR = CHR;
3244 }
3245 
3246 
3247 
3248 /**
3249  * Set certificate holder reference of CA this request shall be sent to
3250  *
3251  * @param {PublicKeyReference} CAR certificate holder reference
3252  */
3253 SmartCardHSMKeySpecGenerator.prototype.setInnerCAR = function(CAR) {
3254 	this.innerCAR = CAR;
3255 }
3256 
3257 
3258 
3259 /**
3260  * Set holder reference of the key signing this request
3261  *
3262  * @param {PublicKeyReference} CAR certificate holder reference
3263  */
3264 SmartCardHSMKeySpecGenerator.prototype.setOuterCAR = function(CAR) {
3265 	this.outerCAR = CAR;
3266 }
3267 
3268 
3269 
3270 /**
3271  * @private
3272  */
3273 SmartCardHSMKeySpecGenerator.prototype.encodeRSAKeySpec = function() {
3274 	var p = new ASN1("Public Key", 0x7F49,
3275 			new ASN1("Object Identifier", 0x06, this.defaultAlgo),
3276 			new ASN1("Public Key Exponent", 0x82, ByteString.valueOf(65537)),
3277 			new ASN1("Key Size", 0x02, ByteString.valueOf(this.keysize))
3278 		);
3279 	return p;
3280 }
3281 
3282 
3283 
3284 /**
3285  * @private
3286  */
3287 SmartCardHSMKeySpecGenerator.prototype.encodeECKeySpec = function() {
3288 	// Encode G
3289 	var bb = new ByteBuffer();
3290 	// uncompressed encoding
3291 	bb.append(new ByteString("04", HEX));
3292 	bb.append(this.domainParameter.getComponent(Key.ECC_GX));
3293 	bb.append(this.domainParameter.getComponent(Key.ECC_GY));
3294 	var G = bb.toByteString();
3295 
3296 	var p = new ASN1("Public Key", 0x7F49,
3297 			new ASN1("Object Identifier", 0x06, this.defaultAlgo),
3298 			new ASN1("Prime Modulus", 0x81, this.domainParameter.getComponent(Key.ECC_P)),
3299 			new ASN1("First coefficient a", 0x82, this.domainParameter.getComponent(Key.ECC_A)),
3300 			new ASN1("Second coefficient b", 0x83, this.domainParameter.getComponent(Key.ECC_B)),
3301 			new ASN1("Base Point G", 0x84, G),
3302 			new ASN1("Order of the base point", 0x85, this.domainParameter.getComponent(Key.ECC_N)),
3303 			new ASN1("Cofactor f", 0x87, SmartCardHSM.stripLeadingZeros(this.domainParameter.getComponent(Key.ECC_H)))
3304 		);
3305 	return p;
3306 }
3307 
3308 
3309 
3310 /**
3311  * @private
3312  */
3313 SmartCardHSMKeySpecGenerator.prototype.encodeKeySpec = function() {
3314 	if (this.keytype == Crypto.RSA) {
3315 		return this.encodeRSAKeySpec();
3316 	} else {
3317 		return this.encodeECKeySpec();
3318 	}
3319 }
3320 
3321 
3322 
3323 /**
3324  * Return the encoded key specification
3325  *
3326  * @type ByteString
3327  * @return the encoded C-Data for GENERATE ASYMMETRIC KEY PAIR
3328  */
3329 SmartCardHSMKeySpecGenerator.prototype.encode = function() {
3330 	var t = new ASN1(0x30);
3331 
3332 	if (this.keytype != Crypto.AES) {
3333 		t.add(new ASN1("CPI", 0x5F29, new ByteString("00", HEX)));
3334 
3335 		if ((typeof(this.innerCAR) != "undefined") && (this.innerCAR)) {
3336 			t.add(new ASN1("CAR", 0x42, this.innerCAR.getBytes()));
3337 		}
3338 
3339 		t.add(this.encodeKeySpec());
3340 		t.add(new ASN1("CHR", 0x5F20, this.CHR.getBytes()));
3341 
3342 		if (typeof(this.outerCAR) != "undefined") {
3343 			t.add(new ASN1("OuterCAR", 0x45, this.outerCAR.getBytes()));
3344 		}
3345 	}
3346 
3347 	if (typeof(this.keyUseCounter) != "undefined") {
3348 		t.add(new ASN1("Key use counter", 0x90, ByteString.valueOf(this.keyUseCounter, 4)));
3349 	}
3350 
3351 	if (typeof(this.algorithms) != "undefined") {
3352 		t.add(new ASN1("Algorithms", 0x91, this.algorithms));
3353 	}
3354 
3355 	if (typeof(this.keyDomain) != "undefined") {
3356 		t.add(new ASN1("KeyDomain", 0x92, ByteString.valueOf(this.keyDomain)));
3357 	}
3358 
3359 	if (typeof(this.wrappingKey) != "undefined") {
3360 		t.add(new ASN1("Wrapping Key", 0x93, ByteString.valueOf(this.wrappingKey)));
3361 	}
3362 
3363 	return t.value;
3364 }
3365 
3366 
3367 
3368 /**
3369  * Create a key specification generator instance for AES keys
3370  *
3371  * @class Class implementing an encoder for the C-Data required in Generate Symmetric Key
3372  * @param {ByteString} allowedAlgorithms the list of allowed algorithm identifier
3373  */
3374 function SmartCardHSMSymmetricKeySpecGenerator(allowedAlgorithms) {
3375 	this.algorithms = allowedAlgorithms;
3376 }
3377 
3378 exports.SmartCardHSMSymmetricKeySpecGenerator = SmartCardHSMSymmetricKeySpecGenerator;
3379 
3380 
3381 
3382 /**
3383  * Set key domain
3384  *
3385  * @param {Number} keyDomain the key domain to which the key shall be added
3386  */
3387 SmartCardHSMSymmetricKeySpecGenerator.prototype.setKeyDomain = function(keyDomain) {
3388 	this.keyDomain = keyDomain;
3389 }
3390 
3391 
3392 
3393 /**
3394  * Return the encoded AES key specification
3395  *
3396  * @type ByteString
3397  * @return the encoded C-Data for Generate Symmetric Key
3398  */
3399 SmartCardHSMSymmetricKeySpecGenerator.prototype.encode = function() {
3400 	var t = new ASN1(0x30);
3401 
3402 	t.add(new ASN1("Algorithms", 0x91, this.algorithms));
3403 
3404 	if (typeof(this.keyUseCounter) != "undefined") {
3405 		t.add(new ASN1("Key use counter", 0x90, ByteString.valueOf(this.keyUseCounter, 4)));
3406 	}
3407 
3408 	if (typeof(this.keyDomain) != "undefined") {
3409 		t.add(new ASN1("Key Domain", 0x92, ByteString.valueOf(this.keyDomain)));
3410 	}
3411 
3412 	if (typeof(this.wrappingKey) != "undefined") {
3413 		t.add(new ASN1("Wrapping Key", 0x93, this.wrappingKey));
3414 	}
3415 
3416 	return t.value;
3417 }
3418 
3419 
3420 
3421 SmartCardHSM.test = function() {
3422 	var crypto = new Crypto();
3423 	var card = new Card(_scsh3.reader);
3424 	var sc = new SmartCardHSM(card);
3425 
3426 	var sci = new SmartCardHSMInitializer(card);
3427 	sci.initialize();
3428 
3429 	var pubKey = sc.validateCertificateChain(crypto);
3430 	sc.openSecureChannel(crypto, pubKey);
3431 
3432 	sc.verifyUserPIN(sci.userPIN);
3433 
3434 	var kg = new SmartCardHSMKeySpecGenerator(Crypto.RSA, 1024);
3435 	sc.generateAsymmetricKeyPair(1, 0, kg.encode());
3436 
3437 	var dp = new Key();
3438 	dp.setComponent(Key.ECC_CURVE_OID, new ByteString("brainpoolP256r1", OID));
3439 
3440 	var kg = new SmartCardHSMKeySpecGenerator(Crypto.EC, dp);
3441 	sc.generateAsymmetricKeyPair(2, 0, kg.encode());
3442 
3443 	var list = sc.enumerateKeys();
3444 	GPSystem.trace("Keys on device: " + list);
3445 
3446 	var crypto = sc.getCrypto();
3447 	var message = new ByteString("Hello World", ASCII);
3448 
3449 	var key = sc.getKey(1);
3450 	var signature = crypto.sign(key, Crypto.RSA_SHA256, message);
3451 	GPSystem.trace("Signature: " + signature);
3452 
3453 	var key = sc.getKey(2);
3454 	var signature = crypto.sign(key, Crypto.ECDSA, message);
3455 	GPSystem.trace("Signature: " + signature);
3456 }
3457