      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 // Imports
     29 var PublicKeyReference = require('scsh/eac/PublicKeyReference').PublicKeyReference;
     30
     31
     32
     33 /**
     34  * Create a CVC object from a DER encoded ByteString.
     35  *
     36  * @class Class implementing a decoder for card verifiable certificates or requests according to
     37  *        Extended Access Control (EAC) as defined in BSI TR-03110 1.11 and 2.02.
     38  * @constructor
     39  * @param {ByteString} param the DER encoded certificate
     40  * @return
     41  */
     42 function CVC() {
     43 	if (arguments.length > 0) {
     44 		var arg = arguments[0];
     45 		if (arg instanceof ASN1) {
     46 			this.asn = arg;
     47 			this.bin = this.asn.getBytes();
     48 		} else if (arg instanceof ByteString) {
     49 			this.bin = arg;
     50 			this.asn = new ASN1(this.bin);
     51 		} else {
     52 			throw new GPError("CVC", GPError.INVALID_DATA, 0, "Argument must be of type ByteString or ASN1");
     53 		}
     54 		if (this.asn.tag == CVC.TAG_AT) {
     55 			this.body = this.asn.get(0).get(0);
     56 		} else if (this.asn.tag == CVC.TAG_CVC) {
     57 			this.body = this.asn.get(0);
     58 		} else {
     59 			throw new GPError("CVC", GPError.INVALID_DATA, 0, "Argument is neither a CVC or CVC request");
     60 		}
     61 	}
     62 }
     63
     64 exports.CVC = CVC;
     65
     66 CVC.crypto = new Crypto();
     67
     68
     69 /** Authentication Template */
     70 CVC.TAG_AT = 0x67;
     71 /** CV Certificate */
     72 CVC.TAG_CVC = 0x7F21;
     73 /** Certificate Body */
     74 CVC.TAG_BODY = 0x7F4E;
     75 /** Certificate Profile Identifier */
     76 CVC.TAG_CPI = 0x5F29;
     77 /** Certification Authority Reference */
     78 CVC.TAG_CAR = 0x42;
     79 /** Public Key */
     80 CVC.TAG_PUK = 0x7F49;
     81 /** Prime Modulus */
     82 CVC.TAG_ECC_P = 0x81;
     83 /** First coefficient a */
     84 CVC.TAG_ECC_A = 0x82;
     85 /** Second coefficient b */
     86 CVC.TAG_ECC_B = 0x83;
     87 /** Base Point G */
     88 CVC.TAG_ECC_G = 0x84;
     89 /** Order of the base point */
     90 CVC.TAG_ECC_N = 0x85;
     91 /** Public Point y */
     92 CVC.TAG_ECC_Q = 0x86;
     93 /** Cofactor f */
     94 CVC.TAG_ECC_H = 0x87;
     95 /** Certificate Holder Reference */
     96 CVC.TAG_CHR = 0x5F20;
     97 /** Certificate Holder Authorisation Template */
     98 CVC.TAG_CHAT = 0x7F4C;
     99 /** Relative Authorization */
    100 CVC.TAG_AUT = 0x53;
    101 /** Certificate Extension */
    102 CVC.TAG_EXTN = 0x65;
    103 /** Certificate Effective Date */
    104 CVC.TAG_CED = 0x5F25;
    105 /** Certificate Expiration Date */
    106 CVC.TAG_CXD = 0x5F24;
    107 /** Signature */
    108 CVC.TAG_SIG = 0x5F37;
    109
    110
    111 /** Table of tag names */
    112 CVC.OBJECTNAMES = []
    113 CVC.OBJECTNAMES[CVC.TAG_AT] = "Authentication Template";
    114 CVC.OBJECTNAMES[CVC.TAG_CVC] = "CV Certificate";
    115 CVC.OBJECTNAMES[CVC.TAG_BODY] = "Certificate Body";
    116 CVC.OBJECTNAMES[CVC.TAG_CPI] = "Certificate Profile Indicator";
    117 CVC.OBJECTNAMES[CVC.TAG_CAR] = "Certification Authority Reference";
    118 CVC.OBJECTNAMES[CVC.TAG_PUK] = "Public Key";
    119 CVC.OBJECTNAMES[CVC.TAG_ECC_P] = "Prime/Modulus";
    120 CVC.OBJECTNAMES[CVC.TAG_ECC_A] = "First coefficient a/Exponent";
    121 CVC.OBJECTNAMES[CVC.TAG_ECC_B] = "Second coefficient b";
    122 CVC.OBJECTNAMES[CVC.TAG_ECC_G] = "Base Point G";
    123 CVC.OBJECTNAMES[CVC.TAG_ECC_N] = "Order of the base point";
    124 CVC.OBJECTNAMES[CVC.TAG_ECC_Q] = "Public Point y";
    125 CVC.OBJECTNAMES[CVC.TAG_ECC_H] = "Cofactor f";
    126 CVC.OBJECTNAMES[CVC.TAG_CHR] = "Certificate Holder Reference";
    127 CVC.OBJECTNAMES[CVC.TAG_CHAT] = "Certificate Holder Authentication Template";
    128 CVC.OBJECTNAMES[CVC.TAG_AUT] = "Relative Authorization";
    129 CVC.OBJECTNAMES[CVC.TAG_EXTN] = "Extension";
    130 CVC.OBJECTNAMES[CVC.TAG_CED] = "Certificate Effective Date";
    131 CVC.OBJECTNAMES[CVC.TAG_CXD] = "Certificate Expiration Date";
    132 CVC.OBJECTNAMES[CVC.TAG_SIG] = "Signature";
    133
    134 CVC.PUK_SYNTAX = [
    135 	{ tag: 0x06, minlen: 2, maxlen: 20 },
    136 	{ tag: CVC.TAG_ECC_P, minlen: 20, maxlen: 512, optional: true },
    137 	{ tag: CVC.TAG_ECC_A, minlen: 1, maxlen: 512, optional: true },
    138 	{ tag: CVC.TAG_ECC_B, minlen: 20, maxlen: 66, optional: true },
    139 	{ tag: CVC.TAG_ECC_G, minlen: 41, maxlen: 133, optional: true },
    140 	{ tag: CVC.TAG_ECC_N, minlen: 20, maxlen: 66, optional: true },
    141 	{ tag: CVC.TAG_ECC_Q, minlen: 41, maxlen: 133, optional: true },
    142 	{ tag: CVC.TAG_ECC_H, minlen: 1, maxlen: 1, optional: true }
    143 ];
    144
    145 CVC.REQ_BODY_SYNTAX = [
    146 	{ tag: CVC.TAG_CPI, minlen: 1, maxlen: 1 },
    147 	{ tag: CVC.TAG_CAR, minlen: 8, maxlen: 16, optional: true },
    148 	{ tag: CVC.TAG_PUK, content: CVC.PUK_SYNTAX },
    149 	{ tag: CVC.TAG_CHR, minlen: 8, maxlen: 16 },
    150 	{ tag: CVC.TAG_EXTN, optional: true }
    151 ];
    152
    153 CVC.REQ_SYNTAX = [
    154 	{ tag: CVC.TAG_BODY, content: CVC.REQ_BODY_SYNTAX },
    155 	{ tag: CVC.TAG_SIG, minlen: 40, maxlen: 550 }
    156 ];
    157
    158 CVC.ATREQ_SYNTAX = [
    159 	{ tag: CVC.TAG_CVC, content: CVC.REQ_SYNTAX },
    160 	{ tag: CVC.TAG_CAR, minlen: 8, maxlen: 16 },
    161 	{ tag: CVC.TAG_SIG, minlen: 40, maxlen: 550 }
    162 ];
    163
    164 CVC.CHAT_SYNTAX = [
    165 	{ tag: 0x06, minlen: 2, maxlen: 20 },
    166 	{ tag: CVC.TAG_AUT, minlen: 1, maxlen: 5 }
    167 ];
    168
    169 CVC.CERT_BODY_SYNTAX = [
    170 	{ tag: CVC.TAG_CPI, minlen: 1, maxlen: 1 },
    171 	{ tag: CVC.TAG_CAR, minlen: 8, maxlen: 16 },
    172 	{ tag: CVC.TAG_PUK, content: CVC.PUK_SYNTAX },
    173 	{ tag: CVC.TAG_CHR, minlen: 8, maxlen: 16 },
    174 	{ tag: CVC.TAG_CHAT, content: CVC.CHAT_SYNTAX },
    175 	{ tag: CVC.TAG_CED, minlen: 6, maxlen: 6 },
    176 	{ tag: CVC.TAG_CXD, minlen: 6, maxlen: 6 },
    177 	{ tag: CVC.TAG_EXTN, optional: true }
    178 ];
    179
    180 CVC.CERT_SYNTAX = [
    181 	{ tag: CVC.TAG_BODY, content: CVC.CERT_BODY_SYNTAX },
    182 	{ tag: CVC.TAG_SIG, minlen: 24, maxlen: 550 }
    183 ];
    184
    185
    186
    187 /** Table of rights description for id-IS */
    188 CVC.ISRIGHTS = [
    189 	"Read access to ePassport application: DG 3 (Fingerprint)",
    190 	"Read access to ePassport application: DG 4 (Iris)",
    191 	"RFU (Bit 3)",
    192 	"RFU (Bit 4)",
    193 	"RFU (Bit 5)",
    194 	"Read access to eID application"
    195 ];
    196 CVC.idIS = new ByteString("id-IS", OID);
    197
    198
    199 /** Table of rights description for id-AT */
    200 CVC.ATRIGHTS = [
    201 	"Age Verification",
    202 	"Community ID Verification",
    203 	"Restricted Identification",
    204 	"Privileged Terminal",
    205 	"CAN allowed",
    206 	"PIN Management",
    207 	"Install Certificate",
    208 	"Install Qualified Certificate",
    209
    210 	"Read Access DG 1 (Document Type)",
    211 	"Read Access DG 2 (Issuing State)",
    212 	"Read Access DG 3 (Date of Expiration)",
    213 	"Read Access DG 4 (Given Name)",
    214 	"Read Access DG 5 (Surname)",
    215 	"Read Access DG 6 (Pseudonym)",
    216 	"Read Access DG 7 (Academic Grade)",
    217 	"Read Access DG 8 (Date of Birth)",
    218
    219 	"Read Access DG 9 (Place of Birth)",
    220 	"Read Access DG 10",
    221 	"Read Access DG 11",
    222 	"Read Access DG 12",
    223 	"Read Access DG 13",
    224 	"Read Access DG 14",
    225 	"Read Access DG 15",
    226 	"Read Access DG 16",
    227
    228 	"Read Access DG 17 (Place of Residence)",
    229 	"Read Access DG 18 (Community ID)",
    230 	"Read Access DG 19 (Conditions I-eAT)",
    231 	"Read Access DG 20 (Conditions II-eAT)",
    232 	"Read Access DG 21",
    233 	"RFU (Bit 29)",
    234 	"RFU (Bit 30)",
    235 	"RFU (Bit 31)",
    236
    237 	"RFU (Bit 32)",
    238 	"Write Access DG 21",
    239 	"Write Access DG 20 (Conditions II-eAT)",
    240 	"Write Access DG 19 (Conditions I-eAT)",
    241 	"Write Access DG 18 (Community ID)",
    242 	"Write Access DG 17 (Place of Residence)"
    243 ];
    244 CVC.idAT = new ByteString("id-AT", OID);
    245
    246
    247
    248 /** Table of rights description for id-ST */
    249 CVC.STRIGHTS = [
    250 	"Generate electronic signature",
    251 	"Generate qualified electronic signature",
    252 	"RFU (Bit 2)",
    253 	"RFU (Bit 3)",
    254 	"RFU (Bit 4)",
    255 	"RFU (Bit 5)"
    256 ];
    257 CVC.idST = new ByteString("id-ST", OID);
    258
    259 CVC.idSC_HSM = new ByteString("2B0601040181C31F030101", HEX);
    260 CVC.idBW_SE = new ByteString("2B0601040181C31F030102", HEX);
    261
    262
    263
    264 /** TA constants */
    265 CVC.id_TA_ECDSA = new ByteString("id-TA-ECDSA", OID);
    266 CVC.id_TA_ECDSA_SHA_1 = new ByteString("id-TA-ECDSA-SHA-1", OID);
    267 CVC.id_TA_ECDSA_SHA_224 = new ByteString("id-TA-ECDSA-SHA-224", OID);
    268 CVC.id_TA_ECDSA_SHA_256 = new ByteString("id-TA-ECDSA-SHA-256", OID);
    269 CVC.id_TA_ECDSA_SHA_384 = new ByteString("id-TA-ECDSA-SHA-384", OID);
    270 CVC.id_TA_ECDSA_SHA_512 = new ByteString("id-TA-ECDSA-SHA-512", OID);
    271 CVC.id_TA_RSA_v1_5_SHA_1 = new ByteString("id-TA-RSA-v1-5-SHA-1", OID);
    272 CVC.id_TA_RSA_v1_5_SHA_256 = new ByteString("id-TA-RSA-v1-5-SHA-256", OID);
    273 CVC.id_TA_RSA_v1_5_SHA_512 = new ByteString("id-TA-RSA-v1-5-SHA-512", OID);
    274 CVC.id_TA_RSA_PSS_SHA_1 = new ByteString("id-TA-RSA-PSS-SHA-1", OID);
    275 CVC.id_TA_RSA_PSS_SHA_256 = new ByteString("id-TA-RSA-PSS-SHA-256", OID);
    276 CVC.id_TA_RSA_PSS_SHA_512 = new ByteString("id-TA-RSA-PSS-SHA-512", OID);
    277
    278 CVC.id_ECPUBLICKEY = new ByteString("id-ecPublicKey", OID);
    279 CVC.id_ANSIX9 = new ByteString("iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) prime(1)", OID);
    280 CVC.id_CERTICOM = new ByteString("iso(1) identified-organization(3) certicom(132) curve(0)", OID);
    281 CVC.id_BRAINPOOL = new ByteString("ellipticCurve", OID);
    282
    283 CVC.id_ECDSA_WITH_SHA2 = new ByteString("iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3)", OID);
    284 CVC.id_ECDSA_WITH_SHA256 = new ByteString("ecdsa-with-SHA256", OID);
    285 CVC.id_ECDSA_WITH_SHA384 = new ByteString("ecdsa-with-SHA384", OID);
    286 CVC.id_ECDSA_WITH_SHA512 = new ByteString("ecdsa-with-SHA512", OID);
    287
    288
    289
    290
    291 /**
    292  * Return signature mechanism for object identifier
    293  *
    294  * @param {ByteString} oid the object identifer from the public key object
    295  * @returns the signature mechanism as Crypto. constant or -1 if not defined
    296  * @type Number
    297  */
    298 CVC.getSignatureMech = function(oid, keysize) {
    299 	if (oid.equals(CVC.id_TA_ECDSA_SHA_1))
    300 		return Crypto.ECDSA_SHA1;
    301 	if (oid.equals(CVC.id_TA_ECDSA_SHA_224))
    302 		return Crypto.ECDSA_SHA224;
    303 	if (oid.equals(CVC.id_TA_ECDSA_SHA_256))
    304 		return Crypto.ECDSA_SHA256;
    305 	if (oid.equals(CVC.id_TA_ECDSA_SHA_384))
    306 		return Crypto.ECDSA_SHA384;
    307 	if (oid.equals(CVC.id_TA_ECDSA_SHA_512))
    308 		return Crypto.ECDSA_SHA512;
    309 	if (oid.equals(CVC.id_TA_RSA_v1_5_SHA_1))
    310 		return Crypto.RSA_SHA1;
    311 	if (oid.equals(CVC.id_TA_RSA_v1_5_SHA_256))
    312 		return Crypto.RSA_SHA256;
    313 	if (oid.equals(CVC.id_TA_RSA_v1_5_SHA_512))
    314 		return Crypto.RSA_SHA512;
    315 	if (oid.equals(CVC.id_TA_RSA_PSS_SHA_1))
    316 		return Crypto.RSA_PSS_SHA1;
    317 	if (oid.equals(CVC.id_TA_RSA_PSS_SHA_256))
    318 		return Crypto.RSA_PSS_SHA256;
    319 	if (oid.equals(CVC.id_TA_RSA_PSS_SHA_512))
    320 		return Crypto.RSA_PSS_SHA512;
    321 	if (oid.equals(CVC.id_ECDSA_WITH_SHA256))
    322 		return Crypto.ECDSA_SHA256;
    323 	if (oid.equals(CVC.id_ECDSA_WITH_SHA384))
    324 		return Crypto.ECDSA_SHA384;
    325 	if (oid.equals(CVC.id_ECDSA_WITH_SHA512))
    326 		return Crypto.ECDSA_SHA512;
    327 	if (CVC.isCurveOID(oid)) {
    328 		assert(typeof(keysize) == "number", "Argument keysize must be number");
    329 		if (keysize >= 512) {
    330 			return Crypto.ECDSA_SHA512;
    331 		} else if (keysize >= 384) {
    332 			return Crypto.ECDSA_SHA384;
    333 		} else if (keysize >= 256) {
    334 			return Crypto.ECDSA_SHA256;
    335 		} else if (keysize >= 224) {
    336 			return Crypto.ECDSA_SHA224;
    337 		}
    338 	}
    339
    340 	return -1;
    341 }
    342
    343
    344
    345 /**
    346  * Return hash mechanism for object identifier
    347  *
    348  * @param {ByteString} oid the object identifer from the public key object
    349  * @returns the hash mechanism as Crypto. constant or -1 if not defined
    350  * @type Number
    351  */
    352 CVC.getHashMech = function(oid) {
    353 	if (oid.equals(CVC.id_TA_ECDSA_SHA_1))
    354 		return Crypto.SHA_1;
    355 	if (oid.equals(CVC.id_TA_ECDSA_SHA_224))
    356 		return Crypto.SHA_224;
    357 	if (oid.equals(CVC.id_TA_ECDSA_SHA_256))
    358 		return Crypto.SHA_256;
    359 	if (oid.equals(CVC.id_TA_ECDSA_SHA_384))
    360 		return Crypto.SHA_384;
    361 	if (oid.equals(CVC.id_TA_ECDSA_SHA_512))
    362 		return Crypto.SHA_512;
    363 	if (oid.equals(CVC.id_ECDSA_WITH_SHA256))
    364 		return Crypto.SHA_256;
    365 	if (oid.equals(CVC.id_ECDSA_WITH_SHA384))
    366 		return Crypto.SHA_384;
    367 	if (oid.equals(CVC.id_ECDSA_WITH_SHA512))
    368 		return Crypto.SHA_512;
    369 	if (oid.equals(CVC.id_TA_RSA_v1_5_SHA_1))
    370 		return Crypto.SHA_1;
    371 	if (oid.equals(CVC.id_TA_RSA_v1_5_SHA_256))
    372 		return Crypto.SHA_256;
    373 	if (oid.equals(CVC.id_TA_RSA_v1_5_SHA_512))
    374 		return Crypto.SHA_512;
    375 	if (oid.equals(CVC.id_TA_RSA_PSS_SHA_1))
    376 		return Crypto.SHA_1;
    377 	if (oid.equals(CVC.id_TA_RSA_PSS_SHA_256))
    378 		return Crypto.SHA_256;
    379 	if (oid.equals(CVC.id_TA_RSA_PSS_SHA_512))
    380 		return Crypto.SHA_512;
    381 	return -1;
    382 }
    383
    384
    385
    386 /**
    387  * Return true of the object identifier denotes a curve
    388  *
    389  * @type boolean
    390  * @return true, if ECDSA based OID
    391  */
    392 CVC.isCurveOID = function(oid) {
    393 	if (oid.startsWith(CVC.id_BRAINPOOL) == CVC.id_BRAINPOOL.length) {
    394 		return true;
    395 	}
    396 	if (oid.startsWith(CVC.id_ANSIX9) == CVC.id_ANSIX9.length) {
    397 		return true;
    398 	}
    399 	if (oid.startsWith(CVC.id_CERTICOM) == CVC.id_CERTICOM.length) {
    400 		return true;
    401 	}
    402 	return false;
    403 }
    404
    405
    406
    407 /**
    408  * Return true of the object identifier starts with id-TA-ECDSA
    409  *
    410  * @type boolean
    411  * @return true, if ECDSA based OID
    412  */
    413 CVC.isECDSA = function(oid) {
    414 	if (oid.startsWith(CVC.id_TA_ECDSA) == CVC.id_TA_ECDSA.length) {
    415 		return true;
    416 	}
    417 	if (oid.startsWith(CVC.id_ECDSA_WITH_SHA2) == CVC.id_ECDSA_WITH_SHA2.length) {
    418 		return true;
    419 	}
    420 	if (oid.equals(CVC.id_ECPUBLICKEY)) {
    421 		return true;
    422 	}
    423 	if (CVC.isCurveOID(oid)) {
    424 		return true;
    425 	}
    426 	return false;
    427 }
    428
    429
    430
    431 /**
    432  * Wrap an ECDSA signature in the format r || s into a TLV encoding as defined by RFC 3279
    433  *
    434  * @param signature ByteString containing the concatenation of r and s as unsigned integer values
    435  * @returns ASN.1 SEQUENCE objects containing two signed integer r and s
    436  */
    437 CVC.wrapSignature = function(signature) {
    438 	var len = signature.length / 2;
    439
    440 	// r and s are unsigned big integer. We might need to pad a zero for ASN.1 INTEGER which is signed
    441 	var r = signature.bytes(0, len);
    442 	while ((r.length > 1) && (r.byteAt(0) == 0)) {
    443 		r = r.bytes(1);
    444 	}
    445 	if (r.byteAt(0) >= 0x80) {
    446 		r = ByteString.valueOf(0, 1).concat(r);
    447 	}
    448
    449 	var s = signature.bytes(len, len);
    450 	while ((s.length > 1) && (s.byteAt(0) == 0)) {
    451 		s = s.bytes(1);
    452 	}
    453 	if (s.byteAt(0) >= 0x80) {
    454 		s = ByteString.valueOf(0, 1).concat(s);
    455 	}
    456
    457 	var t = new ASN1(ASN1.SEQUENCE);
    458 	t.add(new ASN1(ASN1.INTEGER, r));
    459 	t.add(new ASN1(ASN1.INTEGER, s));
    460
    461 	return t.getBytes();
    462 }
    463
    464
    465
    466 /**
    467  * Integer to octet string conversion
    468  */
    469 CVC.I2O = function(value, length) {
    470 	if (value.length > length) {
    471 		value = value.right(length);
    472 	}
    473 	while (value.length < length) {
    474 		value = CVC.PAD.left((length - value.length - 1 & 15) + 1).concat(value);
    475 	}
    476 	return value;
    477 }
    478 CVC.PAD = new ByteString("00000000000000000000000000000000", HEX);
    479
    480
    481
    482 /**
    483  * Unwrap a ECDSA signature from the TLV encoding according to RFC3279 into the concatenation
    484  * of the unsigned integer r and s
    485  *
    486  * @param signature TLV encoded signature
    487  * @param keylen optional parameter to specify the key lengths in bytes.
    488  * @returns concatenation of r and s
    489  */
    490 CVC.unwrapSignature = function(signature, keylen) {
    491 	var t = new ASN1(signature);
    492 	if (typeof(keylen) != "undefined") {
    493 		var r = CVC.I2O(t.get(0).value, keylen);
    494 		var s = CVC.I2O(t.get(1).value, keylen);
    495 	} else {
    496 		var r = t.get(0).value;
    497 		if (r.byteAt(0) == 00)
    498 			r = r.bytes(1);
    499
    500 		var s = t.get(1).value;
    501 		if (s.byteAt(0) == 00)
    502 			s = s.bytes(1);
    503 	}
    504
    505 	return r.concat(s);
    506 }
    507
    508
    509
    510 /**
    511  * Rewrap an ECDSA signature that contains redundant leading zeros in integer.
    512  *
    513  * @param signature the signature
    514  * @type ByteString
    515  * @param the fixed signature
    516  */
    517 CVC.rewrapSignature = function(signature) {
    518 	var a = new ASN1(signature);
    519 	var r = a.get(0).value;
    520 	while ((r.byteAt(0) == 0) && (r.byteAt(1) < 0x80)) {
    521 		r = r.bytes(1);
    522 	}
    523
    524 	var s = a.get(1).value;
    525 	while ((s.byteAt(0) == 0) && (s.byteAt(1) < 0x80)) {
    526 		s = s.bytes(1);
    527 	}
    528 	return (new ASN1(0x30, new ASN1(0x02, r), new ASN1(0x02, s))).getBytes();
    529 }
    530
    531
    532
    533 /**
    534  * Check a ASN sequence against a structure description
    535  *
    536  * @private
    537  * @param {Object} s the structure description
    538  * @param {ASN1} asn the asn sequence
    539  * @type String
    540  * @return null if valid or the validation error message
    541  */
    542 CVC.checkStructure = function(s, asn) {
    543 	var j = 0;
    544 	for (var i = 0; i < s.length; i++) {
    545 		var d = s[i];
    546
    547 //		print("Checking tag " + d.tag.toString(HEX));
    548
    549 		if (j < asn.elements) {
    550 			var a = asn.get(j);
    551
    552 			if (a.tag == d.tag) {
    553 				if ((typeof(d.minlen) != "undefined") && (a.value.length < d.minlen)) {
    554 					return "Length (" + a.value.length + ") of " + CVC.OBJECTNAMES[d.tag] + "(" + d.tag.toString(HEX) + ") less than " + d.minlen;
    555 				}
    556 				if ((typeof(d.maxlen) != "undefined") && (a.value.length > d.maxlen)) {
    557 					return "Length (" + a.value.length + ") of " + CVC.OBJECTNAMES[d.tag] + "(" + d.tag.toString(HEX) + ") more than " + d.maxlen;
    558 				}
    559 				if ((typeof(d.content) != "undefined")) {
    560 					var r = CVC.checkStructure(d.content, a);
    561 					if (r) {
    562 						return r;
    563 					}
    564 				}
    565 				j++;
    566 			} else {
    567 				if (!d.optional) {
    568 					return "Expecting " + CVC.OBJECTNAMES[d.tag] + "(" + d.tag.toString(HEX) + ") but found tag " + a.tag.toString(HEX);
    569 				}
    570 			}
    571 		} else {
    572 			if (!d.optional) {
    573 				return "Expecting " + CVC.OBJECTNAMES[d.tag] + "(" + d.tag.toString(HEX) + ") but sequence is exhaused";
    574 			}
    575 		}
    576 	}
    577 	return null;
    578 }
    579
    580
    581
    582 /**
    583  * Validate ASN1 semantic for card verifiable certificate or certificate request
    584  *
    585  * @type String
    586  * @return null if no error, or error message
    587  */
    588 CVC.prototype.validate = function() {
    589 	var r = null;
    590 	if (this.asn.tag == CVC.TAG_AT) {
    591 		r = CVC.checkStructure(CVC.ATREQ_SYNTAX, this.asn);
    592 	} else {
    593 		if (this.body.find(CVC.TAG_CED)) {
    594 			r = CVC.checkStructure(CVC.CERT_SYNTAX, this.asn);
    595 		} else {
    596 			r = CVC.checkStructure(CVC.REQ_SYNTAX, this.asn);
    597 		}
    598 	}
    599 	return r;
    600 }
    601
    602
    603
    604 /**
    605  * Return true of the certificate contains domain parameter
    606  *
    607  * @type boolean
    608  * @return true, if certificate contains domain parameter
    609  */
    610 CVC.prototype.containsDomainParameter = function() {
    611 	var pdo = this.body.find(CVC.TAG_PUK);
    612 	if (pdo == null) {
    613 		return false;
    614 	}
    615
    616 	var d = pdo.find(0x84);		// Generator
    617 	return (d != null);
    618 }
    619
    620
    621
    622 /**
    623  * Returns the certificate profile indicator (CPI)
    624  *
    625  * @return the CPI or null
    626  * @type Number
    627  */
    628 CVC.prototype.getCPI = function() {
    629 	var cpido = this.body.find(CVC.TAG_CPI);
    630
    631 	if (!cpido) {
    632 		return null;
    633 	}
    634
    635 	return cpido.value.toUnsigned();
    636 }
    637
    638
    639
    640 /**
    641  * Returns the certification authority reference (CAR).
    642  *
    643  * @return the CAR or null
    644  * @type PublicKeyReference
    645  */
    646 CVC.prototype.getCAR = function() {
    647 	var cardo = this.body.find(CVC.TAG_CAR);
    648
    649 	if (!cardo) {
    650 		return null;
    651 	}
    652
    653 	return new PublicKeyReference(cardo.value);
    654 }
    655
    656
    657
    658 /**
    659  * Returns the certificate holder reference (CHR).
    660  *
    661  * @return the CHR
    662  * @type PublicKeyReference
    663  */
    664 CVC.prototype.getCHR = function() {
    665 	var chrdo = this.body.find(CVC.TAG_CHR);
    666
    667 	if (!chrdo) {
    668 		throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Certificate does not contain a CHR");
    669 	}
    670
    671 	return new PublicKeyReference(chrdo.value);
    672 }
    673
    674
    675
    676 /**
    677  * Returns the certificate effective date (CED).
    678  *
    679  * @return the CED or null
    680  * @type Date
    681  */
    682 CVC.prototype.getCED = function() {
    683 	var ceddo = this.body.find(CVC.TAG_CED);
    684
    685 	if (!ceddo) {
    686 		return null
    687 	}
    688
    689 	var b = ceddo.value;
    690
    691 	var d = new Date();
    692 	d.setFullYear(b.byteAt(0) * 10 + b.byteAt(1) + 2000,
    693 				  b.byteAt(2) * 10 + b.byteAt(3) - 1,
    694 				  b.byteAt(4) * 10 + b.byteAt(5));
    695 	d.setHours(12, 0, 0, 0);
    696 	return d;
    697 }
    698
    699
    700
    701 /**
    702  * Returns the certificate expiration date (CXD).
    703  *
    704  * @return the CXD or null
    705  * @type Date
    706  */
    707 CVC.prototype.getCXD = function() {
    708 	var cxddo = this.body.find(CVC.TAG_CXD);
    709
    710 	if (!cxddo) {
    711 		return null
    712 	}
    713
    714 	var b = cxddo.value;
    715
    716 	var d = new Date();
    717 	d.setFullYear(b.byteAt(0) * 10 + b.byteAt(1) + 2000,
    718 				  b.byteAt(2) * 10 + b.byteAt(3) - 1,
    719 				  b.byteAt(4) * 10 + b.byteAt(5));
    720 	d.setHours(12, 0, 0, 0);
    721 	return d;
    722 }
    723
    724
    725
    726 /**
    727  * Returns the outer certification authority reference (CAR).
    728  *
    729  * @return the outer CAR or null
    730  * @type PublicKeyReference
    731  */
    732 CVC.prototype.getOuterCAR = function() {
    733 	if (!this.isAuthenticatedRequest()) {
    734 		return null;
    735 	}
    736 	var cardo = this.asn.get(1);
    737
    738 	if (!cardo) {
    739 		return null
    740 	}
    741
    742 	return new PublicKeyReference(cardo.value);
    743 }
    744
    745
    746
    747 /**
    748  * Returns the extension identified by the object identifier.
    749  *
    750  * @return the extension including the OID or null if not defined
    751  * @type ASN1
    752  */
    753 CVC.prototype.getExtension = function(extoid) {
    754 	var extdo = this.body.find(CVC.TAG_EXTN);
    755
    756 	if (!extdo) {
    757 		return null;
    758 	}
    759
    760 //	print(extdo);
    761
    762 	for (var i = 0; i < extdo.elements; i++) {
    763 		var ext = extdo.get(i);
    764 		var oid = ext.get(0);
    765 		assert(oid.tag == ASN1.OBJECT_IDENTIFIER);
    766 		if (oid.value.equals(extoid)) {
    767 			return ext;
    768 		}
    769 	}
    770 	return null;
    771 }
    772
    773
    774
    775 /**
    776  * Returns the Certificate Holder Authorization Template.
    777  *
    778  * @return the chat or null if not defined
    779  * @type ASN1
    780  */
    781 CVC.prototype.getCHAT = function() {
    782 	var chat = this.body.find(CVC.TAG_CHAT);
    783
    784 	return chat;
    785 }
    786
    787
    788
    789 /**
    790  * Returns the public key object identifier
    791  *
    792  * @returns the object identifier assigned to the public key
    793  * @type ByteString
    794  */
    795 CVC.prototype.getPublicKeyOID = function() {
    796 	var pdo = this.body.find(CVC.TAG_PUK);
    797 	if (pdo == null) {
    798 		throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Certificate does not contain a public key");
    799 	}
    800
    801 	var d = pdo.find(ASN1.OBJECT_IDENTIFIER);
    802 	if (d == null) {
    803 		throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Public key does not contain an object identifier");
    804 	}
    805 	return d.value;
    806 }
    807
    808
    809
    810 /**
    811  * Decode a public key from the TR-03110 format
    812  *
    813  * @param {ASN1} pdo the public key data object
    814  * @param {Key} key the key object to fill
    815  */
    816 CVC.decodeECPublicKey = function(pdo, key) {
    817
    818 	var d = pdo.find(0x86);		// Public point
    819 	if (d == null) {
    820 		throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Certificate does not contain a public key value");
    821 	}
    822
    823 	var b = d.value.bytes(1);
    824 	key.setComponent(Key.ECC_QX, b.left(b.length >> 1));
    825 	key.setComponent(Key.ECC_QY, b.right(b.length >> 1));
    826
    827 	var d = pdo.find(0x81);		// Prime modulus
    828 	if (d != null) {
    829 		key.setComponent(Key.ECC_P, d.value);
    830 	}
    831
    832 	var d = pdo.find(0x82);		// First coefficient a
    833 	if (d != null) {
    834 		key.setComponent(Key.ECC_A, d.value);
    835 	}
    836
    837 	var d = pdo.find(0x83);		// First coefficient b
    838 	if (d != null) {
    839 		key.setComponent(Key.ECC_B, d.value);
    840 	}
    841
    842 	var d = pdo.find(0x84);		// Base Point G
    843 	if (d != null) {
    844 		var b = d.value.bytes(1);
    845 		key.setComponent(Key.ECC_GX, b.left(b.length >> 1));
    846 		key.setComponent(Key.ECC_GY, b.right(b.length >> 1));
    847 	}
    848
    849 	var d = pdo.find(0x85);		// Order of the base point
    850 	if (d != null) {
    851 		key.setComponent(Key.ECC_N, d.value);
    852 	}
    853
    854 	var d = pdo.find(0x87);		// Cofactor f
    855 	if (d != null) {
    856 		key.setComponent(Key.ECC_H, d.value);
    857 	}
    858 }
    859
    860
    861
    862 /**
    863  * Returns the EC public key contained in the certificate.
    864  *
    865  * @param {Key} domParam optional domain parameter if they are not contained in certificate
    866  * @return the public key object
    867  * @type Key
    868  */
    869 CVC.prototype.getECPublicKey = function(domParam) {
    870 	var oid = this.getPublicKeyOID();
    871 	if (CVC.isCurveOID(oid)) {
    872 		var key = new Key();
    873 		key.setComponent(Key.ECC_CURVE_OID, oid);
    874 	} else if (typeof(domParam) != "undefined") {
    875 		var key = new Key(domParam);
    876 	} else {
    877 		if (typeof(this.domParam) != "undefined") {
    878 			var key = new Key(this.domParam);
    879 		} else {
    880 			var key = new Key();
    881 		}
    882 	}
    883
    884 	key.setType(Key.PUBLIC);
    885
    886 	var pdo = this.body.find(CVC.TAG_PUK);
    887 	if (pdo == null) {
    888 		throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Certificate does not contain a public key");
    889 	}
    890
    891 	CVC.decodeECPublicKey(pdo, key);
    892
    893 	return key;
    894 }
    895
    896
    897
    898 /**
    899  * Returns the RSA public key contained in the certificate.
    900  *
    901  * @return the public key object
    902  * @type Key
    903  */
    904 CVC.prototype.getRSAPublicKey = function() {
    905 	var key = new Key();
    906
    907 	key.setType(Key.PUBLIC);
    908
    909 	var pdo = this.body.find(CVC.TAG_PUK);
    910 	if (pdo == null) {
    911 		throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Certificate does not contain a public key");
    912 	}
    913
    914 	var d = pdo.find(0x81);		// modulus
    915 	if (d != null) {
    916 		key.setComponent(Key.MODULUS, d.value);
    917 	}
    918
    919 	var d = pdo.find(0x82);		// public exponent
    920 	if (d != null) {
    921 		key.setComponent(Key.EXPONENT, d.value);
    922 	}
    923
    924 	return key;
    925 }
    926
    927
    928
    929 /**
    930  * Returns the public key contained in the certificate.
    931  *
    932  * @param {Key} domParam optional domain parameter if they are not contained in certificate
    933  * @return the public key object
    934  * @type Key
    935  */
    936 CVC.prototype.getPublicKey = function(domParam) {
    937 	var pkoid = this.getPublicKeyOID();
    938
    939 	if (CVC.isECDSA(pkoid)) {
    940 		return this.getECPublicKey(domParam);
    941 	}
    942 	return this.getRSAPublicKey();
    943 }
    944
    945
    946
    947 /**
    948  * Determine the SubjectKeyIdentifier as defined in X.509
    949  *
    950  * @return the key identifier
    951  * @type ByteString
    952  */
    953 CVC.prototype.determineKeyIdentifier = function() {
    954 	var pdo = this.body.find(CVC.TAG_PUK);
    955 	if (pdo == null) {
    956 		throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Certificate does not contain a public key");
    957 	}
    958
    959 	var pkoid = this.getPublicKeyOID();
    960
    961 	var keybin;
    962 	if (CVC.isECDSA(pkoid)) {
    963 		var d = pdo.find(0x86);		// Public point
    964 		keybin = d.value;
    965 	} else {
    966 		var modulus = pdo.find(0x81).value;		// modulus
    967 		if (modulus.byteAt(0) >= 0x80) {
    968 			modulus = ByteString.valueOf(0).concat(modulus);
    969 		}
    970 		var exponent = pdo.find(0x82).value;		// public exponent
    971 		var rsapub = new ASN1("RSAPublicKey", ASN1.SEQUENCE,
    972 				      new ASN1("modulus", ASN1.INTEGER, modulus),
    973 				      new ASN1("publicKeyExponent", ASN1.INTEGER, exponent));
    974
    975 		keybin = rsapub.getBytes();
    976 	}
    977 	return CVC.crypto.digest(Crypto.SHA_1, keybin);
    978 }
    979
    980
    981
    982 /**
    983  * Return the x-coordinate of the EC Public Key.
    984  *
    985  * @return the key identifier
    986  * @type ByteString
    987  */
    988 CVC.prototype.getECPublicKeyIdentifier = function() {
    989 	var pdo = this.body.find(CVC.TAG_PUK);
    990 	if (pdo == null) {
    991 		throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Certificate does not contain a public key");
    992 	}
    993
    994 	var pkoid = this.getPublicKeyOID();
    995 	if (!CVC.isECDSA(pkoid)) {
    996 		throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Certificate does not contain a EC Public Key");
    997 	}
    998
    999 	var d = pdo.find(0x86);		// Public point
    1000 	var l = d.length >> 1;
    1001 	return d.value.bytes(1, l);
    1002 }
    1003
    1004
    1005
    1006 /**
    1007  * Determine if this is an authenticated request
    1008  *
    1009  * @returns true, if authenticated request
    1010  * @type Boolean
    1011  */
    1012 CVC.prototype.isAuthenticatedRequest = function() {
    1013 	return (this.asn.tag == CVC.TAG_AT);
    1014 }
    1015
    1016
    1017
    1018 /**
    1019  * Determine if this is a certificate request
    1020  *
    1021  * @returns true, if certificate request
    1022  * @type Boolean
    1023  */
    1024 CVC.prototype.isCertificateRequest = function() {
    1025 	if (this.isAuthenticatedRequest()) {
    1026 		return true;
    1027 	}
    1028
    1029 	var ced = this.getCED();
    1030 	return ced == null;
    1031 }
    1032
    1033
    1034
    1035 /**
    1036  * Determine if this is a countersigned authenticated request
    1037  *
    1038  * @returns true, if countersigned authenticated request
    1039  * @type Boolean
    1040  */
    1041 CVC.prototype.isCountersignedRequest = function() {
    1042 	if (!this.isAuthenticatedRequest()) {
    1043 		return false;
    1044 	}
    1045 	return (this.getCHR().getHolder() != this.getOuterCAR().getHolder());
    1046 }
    1047
    1048
    1049
    1050 /**
    1051  * Determine if this certificate is expired
    1052  *
    1053  * @returns true, if certificate is expired
    1054  * @type Boolean
    1055  */
    1056 CVC.prototype.isExpired = function() {
    1057 	var now = new Date();
    1058 	now.setHours(12, 0, 0, 0);
    1059 	return (now.valueOf() > this.getCXD().valueOf());
    1060 }
    1061
    1062
    1063
    1064 /**
    1065  * Verify certificate signature with public key
    1066  *
    1067  * @param {Crypto} crypto the crypto instance to use for verification
    1068  * @param {Key} puk the public key
    1069  * @param {ByteString} oid the signature algorithm
    1070  * @returns true if the signature is valid
    1071  * @type Boolean
    1072  */
    1073 CVC.prototype.verifyWith = function(crypto, puk, oid) {
    1074 	if (this.asn.tag == CVC.TAG_AT) {
    1075 		var signature = this.asn.get(0).get(1);
    1076 	} else {
    1077 		var signature = this.asn.get(1);
    1078 	}
    1079
    1080 	if (typeof(oid) == "undefined") {
    1081 		var oid = this.getPublicKeyOID();
    1082 	}
    1083 	var mech = CVC.getSignatureMech(oid, puk.getSize());
    1084
    1085 	if (CVC.isECDSA(oid)) {
    1086 		var signatureValue = CVC.wrapSignature(signature.value);
    1087 		this.domParam = puk;
    1088 	} else {
    1089 		var signatureValue = signature.value;
    1090 	}
    1091
    1092 	return crypto.verify(puk, mech, this.body.getBytes(), signatureValue);
    1093 }
    1094
    1095
    1096
    1097 /**
    1098  * Verify certificate signature with public key from card verifiable certificate
    1099  *
    1100  * @param {CVC} cvc the card verifiable certificate used to obtain the public key
    1101  * @returns true if the signature is valid
    1102  * @type Boolean
    1103  */
    1104 CVC.prototype.verifyWithCVC = function(crypto, cvc) {
    1105 	return this.verifyWith(crypto, cvc.getPublicKey(), cvc.getPublicKeyOID());
    1106 }
    1107
    1108
    1109
    1110 /**
    1111  * Verify outer signature of an authenticated request with public key
    1112  *
    1113  * @param {Key} puk the public key
    1114  * @param {ByteString} oid the signature algorithm
    1115  * @returns true if the signature is valid
    1116  * @type Boolean
    1117  */
    1118 CVC.prototype.verifyATWith = function(crypto, puk, oid) {
    1119 	if (!this.isAuthenticatedRequest()) {
    1120 		throw new GPError("CVC", GPError.INVALID_DATA, 0, "Not an authenticated request");
    1121 	}
    1122
    1123 	var signature = this.asn.get(2);
    1124 	var signatureInput = this.asn.get(0).getBytes().concat(this.asn.get(1).getBytes());
    1125
    1126 	if (typeof(oid) == "undefined") {
    1127 		var oid = this.getPublicKeyOID();
    1128 	}
    1129 	var mech = CVC.getSignatureMech(oid);
    1130
    1131 	if (CVC.isECDSA(oid)) {
    1132 		var signatureValue = CVC.wrapSignature(signature.value);
    1133 	} else {
    1134 		var signatureValue = signature.value;
    1135 	}
    1136 	return crypto.verify(puk, mech, signatureInput, signatureValue);
    1137 }
    1138
    1139
    1140
    1141 /**
    1142  * Verify outer signature of an authenticated request with public key from card verifiable certificate
    1143  *
    1144  * @param {CVC} cvc the card verifiable certificate used to obtain the public key
    1145  * @returns true if the signature is valid
    1146  * @type Boolean
    1147  */
    1148 CVC.prototype.verifyATWithCVC = function(crypto, cvc) {
    1149 	return this.verifyATWith(crypto, cvc.getPublicKey(), cvc.getPublicKeyOID());
    1150 }
    1151
    1152
    1153
    1154 /**
    1155  * Returns the encoded certificate
    1156  *
    1157  * @return the DER encoded certificate
    1158  * @type ByteString
    1159  */
    1160 CVC.prototype.getBytes = function() {
    1161 	return this.bin;
    1162 }
    1163
    1164
    1165
    1166 /**
    1167  * Returns the certificate as ASN1 structure
    1168  *
    1169  * @return the certificate as ASN1 structure
    1170  * @type ASN1
    1171  */
    1172 CVC.prototype.getASN1 = function() {
    1173 	return this.asn;
    1174 }
    1175
    1176
    1177
    1178 /**
    1179  * Function to recursively walk the ASN.1 tree
    1180  */
    1181 CVC.decorateTree = function(node) {
    1182 	var name = CVC.OBJECTNAMES[node.tag];
    1183
    1184 	if (name) {
    1185 		node.setName(name);
    1186 	}
    1187
    1188 	if (node.isconstructed) {
    1189 		for (var i = 0; i < node.elements; i++) {
    1190 			CVC.decorateTree(node.get(i));
    1191 		}
    1192 	}
    1193 }
    1194
    1195
    1196
    1197 /**
    1198  * Decorate the ASN.1 object with the correct name
    1199  */
    1200 CVC.prototype.decorate = function() {
    1201 	CVC.decorateTree(this.asn);
    1202 	var cxddo = this.body.find(CVC.TAG_CXD);
    1203 	if (cxddo == null) {
    1204 		if (this.asn.tag == CVC.TAG_AT) {
    1205 			this.asn.setName("Authenticated CVC Request");
    1206 		} else {
    1207 			this.asn.setName("CVC Request");
    1208 		}
    1209 	}
    1210 }
    1211
    1212
    1213
    1214 /**
    1215  * Return list of rights granted by the certificate
    1216  *
    1217  * @returns the list of rights
    1218  * @type String[]
    1219  */
    1220 CVC.prototype.getRightsAsList = function() {
    1221 	var list = [];
    1222
    1223 	var rtab;
    1224 	var chat = this.getCHAT();
    1225 	if (chat == null) {
    1226 		return list;
    1227 	}
    1228
    1229 	var oid = chat.get(0).value;
    1230
    1231 	if (oid.equals(CVC.idIS)) {
    1232 		rtab = CVC.ISRIGHTS;
    1233 	} else if (oid.equals(CVC.idAT)) {
    1234 		rtab = CVC.ATRIGHTS;
    1235 	} else if (oid.equals(CVC.idST)) {
    1236 		rtab = CVC.STRIGHTS;
    1237 	} else {
    1238 		return null;
    1239 	}
    1240
    1241 	var mask = chat.get(1).value;
    1242 	var c = 0;
    1243 	for (var i = mask.length - 1; i >= 0; i--) {
    1244 		var akku = mask.byteAt(i);
    1245 		for (var j = 0; j < (i == 0 ? 6 : 8); j++) {
    1246 			if (akku & 1) {
    1247 				list.push(rtab[c]);
    1248 			}
    1249 			c++;
    1250 			akku >>= 1;
    1251 		}
    1252 	}
    1253 	return list;
    1254 }
    1255
    1256
    1257
    1258 /**
    1259  * Return position of certificate in PKI hierachie
    1260  *
    1261  * @returns Position in PKI hierachie: 0 unknown, 1-CVCA, 2-DVCA, 3-Terminal
    1262  * @type Number
    1263  */
    1264 CVC.prototype.getLevel = function() {
    1265 	var chat = this.getCHAT();
    1266 	if (!chat) {
    1267 		return 0;
    1268 	}
    1269
    1270 	var l = chat.get(1).value.byteAt(0) & 0xC0;
    1271 	if (l == 0xC0) {
    1272 		return 1;
    1273 	}
    1274 	return l == 0x00 ? 3 : 2;
    1275 }
    1276
    1277
    1278
    1279 /**
    1280  * Return a string describing the certificate type
    1281  *
    1282  * @returns a describing string
    1283  * @type String
    1284  */
    1285 CVC.prototype.getType = function() {
    1286 	var ced = this.getCED();
    1287 	var chat = this.getCHAT();
    1288
    1289 	// Decode certificate / request type
    1290 	var str = "CVC ";
    1291 	if (ced == null) {
    1292 		if (this.asn.tag == CVC.TAG_AT) {
    1293 			str = "AT-CVREQ ";
    1294 		} else {
    1295 			str = "CVREQ ";
    1296 		}
    1297 	}
    1298
    1299 	// Decode CA type
    1300 	if (chat != null) {
    1301 		var oid = chat.get(0).value;
    1302
    1303 		if (oid.equals(CVC.idSC_HSM) || oid.equals(CVC.idBW_SE)) {
    1304 			if (oid.equals(CVC.idSC_HSM)) {
    1305 				str += "id-SC-HSM ";
    1306 			} else {
    1307 				str += "id-BW-SE ";
    1308 			}
    1309 			switch(chat.get(1).value.byteAt(0) & 0xC0) {
    1310 				case 0xC0: str += "SRCA "; break;
    1311 				case 0x80: str += "DICA "; break;
    1312 				case 0x40: str += "MICA "; break;
    1313 				case 0x00: str += "Device "; break;
    1314 			}
    1315 		} else {
    1316 			var trustedDV = "";
    1317 			var untrustedDV = "";
    1318
    1319 			if (oid.equals(CVC.idIS)) {
    1320 				str += "id-IS ";
    1321 				trustedDV = "(official domestic) ";
    1322 				untrustedDV = "(official foreign) ";
    1323 			} else if (oid.equals(CVC.idAT)) {
    1324 				str += "id-AT ";
    1325 				trustedDV = "(official domestic) ";
    1326 				untrustedDV = "(non-official / foreign) ";
    1327 			} else if (oid.equals(CVC.idST)) {
    1328 				str += "id-ST ";
    1329 				trustedDV = "(accreditation body) ";
    1330 				untrustedDV = "(certification service provider) ";
    1331 			} else {
    1332 				str += oid.toString(OID) + " ";
    1333 			}
    1334
    1335 			switch(chat.get(1).value.byteAt(0) & 0xC0) {
    1336 				case 0xC0: str += "CVCA "; break;
    1337 				case 0x80: str += "DV " + trustedDV; break;
    1338 				case 0x40: str += "DV " + untrustedDV; break;
    1339 				case 0x00: str += "Terminal "; break;
    1340 			}
    1341 		}
    1342 	}
    1343
    1344 	return str;
    1345 }
    1346
    1347
    1348
    1349 /**
    1350  * Return a textual description of the certificate
    1351  *
    1352  * @returns a string containing information about the certificate
    1353  * @type String
    1354  */
    1355 CVC.prototype.toString = function() {
    1356 	var car = this.getCAR();
    1357 	var ced = this.getCED();
    1358
    1359 	var str = this.getType();
    1360
    1361 	if (car) {
    1362 		str += "CAR=" + car.toString() + " ";
    1363 	}
    1364
    1365 	str += "CHR=" + this.getCHR().toString() + " ";
    1366
    1367 	if (ced) {
    1368 		str += "CED=" + ced.toLocaleDateString() + " ";
    1369 	}
    1370
    1371 	var cxd = this.getCXD();
    1372 	if (cxd) {
    1373 		str += "CXD=" + cxd.toLocaleDateString() + " ";
    1374 	}
    1375
    1376 	if (this.isAuthenticatedRequest()) {
    1377 		str += "oCAR=" + this.getOuterCAR().toString() + " ";
    1378 	}
    1379
    1380 	return str;
    1381 }
    1382
    1383
    1384
    1385 /**
    1386  * Return object suitable for JSON encoding
    1387  *
    1388  * @returns a JSON encodable object
    1389  * @type Object
    1390  */
    1391 CVC.prototype.toJSON = function() {
    1392 	return { clazz: "CVC", value: this.bin };
    1393 }
    1394
    1395
    1396
    1397 /**
    1398  * Recreate object from JSON encoding
    1399  *
    1400  * @returns the CVC object
    1401  * @type Object
    1402  */
    1403 CVC.fromJSON = function(obj) {
    1404 	assert(obj.clazz.equals("CVC"), "JSON object must contain clazz: CVC");
    1405 	return new CVC(obj.value);
    1406 }
    1407