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