1 /**
  2  *  ---------
  3  * |.##> <##.|  Open Smart Card Development Platform (www.openscdp.org)
  4  * |#       #|  
  5  * |#       #|  Copyright (c) 1999-2009 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 Support for card verifiable certificates and certificate requests according to EAC 1.1/2.0
 25  */
 26 
 27 
 28 
 29 load("tools/eccutils.js");
 30 
 31 if (typeof(__ScriptingServer) == "undefined") {
 32 	load("publickeyreference.js");
 33 }
 34 
 35 
 36 
 37 /**
 38  * Create a CVC object from a DER encoded ByteString.
 39  *
 40  * @class Class implementing a decoder for card verifiable certificates or requests according to 
 41  *        Extended Access Control (EAC) as defined in BSI TR-03110 1.11 and 2.02.
 42  * @constructor
 43  * @param {ByteString} param the DER encoded certificate
 44  * @return
 45  */
 46 function CVC() {
 47 	if (arguments.length > 0) {
 48 		var arg = arguments[0];
 49 		if (arg instanceof ASN1) {
 50 			this.asn = arg;
 51 			this.bin = this.asn.getBytes();
 52 		} else if (arg instanceof ByteString) {
 53 			this.bin = arg;
 54 			this.asn = new ASN1(this.bin);
 55 		} else {
 56 			throw new GPError("CVC", GPError.INVALID_DATA, 0, "Argument must be of type ByteString or ASN1");
 57 		}
 58 		if (this.asn.tag == CVC.TAG_AT) {
 59 			this.body = this.asn.get(0).get(0);
 60 		} else if (this.asn.tag == CVC.TAG_CVC) {
 61 			this.body = this.asn.get(0);
 62 		} else {
 63 			throw new GPError("CVC", GPError.INVALID_DATA, 0, "Argument is neither a CVC or CVC request");
 64 		}
 65 	}
 66 }
 67 
 68 
 69 
 70 /** Authentication Template */
 71 CVC.TAG_AT = 0x67;
 72 /** CV Certificate */
 73 CVC.TAG_CVC = 0x7F21;
 74 /** Certificate Body */
 75 CVC.TAG_BODY = 0x7F4E;
 76 /** Certificate Profile Identifier */
 77 CVC.TAG_CPI = 0x5F29;
 78 /** Certification Authority Reference */
 79 CVC.TAG_CAR = 0x42;
 80 /** Public Key */
 81 CVC.TAG_PUK = 0x7F49;
 82 /** Prime Modulus */
 83 CVC.TAG_ECC_P = 0x81;
 84 /** First coefficient a */
 85 CVC.TAG_ECC_A = 0x82;
 86 /** Second coefficient b */
 87 CVC.TAG_ECC_B = 0x83;
 88 /** Base Point G */
 89 CVC.TAG_ECC_G = 0x84;
 90 /** Order of the base point */
 91 CVC.TAG_ECC_N = 0x85;
 92 /** Public Point y */
 93 CVC.TAG_ECC_Q = 0x86;
 94 /** Cofactor f */
 95 CVC.TAG_ECC_H = 0x87;
 96 /** Certificate Holder Reference */
 97 CVC.TAG_CHR = 0x5F20;
 98 /** Certificate Holder Authorisation Template */
 99 CVC.TAG_CHAT = 0x7F4C;
