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 PKIXCommon.parseDN = function(dn) {
614 	assert(typeof(dn) == "string", "Parameter dn must be string");
615 
616 	var e = dn.split(",");
617 	var rdnlist = [];
618 
619 	for (var i = 0; i < e.length; i++) {
620 		var p = e[i].split("=");
621 
622 		if (p.length < 2) {
623 			throw new GPError(module.id, GPError.INVALID_DATA, i, "Missing '=' in RDN " + e[i]);
624 		}
625 
626 		if (p.length > 2) {
627 			throw new GPError(module.id, GPError.INVALID_DATA, i, "Too many '=' in RDN " + e[i]);
628 		}
629 
630 		var key = p[0].trim().toUpperCase();
631 
632 		if (key.length == 0) {
633 			throw new GPError(module.id, GPError.INVALID_DATA, i, "Key in RDN " + e[i] + " can't be empty");
634 		}
635 
636 		if (PKIXCommon.validRDN.indexOf(key) == -1) {
637 			throw new GPError(module.id, GPError.INVALID_DATA, i, key + " is not a supported RDN (Valid RDNs are " + PKIXCommon.validRDN + ")");
638 		}
639 
640 		var value = p[1].trim();
641 
642 		if (value.length == 0) {
643 			throw new GPError(module.id, GPError.INVALID_DATA, i, "Value for " + key + " can't be empty");
644 		}
645 		var rdn = { };
646 		rdn[key] = value;
647 		rdnlist.push(rdn);
648 	}
649 	return rdnlist;
650 }
651 
652 
653 
654 /**
655  * Convert a DN parsed with parseDN() back into the string format
656  *
657  * @param {Object[]} dn the dn array
658  * @type String
659  * @return the DN in string format
660  */
661 PKIXCommon.dnToString = function(dn) {
662 	var str = "";
663 
664 	for (var i = 0; i < dn.length; i++) {
665 		if (str.length > 0) {
666 			str += ",";
667 		}
668 
669 		for (var j in dn[i]) {
670 			str += j + "=" + dn[i][j];
671 		}
672 	}
673 	return str;
674 }
675 
676 
677 
678 PKIXCommon.findRDN = function(rdnlist, c) {
679 	for (var i = 0; i < rdnlist.length; i++) {
680 		var v = rdnlist[i][c];
681 		if (v) {
682 			return v;
683 		}
684 	}
685 }
686 
687 
688 
689 PKIXCommon.countryNames = {
690 AF:"Afghanistan",
691 AX:"Aeland Islands",
692 AL:"Albania",
693 DZ:"Algeria",
694 AS:"American Samoa",
695 AD:"Andorra",
696 AO:"Angola",
697 AI:"Anguilla",
698 AQ:"Antarctica",
699 AG:"Antigua and Barbuda",
700 AR:"Argentina",
701 AM:"Armenia",
702 AW:"Aruba",
703 AU:"Australia",
704 AT:"Austria",
705 AZ:"Azerbaijan",
706 BS:"Bahamas",
707 BH:"Bahrain",
708 BD:"Bangladesh",
709 BB:"Barbados",
710 BY:"Belarus",
711 BE:"Belgium",
712 BZ:"Belize",
713 BJ:"Benin",
714 BM:"Bermuda",
715 BT:"Bhutan",
716 BO:"Bolivia, Plurinational State of",
717 BQ:"Bonaire, Sint Eustatius and Saba",
718 BA:"Bosnia and Herzegovina",
719 BW:"Botswana",
720 BV:"Bouvet Island",
721 BR:"Brazil",
722 IO:"British Indian Ocean Territory",
723 BN:"Brunei Darussalam",
724 BG:"Bulgaria",
725 BF:"Burkina Faso",
726 BI:"Burundi",
727 KH:"Cambodia",
728 CM:"Cameroon",
729 CA:"Canada",
730 CV:"Cape Verde",
731 KY:"Cayman Islands",
732 CF:"Central African Republic",
733 TD:"Chad",
734 CL:"Chile",
735 CN:"China",
736 CX:"Christmas Island",
737 CC:"Cocos (Keeling) Islands",
738 CO:"Colombia",
739 KM:"Comoros",
740 CG:"Congo",
741 CD:"Congo, the Democratic Republic of the",
742 CK:"Cook Islands",
743 CR:"Costa Rica",
744 CI:"Cote d'Ivoire",
745 HR:"Croatia",
746 CU:"Cuba",
747 CW:"Curacao",
748 CY:"Cyprus",
749 CZ:"Czech Republic",
750 DK:"Denmark",
751 DJ:"Djibouti",
752 DM:"Dominica",
753 DO:"Dominican Republic",
754 EC:"Ecuador",
755 EG:"Egypt",
756 SV:"El Salvador",
757 GQ:"Equatorial Guinea",
758 ER:"Eritrea",
759 EE:"Estonia",
760 ET:"Ethiopia",
761 FK:"Falkland Islands (Malvinas)",
762 FO:"Faroe Islands",
763 FJ:"Fiji",
764 FI:"Finland",
765 FR:"France",
766 GF:"French Guiana",
767 PF:"French Polynesia",
768 TF:"French Southern Territories",
769 GA:"Gabon",
770 GM:"Gambia",
771 GE:"Georgia",
772 DE:"Germany",
773 GH:"Ghana",
774 GI:"Gibraltar",
775 GR:"Greece",
776 GL:"Greenland",
777 GD:"Grenada",
778 GP:"Guadeloupe",
779 GU:"Guam",
780 GT:"Guatemala",
781 GG:"Guernsey",
782 GN:"Guinea",
783 GW:"Guinea-Bissau",
784 GY:"Guyana",
785 HT:"Haiti",
786 HM:"Heard Island and McDonald Islands",
787 VA:"Holy See (Vatican City State)",
788 HN:"Honduras",
789 HK:"Hong Kong",
790 HU:"Hungary",
791 IS:"Iceland",
792 IN:"India",
793 ID:"Indonesia",
794 IR:"Iran, Islamic Republic of",
795 IQ:"Iraq",
796 IE:"Ireland",
797 IM:"Isle of Man",
798 IL:"Israel",
799 IT:"Italy",
800 JM:"Jamaica",
801 JP:"Japan",
802 JE:"Jersey",
803 JO:"Jordan",
804 KZ:"Kazakhstan",
805 KE:"Kenya",
806 KI:"Kiribati",
807 KP:"Korea, Democratic People's Republic of",
808 KR:"Korea, Republic of",
809 KW:"Kuwait",
810 KG:"Kyrgyzstan",
811 LA:"Lao People's Democratic Republic",
812 LV:"Latvia",
813 LB:"Lebanon",
814 LS:"Lesotho",
815 LR:"Liberia",
816 LY:"Libya",
817 LI:"Liechtenstein",
818 LT:"Lithuania",
819 LU:"Luxembourg",
820 MO:"Macao",
821 MK:"Macedonia, the Former Yugoslav Republic of",
822 MG:"Madagascar",
823 MW:"Malawi",
824 MY:"Malaysia",
825 MV:"Maldives",
826 ML:"Mali",
827 MT:"Malta",
828 MH:"Marshall Islands",
829 MQ:"Martinique",
830 MR:"Mauritania",
831 MU:"Mauritius",
832 YT:"Mayotte",
833 MX:"Mexico",
834 FM:"Micronesia, Federated States of",
835 MD:"Moldova, Republic of",
836 MC:"Monaco",
837 MN:"Mongolia",
838 ME:"Montenegro",
839 MS:"Montserrat",
840 MA:"Morocco",
841 MZ:"Mozambique",
842 MM:"Myanmar",
843 NA:"Namibia",
844 NR:"Nauru",
845 NP:"Nepal",
846 NL:"Netherlands",
847 NC:"New Caledonia",
848 NZ:"New Zealand",
849 NI:"Nicaragua",
850 NE:"Niger",
851 NG:"Nigeria",
852 NU:"Niue",
853 NF:"Norfolk Island",
854 MP:"Northern Mariana Islands",
855 NO:"Norway",
856 OM:"Oman",
857 PK:"Pakistan",
858 PW:"Palau",
859 PS:"Palestine, State of",
860 PA:"Panama",
861 PG:"Papua New Guinea",
862 PY:"Paraguay",
863 PE:"Peru",
864 PH:"Philippines",
865 PN:"Pitcairn",
866 PL:"Poland",
867 PT:"Portugal",
868 PR:"Puerto Rico",
869 QA:"Qatar",
870 RE:"Reunion",
871 RO:"Romania",
872 RU:"Russian Federation",
873 RW:"Rwanda",
874 BL:"Saint Bartholemy",
875 SH:"Saint Helena, Ascension and Tristan da Cunha",
876 KN:"Saint Kitts and Nevis",
877 LC:"Saint Lucia",
878 MF:"Saint Martin (French part)",
879 PM:"Saint Pierre and Miquelon",
880 VC:"Saint Vincent and the Grenadines",
881 WS:"Samoa",
882 SM:"San Marino",
883 ST:"Sao Tome and Principe",
884 SA:"Saudi Arabia",
885 SN:"Senegal",
886 RS:"Serbia",
887 SC:"Seychelles",
888 SL:"Sierra Leone",
889 SG:"Singapore",
890 SX:"Sint Maarten (Dutch part)",
891 SK:"Slovakia",
892 SI:"Slovenia",
893 SB:"Solomon Islands",
894 SO:"Somalia",
895 ZA:"South Africa",
896 GS:"South Georgia and the South Sandwich Islands",
897 SS:"South Sudan",
898 ES:"Spain",
899 LK:"Sri Lanka",
900 SD:"Sudan",
901 SR:"Suriname",
902 SJ:"Svalbard and Jan Mayen",
903 SZ:"Swaziland",
904 SE:"Sweden",
905 CH:"Switzerland",
906 SY:"Syrian Arab Republic",
907 TW:"Taiwan, Province of China",
908 TJ:"Tajikistan",
909 TZ:"Tanzania, United Republic of",
910 TH:"Thailand",
911 TL:"Timor-Leste",
912 TG:"Togo",
913 TK:"Tokelau",
914 TO:"Tonga",
915 TT:"Trinidad and Tobago",
916 TN:"Tunisia",
917 TR:"Turkey",
918 TM:"Turkmenistan",
919 TC:"Turks and Caicos Islands",
920 TV:"Tuvalu",
921 UG:"Uganda",
922 UA:"Ukraine",
923 AE:"United Arab Emirates",
924 GB:"United Kingdom",
925 US:"United States",
926 UM:"United States Minor Outlying Islands",
927 UY:"Uruguay",
928 UZ:"Uzbekistan",
929 VU:"Vanuatu",
930 VE:"Venezuela, Bolivarian Republic of",
931 VN:"Viet Nam",
932 VG:"Virgin Islands, British",
933 VI:"Virgin Islands, U.S.",
934 WF:"Wallis and Futuna",
935 EH:"Western Sahara",
936 YE:"Yemen",
937 ZM:"Zambia",
938 ZW:"Zimbabwe"
939 };
940 
941 
942 
943 /**
944  * Extract subject from certificate as ASN1 object
945  *
946  * @param {X509} cert the certificate
947  * @type ASN1
948  * @return the subject as ASN1
949  */
950 PKIXCommon.getSubjectAsASN1 = function(cert) {
951 	var a = new ASN1(cert.getBytes());
952 	return a.get(0).get(5);
953 }
954 
955 
956 
957 /**
958  * Extract issuer from certificate as ASN1 object
959  *
960  * @param {X509} cert the certificate
961  * @type ASN1
962  * @return the issuer as ASN1
963  */
964 PKIXCommon.getIssuerAsASN1 = function(cert) {
965 	var a = new ASN1(cert.getBytes());
966 	return a.get(0).get(3);
967 }
968 
969 
970 
971 /**
972  * Convert binary data to PEM format
973  *
974  * @param {String} label the label to be used in the MIME header and footer
975  * @param {ByteString} bin the binary data
976  * @type String
977  * @return the MIME/BASE64 encoded string
978  */
979 PKIXCommon.toPEM = function(label, bin) {
980 	assert(typeof(label) == "string", "Parameter label must be string");
981 	assert(bin instanceof ByteString, "Parameter bin must be ByteString");
982 
983 	var str = "-----BEGIN " + label + "-----\n";
984 
985 	var b64 = bin.toString(BASE64);
986 	while(b64.length > 0) {
987 		str += b64.substr(0, 64) + "\n";
988 		b64 = b64.substr(64);
989 	}
990 
991 	str += "-----END " + label + "-----\n";
992 	return str;
993 }
994 
995 
996 
997 /**
998  * Parse PEM format and extract binary data
999  *
1000  * @param {String} label the label of the section
1001  * @param {ByteString} bin the binary data
1002  * @type String
1003  * @return the MIME/BASE64 encoded string
1004  */
1005 PKIXCommon.parsePEM = function(label, pem) {
1006 	assert(typeof(label) == "string", "Parameter label must be string");
1007 	assert(typeof(pem) == "string", "Parameter pem must be string");
1008 
1009 	var lines = pem.split("\n");
1010 
1011 	var b64str = "";
1012 	var parse = false;
1013 	for (var i = 0; i < lines.length; i++) {
1014 		var str = lines[i];
1015 
1016 		if (str == "-----BEGIN " + label + "-----") {
1017 			parse = true;
1018 		} else if (str == "-----END " + label + "-----") {
1019 			break;
1020 		} else if (parse) {
1021 			b64str += str;
1022 		}
1023 	}
1024 
1025 	return new ByteString(b64str, BASE64);
1026 }
1027 
1028 
1029 
1030 /**
1031  * Writes a byte string object to file
1032  *
1033  * <p>The filename is mapped to the workspace location.</p>
1034  *
1035  * @param {String} filename the fully qualified name of the file
1036  * @param {ByteString} content the content to write
1037  */
1038 PKIXCommon.writeFileToDisk = function(filename, content) {
1039 	var file = new java.io.FileOutputStream(filename);
1040 	file.write(content);
1041 	file.close();
1042 }
1043 
1044 
1045 
1046 /**
1047  * Loads a binary file from disk
1048  *
1049  * @param {String} filename the fully qualified file name
1050  * @return the binary content
1051  * @type ByteString
1052  */
1053 PKIXCommon.readFileFromDisk = function(filename) {
1054 	// Open stream
1055 	var f = new java.io.FileInputStream(filename);
1056 
1057 	// Determine file size
1058 	var flen = f.available();
1059 
1060 	// Allocate native byte array
1061 	var bs = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, flen);
1062 
1063 	// Read into byte array
1064 	var len = f.read(bs);
1065 
1066 	f.close();
1067 
1068 	// Allocate JavaScript ByteBuffer from native/wrapped byte array
1069 	var bb = new ByteBuffer(bs);
1070 
1071 	// Convert to JavaScript ByteString
1072 	var data = bb.toByteString();
1073 
1074 	return data;
1075 }
1076 
1077 
1078 
1079 PKIXCommon.test = function() {
1080 	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" };
1081 	var dn = PKIXCommon.encodeName(issuer);
1082 	print(dn);
1083 
1084 	var r = PKIXCommon.convertUnsignedInteger(new ByteString("00", HEX));
1085 	assert(r.toString(HEX) == "00");
1086 	var r = PKIXCommon.convertUnsignedInteger(new ByteString("80", HEX));
1087 	assert(r.toString(HEX) == "0080");
1088 	var r = PKIXCommon.convertUnsignedInteger(new ByteString("FF", HEX));
1089 	assert(r.toString(HEX) == "00FF");
1090 	var r = PKIXCommon.convertUnsignedInteger(new ByteString("0000", HEX));
1091 	assert(r.toString(HEX) == "00");
1092 	var r = PKIXCommon.convertUnsignedInteger(new ByteString("0080", HEX));
1093 	assert(r.toString(HEX) == "0080");
1094 	var r = PKIXCommon.convertUnsignedInteger(new ByteString("000080", HEX));
1095 	assert(r.toString(HEX) == "0080");
1096 }
1097