      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 Common classes and functions for PKIX
     25  */
     26
     27
     28
     29 /**
     30  * Common functions and constants
     31  */
     32 function PKIXCommon() {
     33 }
     34
     35 exports.PKIXCommon = PKIXCommon;
     36
     37
     38 PKIXCommon.digitalSignature	= 0x0080;
     39 PKIXCommon.nonRepudiation	= 0x0040;
     40 PKIXCommon.keyEncipherment	= 0x0020;
     41 PKIXCommon.dataEncipherment	= 0x0010;
     42 PKIXCommon.keyAgreement		= 0x0008;
     43 PKIXCommon.keyCertSign		= 0x0004;
     44 PKIXCommon.cRLSign		= 0x0002;
     45 PKIXCommon.encipherOnly		= 0x0001;
     46 PKIXCommon.decipherOnly		= 0x8000;
     47
     48
     49
     50 /**
     51  * Convert integer to fixed length string with leading zeros.
     52  *
     53  * @private
     54  * @param {Number} value the value to convert to a string.
     55  * @param {Number} digits the number of digits in output string. Must be <= 20.
     56  * @return the 0-padded string
     57  * @type String
     58  */
     59 PKIXCommon.itos = function(value, digits) {
     60 	if (digits > 20) {
     61 		throw new Error("Digits must be <= 20");
     62 	}
     63 	var str = "" + value;
     64 	str = "0000000000000000000".substr(19 - (digits - str.length)).concat(str);
     65 	return str;
     66 }
     67
     68
     69
     70 /**
     71  * Convert date and time to UTC string with format YYMMDDHHMMSSZ.
     72  *
     73  * @param {Date} d the date object.
     74  * @return the date/time string.
     75  * @type String
     76  */
     77 PKIXCommon.dtoUTC = function(d) {
     78 	var s = PKIXCommon.itos(d.getUTCFullYear() % 100, 2) +
     79 			PKIXCommon.itos(d.getUTCMonth() + 1, 2) +
     80 			PKIXCommon.itos(d.getUTCDate(), 2) +
     81 			PKIXCommon.itos(d.getUTCHours(), 2) +
     82 			PKIXCommon.itos(d.getUTCMinutes(), 2) +
     83 			PKIXCommon.itos(d.getUTCSeconds(), 2) + "Z";
     84 	return s;
     85 }
     86
     87
     88
     89 /**
     90  * Convert date and time to UTC string with format YYYYMMDDHHMMSSZ.
     91  *
     92  * @param {Date} d the date object.
     93  * @return the date/time string.
     94  * @type String
     95  */
     96 PKIXCommon.dtoUTCFullYear = function(d) {
     97 	var s = 	d.getUTCFullYear() +
     98 			PKIXCommon.itos(d.getUTCMonth() + 1, 2) +
     99 			PKIXCommon.itos(d.getUTCDate(), 2) +
    100 			PKIXCommon.itos(d.getUTCHours(), 2) +
    101 			PKIXCommon.itos(d.getUTCMinutes(), 2) +
    102 			PKIXCommon.itos(d.getUTCSeconds(), 2) + "Z";
    103 	return s;
    104 }
    105
    106
    107
    108 /**
    109  * Add the specified number of days to a date object
    110  *
    111  * @param {Date} d the date object
    112  * @param {Number} days the number of days to add, may be negative
    113  * @type Date
    114  * @return a new Date object
    115  */
    116 PKIXCommon.addDays = function(d, days) {
    117 	var hour = d.getUTCHours();
    118 	var minute = d.getUTCMinutes();
    119 	var second = d.getUTCSeconds();
    120 	var cd = new Date(d);
    121 	cd.setHours(12);
    122
    123 	var ts = cd.getTime();
    124 	ts += days * 24 * 60 * 60 * 1000;
    125 	var nd = new Date(ts);
    126
    127 	nd.setUTCHours(hour);
    128 	nd.setUTCMinutes(minute);
    129 	nd.setUTCSeconds(second);
    130 	return nd;
    131 }
    132
    133
    134
    135 /**
    136  * Converts the integer value into a BIT STRING value.
    137  * <p>The function interprets the integer value as bitmap, where
    138  * bit 0 is the most significant bit of the least significant byte.</p>
    139  * <p>The function adds the minimum number of bytes to the final bit string
    140  * and encodes the "number of unused bits at the beginning.</p>
    141  *
    142  * @param {Number} val the value to convert
    143  * @return the bit string
    144  * @type ByteString
    145  */
    146 PKIXCommon.bitstringForInteger = function(val) {
    147 	var bb = new ByteBuffer();
    148 	var b = 0;
    149
    150 	// Encode starting with the least significant byte
    151 	while (val > 0) {
    152 		b = val & 0xFF;
    153 		bb.append(b);
    154 		val = val >> 8;
    155 	}
    156
    157 	// Determine number of unused bits
    158 	var i = 0;
    159 	while ((i < 8) && !(b & 1)) {
    160 		i++;
    161 		b >>= 1;
    162 	}
    163
    164 	bb.insert(0, i);
    165 	return bb.toByteString();
    166 }
    167
    168
    169
    170 /**
    171  * Removes leading zeros and prepends a single '00' to ByteStrings which have the most significant bit set.
    172  *
    173  * This prevent interpretation of the integer representation if converted into
    174  * a signed ASN1 INTEGER.
    175  *
    176  * @param {ByteString} value the value to convert
    177  * @return the converted value
    178  * @type ByteString
    179  */
    180 PKIXCommon.convertUnsignedInteger = function(value) {
    181 	assert(value.length > 0);
    182
    183 	var i = 0;
    184 	for (var i = 0; (i < value.length - 1) && (value.byteAt(i) == 0); i++);
    185
    186 	if (value.byteAt(i) >= 0x80) {
    187 		value = (new ByteString("00", HEX)).concat(value.bytes(i));
    188 	} else {
    189 		value = value.bytes(i);
    190 	}
    191
    192 	return value;
    193 }
    194
    195
    196
    197 /**
    198  * Removes leading zero byte.
    199  *
    200  * @param {ByteString} value the value to process
    201  * @return the processed ByteString without leading zero byte
    202  * @type ByteString
    203  */
    204 PKIXCommon.removeLeadingZeroBytes = function(value) {
    205 	if (value.length > 0 && value.byteAt(0) == 0x00) {
    206 		value = value.bytes(1);
    207 	}
    208
    209 	return value;
    210 }
    211
    212
    213
    214 /**
    215  * Encode PSS algorithm parameter
    216  */
    217 PKIXCommon.encodePSSAlgorithmParameter = function(hashAlgorithm, saltLength) {
    218 	var param =  new ASN1("parameters", ASN1.SEQUENCE,
    219 			new ASN1("hashAlgorithm", 0xA0,
    220 				new ASN1("sha256Identifier", ASN1.SEQUENCE,
    221 					new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, hashAlgorithm),
    222 					new ASN1("parameter", ASN1.NULL, new ByteString("", HEX)))),
    223 			new ASN1("maskGenAlgorithm", 0xA1,
    224 				new ASN1("mgf1SHA256Identifier", ASN1.SEQUENCE,
    225 					new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, new ByteString("pkcs-1 8", OID)), // id-mgf1
    226 					new ASN1("parameters", ASN1.SEQUENCE,
    227 						new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, hashAlgorithm),
    228 						new ASN1("parameter", ASN1.NULL, new ByteString("", HEX))))),
    229 			new ASN1("hashAlgorithm", 0xA2,
    230 				new ASN1("saltLength", ASN1.INTEGER, ByteString.valueOf(saltLength)))
    231 			);
    232
    233 	return param;
    234 }
    235
    236
    237
    238 /**
    239  * Gets the signature algorithm TLV object
    240  *
    241  * @return the signature algorithm object
    242  * @type ASN1
    243  */
    244 PKIXCommon.encodeSignatureAlgorithm = function(signatureAlgorithm) {
    245 	var t = new ASN1("signatureAlgorithm", ASN1.SEQUENCE);
    246
    247 	if ((signatureAlgorithm == Crypto.RSA) || (signatureAlgorithm == Crypto.RSA_SHA1)) {
    248 		t.add(new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, new ByteString("sha1WithRSAEncryption", OID)));
    249 		t.add(new ASN1("parameters", ASN1.NULL, new ByteString("", HEX)));
    250 	} else if (signatureAlgorithm == Crypto.RSA_SHA256) {
    251 		t.add(new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, new ByteString("sha256WithRSAEncryption", OID)));
    252 		t.add(new ASN1("parameters", ASN1.NULL, new ByteString("", HEX)));
    253 	} else if (signatureAlgorithm == Crypto.RSA_SHA384) {
    254 		t.add(new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, new ByteString("sha384WithRSAEncryption", OID)));
    255 		t.add(new ASN1("parameters", ASN1.NULL, new ByteString("", HEX)));
    256 	} else if (signatureAlgorithm == Crypto.RSA_SHA512) {
    257 		t.add(new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, new ByteString("sha512WithRSAEncryption", OID)));
    258 		t.add(new ASN1("parameters", ASN1.NULL, new ByteString("", HEX)));
    259 	} else if (signatureAlgorithm == Crypto.RSA_PSS_SHA1) {
    260 		t.add(new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, new ByteString("id-RSASSA-PSS", OID)));
    261 		t.add(new ASN1("parameters", ASN1.NULL, new ByteString("", HEX)));
    262 	} else if (signatureAlgorithm == Crypto.RSA_PSS_SHA256) {
    263 		t.add(new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, new ByteString("id-RSASSA-PSS", OID)));
    264 		t.add(PKIXCommon.encodePSSAlgorithmParameter(new ByteString("id-sha256", OID), 32));
    265 	} else if (signatureAlgorithm == Crypto.RSA_PSS_SHA384) {
    266 		t.add(new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, new ByteString("id-RSASSA-PSS", OID)));
    267 		t.add(PKIXCommon.encodePSSAlgorithmParameter(new ByteString("id-sha384", OID), 48));
    268 	} else if (signatureAlgorithm == Crypto.RSA_PSS_SHA512) {
    269 		t.add(new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, new ByteString("id-RSASSA-PSS", OID)));
    270 		t.add(PKIXCommon.encodePSSAlgorithmParameter(new ByteString("id-sha512", OID), 64));
    271 	} else if (signatureAlgorithm == Crypto.ECDSA_SHA1) {
    272 		t.add(new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, new ByteString("ecdsa-with-SHA1", OID)));
    273 	} else if (signatureAlgorithm == Crypto.ECDSA_SHA224) {
    274 		t.add(new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, new ByteString("ecdsa-with-SHA224", OID)));
    275 	} else if (signatureAlgorithm == Crypto.ECDSA_SHA256) {
    276 		t.add(new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, new ByteString("ecdsa-with-SHA256", OID)));
    277 	} else if (signatureAlgorithm == Crypto.ECDSA_SHA384) {
    278 		t.add(new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, new ByteString("ecdsa-with-SHA384", OID)));
    279 	} else if (signatureAlgorithm == Crypto.ECDSA_SHA512) {
    280 		t.add(new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, new ByteString("ecdsa-with-SHA512", OID)));
    281 	} else {
    282 		throw new GPError(module.id, GPError.INVALID_MECH, signatureAlgorithm, "Invalid algorithm");
    283 	}
    284
    285 	return t;
    286 }
    287
    288
    289
    290 PKIXCommon.algIdMap = {};
    291 PKIXCommon.algIdMap[(new ByteString("sha1WithRSAEncryption", OID)).toString(HEX)] = Crypto.RSA_SHA1;
    292 PKIXCommon.algIdMap[(new ByteString("sha256WithRSAEncryption", OID)).toString(HEX)] = Crypto.RSA_SHA256;
    293 PKIXCommon.algIdMap[(new ByteString("sha384WithRSAEncryption", OID)).toString(HEX)] = Crypto.RSA_SHA384;
    294 PKIXCommon.algIdMap[(new ByteString("sha512WithRSAEncryption", OID)).toString(HEX)] = Crypto.RSA_SHA512;
    295 PKIXCommon.algIdMap[(new ByteString("id-RSASSA-PSS", OID)).toString(HEX)] = Crypto.RSA_PSS_SHA1;
    296 PKIXCommon.algIdMap[(new ByteString("ecdsa-with-SHA1", OID)).toString(HEX)] = Crypto.ECDSA_SHA1;
    297 PKIXCommon.algIdMap[(new ByteString("ecdsa-with-SHA224", OID)).toString(HEX)] = Crypto.ECDSA_SHA224;
    298 PKIXCommon.algIdMap[(new ByteString("ecdsa-with-SHA256", OID)).toString(HEX)] = Crypto.ECDSA_SHA256;
    299 PKIXCommon.algIdMap[(new ByteString("ecdsa-with-SHA384", OID)).toString(HEX)] = Crypto.ECDSA_SHA384;
    300 PKIXCommon.algIdMap[(new ByteString("ecdsa-with-SHA512", OID)).toString(HEX)] = Crypto.ECDSA_SHA512;
    301
    302
    303
    304 /**
    305  * Return Crypto.x constant for given signatureAlgorithm
    306  *
    307  * @param {ByteString} signatureAlgorithm the algorithm
    308  * @param {ByteString} param the parameter (optional)
    309  * @type Number
    310  * @return the Crypto.X constant
    311  */
    312 PKIXCommon.decodeSignatureAlgorithm = function(signatureAlgorithm, param) {
    313 	if (signatureAlgorithm.equals(new ByteString("id-RSASSA-PSS", OID))) {
    314 		if (typeof(param) == "undefined") {
    315 			return Crypto.RSA_PSS_SHA1;
    316 		}
    317
    318 		var a = new ASN1(param);
    319 		var hashAlgorithm = null;
    320
    321 		for (var i = 0; i < a.elements; i++) {
    322 			var o = a.get(i);
    323 			if (o.tag == 0xA0) { // hashAlgorithm
    324 				var oid = o.get(0).get(0).value;
    325 				hashAlgorithm = this.decodeHashAlgorithm(oid);
    326 			} else if (o.tag == 0xA1) { // MGF
    327 				// Check MGF
    328 				var m = o.get(0).get(0).value;
    329 				if (!m.equals(new ByteString("pkcs-1 8", OID))) {
    330 					throw new GPError(module.id, GPError.INVALID_MECH, 2, "Unsupported MGF");
    331 				}
    332
    333 				// Check hashAlgorithm
    334 				var oid = o.get(0).get(1).get(0).value;
    335 				var h = this.decodeHashAlgorithm(oid);
    336 				if (hashAlgorithm == null) {
    337 					hashAlgorithm = h;
    338 				} else if (hashAlgorithm != h) {
    339 					throw new GPError(module.id, GPError.INVALID_MECH, 2, "Signature hash algorithm and MGF hash algorithm must be the same");
    340 				}
    341 			} else if (o.tag == 0xA2) { // saltLength
    342 				switch(hashAlgorithm) {
    343 					case Crypto.SHA_224:
    344 						var expectedSalt = 28;
    345 						break;
    346 					case Crypto.SHA_256:
    347 						var expectedSalt = 32;
    348 						break;
    349 					case Crypto.SHA_384:
    350 						var expectedSalt = 48;
    351 						break;
    352 					case Crypto.SHA_512:
    353 						var expectedSalt = 64;
    354 						break;
    355 					case Crypto.SHA_1:
    356 					default:
    357 						var expectedSalt = 20;
    358 				}
    359
    360 				var salt = o.get(0).value.toUnsigned();
    361 				if (salt != expectedSalt) {
    362 					throw new GPError(module.id, GPError.INVALID_MECH, 2, "saltLength (" + salt + ") must match hash size (" + expectedSalt + ")");
    363 				}
    364 			} else if (o.tag == 0xA3) { // trailerField
    365 				var trailerField = o.get(0).value.toUnsigned();
    366 				if (trailerField != 1) {
    367 					throw new GPError(module.id, GPError.INVALID_MECH, 2, "trailerField value must be 1");
    368 				}
    369 			}
    370 		}
    371
    372 		switch(hashAlgorithm) {
    373 			case Crypto.SHA_224:
    374 				return Crypto.RSA_PSS_SHA224;
    375 			case Crypto.SHA_256:
    376 				return Crypto.RSA_PSS_SHA256;
    377 			case Crypto.SHA_384:
    378 				return Crypto.RSA_PSS_SHA384;
    379 			case Crypto.SHA_512:
    380 				return Crypto.RSA_PSS_SHA512;
    381 			case Crypto.SHA_1:
    382 			default:
    383 				return Crypto.RSA_PSS_SHA1;
    384 		}
    385 	}
    386
    387 	var alg = PKIXCommon.algIdMap[signatureAlgorithm.toString(HEX)];
    388 	return alg;
    389 }
    390
    391
    392 /**
    393  * Return Crypto.SHA_x constant for given OID
    394  *
    395  * @param {ByteString} oid the hash OID
    396  * @type Number
    397  * @return the Crypto.SHA_x constant
    398  */
    399 PKIXCommon.decodeHashAlgorithm = function(oid) {
    400 	//var oid = algorithmId.get(0).get(0).value.toString(HEX);
    401
    402 	switch (oid.toString(HEX)) {
    403 		case new ByteString("id-sha1", OID).toString(HEX):
    404 			return Crypto.SHA_1;
    405 		case new ByteString("id-sha224", OID).toString(HEX):
    406 			return Crypto.SHA_224;
    407 		case new ByteString("id-sha256", OID).toString(HEX):
    408 			return Crypto.SHA_256;
    409 		case new ByteString("id-sha384", OID).toString(HEX):
    410 			return Crypto.SHA_384;
    411 		case new ByteString("id-sha512", OID).toString(HEX):
    412 			return Crypto.SHA_512;
    413 		default:
    414 			throw new GPError(module.id, GPError.INVALID_MECH, 1, "Invalid algorithm");
    415 	}
    416 }
    417
    418
    419
    420 /**
    421  * Return Crypto.RSA or Crypto.EC depending on signature algorithm
    422  *
    423  * @param {Number} alg signature algorithm (one of Crypto.X)
    424  * @type Number
    425  * @return either Crypto.RSA or Crypto.EC
    426  */
    427 PKIXCommon.keyTypeForAlgorithm = function(alg) {
    428 	if     ((alg == Crypto.RSA) ||
    429 		(alg == Crypto.RSA_SHA256) ||
    430 		(alg == Crypto.RSA_SHA384) ||
    431 		(alg == Crypto.RSA_SHA512) ||
    432 		(alg == Crypto.RSA_PSS_SHA1) ||
    433 		(alg == Crypto.RSA_PSS_SHA224) ||
    434 		(alg == Crypto.RSA_PSS_SHA256) ||
    435 		(alg == Crypto.RSA_PSS_SHA384) ||
    436 		(alg == Crypto.RSA_PSS_SHA512)) {
    437 		return Crypto.RSA;
    438 	} else {
    439 		return Crypto.EC;
    440 	}
    441 }
    442
    443
    444
    445 /**
    446  * Create tailored AlgorithmIdentifier that restricts usage of the public key.
    447  *
    448  * @param{String} restriction The restriction to apply.
    449  * @type ASN1
    450  * @return the tailored AlgorithmIdentifier;
    451  */
    452 PKIXCommon.restrictedPublicKeyAlgorithmIdentifier = function(restriction) {
    453 	switch(restriction) {
    454 		case "PSS-SHA1":
    455 			var puboid = new ByteString("id-RSASSA-PSS", OID);
    456 			var hash = new ByteString("id-sha1", OID);
    457 			break;
    458 		case "PSS-SHA224":
    459 			var puboid = new ByteString("id-RSASSA-PSS", OID);
    460 			var hash = new ByteString("id-sha224", OID);
    461 			break;
    462 		case "PSS-SHA256":
    463 			var puboid = new ByteString("id-RSASSA-PSS", OID);
    464 			var hash = new ByteString("id-sha256", OID);
    465 			break;
    466 		case "PSS-SHA384":
    467 			var puboid = new ByteString("id-RSASSA-PSS", OID);
    468 			var hash = new ByteString("id-sha384", OID);
    469 			break;
    470 		case "PSS-SHA512":
    471 			var puboid = new ByteString("id-RSASSA-PSS", OID);
    472 			var hash = new ByteString("id-sha512", OID);
    473 			break;
    474 		case "OEAP":
    475 		default:
    476 			throw new GPError(module.id, GPError.INVALID_DATA, 0, "Unknown public key restriction " + this.policy.restrictPublicKey);
    477 	}
    478
    479 	var info = PKIXCommon.encodePSSAlgorithmParameter(hash, 0);
    480 	var algorithm = new ASN1("algorithm", ASN1.SEQUENCE,
    481 		new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, puboid),
    482 		info
    483 	);
    484
    485 	return algorithm;
    486 }
    487
    488
    489
    490 /**
    491  * Encode EC Parameter for inclusion in the AlgorithmIdentifier structure.
    492  *
    493  * @param{Key} publicKey the public key.
    494  * @type ASN1
    495  * @return the encoded ECParameter.
    496  */
    497 PKIXCommon.encodeECParameter = function(publicKey) {
    498 	if (!publicKey.getComponent(Key.ECC_P)) {		// Make sure curve components are available if only curve oid is defined
    499 		publicKey.setComponent(Key.ECC_CURVE_OID, publicKey.getComponent(Key.ECC_CURVE_OID));
    500 	}
    501 	var ecParameter =
    502 		new ASN1("ecParameters", ASN1.SEQUENCE,
    503 			new ASN1("version", ASN1.INTEGER, new ByteString("01", HEX)),
    504 			new ASN1("fieldID", ASN1.SEQUENCE,
    505 				new ASN1("fieldType", ASN1.OBJECT_IDENTIFIER, new ByteString("prime-field", OID)),
    506 				new ASN1("prime", ASN1.INTEGER,
    507 					PKIXCommon.convertUnsignedInteger(publicKey.getComponent(Key.ECC_P)))
    508 			),
    509 			new ASN1("curve", ASN1.SEQUENCE,
    510 				new ASN1("a", ASN1.OCTET_STRING, publicKey.getComponent(Key.ECC_A)),
    511 				new ASN1("b", ASN1.OCTET_STRING, publicKey.getComponent(Key.ECC_B))
    512 			),
    513 			new ASN1("base", ASN1.OCTET_STRING,
    514 					(new ByteString("04", HEX)).concat(publicKey.getComponent(Key.ECC_GX)).concat(publicKey.getComponent(Key.ECC_GY))),
    515 			new ASN1("order", ASN1.INTEGER,
    516 				PKIXCommon.convertUnsignedInteger(publicKey.getComponent(Key.ECC_N)))
    517 		);
    518
    519 	var cofactor = publicKey.getComponent(Key.ECC_H);
    520 	var i = 0;
    521 	for (; (i < cofactor.length) && (cofactor.byteAt(i) == 0); i++);
    522 	if (i < cofactor.length) {
    523 		ecParameter.add(new ASN1("cofactor", ASN1.INTEGER, cofactor.bytes(i)));
    524 	}
    525 	return ecParameter;
    526 }
    527
    528
    529
    530 /**
    531  * Creates the EC Public Key as subjectPublicKeyInfo TLV structure object.
    532  *
    533  * <p>The structure is defined as:</p>
    534  * <pre>
    535  *	SubjectPublicKeyInfo  ::=  SEQUENCE  {
    536  *		algorithm            AlgorithmIdentifier,
    537  *		subjectPublicKey     BIT STRING  }
    538  *
    539  *	AlgorithmIdentifier  ::=  SEQUENCE  {
    540  *		algorithm               OBJECT IDENTIFIER,
    541  *		parameters              ANY DEFINED BY algorithm OPTIONAL  }
    542  *
    543  *	id-ecPublicKey OBJECT IDENTIFIER ::= {
    544  *		iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 }
    545  *
    546  *	ECParameters ::= CHOICE {
    547  *		namedCurve         OBJECT IDENTIFIER,
    548  *		implicitCurve      NULL,
    549  *		specifiedCurve     SpecifiedECDomain }
    550  * </pre>
    551  * @return the subjectPublicKey TLV structure
    552  * @type ASN1
    553  */
    554 PKIXCommon.createECSubjectPublicKeyInfo = function(publicKey, encodeECDomainParameter) {
    555 	var t = new ASN1("subjectPublicKeyInfo", ASN1.SEQUENCE);
    556
    557 	var algorithm = publicKey.algorithmIdentifier;
    558 	if (typeof(algorithm) == "undefined") {
    559 		algorithm = new ASN1("algorithm", ASN1.SEQUENCE,
    560 				new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, new ByteString("id-ecPublicKey", OID))
    561
    562 			);
    563 		if (encodeECDomainParameter) {
    564 			algorithm.add(PKIXCommon.encodeECParameter(publicKey));
    565 		} else {
    566 			algorithm.add(new ASN1("parameters", ASN1.OBJECT_IDENTIFIER, publicKey.getComponent(Key.ECC_CURVE_OID)));
    567 		}
    568 	}
    569
    570 	t.add(algorithm);
    571
    572 	// Prefix a 00 to form correct bitstring
    573 	// Prefix a 04 to indicate uncompressed format
    574 	var keybin = new ByteString("0004", HEX);
    575 	keybin = keybin.concat(publicKey.getComponent(Key.ECC_QX));
    576 	keybin = keybin.concat(publicKey.getComponent(Key.ECC_QY));
    577 	t.add(new ASN1("subjectPublicKey", ASN1.BIT_STRING, keybin));
    578
    579 	return t;
    580 }
    581
    582
    583
    584 /**
    585  * Creates the RSA Public Key as subjectPublicKeyInfo TLV structure object.
    586  *
    587  * <p>The structure is defined as:</p>
    588  * <pre>
    589  *	SubjectPublicKeyInfo  ::=  SEQUENCE  {
    590  *		algorithm            AlgorithmIdentifier,
    591  *		subjectPublicKey     BIT STRING  }
    592  *
    593  *	AlgorithmIdentifier  ::=  SEQUENCE  {
    594  *		algorithm               OBJECT IDENTIFIER,
    595  *		parameters              ANY DEFINED BY algorithm OPTIONAL  }
    596  *
    597  *	pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
    598  *
    599  *	rsaEncryption OBJECT IDENTIFIER ::=  { pkcs-1 1}
    600  *
    601  *	RSAPublicKey ::= SEQUENCE {
    602  *		modulus            INTEGER,    -- n
    603  *		publicExponent     INTEGER  }  -- e
    604  * </pre>
    605  *
    606  * @return the subjectPublicKey TLV structure
    607  * @type ASN1
    608  */
    609 PKIXCommon.createRSASubjectPublicKeyInfo = function(publicKey) {
    610 	var t = new ASN1("subjectPublicKeyInfo", ASN1.SEQUENCE);
    611
    612 	var algorithm = publicKey.algorithmIdentifier;
    613 	if (typeof(algorithm) == "undefined") {
    614 		algorithm = new ASN1("algorithm", ASN1.SEQUENCE,
    615 				new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, new ByteString("rsaEncryption", OID)),
    616 				new ASN1("parameters", ASN1.NULL, new ByteString("", HEX))
    617 			);
    618 	}
    619
    620 	t.add(algorithm);
    621 	// Prefix a 00 to form correct bitstring
    622 	var keybin = new ByteString("00", HEX);
    623
    624 	var modulus = publicKey.getComponent(Key.MODULUS);
    625 	modulus = PKIXCommon.convertUnsignedInteger(modulus);
    626
    627 	var exponent = publicKey.getComponent(Key.EXPONENT);
    628 	exponent = PKIXCommon.convertUnsignedInteger(exponent);
    629
    630 	var rsapub = new ASN1("RSAPublicKey", ASN1.SEQUENCE,
    631 			new ASN1("modulus", ASN1.INTEGER, modulus),
    632 			new ASN1("publicKeyExponent", ASN1.INTEGER, exponent));
    633
    634 	keybin = keybin.concat(rsapub.getBytes());
    635 	t.add(new ASN1("subjectPublicKey", ASN1.BIT_STRING, keybin));
    636
    637 	return t;
    638 }
    639
    640
    641
    642 /**
    643  * Determine key identifier according to RFC5280 using SHA-1 over the SubjectPublicKeyInfo
    644  *
    645  * @param {Key} publicKey the public key
    646  * @param {Boolean} encodeECDomainParameter true to include domain parameter in SPKI of EC key
    647  */
    648 PKIXCommon.determineKeyIdentifier = function(publicKey, encodeECDomainParameter) {
    649 	if (typeof(encodeECDomainParameter) == "undefined") {
    650 		encodeECDomainParameter = true;
    651 	}
    652
    653 	var spki;
    654
    655 	if (publicKey.getComponent(Key.MODULUS)) {
    656 		spki = PKIXCommon.createRSASubjectPublicKeyInfo(publicKey);
    657 	} else {
    658 		spki = PKIXCommon.createECSubjectPublicKeyInfo(publicKey, encodeECDomainParameter);
    659 	}
    660
    661 	var keyvalue = spki.get(1).value.bytes(1);
    662 	var crypto = new Crypto();
    663 	return (crypto.digest(Crypto.SHA_1, keyvalue));
    664 }
    665
    666
    667
    668 /**
    669  * Creates a relative distinguished name component.
    670  *
    671  * <p>The structure is defined as:</p>
    672  * <pre>
    673  *	RelativeDistinguishedName ::=
    674  *		SET SIZE (1..MAX) OF AttributeTypeAndValue
    675  *
    676  *	AttributeTypeAndValue ::= SEQUENCE {
    677  *		type     AttributeType,
    678  *		value    AttributeValue }
    679  *
    680  *	AttributeType ::= OBJECT IDENTIFIER
    681  *
    682  *	AttributeValue ::= ANY -- DEFINED BY AttributeType
    683  *
    684  *	DirectoryString ::= CHOICE {
    685  *		teletexString           TeletexString (SIZE (1..MAX)),
    686  *		printableString         PrintableString (SIZE (1..MAX)),
    687  *		universalString         UniversalString (SIZE (1..MAX)),
    688  *		utf8String              UTF8String (SIZE (1..MAX)),
    689  *		bmpString               BMPString (SIZE (1..MAX)) }
    690  *</pre>
    691  *
    692  * @param {String} name the components name
    693  * @param {String} oid the oid for the RDN
    694  * @param {ASN1} value the value object
    695  * @return the
    696  */
    697 PKIXCommon.makeRDN = function(name, oid, value) {
    698 	return new ASN1(name, ASN1.SET,
    699 				new ASN1(ASN1.SEQUENCE,
    700 					new ASN1(ASN1.OBJECT_IDENTIFIER, new ByteString(oid, OID)),
    701 					value
    702 				)
    703 			);
    704 }
    705
    706
    707
    708 /**
    709  * Adds names from the name object to the RDNSequence.
    710  *
    711  * @param {ASN1} t the sequence object
    712  * @param {Object} name the name object
    713  */
    714 PKIXCommon.addNames = function(t, name) {
    715 	if (name.C) {
    716 		t.add(PKIXCommon.makeRDN("country", "id-at-countryName", new ASN1(ASN1.PrintableString, new ByteString(name.C, ASCII))));
    717 	}
    718 	if (name.ST) {
    719 		t.add(PKIXCommon.makeRDN("stateOrProvinceName", "id-at-stateOrProvinceName", new ASN1(ASN1.UTF8String, new ByteString(name.ST, UTF8))));
    720 	}
    721 	if (name.O) {
    722 		t.add(PKIXCommon.makeRDN("organization", "id-at-organizationName", new ASN1(ASN1.UTF8String, new ByteString(name.O, UTF8))));
    723 	}
    724 	if (name.OU) {
    725 		t.add(PKIXCommon.makeRDN("organizationalUnit", "id-at-organizationalUnitName", new ASN1(ASN1.UTF8String, new ByteString(name.OU, UTF8))));
    726 	}
    727 	if (name.S) {
    728 		t.add(PKIXCommon.makeRDN("stateOrProvince", "id-at-stateOrProvinceName", new ASN1(ASN1.UTF8String, new ByteString(name.S, UTF8))));
    729 	}
    730 	if (name.L) {
    731 		t.add(PKIXCommon.makeRDN("locality", "id-at-localityName", new ASN1(ASN1.UTF8String, new ByteString(name.L, UTF8))));
    732 	}
    733 	if (name.DC) {
    734 		t.add(PKIXCommon.makeRDN("domainComponent", "id-domainComponent", new ASN1(ASN1.UTF8String, new ByteString(name.DC, UTF8))));
    735 	}
    736 	if (name.T) {
    737 		t.add(PKIXCommon.makeRDN("title", "id-at-title", new ASN1(ASN1.UTF8String, new ByteString(name.T, UTF8))));
    738 	}
    739 	if (name.G) {
    740 		t.add(PKIXCommon.makeRDN("givenName", "id-at-givenName", new ASN1(ASN1.UTF8String, new ByteString(name.G, UTF8))));
    741 	}
    742 	if (name.SN) {
    743 		t.add(PKIXCommon.makeRDN("surname", "id-at-surname", new ASN1(ASN1.UTF8String, new ByteString(name.SN, UTF8))));
    744 	}
    745 	if (name.CN) {
    746 		t.add(PKIXCommon.makeRDN("commonName", "id-at-commonName", new ASN1(ASN1.UTF8String, new ByteString(name.CN, UTF8))));
    747 	}
    748 	if (name.SERIALNUMBER) {
    749 		t.add(PKIXCommon.makeRDN("serialNumber", "id-at-serialNumber", new ASN1(ASN1.UTF8String, new ByteString(name.SERIALNUMBER, UTF8))));
    750 	}
    751 	if (name.DNQ) {
    752 		t.add(PKIXCommon.makeRDN("dnQualifier", "id-at-dnQualifier", new ASN1(ASN1.UTF8String, new ByteString(name.DNQ, UTF8))));
    753 	}
    754 	if (name.E) {
    755 		t.add(PKIXCommon.makeRDN("emailAddress", "id-emailAddress", new ASN1(ASN1.IA5String, new ByteString(name.E, ASCII))));
    756 	}
    757 	if (name.UID) {
    758 		t.add(PKIXCommon.makeRDN("userId", "id-userId", new ASN1(ASN1.UTF8String, new ByteString(name.UID, UTF8))));
    759 	}
    760 }
    761
    762
    763
    764 PKIXCommon.validRDN = [ "C","ST","L","O","OU","S","DC","T","G","SN","PSEUDONYM","CN","SERIALNUMBER","DNQ","E","UID" ];
    765
    766 /**
    767  * Gets the dn as TLV object
    768  *
    769  * <p>This function support two format for names</p>
    770  * <pre>
    771  *  var issuer = { C:"UT", O:"ACME Corporation", CN:"Test-CA" };
    772  * or
    773  *  var issuer = [ { C:"UT"}, { O:"ACME Corporation" }, { CN:"Test-CA"} ];
    774  * </pre>
    775  *
    776  * <p>It supports the following RDNs:</p>
    777  * <ul>
    778  * <li>C - country</li>
    779  * <li>ST - state</li>
    780  * <li>O - organization</li>
    781  * <li>OU - organizational unit</li>
    782  * <li>S - state or province</li>
    783  * <li>L - locality</li>
    784  * <li>DC - domain component</li>
    785  * <li>T - title</li>
    786  * <li>G - given name</li>
    787  * <li>SN - surname</li>
    788  * <li>CN - common name</li>
    789  * <li>SERIALNUMBER - serial number</li>
    790  * <li>DNQ - domain name qualifier</li>
    791  * <li>E - e-mail address</li>
    792  * <li>UID - user Id</li>
    793  * <p>The first format sorts the RDS in the sequence C,ST,L,O,OU,S,DC,T,G,SN,PSEUDONYM,CN,SERIALNUMBER,DNQ,E,UID</p>
    794  * </ul>
    795  * @param {Object} name the name object
    796  * @return the RDNSequence
    797  * @type ASN1
    798  */
    799 PKIXCommon.encodeName = function(name) {
    800 	var t = new ASN1("subject", ASN1.SEQUENCE);
    801 	if (typeof(name.C) == "undefined") {
    802 		for (var i = 0; i < name.length; i++) {
    803 			PKIXCommon.addNames(t, name[i]);
    804 		}
    805 	} else {
    806 		PKIXCommon.addNames(t, name);
    807 	}
    808 	return t;
    809 }
    810
    811
    812
    813 /**
    814  * Return the value of the last RDN
    815  *
    816  * @param {Object[]} dn the dn array
    817  * @type String
    818  * @return the value of the last RDN
    819  */
    820 PKIXCommon.makeName = function(rdnlist) {
    821 	if (rdnlist.length == 0) {
    822 		return undefined;
    823 	}
    824 	var l = rdnlist[rdnlist.length - 1];
    825
    826 	for (var i in l) {
    827 		return l[i];
    828 	}
    829
    830 	return undefined;
    831 }
    832
    833
    834
    835 PKIXCommon.parseDN = function(dn) {
    836 	assert(typeof(dn) == "string", "Parameter dn must be string");
    837
    838 	var e = dn.split(",");
    839 	var rdnlist = [];
    840
    841 	for (var i = 0; i < e.length; i++) {
    842 		var p = e[i].split("=");
    843
    844 		if (p.length < 2) {
    845 			throw new GPError(module.id, GPError.INVALID_DATA, i, "Missing '=' in RDN " + e[i]);
    846 		}
    847
    848 		if (p.length > 2) {
    849 			throw new GPError(module.id, GPError.INVALID_DATA, i, "Too many '=' in RDN " + e[i]);
    850 		}
    851
    852 		var key = p[0].trim().toUpperCase();
    853
    854 		if (key.length == 0) {
    855 			throw new GPError(module.id, GPError.INVALID_DATA, i, "Key in RDN " + e[i] + " can't be empty");
    856 		}
    857
    858 		if (PKIXCommon.validRDN.indexOf(key) == -1) {
    859 			throw new GPError(module.id, GPError.INVALID_DATA, i, key + " is not a supported RDN (Valid RDNs are " + PKIXCommon.validRDN + ")");
    860 		}
    861
    862 		var value = p[1].trim();
    863
    864 		if (value.length == 0) {
    865 			throw new GPError(module.id, GPError.INVALID_DATA, i, "Value for " + key + " can't be empty");
    866 		}
    867 		var rdn = { };
    868 		rdn[key] = value;
    869 		rdnlist.push(rdn);
    870 	}
    871 	return rdnlist;
    872 }
    873
    874
    875
    876 /**
    877  * Convert a DN parsed with parseDN() back into the string format
    878  *
    879  * @param {Object[]} dn the dn array
    880  * @type String
    881  * @return the DN in string format
    882  */
    883 PKIXCommon.dnToString = function(dn) {
    884 	var str = "";
    885
    886 	for (var i = 0; i < dn.length; i++) {
    887 		if (str.length > 0) {
    888 			str += ",";
    889 		}
    890
    891 		for (var j in dn[i]) {
    892 			str += j + "=" + dn[i][j];
    893 		}
    894 	}
    895 	return str;
    896 }
    897
    898
    899
    900 PKIXCommon.findRDN = function(rdnlist, c) {
    901 	for (var i = 0; i < rdnlist.length; i++) {
    902 		var v = rdnlist[i][c];
    903 		if (v) {
    904 			return v;
    905 		}
    906 	}
    907 }
    908
    909
    910
    911 PKIXCommon.countryNames = {
    912 AF:"Afghanistan",
    913 AX:"Aeland Islands",
    914 AL:"Albania",
    915 DZ:"Algeria",
    916 AS:"American Samoa",
    917 AD:"Andorra",
    918 AO:"Angola",
    919 AI:"Anguilla",
    920 AQ:"Antarctica",
    921 AG:"Antigua and Barbuda",
    922 AR:"Argentina",
    923 AM:"Armenia",
    924 AW:"Aruba",
    925 AU:"Australia",
    926 AT:"Austria",
    927 AZ:"Azerbaijan",
    928 BS:"Bahamas",
    929 BH:"Bahrain",
    930 BD:"Bangladesh",
    931 BB:"Barbados",
    932 BY:"Belarus",
    933 BE:"Belgium",
    934 BZ:"Belize",
    935 BJ:"Benin",
    936 BM:"Bermuda",
    937 BT:"Bhutan",
    938 BO:"Bolivia, Plurinational State of",
    939 BQ:"Bonaire, Sint Eustatius and Saba",
    940 BA:"Bosnia and Herzegovina",
    941 BW:"Botswana",
    942 BV:"Bouvet Island",
    943 BR:"Brazil",
    944 IO:"British Indian Ocean Territory",
    945 BN:"Brunei Darussalam",
    946 BG:"Bulgaria",
    947 BF:"Burkina Faso",
    948 BI:"Burundi",
    949 KH:"Cambodia",
    950 CM:"Cameroon",
    951 CA:"Canada",
    952 CV:"Cape Verde",
    953 KY:"Cayman Islands",
    954 CF:"Central African Republic",
    955 TD:"Chad",
    956 CL:"Chile",
    957 CN:"China",
    958 CX:"Christmas Island",
    959 CC:"Cocos (Keeling) Islands",
    960 CO:"Colombia",
    961 KM:"Comoros",
    962 CG:"Congo",
    963 CD:"Congo, the Democratic Republic of the",
    964 CK:"Cook Islands",
    965 CR:"Costa Rica",
    966 CI:"Cote d'Ivoire",
    967 HR:"Croatia",
    968 CU:"Cuba",
    969 CW:"Curacao",
    970 CY:"Cyprus",
    971 CZ:"Czech Republic",
    972 DK:"Denmark",
    973 DJ:"Djibouti",
    974 DM:"Dominica",
    975 DO:"Dominican Republic",
    976 EC:"Ecuador",
    977 EG:"Egypt",
    978 SV:"El Salvador",
    979 GQ:"Equatorial Guinea",
    980 ER:"Eritrea",
    981 EE:"Estonia",
    982 ET:"Ethiopia",
    983 FK:"Falkland Islands (Malvinas)",
    984 FO:"Faroe Islands",
    985 FJ:"Fiji",
    986 FI:"Finland",
    987 FR:"France",
    988 GF:"French Guiana",
    989 PF:"French Polynesia",
    990 TF:"French Southern Territories",
    991 GA:"Gabon",
    992 GM:"Gambia",
    993 GE:"Georgia",
    994 DE:"Germany",
    995 GH:"Ghana",
    996 GI:"Gibraltar",
    997 GR:"Greece",
    998 GL:"Greenland",
    999 GD:"Grenada",
    1000 GP:"Guadeloupe",
    1001 GU:"Guam",
    1002 GT:"Guatemala",
    1003 GG:"Guernsey",
    1004 GN:"Guinea",
    1005 GW:"Guinea-Bissau",
    1006 GY:"Guyana",
    1007 HT:"Haiti",
    1008 HM:"Heard Island and McDonald Islands",
    1009 VA:"Holy See (Vatican City State)",
    1010 HN:"Honduras",
    1011 HK:"Hong Kong",
    1012 HU:"Hungary",
    1013 IS:"Iceland",
    1014 IN:"India",
    1015 ID:"Indonesia",
    1016 IR:"Iran, Islamic Republic of",
    1017 IQ:"Iraq",
    1018 IE:"Ireland",
    1019 IM:"Isle of Man",
    1020 IL:"Israel",
    1021 IT:"Italy",
    1022 JM:"Jamaica",
    1023 JP:"Japan",
    1024 JE:"Jersey",
    1025 JO:"Jordan",
    1026 KZ:"Kazakhstan",
    1027 KE:"Kenya",
    1028 KI:"Kiribati",
    1029 KP:"Korea, Democratic People's Republic of",
    1030 KR:"Korea, Republic of",
    1031 KW:"Kuwait",
    1032 KG:"Kyrgyzstan",
    1033 LA:"Lao People's Democratic Republic",
    1034 LV:"Latvia",
    1035 LB:"Lebanon",
    1036 LS:"Lesotho",
    1037 LR:"Liberia",
    1038 LY:"Libya",
    1039 LI:"Liechtenstein",
    1040 LT:"Lithuania",
    1041 LU:"Luxembourg",
    1042 MO:"Macao",
    1043 MK:"Macedonia, the Former Yugoslav Republic of",
    1044 MG:"Madagascar",
    1045 MW:"Malawi",
    1046 MY:"Malaysia",
    1047 MV:"Maldives",
    1048 ML:"Mali",
    1049 MT:"Malta",
    1050 MH:"Marshall Islands",
    1051 MQ:"Martinique",
    1052 MR:"Mauritania",
    1053 MU:"Mauritius",
    1054 YT:"Mayotte",
    1055 MX:"Mexico",
    1056 FM:"Micronesia, Federated States of",
    1057 MD:"Moldova, Republic of",
    1058 MC:"Monaco",
    1059 MN:"Mongolia",
    1060 ME:"Montenegro",
    1061 MS:"Montserrat",
    1062 MA:"Morocco",
    1063 MZ:"Mozambique",
    1064 MM:"Myanmar",
    1065 NA:"Namibia",
    1066 NR:"Nauru",
    1067 NP:"Nepal",
    1068 NL:"Netherlands",
    1069 NC:"New Caledonia",
    1070 NZ:"New Zealand",
    1071 NI:"Nicaragua",
    1072 NE:"Niger",
    1073 NG:"Nigeria",
    1074 NU:"Niue",
    1075 NF:"Norfolk Island",
    1076 MP:"Northern Mariana Islands",
    1077 NO:"Norway",
    1078 OM:"Oman",
    1079 PK:"Pakistan",
    1080 PW:"Palau",
    1081 PS:"Palestine, State of",
    1082 PA:"Panama",
    1083 PG:"Papua New Guinea",
    1084 PY:"Paraguay",
    1085 PE:"Peru",
    1086 PH:"Philippines",
    1087 PN:"Pitcairn",
    1088 PL:"Poland",
    1089 PT:"Portugal",
    1090 PR:"Puerto Rico",
    1091 QA:"Qatar",
    1092 RE:"Reunion",
    1093 RO:"Romania",
    1094 RU:"Russian Federation",
    1095 RW:"Rwanda",
    1096 BL:"Saint Bartholemy",
    1097 SH:"Saint Helena, Ascension and Tristan da Cunha",
    1098 KN:"Saint Kitts and Nevis",
    1099 LC:"Saint Lucia",
    1100 MF:"Saint Martin (French part)",
    1101 PM:"Saint Pierre and Miquelon",
    1102 VC:"Saint Vincent and the Grenadines",
    1103 WS:"Samoa",
    1104 SM:"San Marino",
    1105 ST:"Sao Tome and Principe",
    1106 SA:"Saudi Arabia",
    1107 SN:"Senegal",
    1108 RS:"Serbia",
    1109 SC:"Seychelles",
    1110 SL:"Sierra Leone",
    1111 SG:"Singapore",
    1112 SX:"Sint Maarten (Dutch part)",
    1113 SK:"Slovakia",
    1114 SI:"Slovenia",
    1115 SB:"Solomon Islands",
    1116 SO:"Somalia",
    1117 ZA:"South Africa",
    1118 GS:"South Georgia and the South Sandwich Islands",
    1119 SS:"South Sudan",
    1120 ES:"Spain",
    1121 LK:"Sri Lanka",
    1122 SD:"Sudan",
    1123 SR:"Suriname",
    1124 SJ:"Svalbard and Jan Mayen",
    1125 SZ:"Swaziland",
    1126 SE:"Sweden",
    1127 CH:"Switzerland",
    1128 SY:"Syrian Arab Republic",
    1129 TW:"Taiwan, Province of China",
    1130 TJ:"Tajikistan",
    1131 TZ:"Tanzania, United Republic of",
    1132 TH:"Thailand",
    1133 TL:"Timor-Leste",
    1134 TG:"Togo",
    1135 TK:"Tokelau",
    1136 TO:"Tonga",
    1137 TT:"Trinidad and Tobago",
    1138 TN:"Tunisia",
    1139 TR:"Turkey",
    1140 TM:"Turkmenistan",
    1141 TC:"Turks and Caicos Islands",
    1142 TV:"Tuvalu",
    1143 UG:"Uganda",
    1144 UA:"Ukraine",
    1145 AE:"United Arab Emirates",
    1146 GB:"United Kingdom",
    1147 US:"United States",
    1148 UM:"United States Minor Outlying Islands",
    1149 UY:"Uruguay",
    1150 UZ:"Uzbekistan",
    1151 VU:"Vanuatu",
    1152 VE:"Venezuela, Bolivarian Republic of",
    1153 VN:"Viet Nam",
    1154 VG:"Virgin Islands, British",
    1155 VI:"Virgin Islands, U.S.",
    1156 WF:"Wallis and Futuna",
    1157 EH:"Western Sahara",
    1158 YE:"Yemen",
    1159 ZM:"Zambia",
    1160 ZW:"Zimbabwe"
    1161 };
    1162
    1163
    1164
    1165 /**
    1166  * Extract subject from certificate as ASN1 object
    1167  *
    1168  * @param {X509} cert the certificate
    1169  * @type ASN1
    1170  * @return the subject as ASN1
    1171  */
    1172 PKIXCommon.getSubjectAsASN1 = function(cert) {
    1173 	var a = new ASN1(cert.getBytes());
    1174 	return a.get(0).get(5);
    1175 }
    1176
    1177
    1178
    1179 /**
    1180  * Extract issuer from certificate as ASN1 object
    1181  *
    1182  * @param {X509} cert the certificate
    1183  * @type ASN1
    1184  * @return the issuer as ASN1
    1185  */
    1186 PKIXCommon.getIssuerAsASN1 = function(cert) {
    1187 	var a = new ASN1(cert.getBytes());
    1188 	return a.get(0).get(3);
    1189 }
    1190
    1191
    1192
    1193 /**
    1194  * Convert binary data to PEM format
    1195  *
    1196  * @param {String} label the label to be used in the MIME header and footer
    1197  * @param {ByteString} bin the binary data
    1198  * @type String
    1199  * @return the MIME/BASE64 encoded string
    1200  */
    1201 PKIXCommon.toPEM = function(label, bin) {
    1202 	assert(typeof(label) == "string", "Parameter label must be string");
    1203 	assert(bin instanceof ByteString, "Parameter bin must be ByteString");
    1204
    1205 	var str = "-----BEGIN " + label + "-----\n";
    1206
    1207 	var b64 = bin.toString(BASE64);
    1208 	while(b64.length > 0) {
    1209 		str += b64.substr(0, 64) + "\n";
    1210 		b64 = b64.substr(64);
    1211 	}
    1212
    1213 	str += "-----END " + label + "-----\n";
    1214 	return str;
    1215 }
    1216
    1217
    1218
    1219 /**
    1220  * Parse PEM format and extract binary data
    1221  *
    1222  * @param {String} label the label of the section
    1223  * @param {String} bin the binary data
    1224  * @type String
    1225  * @return the MIME/BASE64 encoded string
    1226  */
    1227 PKIXCommon.parsePEM = function(label, pem) {
    1228 	assert(typeof(label) == "string", "Parameter label must be string");
    1229 	assert(typeof(pem) == "string", "Parameter pem must be string");
    1230
    1231 	var lines = pem.split("\n");
    1232
    1233 	var b64str = "";
    1234 	var parse = false;
    1235 	for (var i = 0; i < lines.length; i++) {
    1236 		var str = lines[i];
    1237
    1238 		if (str == "-----BEGIN " + label + "-----") {
    1239 			parse = true;
    1240 		} else if (str == "-----END " + label + "-----") {
    1241 			break;
    1242 		} else if (parse) {
    1243 			b64str += str;
    1244 		}
    1245 	}
    1246
    1247 	return new ByteString(b64str, BASE64);
    1248 }
    1249
    1250
    1251
    1252 /**
    1253  * Writes a byte string object to file
    1254  *
    1255  * <p>The filename is mapped to the workspace location.</p>
    1256  *
    1257  * @param {String} filename the fully qualified name of the file
    1258  * @param {ByteString} content the content to write
    1259  */
    1260 PKIXCommon.writeFileToDisk = function(filename, content) {
    1261 	var file = new java.io.FileOutputStream(filename);
    1262 	file.write(content);
    1263 	file.close();
    1264 }
    1265
    1266
    1267
    1268 /**
    1269  * Loads a binary file from disk
    1270  *
    1271  * @param {String} filename the fully qualified file name
    1272  * @return the binary content
    1273  * @type ByteString
    1274  */
    1275 PKIXCommon.readFileFromDisk = function(filename) {
    1276 	// Open stream
    1277 	var f = new java.io.FileInputStream(filename);
    1278
    1279 	// Determine file size
    1280 	var flen = f.available();
    1281
    1282 	// Allocate native byte array
    1283 	var bs = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, flen);
    1284
    1285 	// Read into byte array
    1286 	var len = f.read(bs);
    1287
    1288 	f.close();
    1289
    1290 	// Allocate JavaScript ByteBuffer from native/wrapped byte array
    1291 	var bb = new ByteBuffer(bs);
    1292
    1293 	// Convert to JavaScript ByteString
    1294 	var data = bb.toByteString();
    1295
    1296 	return data;
    1297 }
    1298
    1299
    1300
    1301 PKIXCommon.test = function() {
    1302 	var issuer = { C:"C", O:"O", OU:"OU", SP:"SP", L:"L", DC:"DC", T:"T", G:"G", SN:"SN", CN:"CN", SERIALNUMBER:"serial", DNQ:"DNQ" };
    1303 	var dn = PKIXCommon.encodeName(issuer);
    1304 	print(dn);
    1305
    1306 	var r = PKIXCommon.convertUnsignedInteger(new ByteString("00", HEX));
    1307 	assert(r.toString(HEX) == "00");
    1308 	var r = PKIXCommon.convertUnsignedInteger(new ByteString("80", HEX));
    1309 	assert(r.toString(HEX) == "0080");
    1310 	var r = PKIXCommon.convertUnsignedInteger(new ByteString("FF", HEX));
    1311 	assert(r.toString(HEX) == "00FF");
    1312 	var r = PKIXCommon.convertUnsignedInteger(new ByteString("0000", HEX));
    1313 	assert(r.toString(HEX) == "00");
    1314 	var r = PKIXCommon.convertUnsignedInteger(new ByteString("0080", HEX));
    1315 	assert(r.toString(HEX) == "0080");
    1316 	var r = PKIXCommon.convertUnsignedInteger(new ByteString("000080", HEX));
    1317 	assert(r.toString(HEX) == "0080");
    1318 }
    1319