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