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