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.
- package/CHANGELOG.md +106 -0
- package/LICENSE +3 -3
- package/README.md +254 -175
- package/dist/forge.all.min.js +11 -0
- package/dist/forge.all.min.js.map +1 -0
- package/dist/forge.min.js +10 -0
- package/dist/forge.min.js.map +1 -0
- package/dist/prime.worker.min.js +2 -0
- package/dist/prime.worker.min.js.map +1 -0
- package/flash/README.md +48 -0
- package/flash/package.json +28 -0
- package/flash/swf/SocketPool.swf +0 -0
- package/{js → lib}/aes.js +5 -61
- package/{js → lib}/aesCipherSuites.js +4 -58
- package/{js → lib}/asn1.js +371 -132
- package/{js → lib}/cipher.js +3 -59
- package/{js → lib}/cipherModes.js +3 -65
- package/{js → lib}/debug.js +2 -58
- package/{js → lib}/des.js +6 -63
- package/lib/forge.js +13 -0
- package/{js → lib}/form.js +5 -13
- package/{js → lib}/hmac.js +4 -58
- package/{js → lib}/http.js +15 -20
- package/lib/index.all.js +16 -0
- package/lib/index.js +34 -0
- package/{js → lib}/jsbn.js +3 -60
- package/{js → lib}/kem.js +5 -58
- package/{js → lib}/log.js +3 -58
- package/lib/md.all.js +13 -0
- package/lib/md.js +11 -0
- package/{js → lib}/md5.js +4 -60
- package/lib/mgf.js +12 -0
- package/lib/mgf1.js +57 -0
- package/lib/oids.js +159 -0
- package/{js → lib}/pbe.js +29 -79
- package/{js → lib}/pbkdf2.js +10 -64
- package/{js → lib}/pem.js +3 -58
- package/{js → lib}/pkcs1.js +6 -59
- package/{js → lib}/pkcs12.js +15 -74
- package/{js → lib}/pkcs7.js +12 -72
- package/{js → lib}/pkcs7asn1.js +4 -58
- package/{js → lib}/pki.js +12 -71
- package/{js → lib}/prime.js +18 -58
- package/{js → lib}/prime.worker.js +4 -1
- package/{js → lib}/prng.js +5 -62
- package/{js → lib}/pss.js +7 -61
- package/{js → lib}/random.js +11 -57
- package/{js → lib}/rc2.js +13 -73
- package/{js → lib}/rsa.js +13 -71
- package/{js → lib}/sha1.js +4 -60
- package/{js → lib}/sha256.js +4 -60
- package/{js → lib}/sha512.js +19 -61
- package/{js → lib}/socket.js +8 -63
- package/{js → lib}/ssh.js +7 -66
- package/{js → lib}/task.js +5 -58
- package/{js → lib}/tls.js +10 -67
- package/{js → lib}/tlssocket.js +6 -61
- package/{js → lib}/util.js +39 -68
- package/{js → lib}/x509.js +25 -102
- package/{js → lib}/xhr.js +12 -15
- package/package.json +58 -21
- package/js/forge.js +0 -94
- package/js/md.js +0 -75
- package/js/mgf.js +0 -67
- package/js/mgf1.js +0 -112
- package/js/oids.js +0 -288
- package/swf/SocketPool.swf +0 -0
package/{js → lib}/asn1.js
RENAMED
|
@@ -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
|
-
(
|
|
137
|
-
|
|
138
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
260
|
-
if(
|
|
261
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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.
|
|
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 =
|
|
493
|
+
// Note: be lenient with truncated values and use remaining state bytes
|
|
494
|
+
length = remaining;
|
|
297
495
|
}
|
|
298
496
|
|
|
299
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
362
|
-
|
|
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 =
|
|
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(
|
|
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
|
-
//
|
|
404
|
-
|
|
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
|
-
})();
|