node-forge 0.6.47 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/CHANGELOG.md +106 -0
  2. package/LICENSE +3 -3
  3. package/README.md +254 -175
  4. package/dist/forge.all.min.js +11 -0
  5. package/dist/forge.all.min.js.map +1 -0
  6. package/dist/forge.min.js +10 -0
  7. package/dist/forge.min.js.map +1 -0
  8. package/dist/prime.worker.min.js +2 -0
  9. package/dist/prime.worker.min.js.map +1 -0
  10. package/flash/README.md +48 -0
  11. package/flash/package.json +28 -0
  12. package/flash/swf/SocketPool.swf +0 -0
  13. package/{js → lib}/aes.js +5 -61
  14. package/{js → lib}/aesCipherSuites.js +4 -58
  15. package/{js → lib}/asn1.js +371 -132
  16. package/{js → lib}/cipher.js +3 -59
  17. package/{js → lib}/cipherModes.js +3 -65
  18. package/{js → lib}/debug.js +2 -58
  19. package/{js → lib}/des.js +6 -63
  20. package/lib/forge.js +13 -0
  21. package/{js → lib}/form.js +5 -13
  22. package/{js → lib}/hmac.js +4 -58
  23. package/{js → lib}/http.js +15 -20
  24. package/lib/index.all.js +16 -0
  25. package/lib/index.js +34 -0
  26. package/{js → lib}/jsbn.js +3 -60
  27. package/{js → lib}/kem.js +5 -58
  28. package/{js → lib}/log.js +3 -58
  29. package/lib/md.all.js +13 -0
  30. package/lib/md.js +11 -0
  31. package/{js → lib}/md5.js +4 -60
  32. package/lib/mgf.js +12 -0
  33. package/lib/mgf1.js +57 -0
  34. package/lib/oids.js +159 -0
  35. package/{js → lib}/pbe.js +29 -79
  36. package/{js → lib}/pbkdf2.js +10 -64
  37. package/{js → lib}/pem.js +3 -58
  38. package/{js → lib}/pkcs1.js +6 -59
  39. package/{js → lib}/pkcs12.js +15 -74
  40. package/{js → lib}/pkcs7.js +12 -72
  41. package/{js → lib}/pkcs7asn1.js +4 -58
  42. package/{js → lib}/pki.js +12 -71
  43. package/{js → lib}/prime.js +18 -58
  44. package/{js → lib}/prime.worker.js +4 -1
  45. package/{js → lib}/prng.js +5 -62
  46. package/{js → lib}/pss.js +7 -61
  47. package/{js → lib}/random.js +11 -57
  48. package/{js → lib}/rc2.js +13 -73
  49. package/{js → lib}/rsa.js +13 -71
  50. package/{js → lib}/sha1.js +4 -60
  51. package/{js → lib}/sha256.js +4 -60
  52. package/{js → lib}/sha512.js +19 -61
  53. package/{js → lib}/socket.js +8 -63
  54. package/{js → lib}/ssh.js +7 -66
  55. package/{js → lib}/task.js +5 -58
  56. package/{js → lib}/tls.js +10 -67
  57. package/{js → lib}/tlssocket.js +6 -61
  58. package/{js → lib}/util.js +39 -68
  59. package/{js → lib}/x509.js +25 -102
  60. package/{js → lib}/xhr.js +12 -15
  61. package/package.json +58 -21
  62. package/js/forge.js +0 -94
  63. package/js/md.js +0 -75
  64. package/js/mgf.js +0 -67
  65. package/js/mgf1.js +0 -112
  66. package/js/oids.js +0 -288
  67. package/swf/SocketPool.swf +0 -0
@@ -133,12 +133,12 @@
133
133
  * The full OID (including ASN.1 tag and length of 6 bytes) is:
134
134
  * 0x06062A864886F70D
135
135
  */