100 /** Certificate Extension */
101 CVC.TAG_EXTN = 0x65;
102 /** Certificate Effective Date */
103 CVC.TAG_CED = 0x5F25;
104 /** Certificate Expiration Date */
105 CVC.TAG_CXD = 0x5F24;
106 /** Signature */
107 CVC.TAG_SIG = 0x5F37;
108 
109 
110 /** Table of tag names */
111 CVC.OBJECTNAMES = []
112 CVC.OBJECTNAMES[CVC.TAG_AT] = "Authentication Template";
113 CVC.OBJECTNAMES[CVC.TAG_CVC] = "CV Certificate";
114 CVC.OBJECTNAMES[CVC.TAG_BODY] = "Certificate Body";
115 CVC.OBJECTNAMES[CVC.TAG_CPI] = "Certificate Profile Indicator";
116 CVC.OBJECTNAMES[CVC.TAG_CAR] = "Certification Authority Reference";
117 CVC.OBJECTNAMES[CVC.TAG_PUK] = "Public Key";
118 CVC.OBJECTNAMES[CVC.TAG_ECC_P] = "Prime/Modulus";
119 CVC.OBJECTNAMES[CVC.TAG_ECC_A] = "First coefficient a/Exponent";
120 CVC.OBJECTNAMES[CVC.TAG_ECC_B] = "Second coefficient b";
121 CVC.OBJECTNAMES[CVC.TAG_ECC_G] = "Base Point G";
122 CVC.OBJECTNAMES[CVC.TAG_ECC_N] = "Order of the base point";
123 CVC.OBJECTNAMES[CVC.TAG_ECC_Q] = "Public Point y";
124 CVC.OBJECTNAMES[CVC.TAG_ECC_H] = "Cofactor f";
125 CVC.OBJECTNAMES[CVC.TAG_CHR] = "Certificate Holder Reference";
126 CVC.OBJECTNAMES[CVC.TAG_CHAT] = "Certificate Holder Authentication Template";
127 CVC.OBJECTNAMES[CVC.TAG_EXTN] = "Extension";
128 CVC.OBJECTNAMES[CVC.TAG_CED] = "Certificate Effective Date";
129 CVC.OBJECTNAMES[CVC.TAG_CXD] = "Certificate Expiration Date";
130 CVC.OBJECTNAMES[CVC.TAG_SIG] = "Signature";
131 
132 
133 /** Table of rights description for id-IS */
134 CVC.ISRIGHTS = [
135 	"Read access to ePassport application: DG 3 (Fingerprint)",
136 	"Read access to ePassport application: DG 4 (Iris)",
137 	"RFU (Bit 3)",
138 	"RFU (Bit 4)",
139 	"RFU (Bit 5)",
140 	"Read access to eID application"
141 ];
142 CVC.idIS = new ByteString("id-IS", OID);
143 
144 
145 /** Table of rights description for id-AT */
146 CVC.ATRIGHTS = [
147 	"Age Verification",
148 	"Community ID Verification",
149 	"Restricted Identification",
150 	"Privileged Terminal",
151 	"CAN allowed",
152 	"PIN Management",
153 	"Install Certificate",
154 	"Install Qualified Certificate",
155 	
156 	"Read Access DG 1 (Document Type)",
157 	"Read Access DG 2 (Issuing State)",
158 	"Read Access DG 3 (Date of Expiration)",
159 	"Read Access DG 4 (Given Name)",
160 	"Read Access DG 5 (Surname)",
161 	"Read Access DG 6 (Pseudonym)",
162 	"Read Access DG 7 (Academic Grade)",
163 	"Read Access DG 8 (Date of Birth)",
164 
165 	"Read Access DG 9 (Place of Birth)",
166 	"Read Access DG 10",
167 	"Read Access DG 11",
168 	"Read Access DG 12",
169 	"Read Access DG 13",
170 	"Read Access DG 14",
171 	"Read Access DG 15",
172 	"Read Access DG 16",
173 
174 	"Read Access DG 17 (Place of Residence)",
175 	"Read Access DG 18 (Community ID)",
176 	"Read Access DG 19 (Conditions I-eAT)",
177 	"Read Access DG 20 (Conditions II-eAT)",
178 	"Read Access DG 21",
179 	"RFU (Bit 29)",
180 	"RFU (Bit 30)",
181 	"RFU (Bit 31)",
182 
183 	"RFU (Bit 32)",
184 	"Write Access DG 21",
185 	"Write Access DG 20 (Conditions II-eAT)",
186 	"Write Access DG 19 (Conditions I-eAT)",
187 	"Write Access DG 18 (Community ID)",
188 	"Write Access DG 17 (Place of Residence)"
189 ];
190 CVC.idAT = new ByteString("id-AT", OID);
191 
192 
193 
194 /** Table of rights description for id-ST */
195 CVC.STRIGHTS = [
196 	"Generate electronic signature",
197 	"Generate qualified electronic signature",
198 	"RFU (Bit 2)",
199 	"RFU (Bit 3)",
200 	"RFU (Bit 4)",
201 	"RFU (Bit 5)"
202 ];
203 CVC.idST = new ByteString("id-ST", OID);
204 
205 CVC.idSC_HSM = new ByteString("2B0601040181C31F030101", HEX);
206 
207 
208 
209 /** TA constants */
210 CVC.id_TA_ECDSA = new ByteString("id-TA-ECDSA", OID);
211 CVC.id_TA_ECDSA_SHA_1 = new ByteString("id-TA-ECDSA-SHA-1", OID);
212 CVC.id_TA_ECDSA_SHA_224 = new ByteString("id-TA-ECDSA-SHA-224", OID);
213 CVC.id_TA_ECDSA_SHA_256 = new ByteString("id-TA-ECDSA-SHA-256", OID);
214 CVC.id_TA_ECDSA_SHA_384 = new ByteString("id-TA-ECDSA-SHA-384", OID);
215 CVC.id_TA_ECDSA_SHA_512 = new ByteString("id-TA-ECDSA-SHA-512", OID);
216 CVC.id_TA_RSA_v1_5_SHA_1 = new ByteString("id-TA-RSA-v1-5-SHA-1", OID);
217 CVC.id_TA_RSA_v1_5_SHA_256 = new ByteString("id-TA-RSA-v1-5-SHA-256", OID);
218 CVC.id_TA_RSA_v1_5_SHA_512 = new ByteString("id-TA-RSA-v1-5-SHA-512", OID);
219 CVC.id_TA_RSA_PSS_SHA_1 = new ByteString("id-TA-RSA-PSS-SHA-1", OID);
220 CVC.id_TA_RSA_PSS_SHA_256 = new ByteString("id-TA-RSA-PSS-SHA-256", OID);
221 CVC.id_TA_RSA_PSS_SHA_512 = new ByteString("id-TA-RSA-PSS-SHA-512", OID);
222 
223 
224 
225 /**
226  * Return signature mechanism for object identifier
227  *
228  * @param {ByteString} oid the object identifer from the public key object
229  * @returns the signature mechanism as Crypto. constant or -1 if not defined
230  * @type Number
231  */
232 CVC.getSignatureMech = function(oid) {
233 	if (oid.equals(CVC.id_TA_ECDSA_SHA_1))
234 		return Crypto.ECDSA_SHA1;
235 	if (oid.equals(CVC.id_TA_ECDSA_SHA_224))
236 		return Crypto.ECDSA_SHA224;
237 	if (oid.equals(CVC.id_TA_ECDSA_SHA_256))
238 		return Crypto.ECDSA_SHA256;
239 	if (oid.equals(CVC.id_TA_ECDSA_SHA_384))
240 		return Crypto.ECDSA_SHA384;
241 	if (oid.equals(CVC.id_TA_ECDSA_SHA_512))
242 		return Crypto.ECDSA_SHA512;
243 	if (oid.equals(CVC.id_TA_RSA_v1_5_SHA_1))
244 		return Crypto.RSA_SHA1;
245 	if (oid.equals(CVC.id_TA_RSA_v1_5_SHA_256))
246 		return Crypto.RSA_SHA256;
247 	if (oid.equals(CVC.id_TA_RSA_v1_5_SHA_512))
248 		return Crypto.RSA_SHA512;
249 	if (oid.equals(CVC.id_TA_RSA_PSS_SHA_1))
250 		return Crypto.RSA_PSS_SHA1;
251 	if (oid.equals(CVC.id_TA_RSA_PSS_SHA_256))
252 		return Crypto.RSA_PSS_SHA256;
253 	if (oid.equals(CVC.id_TA_RSA_PSS_SHA_512))
254 		return Crypto.RSA_PSS_SHA512;
255 	return -1;
256 }
257 
258 
259 
260 /**
261  * Return hash mechanism for object identifier
262  *
263  * @param {ByteString} oid the object identifer from the public key object
264  * @returns the hash mechanism as Crypto. constant or -1 if not defined
265  * @type Number
266  */
267 CVC.getHashMech = function(oid) {
268 	if (oid.equals(CVC.id_TA_ECDSA_SHA_1))
269 		return Crypto.SHA_1;
270 	if (oid.equals(CVC.id_TA_ECDSA_SHA_224))
271 		return Crypto.SHA_224;
272 	if (oid.equals(CVC.id_TA_ECDSA_SHA_256))
273 		return Crypto.SHA_256;
274 	if (oid.equals(CVC.id_TA_ECDSA_SHA_384))
275 		return Crypto.SHA_384;
276 	if (oid.equals(CVC.id_TA_ECDSA_SHA_512))
277 		return Crypto.SHA_512;
278 	if (oid.equals(CVC.id_TA_RSA_v1_5_SHA_1))
279 		return Crypto.SHA1;
280 	if (oid.equals(CVC.id_TA_RSA_v1_5_SHA_256))
281 		return Crypto.SHA_256;
282 	if (oid.equals(CVC.id_TA_RSA_v1_5_SHA_512))
283 		return Crypto.SHA_512;
284 	if (oid.equals(CVC.id_TA_RSA_PSS_SHA_1))
285 		return Crypto.SHA_1;
286 	if (oid.equals(CVC.id_TA_RSA_PSS_SHA_256))
287 		return Crypto.SHA_256;
288 	if (oid.equals(CVC.id_TA_RSA_PSS_SHA_512))
289 		return Crypto.SHA_512;
290 	return -1;
291 }
292 
293 
294 
295 /**
296  * Return true of the object identifier starts with id-TA-ECDSA
297  *
298  * @type boolean
299  * @return true, if ECDSA based OID
300  */
301 CVC.isECDSA = function(oid) {
302 	return oid.startsWith(CVC.id_TA_ECDSA) == CVC.id_TA_ECDSA.length;
303 }
304 
305 
306 
307 /**
308  * Return true of the certificate contains domain parameter
309  *
310  * @type boolean
311  * @return true, if certificate contains domain parameter
312  */
313 CVC.prototype.containsDomainParameter = function() {
314 	var pdo = this.body.find(CVC.TAG_PUK);
315 	if (pdo == null) {
316 		return false;
317 	}
318 	
319 	var d = pdo.find(0x84);		// Generator
320 	return (d != null);
321 }
322 
323 
324 
325 /**
326  * Returns the certification authority reference (CAR).
327  *
328  * @return the CAR or null
329  * @type PublicKeyReference
330  */
331 CVC.prototype.getCAR = function() {
332 	var cardo = this.body.find(CVC.TAG_CAR);
333 	
334 	if (!cardo) {
335 		return null;
336 	}
337 	
338 	return new PublicKeyReference(cardo.value);
339 }
340 
341 
342 
343 /**
344  * Returns the certificate holder reference (CHR).
345  *
346  * @return the CHR
347  * @type PublicKeyReference
348  */
349 CVC.prototype.getCHR = function() {
350 	var chrdo = this.body.find(CVC.TAG_CHR);
351 	
352 	if (!chrdo) {
353 		throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Certificate does not contain a CHR");
354 	}
355 	
356 	return new PublicKeyReference(chrdo.value);
357 }
358 
359 
360 
361 /**
362  * Returns the certificate effective date (CED).
363  *
364  * @return the CED or null
365  * @type Date
366  */
367 CVC.prototype.getCED = function() {
368 	var ceddo = this.body.find(CVC.TAG_CED);
369 	
370 	if (!ceddo) {
371 		return null
372 	}
373 	
374 	var b = ceddo.value;
375 	
376 	var d = new Date();
377 	d.setFullYear(b.byteAt(0) * 10 + b.byteAt(1) + 2000, 
378 				  b.byteAt(2) * 10 + b.byteAt(3) - 1,
379 				  b.byteAt(4) * 10 + b.byteAt(5));
380 	d.setHours(12, 0, 0, 0);
381 	return d;
382 }
383 
384 
385 
386 /**
387  * Returns the certificate expiration date (CXD).
388  *
389  * @return the CXD or null
390  * @type Date
391  */
392 CVC.prototype.getCXD = function() {
393 	var cxddo = this.body.find(CVC.TAG_CXD);
394 	
395 	if (!cxddo) {
396 		return null
397 	}
398 	
399 	var b = cxddo.value;
400 	
401 	var d = new Date();
402 	d.setFullYear(b.byteAt(0) * 10 + b.byteAt(1) + 2000, 
403 				  b.byteAt(2) * 10 + b.byteAt(3) - 1,
404 				  b.byteAt(4) * 10 + b.byteAt(5));
405 	d.setHours(12, 0, 0, 0);
406 	return d;
407 }
408 
409 
410 
411 /**
412  * Returns the outer certification authority reference (CAR).
413  *
414  * @return the outer CAR or null
415  * @type PublicKeyReference
416  */
417 CVC.prototype.getOuterCAR = function() {
418 	if (!this.isAuthenticatedRequest()) {
419 		return null;
420 	}
421 	var cardo = this.asn.get(1);
422 	
423 	if (!cardo) {
424 		return null
425 	}
426 	
427 	return new PublicKeyReference(cardo.value);
428 }
429 
430 
431 
432 /**
433  * Returns the extension identified by the object identifier.
434  *
435  * @return the extension including the OID or null if not defined
436  * @type ASN1
437  */
438 CVC.prototype.getExtension = function(extoid) {
439 	var extdo = this.body.find(CVC.TAG_EXTN);
440 	
441 	if (!extdo) {
442 		return null;
443 	}
444 
445 //	print(extdo);
446 	
447 	for (var i = 0; i < extdo.length; i++) {
448 		var ext = extdo.get(i);
449 		var oid = ext.get(0);
450 		assert(oid.tag == ASN1.OBJECT_IDENTIFIER);
451 		if (oid.value.equals(extoid)) {
452 			return ext;
453 		}
454 	}
455 	return null;
456 }
457 
458 
459 
460 /**
461  * Returns the extension identified by the object identifier.
462  *
463  * @return the extension including the OID or null if not defined
464  * @type ASN1
465  */
466 CVC.prototype.getCHAT = function() {
467 	var chat = this.body.find(CVC.TAG_CHAT);
468 	
469 	return chat;
470 }
471 
472 
473 
474 /**
475  * Returns the public key object identifier
476  * 
477  * @returns the object identifier assigned to the public key
478  * @type ByteString
479  */
480 CVC.prototype.getPublicKeyOID = function() {
481 	var pdo = this.body.find(CVC.TAG_PUK);
482 	if (pdo == null) {
483 		throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Certificate does not contain a public key");
484 	}
485 	
486 	var d = pdo.find(ASN1.OBJECT_IDENTIFIER);
487 	if (d == null) {
488 		throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Public key does not contain an object identifier");
489 	}
490 	return d.value;
491 }
492 
493 
494 
495 /**
496  * Decode a public key from the TR-03110 format
497  *
498  * @param {ASN1} pdo the public key data object
499  * @param {Key} key the key object to fill
500  */
501 CVC.decodeECPublicKey = function(pdo, key) {
502 
503 	var d = pdo.find(0x86);		// Public point
504 	if (d == null) {
505 		throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Certificate does not contain a public key value");
506 	}
507 
508 	var b = d.value.bytes(1);
509 	key.setComponent(Key.ECC_QX, b.left(b.length >> 1));
510 	key.setComponent(Key.ECC_QY, b.right(b.length >> 1));
511 
512 	var d = pdo.find(0x81);		// Prime modulus
513 	if (d != null) {
514 		key.setComponent(Key.ECC_P, d.value);
515 	}
516 
517 	var d = pdo.find(0x82);		// First coefficient a
518 	if (d != null) {
519 		key.setComponent(Key.ECC_A, d.value);
520 	}
521 
522 	var d = pdo.find(0x83);		// First coefficient b
523 	if (d != null) {
524 		key.setComponent(Key.ECC_B, d.value);
525 	}
526 
527 	var d = pdo.find(0x84);		// Base Point G
528 	if (d != null) {
529 		var b = d.value.bytes(1);
530 		key.setComponent(Key.ECC_GX, b.left(b.length >> 1));
531 		key.setComponent(Key.ECC_GY, b.right(b.length >> 1));
532 	}
533 
534 	var d = pdo.find(0x85);		// Order of the base point
535 	if (d != null) {
536 		key.setComponent(Key.ECC_N, d.value);
537 	}
538 
539 	var d = pdo.find(0x87);		// Cofactor f
540 	if (d != null) {
541 		key.setComponent(Key.ECC_H, d.value);
542 	}
543 }
544 
545 
546 
547 /**
548  * Returns the EC public key contained in the certificate.
549  *
550  * @param {Key} domParam optional domain parameter if they are not contained in certificate
551  * @return the public key object
552  * @type Key
553  */
554 CVC.prototype.getECPublicKey = function(domParam) {
555 	if (typeof(domParam) != "undefined") {
556 		var key = new Key(domParam);
557 	} else {
558 		var key = new Key();
559 	}
560 
561 	key.setType(Key.PUBLIC);
562 
563 	var pdo = this.body.find(CVC.TAG_PUK);
564 	if (pdo == null) {
565 		throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Certificate does not contain a public key");
566 	}
567 
568 	CVC.decodeECPublicKey(pdo, key);
569 
570 	return key;
571 }
572 
573 
574 
575 /**
576  * Returns the RSA public key contained in the certificate.
577  *
578  * @return the public key object
579  * @type Key
580  */
581 CVC.prototype.getRSAPublicKey = function() {
582 	var key = new Key();
583 	
584 	key.setType(Key.PUBLIC);
585 	
586 	var pdo = this.body.find(CVC.TAG_PUK);
587 	if (pdo == null) {
588 		throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Certificate does not contain a public key");
589 	}
590 	
591 	var d = pdo.find(0x81);		// modulus
592 	if (d != null) {
593 		key.setComponent(Key.MODULUS, d.value);
594 	}
595 
596 	var d = pdo.find(0x82);		// public exponent
597 	if (d != null) {
598 		key.setComponent(Key.EXPONENT, d.value);
599 	}
600 	
601 	return key;
602 }
603 
604 
605 
606 /**
607  * Returns the public key contained in the certificate.
608  *
609  * @param {Key} domParam optional domain parameter if they are not contained in certificate
610  * @return the public key object
611  * @type Key
612  */
613 CVC.prototype.getPublicKey = function(domParam) {
614 	var pkoid = this.getPublicKeyOID();
615 	
616 	if (CVC.isECDSA(pkoid)) {
617 		return this.getECPublicKey(domParam);
618 	}
619 	return this.getRSAPublicKey();
620 }
621 
622 
623 
624 /**
625  * Determine if this is an authenticated request
626  *
627  * @returns true, if authenticated request
628  * @type Boolean
629  */
630 CVC.prototype.isAuthenticatedRequest = function() {
631 	return (this.asn.tag == CVC.TAG_AT);
632 }
633 
634 
635 
636 /**
637  * Determine if this is a certificate request
638  *
639  * @returns true, if certificate request
640  * @type Boolean
641  */
642 CVC.prototype.isCertificateRequest = function() {
643 	if (isAuthenticatedRequest()) {
644 		return true;
645 	}
646 	
647 	var ced = this.getCED();
648 	return ced == null;
649 }
650 
651 
652 
653 /**
654  * Determine if this is a countersigned authenticated request
655  *
656  * @returns true, if countersigned authenticated request
657  * @type Boolean
658  */
659 CVC.prototype.isCountersignedRequest = function() {
660 	if (!this.isAuthenticatedRequest()) {
661 		return false;
662 	}
663 	return (this.getCHR().getHolder() != this.getOuterCAR().getHolder());
664 }
665 
666 
667 
668 /**
669  * Determine if this certificate is expired
670  *
671  * @returns true, if certificate is expired
672  * @type Boolean
673  */
674 CVC.prototype.isExpired = function() {
675 	var now = new Date();
676 	now.setHours(12, 0, 0, 0);
677 	return (now.valueOf() > this.getCXD().valueOf());
678 }
679 
680 
681 
682 /**
683  * Verify certificate signature with public key
684  *
685  * @param {Key} puk the public key
686  * @param {ByteString} oid the signature algorithm
687  * @returns true if the signature is valid
688  * @type Boolean
689  */
690 CVC.prototype.verifyWith = function(crypto, puk, oid) {
691 	if (this.asn.tag == CVC.TAG_AT) {
692 		var signature = this.asn.get(0).get(1);
693 	} else {
694 		var signature = this.asn.get(1);
695 	}
696 	
697 	if (typeof(oid) == "undefined") {
698 		var oid = this.getPublicKeyOID();
699 	}
700 	var mech = CVC.getSignatureMech(oid);
701 
702 	if (CVC.isECDSA(oid)) {
703 		var signatureValue = ECCUtils.wrapSignature(signature.value);
704 	} else {
705 		var signatureValue = signature.value;
706 	}
707 	
708 	return crypto.verify(puk, mech, this.body.getBytes(), signatureValue);
709 }
710 
711 
712 
713 /**
714  * Verify certificate signature with public key from card verifiable certificate
715  *
716  * @param {CVC} cvc the card verifiable certificate used to obtain the public key
717  * @returns true if the signature is valid
718  * @type Boolean
719  */
720 CVC.prototype.verifyWithCVC = function(crypto, cvc) {
721 	return this.verifyWith(crypto, cvc.getPublicKey(), cvc.getPublicKeyOID());
722 }
723 
724 
725 
726 /**
727  * Verify outer signature of an authenticated request with public key
728  *
729  * @param {Key} puk the public key
730  * @param {ByteString} oid the signature algorithm
731  * @returns true if the signature is valid
732  * @type Boolean
733  */
734 CVC.prototype.verifyATWith = function(crypto, puk, oid) {
735 	if (!this.isAuthenticatedRequest()) {
736 		throw new GPError("CVC", GPError.INVALID_DATA, 0, "Not an authenticated request");
737 	}
738 	
739 	var signature = this.asn.get(2);
740 	var signatureInput = this.asn.get(0).getBytes().concat(this.asn.get(1).getBytes());
741 	
742 	if (typeof(oid) == "undefined") {
743 		var oid = this.getPublicKeyOID();
744 	}
745 	var mech = CVC.getSignatureMech(oid);
746 	
747 	if (CVC.isECDSA(oid)) {
748 		var signatureValue = ECCUtils.wrapSignature(signature.value);
749 	} else {
750 		var signatureValue = signature.value;
751 	}
752 	return crypto.verify(puk, mech, signatureInput, signatureValue);
753 }
754 
755 
756 
757 /**
758  * Verify outer signature of an authenticated request with public key from card verifiable certificate
759  *
760  * @param {CVC} cvc the card verifiable certificate used to obtain the public key
761  * @returns true if the signature is valid
762  * @type Boolean
763  */
764 CVC.prototype.verifyATWithCVC = function(crypto, cvc) {
765 	return this.verifyATWith(crypto, cvc.getPublicKey(), cvc.getPublicKeyOID());
766 }
767 
768 
769 
770 /**
771  * Returns the encoded certificate
772  *
773  * @return the DER encoded certificate
774  * @type ByteString
775  */
776 CVC.prototype.getBytes = function() {
777 	return this.bin;
778 }
779 
780 
781 
782 /**
783  * Returns the certificate as ASN1 structure
784  *
785  * @return the certificate as ASN1 structure
786  * @type ASN1
787  */
788 CVC.prototype.getASN1 = function() {
789 	return this.asn;
790 }
791 
792 
793 
794 /**
795  * Function to recursively walk the ASN.1 tree
796  */
797 CVC.decorateTree = function(node) {
798 	var name = CVC.OBJECTNAMES[node.tag];
799 	
800 	if (name) {
801 		node.setName(name);
802 	}
803 
804 	if (node.isconstructed) {
805 		for (var i = 0; i < node.elements; i++) {
806 			CVC.decorateTree(node.get(i));
807 		}
808 	}
809 }
810 
811 
812 
813 /**
814  * Decorate the ASN.1 object with the correct name
815  */
816 CVC.prototype.decorate = function() {
817 	CVC.decorateTree(this.asn);
818 	var cxddo = this.body.find(CVC.TAG_CXD);
819 	if (cxddo == null) {
820 		if (this.asn.tag == CVC.TAG_AT) {
821 			this.asn.setName("Authenticated CVC Request");
822 		} else {
823 			this.asn.setName("CVC Request");
824 		}
825 	}
826 }
827 
828 
829 
830 /**
831  * Return list of rights granted by the certificate
832  *
833  * @returns the list of rights
834  * @type String[]
835  */
836 CVC.prototype.getRightsAsList = function() {
837 	var list = [];
838 	
839 	var rtab;
840 	var chat = this.getCHAT();
841 	if (chat == null) {
842 		return list;
843 	}
844 	
845 	var oid = chat.get(0).value;
846 	
847 	if (oid.equals(CVC.idIS)) {
848 		rtab = CVC.ISRIGHTS;
849 	} else if (oid.equals(CVC.idAT)) {
850 		rtab = CVC.ATRIGHTS;
851 	} else if (oid.equals(CVC.idST)) {
852 		rtab = CVC.STRIGHTS;
853 	} else {
854 		return null;
855 	}
856 	
857 	var mask = chat.get(1).value;
858 	var c = 0;
859 	for (var i = mask.length - 1; i >= 0; i--) {
860 		var akku = mask.byteAt(i);
861 		for (var j = 0; j < (i == 0 ? 6 : 8); j++) {
862 			if (akku & 1) {
863 				list.push(rtab[c]);
864 			}
865 			c++;
866 			akku >>= 1;
867 		}
868 	}
869 	return list;
870 }
871 
872 
873 
874 /**
875  * Return a string describing the certificate type
876  *
877  * @returns a describing string
878  * @type String
879  */
880 CVC.prototype.getType = function() {
881 	var ced = this.getCED();
882 	var chat = this.getCHAT();
883 	
884 	// Decode certificate / request type
885 	var str = "CVC ";
886 	if (ced == null) {
887 		if (this.asn.tag == CVC.TAG_AT) {
888 			str = "AT-CVREQ ";
889 		} else {
890 			str = "CVREQ ";
891 		}
892 	}
893 	
894 	// Decode CA type
895 	if (chat != null) {
896 		var oid = chat.get(0).value;
897 	
898 		var trustedDV = "";
899 		var untrustedDV = "";
900 		
901 		if (oid.equals(CVC.idIS)) {
902 			str += "id-IS ";
903 			trustedDV = "(official domestic) ";
904 			untrustedDV = "(official foreign) ";
905 		} else if (oid.equals(CVC.idAT)) {
906 			str += "id-AT ";
907 			trustedDV = "(official domestic) ";
908 			untrustedDV = "(non-official / foreign) ";
909 		} else if (oid.equals(CVC.idST)) {
910 			str += "id-ST ";
911 			trustedDV = "(accreditation body) ";
912 			untrustedDV = "(certification service provider) ";
913 		} else if (oid.equals(CVC.idSC_HSM)) {
914 			str += "id-SC-HSM ";
915 			trustedDV = "";
916 		} else {
917 			str += oid.toString(OID) + " ";
918 		}
919 		
920 		switch(chat.get(1).value.byteAt(0) & 0xC0) {
921 			case 0xC0: str += "CVCA "; break;
922 			case 0x80: str += "DV " + trustedDV; break;
923 			case 0x40: str += "DV " + untrustedDV; break;
924 			case 0x00: str += "Terminal "; break;
925 		}
926 	}
927 	
928 	return str;
929 }
930 
931 
932 
933 /**
934  * Return a textual description of the certificate
935  *
936  * @returns a string containing information about the certificate
937  * @type String
938  */
939 CVC.prototype.toString = function() {
940 	var car = this.getCAR();
941 	var ced = this.getCED();
942 
943 	var str = this.getType();
944 
945 	if (car) {
946 		str += "CAR=" + car.toString() + " ";
947 	}
948 
949 	str += "CHR=" + this.getCHR().toString() + " ";
950 	
951 	if (ced) {
952 		str += "CED=" + ced.toLocaleDateString() + " ";
953 	}
954 
955 	var cxd = this.getCXD();
956 	if (cxd) {
957 		str += "CXD=" + cxd.toLocaleDateString() + " ";
958 	}
959 
960 	if (this.isAuthenticatedRequest()) {
961 		str += "oCAR=" + this.getOuterCAR().toString() + " ";
962 	}
963 	
964 	return str;
965 }
966 
967