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  * Consult your license package for usage terms and conditions.
 10  * 
 11  * @fileoverview SmartCard-HSM Card Service
 12  */
 13 
 14  if (typeof(__ScriptingServer) == "undefined") {
 15 	load("../../icao/cvc.js");
 16 	load("../../icao/chipauthentication.js");
 17 }
 18 
 19 
 20 /**
 21  * Create a SmartCard-HSM access object
 22  * @class Class implementing support for SmartCard-HSM access
 23  * @constructor
 24  * @param {Card} card the card object
 25  */ 
 26 function SmartCardHSM(card) {
 27 	this.card = card;
 28 	this.maxAPDU = 1000;
 29 //	this.maxAPDU = 255;				// Enable for MicroSD card or set in calling application
 30 
 31 	// Check if SmartCard-HSM is already selected
 32 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x20, 0x00, 0x81);
 33 	if ((this.card.SW == 0x6E00) || ((this.card.SW == 0x6900))) {
 34 		this.logout();		// Select application
 35 	}
 36 
 37 	this.namemap = [];
 38 	this.idmap = [];
 39 }
 40 
 41 
 42 SmartCardHSM.C_DevAut = new ByteString("2F02", HEX);
 43 SmartCardHSM.PrK_DevAut = 0;
 44 SmartCardHSM.PIN_User = 0x81;
 45 
 46 SmartCardHSM.PRKDPREFIX = 0xC4;
 47 SmartCardHSM.KEYMETAPREFIX = 0xCB;
 48 SmartCardHSM.KEYPREFIX = 0xCC;
 49 SmartCardHSM.CONFIDENTIALDATAPREFIX = 0xCD;
 50 SmartCardHSM.EECERTIFICATEPREFIX = 0xCE;
 51 SmartCardHSM.CACERTIFICATEPREFIX = 0xCA;
 52 
 53 SmartCardHSM.rootCerts = {
 54 	DESRCACC100001: new CVC(new ByteString("7F218201B47F4E82016C5F290100420E44455352434143433130303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A78641046D025A8026CDBA245F10DF1B72E9880FFF746DAB40A43A3D5C6BEBF27707C30F6DEA72430EE3287B0665C1EAA6EAA4FA26C46303001983F82BD1AA31E03DA0628701015F200E44455352434143433130303030317F4C10060B2B0601040181C31F0301015301C05F25060102010100095F24060302010100085F37409DBB382B1711D2BAACB0C623D40C6267D0B52BA455C01F56333DC9554810B9B2878DAF9EC3ADA19C7B065D780D6C9C3C2ECEDFD78DEB18AF40778ADF89E861CA", HEX)),
 55 	UTSRCACC100001: new CVC(new ByteString("7F218201B47F4E82016C5F290100420E55545352434143433130303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7864104A041FEB2FD116B2AD19CA6B7EACD71C9892F941BB88D67DCEEC92501F070011957E22122BA6C2CF5FF02936F482E35A6129CCBBA8E9383836D3106879C408EF08701015F200E55545352434143433130303030317F4C10060B2B0601040181C31F0301015301C05F25060102010100095F24060302010100085F3740914DD0FA00615C44048D1467435400423A4AD1BD37FD98D6DE84FD8037489582325C72956D4FDFABC6EDBA48184A754F37F1BE5142DD1C27D66569308CE19AAF", HEX))
 56 }
 57 
 58 SmartCardHSM.devAutPuk = new Key();
 59 SmartCardHSM.devAutPuk.setType(Key.PUBLIC);
 60 SmartCardHSM.devAutPuk.setComponent(Key.ECC_CURVE_OID, new ByteString("brainpoolP256r1", OID));
 61 SmartCardHSM.devAutPuk.setComponent(Key.ECC_QX, new ByteString("4C01EA36C5065FF47E8F0676A77CDCED6C8F745E6784F7807F5520124F81ED05", HEX));
 62 SmartCardHSM.devAutPuk.setComponent(Key.ECC_QY, new ByteString("4112DCE471CA003442830A10C75B31F9BFADD60628F47131628C7254AD8B956A", HEX));
 63 
 64 
 65 
 66 /**
 67  * Validate device certificate chain
 68  *
 69  * @param {Crypto} crypto the crypto provider to use
 70  * @param {ByteString} devAutCert the device certificate chain read from EF.C_DevAut
 71  * @type Key
 72  * @return the device authentication public key
 73  */
 74 SmartCardHSM.validateCertificateChain = function(crypto, devAutCert) {
 75 	// Device device certificate
 76 	var cvc = new CVC(devAutCert);
 77 	print("Device Certificate    : " + cvc);
 78 
 79 	if (cvc.getCAR().toString() == "DECA00001") {		// CA used for development version up to 0.17
 80 		if (!cvc.verifyWith(crypto, SmartCardHSM.devAutPuk)) {
 81 			print("Device certificate verification failed for CAR=DECA00001");
 82 			return null;
 83 		}
 84 		var path = "/" + cvc.getCAR().getHolder() + "/" + cvc.getCHR().getHolder();
 85 		return { devicecert: cvc, publicKey:cvc.getPublicKey(), path:path };
 86 	}
 87 
 88 	// Decode device issuer certificate
 89 	var dica = new CVC(devAutCert.bytes(cvc.getASN1().size));
 90 	print("Device Issuer CA      : " + dica);
 91 	
 92 	// Determine root certificate
 93 	var srca = SmartCardHSM.rootCerts[dica.getCAR()];
 94 	print("SmartCard-HSM Root CA : " + srca);
 95 
 96 	// Validate chain
 97 	var srcapuk = srca.getPublicKey();
 98 	var oid = srca.getPublicKeyOID();
 99 	if (!dica.verifyWith(crypto, srcapuk, oid)) {
100 		print("DICA certificate not verified");
101 		return null;
102 	}
103 
104 	var dicapuk = dica.getPublicKey(srcapuk);
105 	if (!cvc.verifyWith(crypto, dicapuk, oid)) {
106 		print("Device certificate verification failed");
107 		return null;
108 	}
109 
110 	var path = "/" + srca.getCHR().getHolder() + "/" + dica.getCHR().getHolder() + "/" + cvc.getCHR().getHolder();
111 	return { srca: srca, dica: dica, devicecert: cvc, publicKey:cvc.getPublicKey(srcapuk), path:path };
112 }
113 
114 
115 
116 /**
117  * Validate device certificate chain
118  *
119  * @param {Crypto} crypto the crypto provider to use
120  * @type Key
121  * @return the device authentication public key
122  */
123 SmartCardHSM.prototype.validateCertificateChain = function(crypto) {
124 	// Read concatenation of both certificates
125 	var devAutCert = this.readBinary(SmartCardHSM.C_DevAut);
126 	var chain = SmartCardHSM.validateCertificateChain(crypto, devAutCert);
127 	if (chain == null) {
128 		return null;
129 	}
130 	return chain.publicKey;
131 }
132 
133 
134 
135 /**
136  * Open a secure channel using device authentication
137  *
138  * @param {Crypto} crypto the crypto provider to use
139  * @param {Key} devAuthPK the device authentication public key
140  * @type ISOSecureChannel
141  * @return the initialized secure channel
142  */
143 SmartCardHSM.prototype.openSecureChannel = function(crypto, devAuthPK) {
144 
145 	var protocol = new ByteString("id-CA-ECDH-3DES-CBC-CBC", OID);
146 	var ca = new ChipAuthentication(crypto, protocol, devAuthPK);	// For domain parameter
147 	ca.noPadding = true;
148 	ca.generateEphemeralCAKeyPair();
149 
150 	// Perform chip authentication
151 
152 	var bb = new ByteBuffer();
153 	bb.append(new ASN1(0x80, protocol).getBytes());
154 
155 	this.card.sendSecMsgApdu(Card.CPRO|Card.CENC|Card.RPRO, 0x00, 0x22, 0x41, 0xA4, bb.toByteString(), [0x9000]);
156 
157 	var ephemeralPublicKeyIfd = ca.getEphemeralPublicKey();
158 
159 	var dado = new ASN1(0x7C, new ASN1(0x80, ephemeralPublicKeyIfd));
160 
161 	var dadobin = this.card.sendSecMsgApdu(Card.CPRO|Card.CENC|Card.RPRO|Card.RENC, 0x00, 0x86, 0x00, 0x00, dado.getBytes(), 0, [0x9000]);
162 
163 //	print(dadobin);
164 
165 	var dado = new ASN1(dadobin);
166 	assert(dado.tag == 0x7C);
167 	assert(dado.elements == 2);
168 	var nonceDO = dado.get(0);
169 	assert(nonceDO.tag == 0x81);
170 	var nonce = nonceDO.value;
171 
172 	var authTokenDO = dado.get(1);
173 	assert(authTokenDO.tag == 0x82);
174 	var authToken = authTokenDO.value;
175 
176 	var enc = new ByteString("04", HEX);
177 	enc = enc.concat(devAuthPK.getComponent(Key.ECC_QX));
178 	enc = enc.concat(devAuthPK.getComponent(Key.ECC_QY));
179 
180 	GPSystem.trace("Encoded CA public key: " + enc);
181 	ca.performKeyAgreement(enc, nonce);
182 	var result = ca.verifyAuthenticationToken(authToken);
183 
184 	if (!result) {
185 		GPSystem.trace("Authentication token invalid");
186 		throw new Error("Authentication token invalid");
187 	}
188 	GPSystem.trace("Authentication token valid");
189 	var sm = new IsoSecureChannel(crypto);
190 	sm.setEncKey(ca.kenc);
191 	sm.setMacKey(ca.kmac);
192 	sm.setMACSendSequenceCounter(new ByteString("0000000000000000", HEX));
193 
194 	this.card.setCredential(sm);
195 	return sm;
196 }
197 
198 
199 
200 /**
201  * Update transparent EF referenced by file identifier
202  *
203  * @param {ByteString} fid the two byte file identifier
204  * @param {Number} offset the offset into the EF
205  * @param {ByteString} data the data to write
206  */
207 SmartCardHSM.prototype.updateBinary = function(fid, offset, data) {
208 
209 	var bytesLeft = data.length;
210 	var offset = 0;
211 
212 	while (bytesLeft > 0) {
213 		var toSend = bytesLeft >= this.maxAPDU ? this.maxAPDU : bytesLeft;
214 
215 		var t54 = new ASN1(0x54, ByteString.valueOf(offset, 2));
216 		var t53 = new ASN1(0x53, data.bytes(offset, toSend));
217 
218 		var cdata = t54.getBytes().concat(t53.getBytes());
219 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, fid.byteAt(0), fid.byteAt(1), cdata, [0x9000]);
220 
221 		bytesLeft -= toSend;
222 		offset += toSend;
223 	}
224 }
225 
226 
227 
228 /**
229  * Read transparent EF referenced by file identifier
230  *
231  * @param {ByteString} fid the two byte file identifier
232  * @param {Number} offset the offset into the EF (optional)
233  * @param {Number} length the number of byte to read (optional)
234  * @type ByteString
235  * @return the data read from the EF
236  */
237 SmartCardHSM.prototype.readBinary = function(fid, offset, length) {
238 	if (typeof(offset) == "undefined") {
239 		offset = 0;
240 	}
241 
242 	var rsp = new ByteBuffer();
243 	do	{
244 		var t54 = new ASN1(0x54, ByteString.valueOf(offset, 2));
245 
246 		if (length) {					// Is a length defined ?
247 			var le = length > this.maxAPDU ? this.maxAPDU : length;			// Truncate if larger than maximum APDU size ?
248 		} else {
249 			var le = this.maxAPDU < 256 ? 0 : 65536;						// Get all with Le=0 in either short or extended APDU mode
250 		}
251 
252 		var data = this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xB1, fid.byteAt(0), fid.byteAt(1), t54.getBytes(), le, [0x9000, 0x6282]);
253 
254 		rsp.append(data);
255 		offset += data.length;
256 
257 		if (le == 65536) {				// Only a single command required when send as extended length APDU
258 			break;
259 		}
260 		if (length) {					// Length was defined, see if we already got everything
261 			length -= data.length;
262 			if (length <= 0) {
263 				break;
264 			}
265 		}
266 	} while ((this.card.SW == 0x9000) && (data.length > 0));
267 
268 	return rsp.toByteString();
269 }
270 
271 
272 
273 /**
274  * Delete file system object (EF or key)
275  *
276  * @param {ByteString} fid the two byte file object identifier
277  */
278 SmartCardHSM.prototype.deleteFile = function(fid) {
279 	return this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xE4, 0x02, 0x00, fid, [0x9000]);
280 }
281 
282 
283 
284 /**
285  * Strips leading zeros of a ByteString
286  *
287  * @param {ByteString} value the ByteString value
288  * @return the stripped ByteString object, may be an empty ByteString
289  * @type ByteString
290  */
291 SmartCardHSM.stripLeadingZeros = function(value) {
292 	var i = 0;
293 	for (; (i < value.length) && (value.byteAt(i) == 0); i++);
294 	
295 	return value.right(value.length - i);
296 }
297 
298 
299 
300 /**
301  * Build input for Generate Asymmetric Key Pair command for generating an ECC key pair
302  *
303  * @param {PublicKeyReference} innerCAR the CA the request shall be directed to
304  * @param {ByteString} algo the public key algorithm
305  * @param {PublicKeyReference} chr the certificate holder reference associated with this key
306  * @param {Key} dp the domain parameter for the key
307  * @param {PublicKeyReference} outerCAR the certificate holder reference of the public key for verifying the outer signature
308  * @param {Key} privateKey optional parameter to supply a private key value for import. This only works with the development version
309  *              of the SmartCard-HSM.
310  * @type ByteString
311  * @return the encoded C-Data for GENERATE ASYMMETRIC KEY PAIR
312  */
313 SmartCardHSM.buildGAKPwithECC = function(innerCAR, algo, chr, dp, outerCAR, priKey) {
314 
315 	// Encode G
316 	var bb = new ByteBuffer();
317 	// uncompressed encoding
318 	bb.append(new ByteString("04", HEX));
319 	bb.append(dp.getComponent(Key.ECC_GX));
320 	bb.append(dp.getComponent(Key.ECC_GY));
321 	var G = bb.toByteString();
322 
323 	var t = new ASN1(0x30,
324 				new ASN1("CPI", 0x5F29, new ByteString("00", HEX)),
325 				new ASN1("CAR", 0x42, innerCAR.getBytes()),
326 				new ASN1("Public Key", 0x7F49,
327 					new ASN1("Object Identifier", 0x06, algo),
328 					new ASN1("Prime Modulus", 0x81, dp.getComponent(Key.ECC_P)),
329 					new ASN1("First coefficient a", 0x82, dp.getComponent(Key.ECC_A)),
330 					new ASN1("Second coefficient b", 0x83, dp.getComponent(Key.ECC_B)),
331 					new ASN1("Base Point G", 0x84, G),
332 					new ASN1("Order of the base point", 0x85, dp.getComponent(Key.ECC_N)),
333 					new ASN1("Cofactor f", 0x87, SmartCardHSM.stripLeadingZeros(dp.getComponent(Key.ECC_H)))
334 				),
335 				new ASN1("CHR", 0x5F20, chr.getBytes())
336 			);
337 	
338 	if (typeof(outerCAR) != "undefined") {
339 		t.add(new ASN1("OuterCAR", 0x45, outerCAR.getBytes()));
340 	}
341 	
342 	if (priKey != undefined) {
343 		var d = new ASN1("Private Key", 0x8A, priKey.getComponent(Key.ECC_D));
344 		t.get(2).add(d);
345 //		print(t);
346 	}
347 	return t.value;
348 }
349 
350 
351 
352 /**
353  * Build input for Generate Asymmetric Key Pair command for generating a RSA key pair
354  *
355  * @param {PublicKeyReference} innerCAR the CA the request shall be directed to
356  * @param {ByteString} algo the public key algorithm
357  * @param {PublicKeyReference} chr the certificate holder reference associated with this key
358  * @param {Number} keysize the module size in bits (1024, 1536 or 2048)
359  * @param {PublicKeyReference} outerCAR the certificate holder reference of the public key for verifying the outer signature
360  * @type ByteString
361  * @return the encoded C-Data for GENERATE ASYMMETRIC KEY PAIR
362  */
363 SmartCardHSM.buildGAKPwithRSA = function(innerCAR, algo, chr, keysize, outerCAR) {
364 
365 	var t = new ASN1(0x30,
366 				new ASN1("CPI", 0x5F29, new ByteString("00", HEX)),
367 				new ASN1("CAR", 0x42, innerCAR.getBytes()),
368 				new ASN1("Public Key", 0x7F49,
369 					new ASN1("Object Identifier", 0x06, algo),
370 					new ASN1("Public Key Exponent", 0x82, ByteString.valueOf(65537)),
371 					new ASN1("Key Size", 0x02, ByteString.valueOf(keysize))
372 				),
373 				new ASN1("CHR", 0x5F20, chr.getBytes())
374 			);
375 	
376 	if (typeof(outerCAR) != "undefined") {
377 		t.add(new ASN1("OuterCAR", 0x45, outerCAR.getBytes()));
378 	}
379 	return t.value;
380 }
381 
382 
383 
384 /**
385  * Create a PKCS#15 PrivateECCKey description
386  *
387  * @param {Number} keyid the key identifier
388  * @param {String} label the key label
389  * @type ASN1
390  * @return the PrivateECCKey description
391  */
392 SmartCardHSM.buildPrkDforECC = function(keyid, label, keysize) {
393 	var prkd = 	new ASN1(0xA0,
394 					new ASN1(ASN1.SEQUENCE, 
395 						new ASN1(ASN1.UTF8String, new ByteString(label, UTF8))
396 //						new ASN1(ASN1.BIT_STRING, new ByteString("0780", HEX)),
397 //						new ASN1(ASN1.OCTET_STRING, new ByteString("01", HEX))
398 					),
399 					new ASN1(ASN1.SEQUENCE,
400 						new ASN1(ASN1.OCTET_STRING, ByteString.valueOf(keyid)),
401 						new ASN1(ASN1.BIT_STRING, new ByteString("072080", HEX))
402 					),
403 					new ASN1(0xA1,
404 						new ASN1(ASN1.SEQUENCE,
405 							new ASN1(ASN1.SEQUENCE,
406 								new ASN1(ASN1.OCTET_STRING, new ByteString("", HEX))
407 							)
408 						)
409 					)
410 				);
411 
412 	if (keysize != undefined) {
413 		assert(keysize > 0);
414 		var tlvint = ByteString.valueOf(keysize);
415 		if (tlvint.byteAt(0) >= 0x80) {
416 			tlvint = (new ByteString("00", HEX)).concat(tlvint);
417 		}
418 		prkd.get(2).get(0).add(new ASN1(ASN1.INTEGER, tlvint));
419 	}
420 	
421 //	print(prkd);
422 	return prkd;
423 }
424 
425 
426 
427 /**
428  * Create a PKCS#15 PrivateRSAKey description
429  *
430  * @param {Number} keyid the key identifier
431  * @param {String} label the key label
432  * @param {Number} modulussize
433  * @type ASN1
434  * @return the PrivateECCKey description
435  */
436 SmartCardHSM.buildPrkDforRSA = function(keyid, label, modulussize) {
437 	var prkd = 	new ASN1(0x30,
438 					new ASN1(ASN1.SEQUENCE, 
439 						new ASN1(ASN1.UTF8String, new ByteString(label, UTF8))
440 //						new ASN1(ASN1.BIT_STRING, new ByteString("0780", HEX)),
441 //						new ASN1(ASN1.OCTET_STRING, new ByteString("01", HEX))
442 					),
443 					new ASN1(ASN1.SEQUENCE,
444 						new ASN1(ASN1.OCTET_STRING, ByteString.valueOf(keyid)),
445 						new ASN1(ASN1.BIT_STRING, new ByteString("0274", HEX))
446 					),
447 					new ASN1(0xA1,
448 						new ASN1(ASN1.SEQUENCE,
449 							new ASN1(ASN1.SEQUENCE,
450 								new ASN1(ASN1.OCTET_STRING, new ByteString("", HEX))
451 							),
452 							new ASN1(ASN1.INTEGER, ByteString.valueOf(modulussize))
453 						)
454 					)
455 				);
456 //	print(prkd);
457 	return prkd;
458 }
459 
460 
461 
462 /**
463  * Dump C-Data of Generate Asymmetric Key Pair command
464  *
465  * @param {ByteString} keydata the content of C-Data
466  */
467 SmartCardHSM.dumpKeyData = function(keydata) {
468 	print(keydata);
469 	var a = new ASN1(0x30, keydata);
470 	var a = new ASN1(a.getBytes());
471 	for (var i = 0; i < a.elements; i++) {
472 		print(a.get(i));
473 	}
474 }
475 
476 
477 
478 /**
479  * Generate an asymmetric key pair
480  *
481  * @param {Number} newkid key identifier for new key
482  * @param {Number} signkid key identifier for signing the new public key
483  * @param {ByteString} keydata the key data template
484  * @type ByteString
485  * @return the certificate signing request containing the new public key
486  */
487 SmartCardHSM.prototype.generateAsymmetricKeyPair = function(newkid, signkid, keydata) {
488 
489 	if (this.maxAPDU > 255) { // Use extended length
490 		var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x46, newkid, signkid, keydata, 65536, [0x9000]);
491 	} else {
492 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x46, newkid, signkid, keydata, [0x9000]);
493 		var rsp = this.readBinary(ByteString.valueOf(0xCE00 + newkid), 0);
494 	}
495 
496 	return rsp;
497 }
498 
499 
500 
501 /**
502  * Initialize device and clear all keys and files
503  *
504  * @param {ByteString} options two byte option mask
505  * @param {ByteString} initialPIN initial user PIN value
506  * @param {ByteString} initializationCode secret code for device initialization (set during first use)
507  * @param {Number} retryCounterInitial retry counter for user PIN
508  * @param {Number} keyshares number of device key encryption key shares (optional)
509  */
510 SmartCardHSM.prototype.initDevice = function(options, initialPIN, initializationCode, retryCounterInitial, keyshares) {
511 	var s = new ASN1(0x30,
512 				new ASN1(0x80, options),
513 				new ASN1(0x81, initialPIN),
514 				new ASN1(0x82, initializationCode),
515 				new ASN1(0x91, ByteString.valueOf(retryCounterInitial))
516 				);
517 	
518 	if (typeof(keyshares) != "undefined") {
519 		s.add(new ASN1(0x92, ByteString.valueOf(keyshares)));
520 	}
521 	this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000]);
522 }
523 
524 
525 
526 /**
527  * Import DKEK share or query status
528  *
529  * @param {ByteString} keyshare 32 byte key share
530  * @type Object
531  * @return object with properties sw{Number}, shares{Number}, outstanding{Number} and kcv{ByteString}
532  */
533 SmartCardHSM.prototype.importKeyShare = function(keyshare) {
534 	if (typeof(keyshare) != "undefined") {
535 		var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x00, 0x00, keyshare, 0);
536 	} else {
537 		var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x00, 0x00, 0);
538 	}
539 	if (status.length == 0) {
540 		return { sw: this.card.SW };
541 	}
542 	return { sw: this.card.SW, shares: status.byteAt(0), outstanding: status.byteAt(1), kcv: status.bytes(2) };
543 }
544 
545 
546 
547 /**
548  * Wrap key under DKEK
549  *
550  * @param {Number} id key id
551  * @type ByteString
552  * @return key blob with encrypted key value
553  */
554 SmartCardHSM.prototype.wrapKey = function(id) {
555 	var keyblob = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x72, id, 0x92, 65536, [0x9000]);
556 	return keyblob;
557 }
558 
559 
560 
561 /**
562  * Unwrap key with DKEK
563  *
564  * @param {Number} id key id
565  * @param {ByteString} keyblob the wrapped key
566  */
567 SmartCardHSM.prototype.unwrapKey = function(id, keyblob) {
568 	this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x74, id, 0x93, keyblob, [0x9000]);
569 }
570 
571 
572 
573 /**
574  * Verify User PIN
575  *
576  * @param {ByteString} userPIN user PIN value
577  * @return the status word SW1/SW2 returned by the device
578  */
579 SmartCardHSM.prototype.verifyUserPIN = function(userPIN) {
580 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x20, 0x00, 0x81, userPIN);
581 	return this.card.SW;
582 }
583 
584 
585 
586 /**
587  * Logout
588  *
589  */
590 SmartCardHSM.prototype.logout = function() {
591 	this.card.sendApdu(0x00, 0xA4, 0x04, 0x04, new ByteString("E82B0601040181C31F0201", HEX), [0x9000]);
592 }
593 
594 
595 
596 /**
597  * Change User PIN
598  *
599  * @param {ByteString} currentPIN current user PIN value
600  * @param {ByteString} newPIN new user PIN value
601  */
602 SmartCardHSM.prototype.changeUserPIN = function(currentPIN, newPIN) {
603 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x24, 0x00, 0x81, currentPIN.concat(newPIN), [0x9000]);
604 }
605 
606 
607 
608 /**
609  * Request PIN Status Information
610  *
611  * @type Number
612  * @return the status word SW1/SW2 returned by the device
613  */
614 SmartCardHSM.prototype.queryUserPINStatus = function() {
615 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x20, 0x00, 0x81, 0, [0x9000, 0x63C7, 0x63C6, 0x63C5, 0x63C4, 0x63C3, 0x63C2, 0x63C1, 0x6983, 0x6984]);
616 	return this.card.SW;
617 }
618 
619 
620 
621 /**
622  * Enumerate Objects
623  *
624  * @return the enumeration
625  */
626 SmartCardHSM.prototype.enumerateObjects = function() {
627 	var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x58, 0x00, 0x00, 65536, [0x9000]);
628 	return rsp;
629 }
630 
631 
632 
633 /**
634  * Generate random data
635  *
636  * @param {Number} length number of bytes
637  * @return the random bytes
638  */
639 SmartCardHSM.prototype.generateRandom = function(length) {
640 	var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x84, 0x00, 0x00, length, [0x9000]);
641 	return rsp;
642 }
643 
644 
645 
646 /**
647  * Sign data using referenced key
648  *
649  * @param {Number} keyid the key identifier for signing
650  * @param {algo} algo the algorithm identifier
651  * @param {ByteString} data the data to be signed
652  * @return the signature value
653  */
654 SmartCardHSM.prototype.sign = function(keyid, algo, data) {
655 	var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x68, keyid, algo, data, 0x00, [0x9000]);
656 	return rsp;
657 }
658 
659 
660 
661 /**
662  * Decipher cryptogram or agree shared secret using Diffie-Hellman
663  *
664  * @param {Number} keyid the key identifier
665  * @param {Number} algo the algorithm identifier
666  * @param {ByteString} data the the cryptogram or concatenation of x || y of ECC public key
667  * @return the plain output
668  */
669 SmartCardHSM.prototype.decipher = function(keyid, algo, data) {
670 	var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x62, keyid, algo, data, 0x00, [0x9000]);
671 	return rsp;
672 }
673 
674 
675 
676 /**
677  * Enumerate key objects in the SmartCard-HSM and build the map of keys
678  *
679  * @type String[]
680  * @return the list of key labels
681  */
682 SmartCardHSM.prototype.enumerateKeys = function() {
683 	this.namemap = [];
684 	this.idmap = [];
685 
686 	var fobs = this.enumerateObjects();
687 	
688 	// Process keys
689 	for (var i = 0; i < fobs.length; i += 2) {
690 		if (fobs.byteAt(i) == SmartCardHSM.KEYPREFIX) {
691 			var kid = fobs.byteAt(i + 1);
692 			if (kid > 0) {
693 //				print("Found key: " + kid);
694 				this.idmap[kid] = new SmartCardHSMKey(this, kid);
695 			}
696 		}
697 	}
698 	
699 	var keylist = [];
700 	// Process PKCS#15 private key descriptions
701 	for (var i = 0; i < fobs.length; i += 2) {
702 		if (fobs.byteAt(i) == SmartCardHSM.PRKDPREFIX) {
703 			var kid = fobs.byteAt(i + 1);
704 			var descbin = this.readBinary(fobs.bytes(i, 2));
705 			var desc = new ASN1(descbin);
706 			var key = this.idmap[kid];
707 			if (key) {
708 				key.setDescription(desc);
709 				var label = key.getLabel();
710 //				print(key.getId() + " - " + label);
711 				keylist.push(label);
712 				this.namemap[label] = key;
713 			}
714 		}
715 	}
716 	
717 	return keylist;
718 }
719 
720 
721 
722 /**
723  * Determine an unused key identifier
724  *
725  * @type Number
726  * @return a free key identifier or -1 if all key identifier in use
727  */
728 SmartCardHSM.prototype.determineFreeKeyId = function() {
729 	for (var i = 1; i < 256; i++) {
730 		if (this.idmap[i] == undefined) {
731 			return i;
732 		}
733 	}
734 	return -1;
735 }
736 
737 
738 
739 /**
740  * Add a new key to the map of keys
741  *
742  * @param {HSMKey} key the HSM key
743  */
744 SmartCardHSM.prototype.addKeyToMap = function(key) {
745 	var label = key.getLabel();
746 	var id = key.getId();
747 	this.namemap[label] = key;
748 	this.idmap[id] = key;
749 }
750 
751 
752 
753 /**
754  * Get a key reference object
755  *
756  * @param {String} path the relative path of the PKI element (e.g. "/UTCVCA1/UTDVCA1/UTTERM")
757  * @returns the key or null if not found
758  * @type Key
759  */
760 SmartCardHSM.prototype.getKey = function(label) {
761 	var key = this.namemap[label];
762 	if (key == undefined) {
763 		return null;
764 	}
765 	return key;
766 }
767 
768 
769 
770 /**
771  * Get crypto object
772  *
773  * @type HSMCrypto
774  * @return the HSMCrypto object
775  */
776 SmartCardHSM.prototype.getCrypto = function() {
777 	if (this.crypto == undefined) {
778 		this.crypto = new SmartCardHSMCrypto(new Crypto());
779 	}
780 	return this.crypto;
781 }
782 
783 
784 
785 /**
786  * Create crypto object implementing access to the SmartCard-HSM
787  *
788  * @class Wrapper to provide Crypto interface to SmartCard-HSM
789  * @constructor
790  * @param {Crypto} crypto the backend crypto provider
791  */
792 function SmartCardHSMCrypto(crypto) {
793 	this.crypto = crypto;
794 }
795 
796 
797 
798 /**
799  * Sign a message using the defined mechanism and key
800  *
801  * @param {HSMKey} key the private key
802  * @param {Number} mech the mechanism (e.g. Crypto.ECDSA)
803  * @param {ByteString} message the message to be signed
804  * @type ByteString
805  * @return the signature
806  */
807 SmartCardHSMCrypto.prototype.sign = function(key, mech, message) {
808 	if (key instanceof SmartCardHSMKey) {
809 		return key.sign(mech, message);
810 	} else {
811 		return this.crypto.sign(key, mech, message);
812 	}
813 }
814 
815 
816 
817 /**
818  * Verify a message using the defined mechanism and key
819  *
820  * @param {Key} key the public key
821  * @param {Number} mech the mechanism (e.g. Crypto.ECDSA)
822  * @param {ByteString} message the message to be signed
823  * @param {ByteString} signature the signature to verify
824  * @type Boolean
825  * @return true if signature is valid
826  */
827 SmartCardHSMCrypto.prototype.verify = function(key, mech, message, signature) {
828 	return this.crypto.verify(key, mech, message, signature);
829 }
830 
831 
832 
833 /**
834  * Create a key access object
835  *
836  * @class Class implementing key access
837  * @param {SmartCardHSM} sc the card access object
838  * @param {Number} id the key identifier
839  */
840 function SmartCardHSMKey(sc, id) {
841 	this.sc = sc;
842 	this.id = id;
843 }
844 
845 
846 
847 /**
848  * Set the PKCS#15 private key description
849  *
850  * @param {ASN1} desc the description
851  */
852 SmartCardHSMKey.prototype.setDescription = function(desc) {
853 	this.desc = desc;
854 }
855 
856 
857 
858 /**
859  * Return the key identifier
860  *
861  * @type Number
862  * @return the key identifier
863  */
864 SmartCardHSMKey.prototype.getId = function() {
865 	return this.id;
866 }
867 
868 
869 
870 /**
871  * Return the key label as encoded in the PKCS#15 structure
872  *
873  * @type String
874  * @return the key label
875  */
876 SmartCardHSMKey.prototype.getLabel = function() {
877 	if (this.desc == undefined) {
878 		return undefined;
879 	}
880 	return this.desc.get(0).get(0).value.toString(UTF8);
881 }
882 
883 
884 
885 /**
886  * Return the key size in bits
887  *
888  * @type Number
889  * @return the key size in bits
890  */
891 SmartCardHSMKey.prototype.getSize = function() {
892 	if (this.desc == undefined) {
893 		return undefined;
894 	}
895 //	print(this.desc);
896 	if (this.desc.get(2).elements > 1) {	// Fix a bug from early versions
897 		return this.desc.get(2).get(1).value.toUnsigned();
898 	} else {
899 		return this.desc.get(2).get(0).get(1).value.toUnsigned();
900 	}
901 }
902 
903 
904 
905 /**
906  * Sign data using a key in the SmartCard-HSM
907  *
908  * @param {ByteString} data to be signed
909  * @param {Number} mech the signing mechanism
910  * @type ByteString
911  * @return the signature
912  */
913 SmartCardHSMKey.prototype.sign = function(mech, data) {
914 	if (mech) {
915 		switch(mech) {
916 		case Crypto.RSA:
917 			algo = 0x20;
918 			break;
919 		case Crypto.RSA_SHA1:
920 			algo = 0x31;
921 			break;
922 		case Crypto.RSA_SHA256:
923 			algo = 0x33;
924 			break;
925 		case Crypto.RSA_PSS_SHA1:
926 			algo = 0x41;
927 			break;
928 		case Crypto.RSA_PSS_SHA256:
929 			algo = 0x43;
930 			break;
931 		case Crypto.ECDSA:
932 			algo = 0x70;
933 			break;
934 		case Crypto.ECDSA_SHA1:
935 			algo = 0x71;
936 			break;
937 		case Crypto.ECDSA_SHA224:
938 			algo = 0x72;
939 			break;
940 		case Crypto.ECDSA_SHA256:
941 			algo = 0x73;
942 			break;
943 		default:
944 			throw new GPError("SmartCardHSMKey", GPError.INVALID_DATA, mech, "Unsupported crypto mechanism");
945 		}
946 	}
947 
948 	return this.sc.sign(this.id, algo, data);
949 }
950 
951 
952 
953 /**
954  * Return human readable string
955  */
956 SmartCardHSMKey.prototype.toString = function() {
957 	return "SmartCardHSMKey(id=" + this.id + ")";
958 }
959 
960 
961 
962 SmartCardHSM.test = function() {
963 	var crypto = new Crypto();
964 	var card = new Card(_scsh3.reader);
965 	var sc = new SmartCardHSM(card);
966 
967 	var pubKey = sc.validateCertificateChain(crypto);
968 	sc.openSecureChannel(crypto, pubKey);
969 
970 	sc.verifyUserPIN(new ByteString("648219", ASCII));
971 	var list = sc.enumerateKeys();
972 	print("Keys on device: " + list);
973 	
974 	var crypto = sc.getCrypto();
975 	var message = new ByteString("Hello World", ASCII);
976 	var key = sc.getKey(list[0]);
977 	var signature = crypto.sign(key, Crypto.ECDSA, message);
978 	print("Signature: " + signature);
979 }
980