136
- (function() {
137
- /* ########## Begin module implementation ########## */
138
- function initModule(forge) {
136
+ var forge = require('./forge');
137
+ require('./util');
138
+ require('./oids');
139
139
 
140
140
  /* ASN.1 API */
141
- var asn1 = forge.asn1 = forge.asn1 || {};
141
+ var asn1 = module.exports = forge.asn1 = forge.asn1 || {};
142
142
 
143
143
  /**
144
144
  * ASN.1 classes.
@@ -185,10 +185,13 @@ asn1.Type = {
185
185
  * @param type the data type (tag number) for the object.
186
186
  * @param constructed true if the asn1 object is in constructed form.
187
187
  * @param value the value for the object, if it is not constructed.
188
+ * @param [options] the options to use:
189
+ * [bitStringContents] the plain BIT STRING content including padding
190
+ * byte.
188
191
  *
189
192
  * @return the asn1 object.
190
193
  */
191
- asn1.create = function(tagClass, type, constructed, value) {
194
+ asn1.create = function(tagClass, type, constructed, value, options) {
192
195
  /* An asn1 object has a tagClass, a type, a constructed flag, and a
193
196
  value. The value's type depends on the constructed flag. If
194
197
  constructed, it will contain a list of other asn1 objects. If not,
@@ -206,13 +209,108 @@ asn1.create = function(tagClass, type, constructed, value) {
206
209
  value = tmp;
207
210
  }
208
211
 
209
- return {
212
+ var obj = {
210
213
  tagClass: tagClass,
211
214
  type: type,
212
215
  constructed: constructed,
213
216
  composed: constructed || forge.util.isArray(value),
214
217
  value: value
215
218
  };
219
+ if(options && 'bitStringContents' in options) {
220
+ // TODO: copy byte buffer if it's a buffer not a string
221
+ obj.bitStringContents = options.bitStringContents;
222
+ // TODO: add readonly flag to avoid this overhead
223
+ // save copy to detect changes
224
+ obj.original = asn1.copy(obj);
225
+ }
226
+ return obj;
227
+ };
228
+
229
+ /**
230
+ * Copies an asn1 object.
231
+ *
232
+ * @param obj the asn1 object.
233
+ * @param [options] copy options:
234
+ * [excludeBitStringContents] true to not copy bitStringContents
235
+ *
236
+ * @return the a copy of the asn1 object.
237
+ */
238
+ asn1.copy = function(obj, options) {
239
+ var copy;
240
+
241
+ if(forge.util.isArray(obj)) {
242
+ copy = [];
243
+ for(var i = 0; i < obj.length; ++i) {
244
+ copy.push(asn1.copy(obj[i], options));
245
+ }
246
+ return copy;
247
+ }
248
+
249
+ if(typeof obj === 'string') {
250
+ // TODO: copy byte buffer if it's a buffer not a string
251
+ return obj;
252
+ }
253
+
254
+ copy = {
255
+ tagClass: obj.tagClass,
256
+ type: obj.type,
257
+ constructed: obj.constructed,
258
+ composed: obj.composed,
259
+ value: asn1.copy(obj.value, options)
260
+ };
261
+ if(options && !options.excludeBitStringContents) {
262
+ // TODO: copy byte buffer if it's a buffer not a string
263
+ copy.bitStringContents = obj.bitStringContents;
264
+ }
265
+ return copy;
266
+ };
267
+
268
+ /**
269
+ * Compares asn1 objects for equality.
270
+ *
271
+ * Note this function does not run in constant time.
272
+ *
273
+ * @param obj1 the first asn1 object.
274
+ * @param obj2 the second asn1 object.
275
+ * @param [options] compare options:
276
+ * [includeBitStringContents] true to compare bitStringContents
277
+ *
278
+ * @return true if the asn1 objects are equal.
279
+ */
280
+ asn1.equals = function(obj1, obj2, options) {
281
+ if(forge.util.isArray(obj1)) {
282
+ if(!forge.util.isArray(obj2)) {
283
+ return false;
284
+ }
285
+ if(obj1.length !== obj2.length) {
286
+ return false;
287
+ }
288
+ for(var i = 0; i < obj1.length; ++i) {
289
+ if(!asn1.equals(obj1[i], obj2[i])) {
290
+ return false;
291
+ }
292
+ return true;
293
+ }
294
+ }
295
+
296
+ if(typeof obj1 !== typeof obj2) {
297
+ return false;
298
+ }
299
+
300
+ if(typeof obj1 === 'string') {
301
+ return obj1 === obj2;
302
+ }
303
+
304
+ var equal = obj1.tagClass === obj2.tagClass &&
305
+ obj1.type === obj2.type &&
306
+ obj1.constructed === obj2.constructed &&
307
+ obj1.composed === obj2.composed &&
308
+ asn1.equals(obj1.value, obj2.value);
309
+ if(options && options.includeBitStringContents) {
310
+ equal = equal && (obj1.bitStringContents === obj2.bitStringContents);
311
+ }
312
+
313
+ return equal;
216
314
  };
217
315
 
218
316
  /**
@@ -225,7 +323,7 @@ asn1.create = function(tagClass, type, constructed, value) {
225
323
  *
226
324
  * @return the length of the BER-encoded ASN.1 value or undefined.
227
325
  */
228
- var _getValueLength = asn1.getBerValueLength = function(b) {
326
+ asn1.getBerValueLength = function(b) {
229
327
  // TODO: move this function and related DER/BER functions to a der.js
230
328
  // file; better abstract ASN.1 away from der/ber.
231
329
  var b2 = b.getByte();
@@ -247,18 +345,99 @@ var _getValueLength = asn1.getBerValueLength = function(b) {
247
345
  return length;
248
346
  };
249
347
 
348
+ /**
349
+ * Check if the byte buffer has enough bytes. Throws an Error if not.
350
+ *
351
+ * @param bytes the byte buffer to parse from.
352
+ * @param remaining the bytes remaining in the current parsing state.
353
+ * @param n the number of bytes the buffer must have.
354
+ */
355
+ function _checkBufferLength(bytes, remaining, n) {
356
+ if(n > remaining) {
357
+ var error = new Error('Too few bytes to parse DER.');
358
+ error.available = bytes.length();
359
+ error.remaining = remaining;
360
+ error.requested = n;
361
+ throw error;
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Gets the length of a BER-encoded ASN.1 value.
367
+ *
368
+ * In case the length is not specified, undefined is returned.
369
+ *
370
+ * @param bytes the byte buffer to parse from.
371
+ * @param remaining the bytes remaining in the current parsing state.
372
+ *
373
+ * @return the length of the BER-encoded ASN.1 value or undefined.
374
+ */
375
+ var _getValueLength = function(bytes, remaining) {
376
+ // TODO: move this function and related DER/BER functions to a der.js
377
+ // file; better abstract ASN.1 away from der/ber.
378
+ // fromDer already checked that this byte exists
379
+ var b2 = bytes.getByte();
380
+ remaining--;
381
+ if(b2 === 0x80) {
382
+ return undefined;
383
+ }
384
+
385
+ // see if the length is "short form" or "long form" (bit 8 set)
386
+ var length;
387
+ var longForm = b2 & 0x80;
388
+ if(!longForm) {
389
+ // length is just the first byte
390
+ length = b2;
391
+ } else {
392
+ // the number of bytes the length is specified in bits 7 through 1
393
+ // and each length byte is in big-endian base-256
394
+ var longFormBytes = b2 & 0x7F;
395
+ _checkBufferLength(bytes, remaining, longFormBytes);
396
+ length = bytes.getInt(longFormBytes << 3);
397
+ }
398
+ // FIXME: this will only happen for 32 bit getInt with high bit set
399
+ if(length < 0) {
400
+ throw new Error('Negative length: ' + length);
401
+ }
402
+ return length;
403
+ };
404
+
250
405
  /**
251
406
  * Parses an asn1 object from a byte buffer in DER format.
252
407
  *
253
408
  * @param bytes the byte buffer to parse from.
254
- * @param strict true to be strict when checking value lengths, false to
409
+ * @param [strict] true to be strict when checking value lengths, false to
255
410
  * allow truncated values (default: true).
411
+ * @param [options] object with options or boolean strict flag
412
+ * [strict] true to be strict when checking value lengths, false to
413
+ * allow truncated values (default: true).
414
+ * [decodeBitStrings] true to attempt to decode the content of
415
+ * BIT STRINGs (not OCTET STRINGs) using strict mode. Note that
416
+ * without schema support to understand the data context this can
417
+ * erroneously decode values that happen to be valid ASN.1. This
418
+ * flag will be deprecated or removed as soon as schema support is
419
+ * available. (default: true)
256
420
  *
257
421
  * @return the parsed asn1 object.
258
422
  */
259
- asn1.fromDer = function(bytes, strict) {
260
- if(strict === undefined) {
261
- strict = true;
423
+ asn1.fromDer = function(bytes, options) {
424
+ if(options === undefined) {
425
+ options = {
426
+ strict: true,
427
+ decodeBitStrings: true
428
+ };
429
+ }
430
+ if(typeof options === 'boolean') {
431
+ options = {
432
+ strict: options,
433
+ decodeBitStrings: true
434
+ };
435
+ }
436
+ if(!('strict' in options)) {
437
+ options.strict = true;
438
+ }
439
+ if(!('decodeBitStrings' in options)) {
440
+ options.decodeBitStrings = true;
262
441
  }
263
442
 
264
443
  // wrap in buffer if needed
@@ -266,15 +445,30 @@ asn1.fromDer = function(bytes, strict) {
266
445
  bytes = forge.util.createBuffer(bytes);
267
446
  }
268
447
 
448
+ return _fromDer(bytes, bytes.length(), 0, options);
449
+ }
450
+
451
+ /**
452
+ * Internal function to parse an asn1 object from a byte buffer in DER format.
453
+ *
454
+ * @param bytes the byte buffer to parse from.
455
+ * @param remaining the number of bytes remaining for this chunk.
456
+ * @param depth the current parsing depth.
457
+ * @param options object with same options as fromDer().
458
+ *
459
+ * @return the parsed asn1 object.
460
+ */
461
+ function _fromDer(bytes, remaining, depth, options) {
462
+ // temporary storage for consumption calculations
463
+ var start;
464
+
269
465
  // minimum length for ASN.1 DER structure is 2
270
- if(bytes.length() < 2) {
271
- var error = new Error('Too few bytes to parse DER.');
272
- error.bytes = bytes.length();
273
- throw error;
274
- }
466
+ _checkBufferLength(bytes, remaining, 2);
275
467
 
276
468
  // get the first byte
277
469
  var b1 = bytes.getByte();
470
+ // consumed one byte
471
+ remaining--;
278
472
 
279
473
  // get the tag class
280
474
  var tagClass = (b1 & 0xC0);
@@ -282,107 +476,156 @@ asn1.fromDer = function(bytes, strict) {
282
476
  // get the type (bits 1-5)
283
477
  var type = b1 & 0x1F;
284
478
 
285
- // get the value length
286
- var length = _getValueLength(bytes);
479
+ // get the variable value length and adjust remaining bytes
480
+ start = bytes.length();
481
+ var length = _getValueLength(bytes, remaining);
482
+ remaining -= start - bytes.length();
287
483
 
288
484
  // ensure there are enough bytes to get the value
289
- if(bytes.length() < length) {
290
- if(strict) {
485
+ if(length !== undefined && length > remaining) {
486
+ if(options.strict) {
291
487
  var error = new Error('Too few bytes to read ASN.1 value.');
292
- error.detail = bytes.length() + ' < ' + length;
488
+ error.available = bytes.length();
489
+ error.remaining = remaining;
490
+ error.requested = length;
293
491
  throw error;
294
492
  }
295
- // Note: be lenient with truncated values
296
- length = bytes.length();
493
+ // Note: be lenient with truncated values and use remaining state bytes
494
+ length = remaining;
297
495
  }
298
496
 
299
- // prepare to get value
497
+ // value storage
300
498
  var value;
499
+ // possible BIT STRING contents storage
500
+ var bitStringContents;
301
501
 
302
502
  // constructed flag is bit 6 (32 = 0x20) of the first byte
303
503
  var constructed = ((b1 & 0x20) === 0x20);
304
-
305
- // determine if the value is composed of other ASN.1 objects (if its
306
- // constructed it will be and if its a BITSTRING it may be)
307
- var composed = constructed;
308
- if(!composed && tagClass === asn1.Class.UNIVERSAL &&
309
- type === asn1.Type.BITSTRING && length > 1) {
310
- /* The first octet gives the number of bits by which the length of the
311
- bit string is less than the next multiple of eight (this is called
312
- the "number of unused bits").
313
-
314
- The second and following octets give the value of the bit string
315
- converted to an octet string. */
316
- // if there are no unused bits, maybe the bitstring holds ASN.1 objs
317
- var read = bytes.read;
318
- var unused = bytes.getByte();
319
- if(unused === 0) {
320
- // if the first byte indicates UNIVERSAL or CONTEXT_SPECIFIC,
321
- // and the length is valid, assume we've got an ASN.1 object
322
- b1 = bytes.getByte();
323
- var tc = (b1 & 0xC0);
324
- if(tc === asn1.Class.UNIVERSAL || tc === asn1.Class.CONTEXT_SPECIFIC) {
325
- try {
326
- var len = _getValueLength(bytes);
327
- composed = (len === length - (bytes.read - read));
328
- if(composed) {
329
- // adjust read/length to account for unused bits byte
330
- ++read;
331
- --length;
332
- }
333
- } catch(ex) {}
334
- }
335
- }
336
- // restore read pointer
337
- bytes.read = read;
338
- }
339
-
340
- if(composed) {
504
+ if(constructed) {
341
505
  // parse child asn1 objects from the value
342
506
  value = [];
343
507
  if(length === undefined) {
344
508
  // asn1 object of indefinite length, read until end tag
345
509
  for(;;) {
510
+ _checkBufferLength(bytes, remaining, 2);
346
511
  if(bytes.bytes(2) === String.fromCharCode(0, 0)) {
347
512
  bytes.getBytes(2);
513
+ remaining -= 2;
348
514
  break;
349
515
  }
350
- value.push(asn1.fromDer(bytes, strict));
516
+ start = bytes.length();
517
+ value.push(_fromDer(bytes, remaining, depth + 1, options));
518
+ remaining -= start - bytes.length();
351
519
  }
352
520
  } else {
353
521
  // parsing asn1 object of definite length
354
- var start = bytes.length();
355
522
  while(length > 0) {
356
- value.push(asn1.fromDer(bytes, strict));
523
+ start = bytes.length();
524
+ value.push(_fromDer(bytes, length, depth + 1, options));
525
+ remaining -= start - bytes.length();
357
526
  length -= start - bytes.length();
527
+ }
528
+ }
529
+ }
530
+
531
+ // if a BIT STRING, save the contents including padding
532
+ if(value === undefined && tagClass === asn1.Class.UNIVERSAL &&
533
+ type === asn1.Type.BITSTRING) {
534
+ bitStringContents = bytes.bytes(length);
535
+ }
536
+
537
+ // determine if a non-constructed value should be decoded as a composed
538
+ // value that contains other ASN.1 objects. BIT STRINGs (and OCTET STRINGs)
539
+ // can be used this way.
540
+ if(value === undefined && options.decodeBitStrings &&
541
+ tagClass === asn1.Class.UNIVERSAL &&
542
+ // FIXME: OCTET STRINGs not yet supported here
543
+ // .. other parts of forge expect to decode OCTET STRINGs manually
544
+ (type === asn1.Type.BITSTRING /*|| type === asn1.Type.OCTETSTRING*/) &&
545
+ length > 1) {
546
+ // save read position
547
+ var savedRead = bytes.read;
548
+ var savedRemaining = remaining;
549
+ var unused = 0;
550
+ if(type === asn1.Type.BITSTRING) {
551
+ /* The first octet gives the number of bits by which the length of the
552
+ bit string is less than the next multiple of eight (this is called
553
+ the "number of unused bits").
554
+
555
+ The second and following octets give the value of the bit string
556
+ converted to an octet string. */
557
+ _checkBufferLength(bytes, remaining, 1);
558
+ unused = bytes.getByte();
559
+ remaining--;
560
+ }
561
+ // if all bits are used, maybe the BIT/OCTET STRING holds ASN.1 objs
562
+ if(unused === 0) {
563
+ try {
564
+ // attempt to parse child asn1 object from the value
565
+ // (stored in array to signal composed value)
358
566
  start = bytes.length();
567
+ var subOptions = {
568
+ // enforce strict mode to avoid parsing ASN.1 from plain data
569
+ verbose: options.verbose,
570
+ strict: true,
571
+ decodeBitStrings: true
572
+ };
573
+ var composed = _fromDer(bytes, remaining, depth + 1, subOptions);
574
+ var used = start - bytes.length();
575
+ remaining -= used;
576
+ if(type == asn1.Type.BITSTRING) {
577
+ used++;
578
+ }
579
+
580
+ // if the data all decoded and the class indicates UNIVERSAL or
581
+ // CONTEXT_SPECIFIC then assume we've got an encapsulated ASN.1 object
582
+ var tc = composed.tagClass;
583
+ if(used === length &&
584
+ (tc === asn1.Class.UNIVERSAL || tc === asn1.Class.CONTEXT_SPECIFIC)) {
585
+ value = [composed];
586
+ }
587
+ } catch(ex) {
359
588
  }
360
589
  }
361
- } else {
362
- // asn1 not composed, get raw value
590
+ if(value === undefined) {
591
+ // restore read position
592
+ bytes.read = savedRead;
593
+ remaining = savedRemaining;
594
+ }
595
+ }
596
+
597
+ if(value === undefined) {
598
+ // asn1 not constructed or composed, get raw value
363
599
  // TODO: do DER to OID conversion and vice-versa in .toDer?
364
600
 
365
601
  if(length === undefined) {
366
- if(strict) {
602
+ if(options.strict) {
367
603
  throw new Error('Non-constructed ASN.1 object of indefinite length.');
368
604
  }
369
- // be lenient and use remaining bytes
370
- length = bytes.length();
605
+ // be lenient and use remaining state bytes
606
+ length = remaining;
371
607
  }
372
608
 
373
609
  if(type === asn1.Type.BMPSTRING) {
374
610
  value = '';
375
- for(var i = 0; i < length; i += 2) {
611
+ for(; length > 0; length -= 2) {
612
+ _checkBufferLength(bytes, remaining, 2);
376
613
  value += String.fromCharCode(bytes.getInt16());
614
+ remaining -= 2;
377
615
  }
378
616
  } else {
379
617
  value = bytes.getBytes(length);
380
618
  }
381
619
  }
382
620
 
621
+ // add BIT STRING contents if available
622
+ var asn1Options = bitStringContents === undefined ? null : {
623
+ bitStringContents: bitStringContents
624
+ };
625
+
383
626
  // create and return asn1 object
384
- return asn1.create(tagClass, type, constructed, value);
385
- };
627
+ return asn1.create(tagClass, type, constructed, value, asn1Options);
628
+ }
386
629
 
387
630
  /**
388
631
  * Converts the given asn1 object to a buffer of bytes in DER format.
@@ -400,8 +643,19 @@ asn1.toDer = function(obj) {
400
643
  // for storing the ASN.1 value
401
644
  var value = forge.util.createBuffer();
402
645
 
403
- // if composed, use each child asn1 object's DER bytes as value
404
- if(obj.composed) {
646
+ // use BIT STRING contents if available and data not changed
647
+ var useBitStringContents = false;
648
+ if('bitStringContents' in obj) {
649
+ useBitStringContents = true;
650
+ if(obj.original) {
651
+ useBitStringContents = asn1.equals(obj, obj.original);
652
+ }
653
+ }
654
+
655
+ if(useBitStringContents) {
656
+ value.putBytes(obj.bitStringContents);
657
+ } else if(obj.composed) {
658
+ // if composed, use each child asn1 object's DER bytes as value
405
659
  // turn on 6th bit (0x20 = 32) to indicate asn1 is constructed
406
660
  // from other asn1 objects
407
661
  if(obj.constructed) {
@@ -425,6 +679,8 @@ asn1.toDer = function(obj) {
425
679
  }
426
680
  } else {
427
681
  // ensure integer is minimally-encoded
682
+ // TODO: should all leading bytes be stripped vs just one?
683
+ // .. ex '00 00 01' => '01'?
428
684
  if(obj.type === asn1.Type.INTEGER &&
429
685
  obj.value.length > 1 &&
430
686
  // leading 0x00 for positive integer
@@ -862,7 +1118,10 @@ asn1.derToInteger = function(bytes) {
862
1118
  *
863
1119
  * To capture an ASN.1 value, set an object in the validator's 'capture'
864
1120
  * parameter to the key to use in the capture map. To capture the full
865
- * ASN.1 object, specify 'captureAsn1'.
1121
+ * ASN.1 object, specify 'captureAsn1'. To capture BIT STRING bytes, including
1122
+ * the leading unused bits counter byte, specify 'captureBitStringContents'.
1123
+ * To capture BIT STRING bytes, without the leading unused bits counter byte,
1124
+ * specify 'captureBitStringValue'.
866
1125
  *
867
1126
  * Objects in the validator may set a field 'optional' to true to indicate
868
1127
  * that it isn't necessary to pass validation.
@@ -916,6 +1175,23 @@ asn1.validate = function(obj, v, capture, errors) {
916
1175
  if(v.captureAsn1) {
917
1176
  capture[v.captureAsn1] = obj;
918
1177
  }
1178
+ if(v.captureBitStringContents && 'bitStringContents' in obj) {
1179
+ capture[v.captureBitStringContents] = obj.bitStringContents;
1180
+ }
1181
+ if(v.captureBitStringValue && 'bitStringContents' in obj) {
1182
+ var value;
1183
+ if(obj.bitStringContents.length < 2) {
1184
+ capture[v.captureBitStringValue] = '';
1185
+ } else {
1186
+ // FIXME: support unused bits with data shifting
1187
+ var unused = obj.bitStringContents.charCodeAt(0);
1188
+ if(unused !== 0) {
1189
+ throw new Error(
1190
+ 'captureBitStringValue only supported for zero unused bits');
1191
+ }
1192
+ capture[v.captureBitStringValue] = obj.bitStringContents.slice(1);
1193
+ }
1194
+ }
919
1195
  }
920
1196
  } else if(errors) {
921
1197
  errors.push(
@@ -997,12 +1273,12 @@ asn1.prettyPrint = function(obj, level, indentation) {
997
1273
  case asn1.Type.BOOLEAN:
998
1274
  rval += ' (Boolean)';
999
1275
  break;
1000
- case asn1.Type.BITSTRING:
1001
- rval += ' (Bit string)';
1002
- break;
1003
1276
  case asn1.Type.INTEGER:
1004
1277
  rval += ' (Integer)';
1005
1278
  break;
1279
+ case asn1.Type.BITSTRING:
1280
+ rval += ' (Bit string)';
1281
+ break;
1006
1282
  case asn1.Type.OCTETSTRING:
1007
1283
  rval += ' (Octet string)';
1008
1284
  break;
@@ -1092,6 +1368,23 @@ asn1.prettyPrint = function(obj, level, indentation) {
1092
1368
  } catch(ex) {
1093
1369
  rval += '0x' + forge.util.bytesToHex(obj.value);
1094
1370
  }
1371
+ } else if(obj.type === asn1.Type.BITSTRING) {
1372
+ // TODO: shift bits as needed to display without padding
1373
+ if(obj.value.length > 1) {
1374
+ // remove unused bits field
1375
+ rval += '0x' + forge.util.bytesToHex(obj.value.slice(1));
1376
+ } else {
1377
+ rval += '(none)';
1378
+ }
1379
+ // show unused bit count
1380
+ if(obj.value.length > 0) {
1381
+ var unused = obj.value.charCodeAt(0);
1382
+ if(unused == 1) {
1383
+ rval += ' (1 unused bit shown)';
1384
+ } else if(unused > 1) {
1385
+ rval += ' (' + unused + ' unused bits shown)';
1386
+ }
1387
+ }
1095
1388
  } else if(obj.type === asn1.Type.OCTETSTRING) {
1096
1389
  if(!_nonLatinRegex.test(obj.value)) {
1097
1390
  rval += '(' + obj.value + ') ';
@@ -1113,57 +1406,3 @@ asn1.prettyPrint = function(obj, level, indentation) {
1113
1406
 
1114
1407
  return rval;
1115
1408
  };
1116
-
1117
- } // end module implementation
1118
-
1119
- /* ########## Begin module wrapper ########## */
1120
- var name = 'asn1';
1121
- if(typeof define !== 'function') {
1122
- // NodeJS -> AMD
1123
- if(typeof module === 'object' && module.exports) {
1124
- var nodeJS = true;
1125
- define = function(ids, factory) {
1126
- factory(require, module);
1127
- };
1128
- } else {
1129
- // <script>
1130
- if(typeof forge === 'undefined') {
1131
- forge = {};
1132
- }
1133
- return initModule(forge);
1134
- }
1135
- }
1136
- // AMD
1137
- var deps;
1138
- var defineFunc = function(require, module) {
1139
- module.exports = function(forge) {
1140
- var mods = deps.map(function(dep) {
1141
- return require(dep);
1142
- }).concat(initModule);
1143
- // handle circular dependencies
1144
- forge = forge || {};
1145
- forge.defined = forge.defined || {};
1146
- if(forge.defined[name]) {
1147
- return forge[name];
1148
- }
1149
- forge.defined[name] = true;
1150
- for(var i = 0; i < mods.length; ++i) {
1151
- mods[i](forge);
1152
- }
1153
- return forge[name];
1154
- };
1155
- };
1156
- var tmpDefine = define;
1157
- define = function(ids, factory) {
1158
- deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
1159
- if(nodeJS) {
1160
- delete define;
1161
- return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
1162
- }
1163
- define = tmpDefine;
1164
- return define.apply(null, Array.prototype.slice.call(arguments, 0));
1165
- };
1166
- define(['require', 'module', './util', './oids'], function() {
1167
- defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
1168
- });
1169
- })();