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 Class implementing a key store for X.509 certificate and private keys stored on a SmartCard-HSM
 25  */
 26 
 27 var PublicKeyReference = require('scsh/eac/PublicKeyReference').PublicKeyReference;
 28 var SmartCardHSM = require('scsh/sc-hsm/SmartCardHSM').SmartCardHSM;
 29 var SmartCardHSMKey = require('scsh/sc-hsm/SmartCardHSM').SmartCardHSMKey;
 30 var CVC = require("scsh/eac/CVC").CVC;
 31 
 32 
 33 
 34 /**
 35  * Create a simple key store front-end
 36  *
 37  * @class Class implementing some simple access functions to generate key pairs and store certificates
 38  * @param {SmartCardHSM} sc the SmartCard-HSM card service
 39  */
 40 function HSMKeyStore(sc) {
 41 	this.sc = sc;
 42 	this.chr = new PublicKeyReference("UTNULL00000");
 43 	this.car = new PublicKeyReference("UTNULL00000");
 44 }
 45 
 46 exports.HSMKeyStore = HSMKeyStore;
 47 
 48 
 49 
 50 /**
 51  * Generate a key pair
 52  *
 53  * @param {String} label the label under which the key pair shall be stored
 54  * @param {SmartCardHSMKeySpecGenerator} initialized key spec generator
 55  * @type CVC
 56  * @return the authenticated request
 57  */
 58 HSMKeyStore.prototype.generateKeyPair = function(label, spec) {
 59 
 60 	if ((spec.keytype != Crypto.RSA) && (spec.keytype != Crypto.EC)) {
 61 		throw new GPError("HSMKeyStore", GPError.INVALID_DATA, 0, "Unsupported key type");
 62 	}
 63 
 64 	var key = this.sc.getKey(label);
 65 	if (key) {
 66 		throw new GPError("HSMKeyStore", GPError.INVALID_DATA, 0, "Key with label " + label + " does already exist");
 67 	}
 68 
 69 	var newkid = this.sc.determineFreeKeyId();
 70 	var reqbin = this.sc.generateAsymmetricKeyPair(newkid, 0, spec.encode());
 71 	var req = new CVC(reqbin);
 72 	var keyid = req.determineKeyIdentifier();
 73 
 74 	switch(spec.keytype) {
 75 		case Crypto.RSA:
 76 			var keydesc = SmartCardHSM.buildPrkDforRSA(keyid, label, spec.keysize);
 77 			break;
 78 		case Crypto.EC:
 79 			var keydesc = SmartCardHSM.buildPrkDforECC(keyid, label, spec.domainParameter.getSize());
 80 			break;
 81 		default:
 82 			throw new GPError("HSMKeyStore", GPError.INVALID_DATA, 0, "Unsupported key type");
 83 	}
 84 
 85 	var fid = ByteString.valueOf((SmartCardHSM.PRKDPREFIX << 8) + newkid);
 86 	this.sc.updateBinary(fid, 0, keydesc.getBytes());
 87 
 88 	var hkey = new SmartCardHSMKey(this.sc, newkid);
 89 	hkey.setDescription(keydesc);
 90 	this.sc.addKeyToMap(hkey);
 91 	return req;
 92 }
 93 
 94 
 95 
 96 /**
 97  * Generate a symmetric key
 98  *
 99  * @param {String} label the label under which the key shall be stored
100  * @param {SmartCardHSMKeySpecGenerator} initialized key spec generator
101  * @type ByteString
102  * @return the new key wrapped with the symmetric key defined with SmartCardHSMKeySpecGenerator.setWrappingKey()
103  */
104 HSMKeyStore.prototype.generateKey = function(label, spec) {
105 
106 	if (spec.keytype != Crypto.AES) {
107 		throw new GPError("HSMKeyStore", GPError.INVALID_DATA, 0, "Unsupported key type");
108 	}
109 
110 	var key = this.sc.getKey(label);
111 	if (key) {
112 		throw new GPError("HSMKeyStore", GPError.INVALID_DATA, 0, "Key with label " + label + " does already exist");
113 	}
114 
115 	var newkid = this.sc.determineFreeKeyId();
116 
117 	var genalg;
118 	switch(spec.keysize) {
119 		case 128: genalg = 0xB0; break;
120 		case 192: genalg = 0xB1; break;
121 		case 256: genalg = 0xB2; break;
122 		throw new GPError("HSMKeyStore", GPError.INVALID_DATA, 0, "Unsupported key size");
123 	}
124 
125 	var wrapbin = this.sc.generateSymmetricKey(newkid, genalg, spec.encode());
126 
127 	var deralg;
128 	if (spec.algorithms.find(ByteString.valueOf(SmartCardHSM.ALG_CMAC)) >= 0) {
129 		deralg = SmartCardHSM.ALG_CMAC;
130 	} else if (spec.algorithms.find(ByteString.valueOf(SmartCardHSM.ALG_DERIVE_SP800_56C)) >= 0) {
131 		deralg = SmartCardHSM.ALG_DERIVE_SP800_56C;
132 	}
133 
134 	var keyid;
135 	if (deralg) {
136 		keyid = this.sc.deriveSymmetricKey(newkid, deralg, new ByteString("KeyCheckValue", ASCII)).left(8);
137 	} else {
138 		keyid = ByteString.valueOf(newkid);
139 	}
140 
141 	var keydesc = SmartCardHSM.buildSKDforAES(keyid, label, spec.keysize);
142 
143 	var fid = ByteString.valueOf((SmartCardHSM.PRKDPREFIX << 8) + newkid);
144 	this.sc.updateBinary(fid, 0, keydesc.getBytes());
145 
146 	var hkey = new SmartCardHSMKey(this.sc, newkid);
147 	hkey.setDescription(keydesc);
148 	this.sc.addKeyToMap(hkey);
149 	return wrapbin;
150 }
151 
152 
153 
154 /**
155  * Generate a RSA key pair
156  *
157  * @param {String} label the label under which the key pair shall be stored
158  * @param {Number} keysize the key size in bits (1024, 1536 or 2048)
159  */
160 HSMKeyStore.prototype.generateRSAKeyPair = function(label, keysize) {
161 
162 	var key = this.sc.getKey(label);
163 	if (key) {
164 		var newkid = key.getId();
165 	} else {
166 		var newkid = this.sc.determineFreeKeyId();
167 	}
168 
169 	var algo = new ByteString("id-TA-RSA-v1-5-SHA-256", OID);
170 
171 	var keydata = SmartCardHSM.buildGAKPwithRSA(this.car, algo, this.chr, keysize);
172 	var keydesc = SmartCardHSM.buildPrkDforRSA(newkid, label, keysize);
173 
174 	var reqbin = this.sc.generateAsymmetricKeyPair(newkid, 0, keydata);
175 
176 	var fid = ByteString.valueOf((SmartCardHSM.PRKDPREFIX << 8) + newkid);
177 	this.sc.updateBinary(fid, 0, keydesc.getBytes());
178 	var req = new CVC(reqbin);
179 
180 	var hkey = new SmartCardHSMKey(this.sc, newkid);
181 	hkey.setDescription(keydesc);
182 	this.sc.addKeyToMap(hkey);
183 	return req;
184 }
185 
186 
187 
188 /**
189  * Generate an ECDSA key pair
190  *
191  * @param {String} label the label under which the key pair shall be stored
192  * @param {String} curve the curve object identifier
193  */
194 HSMKeyStore.prototype.generateECCKeyPair = function(label, curve) {
195 
196 	var key = this.sc.getKey(label);
197 	if (key) {
198 		var newkid = key.getId();
199 	} else {
200 		var newkid = this.sc.determineFreeKeyId();
201 	}
202 
203 	var algo = new ByteString("id-TA-ECDSA-SHA-256", OID);
204 
205 	var dp = new Key();
206 	dp.setComponent(Key.ECC_CURVE_OID, new ByteString(curve, OID));
207 
208 	var keydata = SmartCardHSM.buildGAKPwithECC(this.car, algo, this.chr, dp);
209 //	print("Keysize: " + dp.getSize());
210 	var keydesc = SmartCardHSM.buildPrkDforECC(newkid, label, dp.getSize());
211 
212 	var reqbin = this.sc.generateAsymmetricKeyPair(newkid, 0, keydata);
213 
214 	var fid = ByteString.valueOf((SmartCardHSM.PRKDPREFIX << 8) + newkid);
215 	this.sc.updateBinary(fid, 0, keydesc.getBytes());
216 	var req = new CVC(reqbin);
217 
218 	var hkey = new SmartCardHSMKey(this.sc, newkid);
219 	hkey.setDescription(keydesc);
220 	this.sc.addKeyToMap(hkey);
221 
222 	return req;
223 }
224 
225 
226 
227 /**
228  * Import a key blob, meta data and certificate
229  *
230  * @param {ByteString} keywrap the binary key in SmartCard-HSM format
231  */
232 HSMKeyStore.prototype.importKey = function(keywrap) {
233 
234 	var a = new ASN1(keywrap);
235 
236 	var wrap = a.get(0).value;
237 	var id = this.sc.determineFreeKeyId();
238 
239 	if (id < 0) {
240 		throw new GPError("HSMKeyStore", GPError.INVALID_DATA, 0, "Key identifier exhausted");
241 	}
242 
243 	this.sc.unwrapKey(id, wrap);
244 
245 	var hkey = new SmartCardHSMKey(this.sc, id);
246 
247 	if (a.elements > 1) {
248 		var meta = a.get(1);
249 		this.sc.updateBinary(ByteString.valueOf((SmartCardHSM.PRKDPREFIX << 8) + id), 0, meta.getBytes());
250 		hkey.setDescription(meta);
251 	}
252 
253 	var bin = new ByteString("", HEX);
254 	for (var i = 2; i < a.elements; i++) {
255 		var cert = a.get(i);
256 		bin = bin.concat(cert.getBytes());
257 	}
258 	this.sc.updateBinary(ByteString.valueOf((SmartCardHSM.EECERTIFICATEPREFIX << 8) + id), 0, bin);
259 
260 	this.sc.addKeyToMap(hkey);
261 
262 	return hkey;
263 }
264 
265 
266 
267 /**
268  * Export a key blob, meta data and certificate
269  *
270  * @param {String/Number/Key} labelOrIdOrKey the label, id or object of the key to be removed
271  * @type ByteString
272  * @return the blob with key, meta data and certificate
273  */
274 HSMKeyStore.prototype.exportKey = function(labelOrIdOrKey) {
275 
276 	var key = labelOrIdOrKey;
277 	if (!(key instanceof SmartCardHSMKey)) {
278 		key = this.getKey(labelOrIdOrKey);
279 	}
280 
281 	if (key) {
282 		var id = key.getId();
283 	} else {
284 		throw new GPError("HSMKeyStore", GPError.INVALID_DATA, 0, "Could not find a key with label or id " + labelOrIdOrKey);
285 	}
286 
287 	var wrap = this.sc.wrapKey(id);
288 	var a = new ASN1(0x30, new ASN1(0x04, wrap));
289 
290 	try	{
291 		var meta = this.sc.readBinary(ByteString.valueOf((SmartCardHSM.PRKDPREFIX << 8) + id));
292 		a.add(new ASN1(meta));
293 
294 		var fid = ByteString.valueOf((SmartCardHSM.EECERTIFICATEPREFIX << 8) + id);
295 		if (this.sc.hasFile(fid)) {
296 			var cert = this.sc.readBinary(fid);
297 
298 			// Copy list of CVCs
299 			if ((cert.byteAt(0) == 0x67) || (cert.byteAt(0) == 0x7F)) {
300 				var list = SmartCardHSM.parseCertificateList(cert);
301 				for (var i = 0; i < list.length; i++) {
302 					a.add(list[i].getASN1());
303 				}
304 				if ((cert.byteAt(0) == 0x67) && (list.length == 1)) {
305 					print("Adding device and DICA certificate to export");
306 					var devAutCert = this.sc.readBinary(SmartCardHSM.C_DevAut);
307 					var list = SmartCardHSM.parseCertificateList(devAutCert);
308 					for (var i = 0; i < list.length; i++) {
309 						a.add(list[i].getASN1());
310 					}
311 				}
312 			} else {
313 				a.add(new ASN1(cert));
314 			}
315 		}
316 	}
317 	catch(e) {
318 		print("Ignoring meta data or certificate: " + e);
319 	}
320 
321 	return a.getBytes();
322 }
323 
324 
325 
326 /**
327  * Import a RSA key blob
328  *
329  * @param {String} label the key label
330  * @param {ByteString} keyblob the binary key in SmartCard-HSM format
331  * @param {Number} keysize in bits
332  * @param {Number/ByteString} keyid the optional PKCS#15 key identifier.
333  * Default value is the next free key id of the SmartCard-HSM.
334  * @type SmartCardHSMKey
335  */
336 HSMKeyStore.prototype.importRSAKey = function(label, keyblob, keysize, keyid) {
337 	var keytype = keyblob.byteAt(8);
338 	if ((keytype != 5) && (keytype != 6)) {
339 		throw new GPError(module.id, GPError.INVALID_DATA, 0, "keyblob does not contain a RSA key");
340 	}
341 
342 	var key = this.sc.getKey(label);
343 	if (key) {
344 		throw new GPError("HSMKeyStore", GPError.INVALID_DATA, 0, "A key with label " + label + " does already exist");
345 	}
346 	var newkid = this.sc.determineFreeKeyId();
347 
348 	this.sc.unwrapKey(newkid, keyblob);
349 
350 	if (typeof(keyid) == "undefined") {
351 		keyid = newkid;
352 	}
353 
354 	var keydesc = SmartCardHSM.buildPrkDforRSA(keyid, label, keysize);
355 
356 	var fid = ByteString.valueOf((SmartCardHSM.PRKDPREFIX << 8) + newkid);
357 	this.sc.updateBinary(fid, 0, keydesc.getBytes());
358 
359 	var hkey = new SmartCardHSMKey(this.sc, newkid);
360 	hkey.setDescription(keydesc);
361 	this.sc.addKeyToMap(hkey);
362 
363 	return hkey;
364 }
365 
366 
367 
368 /**
369  * Import an ECC key blob
370  *
371  * @param {String} label the key label
372  * @param {ByteString} keyblob the binary key in SmartCard-HSM format
373  * @param {Number} keysize in bits
374  * @param {Number/ByteString} keyid the optional PKCS#15 key identifier.
375  * Default value is the next free key id of the SmartCard-HSM.
376  * @type SmartCardHSMKey
377  */
378 HSMKeyStore.prototype.importECCKey = function(label, keyblob, keysize, keyid) {
379 	var keytype = keyblob.byteAt(8);
380 	if (keytype != 12) {
381 		throw new GPError(module.id, GPError.INVALID_DATA, 0, "keyblob does not contain an ECC key");
382 	}
383 	var key = this.sc.getKey(label);
384 	if (key) {
385 		throw new GPError("HSMKeyStore", GPError.INVALID_DATA, 0, "A key with label " + label + " does already exist");
386 	}
387 	var newkid = this.sc.determineFreeKeyId();
388 
389 	this.sc.unwrapKey(newkid, keyblob);
390 
391 	if (typeof(keyid) == "undefined") {
392 		keyid = newkid;
393 	}
394 
395 	var keydesc = SmartCardHSM.buildPrkDforECC(keyid, label, keysize);
396 
397 	var fid = ByteString.valueOf((SmartCardHSM.PRKDPREFIX << 8) + newkid);
398 	this.sc.updateBinary(fid, 0, keydesc.getBytes());
399 
400 	var hkey = new SmartCardHSMKey(this.sc, newkid);
401 	hkey.setDescription(keydesc);
402 	this.sc.addKeyToMap(hkey);
403 
404 	return hkey;
405 }
406 
407 
408 
409 /**
410  * Import an AES key blob
411  *
412  * @param {String} label the key label
413  * @param {ByteString} keyblob the binary key in SmartCard-HSM format
414  * @param {Number} keysize in bits
415  * @param {ByteString} keyid the PKCS#15 key id (CKA_ID)
416  * @type
417  */
418 HSMKeyStore.prototype.importAESKey = function(label, keyblob, keysize, keyid) {
419 
420 	var key = this.sc.getKey(label);
421 	if (key) {
422 		throw new GPError("HSMKeyStore", GPError.INVALID_DATA, 0, "A key with label " + label + " does already exist");
423 	}
424 	var newkid = this.sc.determineFreeKeyId();
425 
426 	this.sc.unwrapKey(newkid, keyblob);
427 
428 	if (typeof(keyid) == "undefined") {
429 		keyid = newkid;
430 	}
431 
432 	var keydesc = SmartCardHSM.buildSKDforAES(keyid, label, keysize);
433 
434 	var fid = ByteString.valueOf((SmartCardHSM.PRKDPREFIX << 8) + newkid);
435 	this.sc.updateBinary(fid, 0, keydesc.getBytes());
436 
437 	var hkey = new SmartCardHSMKey(this.sc, newkid);
438 	hkey.setDescription(keydesc);
439 	this.sc.addKeyToMap(hkey);
440 
441 	return hkey;
442 }
443 
444 
445 
446 /**
447  * Store certificate under given label
448  *
449  * @param {String/Number/Key} labelOrIdOrKey the label, id or object of the key for which the certificate should be stored
450  * @param {X509} cert the certificate
451  */
452 HSMKeyStore.prototype.storeEndEntityCertificate = function(labelOrIdOrKey, cert) {
453 	var key = labelOrIdOrKey;
454 	if (!(key instanceof SmartCardHSMKey)) {
455 		key = this.getKey(labelOrIdOrKey);
456 	}
457 
458 	if (key) {
459 		var kid = key.getId();
460 	} else {
461 		throw new GPError("HSMKeyStore", GPError.INVALID_DATA, 0, "Could not find a key with label " + label);
462 	}
463 
464 	var fid = ByteString.valueOf((SmartCardHSM.EECERTIFICATEPREFIX << 8) + kid);
465 	if (!(cert instanceof ByteString)) {
466 		cert = cert.getBytes();
467 	}
468 	this.sc.updateBinary(fid, 0, cert);
469 }
470 
471 
472 
473 /**
474  * Store CA certificate under given label
475  *
476  * @param {String} label the label under which the certificate shall be stored
477  * @param {X509} cert the certificate
478  */
479 HSMKeyStore.prototype.storeCACertificate = function(label, cert) {
480 	this.sc.enumerateCACertificates();
481 	var id = this.sc.caidmap[label];
482 	if (id == undefined) {
483 		id = this.sc.determineFreeCAId();
484 	}
485 
486 	var fid = ByteString.valueOf((SmartCardHSM.CACERTIFICATEPREFIX << 8) + id);
487 	this.sc.updateBinary(fid, 0, cert.getBytes());
488 
489 	var descr = SmartCardHSM.buildCertDescription(label, null, cert.getPublicKey(), fid);
490 	var fid = ByteString.valueOf((SmartCardHSM.CERTDPREFIX << 8) + id);
491 	this.sc.updateBinary(fid, 0, descr.getBytes());
492 	this.sc.addCACertificateToMap(cert, id, label);
493 }
494 
495 
496 
497 /**
498  * Delete CA certificate with given label
499  *
500  * @param {String} label the label of certificate to be removed
501  */
502 HSMKeyStore.prototype.deleteCACertificate = function(label) {
503 	var cert = this.sc.getCACertificate(label);
504 
505 	if (!cert) {
506 		throw new GPError("HSMKeyStore", GPError.INVALID_DATA, 0, "Could not find a certificate with label " + label);
507 	}
508 
509 	var fid = ByteString.valueOf((SmartCardHSM.CERTDPREFIX << 8) + cert.id);
510 	this.sc.deleteFile(fid);
511 	var fid = ByteString.valueOf((SmartCardHSM.CACERTIFICATEPREFIX << 8) + cert.id);
512 	this.sc.deleteFile(fid);
513 	this.sc.enumerateCACertificates();
514 }
515 
516 
517 
518 /**
519  * Delete key and certificate with given label
520  *
521  * @param {String/Number/Key} labelOrIdOrKey the label, id or object of the key to be removed
522  */
523 HSMKeyStore.prototype.deleteKey = function(labelOrIdOrKey) {
524 	var key = labelOrIdOrKey;
525 	if (!(key instanceof SmartCardHSMKey)) {
526 		key = this.getKey(labelOrIdOrKey);
527 	}
528 
529 	if (key) {
530 		var kid = key.getId();
531 	} else {
532 		throw new GPError("HSMKeyStore", GPError.INVALID_DATA, 0, "Could not find a key with label " + labelOrIdOrKey);
533 	}
534 
535 	var fid = ByteString.valueOf((SmartCardHSM.KEYPREFIX << 8) + kid);
536 	this.sc.deleteFile(fid);
537 
538 	try	{
539 		var fid = ByteString.valueOf((SmartCardHSM.PRKDPREFIX << 8) + kid);
540 		this.sc.deleteFile(fid);
541 
542 		var fid = ByteString.valueOf((SmartCardHSM.EECERTIFICATEPREFIX << 8) + kid);
543 		this.sc.deleteFile(fid);
544 	}
545 	catch(e) {
546 		// Ignore
547 	}
548 
549 	this.enumerateKeys();
550 }
551 
552 
553 
554 /**
555  * Return list of keys
556  *
557  * @type String[]
558  * @return the list of key names
559  */
560 HSMKeyStore.prototype.enumerateKeys = function() {
561 	return this.sc.enumerateKeys();
562 }
563 
564 
565 
566 /**
567  * Check if key with label exists
568  *
569  * @param {String / Number} the key label or id
570  * @type Boolean
571  * @return true if key exists
572  */
573 HSMKeyStore.prototype.hasKey = function(labelOrId) {
574 	var key = this.sc.getKey(labelOrId);
575 	return key != null;
576 }
577 
578 
579 
580 /**
581  * Get key for given label
582  *
583  * @param {String / Number} the key label or id
584  * @type Key
585  * @return the key
586  */
587 HSMKeyStore.prototype.getKey = function(labelOrId) {
588 	var key = this.sc.getKey(labelOrId);
589 	if (!key) {
590 		throw new GPError("HSMKeyStore", GPError.INVALID_DATA, 0, "Could not find a key with label/id " + labelOrId);
591 	}
592 	return key;
593 }
594 
595 
596 
597 /**
598  * Check if key has a certificate
599  *
600  * @param {String/Number/Key} labelOrIdOrKey the certificate label, id or key
601  * @type Boolean
602  * @return true of a certificate is present
603  */
604 HSMKeyStore.prototype.hasCertificate = function(labelOrIdOrKey) {
605 	var key = labelOrIdOrKey;
606 	if (!(key instanceof SmartCardHSMKey)) {
607 		key = this.getKey(labelOrIdOrKey);
608 	}
609 	var kid = key.getId();
610 	var fid = ByteString.valueOf((SmartCardHSM.EECERTIFICATEPREFIX << 8) + kid);
611 	return this.sc.hasFile(fid);
612 }
613 
614 
615 
616 /**
617  * Get raw certificate for given label
618  *
619  * @param {String/Number/Key} labelOrIdOrKey the certificate label, id or key
620  * @type ByteString
621  * @return the certificate
622  */
623 HSMKeyStore.prototype.getCertificate = function(labelOrIdOrKey) {
624 	var key = labelOrIdOrKey;
625 	if (!(key instanceof SmartCardHSMKey)) {
626 		key = this.getKey(labelOrIdOrKey);
627 	}
628 	var kid = key.getId();
629 	var fid = ByteString.valueOf((SmartCardHSM.EECERTIFICATEPREFIX << 8) + kid);
630 	var certbin = this.sc.readBinary(fid);
631 	return certbin;
632 }
633 
634 
635 
636 /**
637  * Get certificate for given label
638  *
639  * @param {String/Number/Key} labelOrIdOrKey the certificate label, id or key
640  * @type X509
641  * @return the certificate
642  */
643 HSMKeyStore.prototype.getEndEntityCertificate = function(labelOrIdOrKey) {
644 	var certbin = this.getCertificate(labelOrIdOrKey);
645 	return new X509(certbin);
646 }
647