source: trip-planner-front/node_modules/node-forge/lib/asn1.js@ 1ad8e64

Last change on this file since 1ad8e64 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 41.1 KB
RevLine 
[6a3a178]1/**
2 * Javascript implementation of Abstract Syntax Notation Number One.
3 *
4 * @author Dave Longley
5 *
6 * Copyright (c) 2010-2015 Digital Bazaar, Inc.
7 *
8 * An API for storing data using the Abstract Syntax Notation Number One
9 * format using DER (Distinguished Encoding Rules) encoding. This encoding is
10 * commonly used to store data for PKI, i.e. X.509 Certificates, and this
11 * implementation exists for that purpose.
12 *
13 * Abstract Syntax Notation Number One (ASN.1) is used to define the abstract
14 * syntax of information without restricting the way the information is encoded
15 * for transmission. It provides a standard that allows for open systems
16 * communication. ASN.1 defines the syntax of information data and a number of
17 * simple data types as well as a notation for describing them and specifying
18 * values for them.
19 *
20 * The RSA algorithm creates public and private keys that are often stored in
21 * X.509 or PKCS#X formats -- which use ASN.1 (encoded in DER format). This
22 * class provides the most basic functionality required to store and load DSA
23 * keys that are encoded according to ASN.1.
24 *
25 * The most common binary encodings for ASN.1 are BER (Basic Encoding Rules)
26 * and DER (Distinguished Encoding Rules). DER is just a subset of BER that
27 * has stricter requirements for how data must be encoded.
28 *
29 * Each ASN.1 structure has a tag (a byte identifying the ASN.1 structure type)
30 * and a byte array for the value of this ASN1 structure which may be data or a
31 * list of ASN.1 structures.
32 *
33 * Each ASN.1 structure using BER is (Tag-Length-Value):
34 *
35 * | byte 0 | bytes X | bytes Y |
36 * |--------|---------|----------
37 * | tag | length | value |
38 *
39 * ASN.1 allows for tags to be of "High-tag-number form" which allows a tag to
40 * be two or more octets, but that is not supported by this class. A tag is
41 * only 1 byte. Bits 1-5 give the tag number (ie the data type within a
42 * particular 'class'), 6 indicates whether or not the ASN.1 value is
43 * constructed from other ASN.1 values, and bits 7 and 8 give the 'class'. If
44 * bits 7 and 8 are both zero, the class is UNIVERSAL. If only bit 7 is set,
45 * then the class is APPLICATION. If only bit 8 is set, then the class is
46 * CONTEXT_SPECIFIC. If both bits 7 and 8 are set, then the class is PRIVATE.
47 * The tag numbers for the data types for the class UNIVERSAL are listed below:
48 *
49 * UNIVERSAL 0 Reserved for use by the encoding rules
50 * UNIVERSAL 1 Boolean type
51 * UNIVERSAL 2 Integer type
52 * UNIVERSAL 3 Bitstring type
53 * UNIVERSAL 4 Octetstring type
54 * UNIVERSAL 5 Null type
55 * UNIVERSAL 6 Object identifier type
56 * UNIVERSAL 7 Object descriptor type
57 * UNIVERSAL 8 External type and Instance-of type
58 * UNIVERSAL 9 Real type
59 * UNIVERSAL 10 Enumerated type
60 * UNIVERSAL 11 Embedded-pdv type
61 * UNIVERSAL 12 UTF8String type
62 * UNIVERSAL 13 Relative object identifier type
63 * UNIVERSAL 14-15 Reserved for future editions
64 * UNIVERSAL 16 Sequence and Sequence-of types
65 * UNIVERSAL 17 Set and Set-of types
66 * UNIVERSAL 18-22, 25-30 Character string types
67 * UNIVERSAL 23-24 Time types
68 *
69 * The length of an ASN.1 structure is specified after the tag identifier.
70 * There is a definite form and an indefinite form. The indefinite form may
71 * be used if the encoding is constructed and not all immediately available.
72 * The indefinite form is encoded using a length byte with only the 8th bit
73 * set. The end of the constructed object is marked using end-of-contents
74 * octets (two zero bytes).
75 *
76 * The definite form looks like this:
77 *
78 * The length may take up 1 or more bytes, it depends on the length of the
79 * value of the ASN.1 structure. DER encoding requires that if the ASN.1
80 * structure has a value that has a length greater than 127, more than 1 byte
81 * will be used to store its length, otherwise just one byte will be used.
82 * This is strict.
83 *
84 * In the case that the length of the ASN.1 value is less than 127, 1 octet
85 * (byte) is used to store the "short form" length. The 8th bit has a value of
86 * 0 indicating the length is "short form" and not "long form" and bits 7-1
87 * give the length of the data. (The 8th bit is the left-most, most significant
88 * bit: also known as big endian or network format).
89 *
90 * In the case that the length of the ASN.1 value is greater than 127, 2 to
91 * 127 octets (bytes) are used to store the "long form" length. The first
92 * byte's 8th bit is set to 1 to indicate the length is "long form." Bits 7-1
93 * give the number of additional octets. All following octets are in base 256
94 * with the most significant digit first (typical big-endian binary unsigned
95 * integer storage). So, for instance, if the length of a value was 257, the
96 * first byte would be set to:
97 *
98 * 10000010 = 130 = 0x82.
99 *
100 * This indicates there are 2 octets (base 256) for the length. The second and
101 * third bytes (the octets just mentioned) would store the length in base 256:
102 *
103 * octet 2: 00000001 = 1 * 256^1 = 256
104 * octet 3: 00000001 = 1 * 256^0 = 1
105 * total = 257
106 *
107 * The algorithm for converting a js integer value of 257 to base-256 is:
108 *
109 * var value = 257;
110 * var bytes = [];
111 * bytes[0] = (value >>> 8) & 0xFF; // most significant byte first
112 * bytes[1] = value & 0xFF; // least significant byte last
113 *
114 * On the ASN.1 UNIVERSAL Object Identifier (OID) type:
115 *
116 * An OID can be written like: "value1.value2.value3...valueN"
117 *
118 * The DER encoding rules:
119 *
120 * The first byte has the value 40 * value1 + value2.
121 * The following bytes, if any, encode the remaining values. Each value is
122 * encoded in base 128, most significant digit first (big endian), with as
123 * few digits as possible, and the most significant bit of each byte set
124 * to 1 except the last in each value's encoding. For example: Given the
125 * OID "1.2.840.113549", its DER encoding is (remember each byte except the
126 * last one in each encoding is OR'd with 0x80):
127 *
128 * byte 1: 40 * 1 + 2 = 42 = 0x2A.
129 * bytes 2-3: 128 * 6 + 72 = 840 = 6 72 = 6 72 = 0x0648 = 0x8648
130 * bytes 4-6: 16384 * 6 + 128 * 119 + 13 = 6 119 13 = 0x06770D = 0x86F70D
131 *
132 * The final value is: 0x2A864886F70D.
133 * The full OID (including ASN.1 tag and length of 6 bytes) is:
134 * 0x06062A864886F70D
135 */
136var forge = require('./forge');
137require('./util');
138require('./oids');
139
140/* ASN.1 API */
141var asn1 = module.exports = forge.asn1 = forge.asn1 || {};
142
143/**
144 * ASN.1 classes.
145 */
146asn1.Class = {
147 UNIVERSAL: 0x00,
148 APPLICATION: 0x40,
149 CONTEXT_SPECIFIC: 0x80,
150 PRIVATE: 0xC0
151};
152
153/**
154 * ASN.1 types. Not all types are supported by this implementation, only
155 * those necessary to implement a simple PKI are implemented.
156 */
157asn1.Type = {
158 NONE: 0,
159 BOOLEAN: 1,
160 INTEGER: 2,
161 BITSTRING: 3,
162 OCTETSTRING: 4,
163 NULL: 5,
164 OID: 6,
165 ODESC: 7,
166 EXTERNAL: 8,
167 REAL: 9,
168 ENUMERATED: 10,
169 EMBEDDED: 11,
170 UTF8: 12,
171 ROID: 13,
172 SEQUENCE: 16,
173 SET: 17,
174 PRINTABLESTRING: 19,
175 IA5STRING: 22,
176 UTCTIME: 23,
177 GENERALIZEDTIME: 24,
178 BMPSTRING: 30
179};
180
181/**
182 * Creates a new asn1 object.
183 *
184 * @param tagClass the tag class for the object.
185 * @param type the data type (tag number) for the object.
186 * @param constructed true if the asn1 object is in constructed form.
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.
191 *
192 * @return the asn1 object.
193 */
194asn1.create = function(tagClass, type, constructed, value, options) {
195 /* An asn1 object has a tagClass, a type, a constructed flag, and a
196 value. The value's type depends on the constructed flag. If
197 constructed, it will contain a list of other asn1 objects. If not,
198 it will contain the ASN.1 value as an array of bytes formatted
199 according to the ASN.1 data type. */
200
201 // remove undefined values
202 if(forge.util.isArray(value)) {
203 var tmp = [];
204 for(var i = 0; i < value.length; ++i) {
205 if(value[i] !== undefined) {
206 tmp.push(value[i]);
207 }
208 }
209 value = tmp;
210 }
211
212 var obj = {
213 tagClass: tagClass,
214 type: type,
215 constructed: constructed,
216 composed: constructed || forge.util.isArray(value),
217 value: value
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 */
238asn1.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 */
280asn1.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 }
293 return true;
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;
314};
315
316/**
317 * Gets the length of a BER-encoded ASN.1 value.
318 *
319 * In case the length is not specified, undefined is returned.
320 *
321 * @param b the BER-encoded ASN.1 byte buffer, starting with the first
322 * length byte.
323 *
324 * @return the length of the BER-encoded ASN.1 value or undefined.
325 */
326asn1.getBerValueLength = function(b) {
327 // TODO: move this function and related DER/BER functions to a der.js
328 // file; better abstract ASN.1 away from der/ber.
329 var b2 = b.getByte();
330 if(b2 === 0x80) {
331 return undefined;
332 }
333
334 // see if the length is "short form" or "long form" (bit 8 set)
335 var length;
336 var longForm = b2 & 0x80;
337 if(!longForm) {
338 // length is just the first byte
339 length = b2;
340 } else {
341 // the number of bytes the length is specified in bits 7 through 1
342 // and each length byte is in big-endian base-256
343 length = b.getInt((b2 & 0x7F) << 3);
344 }
345 return length;
346};
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 */
355function _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 */
375var _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
405/**
406 * Parses an asn1 object from a byte buffer in DER format.
407 *
408 * @param bytes the byte buffer to parse from.
409 * @param [strict] true to be strict when checking value lengths, false to
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)
420 *
421 * @return the parsed asn1 object.
422 */
423asn1.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;
441 }
442
443 // wrap in buffer if needed
444 if(typeof bytes === 'string') {
445 bytes = forge.util.createBuffer(bytes);
446 }
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 */
461function _fromDer(bytes, remaining, depth, options) {
462 // temporary storage for consumption calculations
463 var start;
464
465 // minimum length for ASN.1 DER structure is 2
466 _checkBufferLength(bytes, remaining, 2);
467
468 // get the first byte
469 var b1 = bytes.getByte();
470 // consumed one byte
471 remaining--;
472
473 // get the tag class
474 var tagClass = (b1 & 0xC0);
475
476 // get the type (bits 1-5)
477 var type = b1 & 0x1F;
478
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();
483
484 // ensure there are enough bytes to get the value
485 if(length !== undefined && length > remaining) {
486 if(options.strict) {
487 var error = new Error('Too few bytes to read ASN.1 value.');
488 error.available = bytes.length();
489 error.remaining = remaining;
490 error.requested = length;
491 throw error;
492 }
493 // Note: be lenient with truncated values and use remaining state bytes
494 length = remaining;
495 }
496
497 // value storage
498 var value;
499 // possible BIT STRING contents storage
500 var bitStringContents;
501
502 // constructed flag is bit 6 (32 = 0x20) of the first byte
503 var constructed = ((b1 & 0x20) === 0x20);
504 if(constructed) {
505 // parse child asn1 objects from the value
506 value = [];
507 if(length === undefined) {
508 // asn1 object of indefinite length, read until end tag
509 for(;;) {
510 _checkBufferLength(bytes, remaining, 2);
511 if(bytes.bytes(2) === String.fromCharCode(0, 0)) {
512 bytes.getBytes(2);
513 remaining -= 2;
514 break;
515 }
516 start = bytes.length();
517 value.push(_fromDer(bytes, remaining, depth + 1, options));
518 remaining -= start - bytes.length();
519 }
520 } else {
521 // parsing asn1 object of definite length
522 while(length > 0) {
523 start = bytes.length();
524 value.push(_fromDer(bytes, length, depth + 1, options));
525 remaining -= start - bytes.length();
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)
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) {
588 }
589 }
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
599 // TODO: do DER to OID conversion and vice-versa in .toDer?
600
601 if(length === undefined) {
602 if(options.strict) {
603 throw new Error('Non-constructed ASN.1 object of indefinite length.');
604 }
605 // be lenient and use remaining state bytes
606 length = remaining;
607 }
608
609 if(type === asn1.Type.BMPSTRING) {
610 value = '';
611 for(; length > 0; length -= 2) {
612 _checkBufferLength(bytes, remaining, 2);
613 value += String.fromCharCode(bytes.getInt16());
614 remaining -= 2;
615 }
616 } else {
617 value = bytes.getBytes(length);
618 }
619 }
620
621 // add BIT STRING contents if available
622 var asn1Options = bitStringContents === undefined ? null : {
623 bitStringContents: bitStringContents
624 };
625
626 // create and return asn1 object
627 return asn1.create(tagClass, type, constructed, value, asn1Options);
628}
629
630/**
631 * Converts the given asn1 object to a buffer of bytes in DER format.
632 *
633 * @param asn1 the asn1 object to convert to bytes.
634 *
635 * @return the buffer of bytes.
636 */
637asn1.toDer = function(obj) {
638 var bytes = forge.util.createBuffer();
639
640 // build the first byte
641 var b1 = obj.tagClass | obj.type;
642
643 // for storing the ASN.1 value
644 var value = forge.util.createBuffer();
645
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
659 // turn on 6th bit (0x20 = 32) to indicate asn1 is constructed
660 // from other asn1 objects
661 if(obj.constructed) {
662 b1 |= 0x20;
663 } else {
664 // type is a bit string, add unused bits of 0x00
665 value.putByte(0x00);
666 }
667
668 // add all of the child DER bytes together
669 for(var i = 0; i < obj.value.length; ++i) {
670 if(obj.value[i] !== undefined) {
671 value.putBuffer(asn1.toDer(obj.value[i]));
672 }
673 }
674 } else {
675 // use asn1.value directly
676 if(obj.type === asn1.Type.BMPSTRING) {
677 for(var i = 0; i < obj.value.length; ++i) {
678 value.putInt16(obj.value.charCodeAt(i));
679 }
680 } else {
681 // ensure integer is minimally-encoded
682 // TODO: should all leading bytes be stripped vs just one?
683 // .. ex '00 00 01' => '01'?
684 if(obj.type === asn1.Type.INTEGER &&
685 obj.value.length > 1 &&
686 // leading 0x00 for positive integer
687 ((obj.value.charCodeAt(0) === 0 &&
688 (obj.value.charCodeAt(1) & 0x80) === 0) ||
689 // leading 0xFF for negative integer
690 (obj.value.charCodeAt(0) === 0xFF &&
691 (obj.value.charCodeAt(1) & 0x80) === 0x80))) {
692 value.putBytes(obj.value.substr(1));
693 } else {
694 value.putBytes(obj.value);
695 }
696 }
697 }
698
699 // add tag byte
700 bytes.putByte(b1);
701
702 // use "short form" encoding
703 if(value.length() <= 127) {
704 // one byte describes the length
705 // bit 8 = 0 and bits 7-1 = length
706 bytes.putByte(value.length() & 0x7F);
707 } else {
708 // use "long form" encoding
709 // 2 to 127 bytes describe the length
710 // first byte: bit 8 = 1 and bits 7-1 = # of additional bytes
711 // other bytes: length in base 256, big-endian
712 var len = value.length();
713 var lenBytes = '';
714 do {
715 lenBytes += String.fromCharCode(len & 0xFF);
716 len = len >>> 8;
717 } while(len > 0);
718
719 // set first byte to # bytes used to store the length and turn on
720 // bit 8 to indicate long-form length is used
721 bytes.putByte(lenBytes.length | 0x80);
722
723 // concatenate length bytes in reverse since they were generated
724 // little endian and we need big endian
725 for(var i = lenBytes.length - 1; i >= 0; --i) {
726 bytes.putByte(lenBytes.charCodeAt(i));
727 }
728 }
729
730 // concatenate value bytes
731 bytes.putBuffer(value);
732 return bytes;
733};
734
735/**
736 * Converts an OID dot-separated string to a byte buffer. The byte buffer
737 * contains only the DER-encoded value, not any tag or length bytes.
738 *
739 * @param oid the OID dot-separated string.
740 *
741 * @return the byte buffer.
742 */
743asn1.oidToDer = function(oid) {
744 // split OID into individual values
745 var values = oid.split('.');
746 var bytes = forge.util.createBuffer();
747
748 // first byte is 40 * value1 + value2
749 bytes.putByte(40 * parseInt(values[0], 10) + parseInt(values[1], 10));
750 // other bytes are each value in base 128 with 8th bit set except for
751 // the last byte for each value
752 var last, valueBytes, value, b;
753 for(var i = 2; i < values.length; ++i) {
754 // produce value bytes in reverse because we don't know how many
755 // bytes it will take to store the value
756 last = true;
757 valueBytes = [];
758 value = parseInt(values[i], 10);
759 do {
760 b = value & 0x7F;
761 value = value >>> 7;
762 // if value is not last, then turn on 8th bit
763 if(!last) {
764 b |= 0x80;
765 }
766 valueBytes.push(b);
767 last = false;
768 } while(value > 0);
769
770 // add value bytes in reverse (needs to be in big endian)
771 for(var n = valueBytes.length - 1; n >= 0; --n) {
772 bytes.putByte(valueBytes[n]);
773 }
774 }
775
776 return bytes;
777};
778
779/**
780 * Converts a DER-encoded byte buffer to an OID dot-separated string. The
781 * byte buffer should contain only the DER-encoded value, not any tag or
782 * length bytes.
783 *
784 * @param bytes the byte buffer.
785 *
786 * @return the OID dot-separated string.
787 */
788asn1.derToOid = function(bytes) {
789 var oid;
790
791 // wrap in buffer if needed
792 if(typeof bytes === 'string') {
793 bytes = forge.util.createBuffer(bytes);
794 }
795
796 // first byte is 40 * value1 + value2
797 var b = bytes.getByte();
798 oid = Math.floor(b / 40) + '.' + (b % 40);
799
800 // other bytes are each value in base 128 with 8th bit set except for
801 // the last byte for each value
802 var value = 0;
803 while(bytes.length() > 0) {
804 b = bytes.getByte();
805 value = value << 7;
806 // not the last byte for the value
807 if(b & 0x80) {
808 value += b & 0x7F;
809 } else {
810 // last byte
811 oid += '.' + (value + b);
812 value = 0;
813 }
814 }
815
816 return oid;
817};
818
819/**
820 * Converts a UTCTime value to a date.
821 *
822 * Note: GeneralizedTime has 4 digits for the year and is used for X.509
823 * dates past 2049. Parsing that structure hasn't been implemented yet.
824 *
825 * @param utc the UTCTime value to convert.
826 *
827 * @return the date.
828 */
829asn1.utcTimeToDate = function(utc) {
830 /* The following formats can be used:
831
832 YYMMDDhhmmZ
833 YYMMDDhhmm+hh'mm'
834 YYMMDDhhmm-hh'mm'
835 YYMMDDhhmmssZ
836 YYMMDDhhmmss+hh'mm'
837 YYMMDDhhmmss-hh'mm'
838
839 Where:
840
841 YY is the least significant two digits of the year
842 MM is the month (01 to 12)
843 DD is the day (01 to 31)
844 hh is the hour (00 to 23)
845 mm are the minutes (00 to 59)
846 ss are the seconds (00 to 59)
847 Z indicates that local time is GMT, + indicates that local time is
848 later than GMT, and - indicates that local time is earlier than GMT
849 hh' is the absolute value of the offset from GMT in hours
850 mm' is the absolute value of the offset from GMT in minutes */
851 var date = new Date();
852
853 // if YY >= 50 use 19xx, if YY < 50 use 20xx
854 var year = parseInt(utc.substr(0, 2), 10);
855 year = (year >= 50) ? 1900 + year : 2000 + year;
856 var MM = parseInt(utc.substr(2, 2), 10) - 1; // use 0-11 for month
857 var DD = parseInt(utc.substr(4, 2), 10);
858 var hh = parseInt(utc.substr(6, 2), 10);
859 var mm = parseInt(utc.substr(8, 2), 10);
860 var ss = 0;
861
862 // not just YYMMDDhhmmZ
863 if(utc.length > 11) {
864 // get character after minutes
865 var c = utc.charAt(10);
866 var end = 10;
867
868 // see if seconds are present
869 if(c !== '+' && c !== '-') {
870 // get seconds
871 ss = parseInt(utc.substr(10, 2), 10);
872 end += 2;
873 }
874 }
875
876 // update date
877 date.setUTCFullYear(year, MM, DD);
878 date.setUTCHours(hh, mm, ss, 0);
879
880 if(end) {
881 // get +/- after end of time
882 c = utc.charAt(end);
883 if(c === '+' || c === '-') {
884 // get hours+minutes offset
885 var hhoffset = parseInt(utc.substr(end + 1, 2), 10);
886 var mmoffset = parseInt(utc.substr(end + 4, 2), 10);
887
888 // calculate offset in milliseconds
889 var offset = hhoffset * 60 + mmoffset;
890 offset *= 60000;
891
892 // apply offset
893 if(c === '+') {
894 date.setTime(+date - offset);
895 } else {
896 date.setTime(+date + offset);
897 }
898 }
899 }
900
901 return date;
902};
903
904/**
905 * Converts a GeneralizedTime value to a date.
906 *
907 * @param gentime the GeneralizedTime value to convert.
908 *
909 * @return the date.
910 */
911asn1.generalizedTimeToDate = function(gentime) {
912 /* The following formats can be used:
913
914 YYYYMMDDHHMMSS
915 YYYYMMDDHHMMSS.fff
916 YYYYMMDDHHMMSSZ
917 YYYYMMDDHHMMSS.fffZ
918 YYYYMMDDHHMMSS+hh'mm'
919 YYYYMMDDHHMMSS.fff+hh'mm'
920 YYYYMMDDHHMMSS-hh'mm'
921 YYYYMMDDHHMMSS.fff-hh'mm'
922
923 Where:
924
925 YYYY is the year
926 MM is the month (01 to 12)
927 DD is the day (01 to 31)
928 hh is the hour (00 to 23)
929 mm are the minutes (00 to 59)
930 ss are the seconds (00 to 59)
931 .fff is the second fraction, accurate to three decimal places
932 Z indicates that local time is GMT, + indicates that local time is
933 later than GMT, and - indicates that local time is earlier than GMT
934 hh' is the absolute value of the offset from GMT in hours
935 mm' is the absolute value of the offset from GMT in minutes */
936 var date = new Date();
937
938 var YYYY = parseInt(gentime.substr(0, 4), 10);
939 var MM = parseInt(gentime.substr(4, 2), 10) - 1; // use 0-11 for month
940 var DD = parseInt(gentime.substr(6, 2), 10);
941 var hh = parseInt(gentime.substr(8, 2), 10);
942 var mm = parseInt(gentime.substr(10, 2), 10);
943 var ss = parseInt(gentime.substr(12, 2), 10);
944 var fff = 0;
945 var offset = 0;
946 var isUTC = false;
947
948 if(gentime.charAt(gentime.length - 1) === 'Z') {
949 isUTC = true;
950 }
951
952 var end = gentime.length - 5, c = gentime.charAt(end);
953 if(c === '+' || c === '-') {
954 // get hours+minutes offset
955 var hhoffset = parseInt(gentime.substr(end + 1, 2), 10);
956 var mmoffset = parseInt(gentime.substr(end + 4, 2), 10);
957
958 // calculate offset in milliseconds
959 offset = hhoffset * 60 + mmoffset;
960 offset *= 60000;
961
962 // apply offset
963 if(c === '+') {
964 offset *= -1;
965 }
966
967 isUTC = true;
968 }
969
970 // check for second fraction
971 if(gentime.charAt(14) === '.') {
972 fff = parseFloat(gentime.substr(14), 10) * 1000;
973 }
974
975 if(isUTC) {
976 date.setUTCFullYear(YYYY, MM, DD);
977 date.setUTCHours(hh, mm, ss, fff);
978
979 // apply offset
980 date.setTime(+date + offset);
981 } else {
982 date.setFullYear(YYYY, MM, DD);
983 date.setHours(hh, mm, ss, fff);
984 }
985
986 return date;
987};
988
989/**
990 * Converts a date to a UTCTime value.
991 *
992 * Note: GeneralizedTime has 4 digits for the year and is used for X.509
993 * dates past 2049. Converting to a GeneralizedTime hasn't been
994 * implemented yet.
995 *
996 * @param date the date to convert.
997 *
998 * @return the UTCTime value.
999 */
1000asn1.dateToUtcTime = function(date) {
1001 // TODO: validate; currently assumes proper format
1002 if(typeof date === 'string') {
1003 return date;
1004 }
1005
1006 var rval = '';
1007
1008 // create format YYMMDDhhmmssZ
1009 var format = [];
1010 format.push(('' + date.getUTCFullYear()).substr(2));
1011 format.push('' + (date.getUTCMonth() + 1));
1012 format.push('' + date.getUTCDate());
1013 format.push('' + date.getUTCHours());
1014 format.push('' + date.getUTCMinutes());
1015 format.push('' + date.getUTCSeconds());
1016
1017 // ensure 2 digits are used for each format entry
1018 for(var i = 0; i < format.length; ++i) {
1019 if(format[i].length < 2) {
1020 rval += '0';
1021 }
1022 rval += format[i];
1023 }
1024 rval += 'Z';
1025
1026 return rval;
1027};
1028
1029/**
1030 * Converts a date to a GeneralizedTime value.
1031 *
1032 * @param date the date to convert.
1033 *
1034 * @return the GeneralizedTime value as a string.
1035 */
1036asn1.dateToGeneralizedTime = function(date) {
1037 // TODO: validate; currently assumes proper format
1038 if(typeof date === 'string') {
1039 return date;
1040 }
1041
1042 var rval = '';
1043
1044 // create format YYYYMMDDHHMMSSZ
1045 var format = [];
1046 format.push('' + date.getUTCFullYear());
1047 format.push('' + (date.getUTCMonth() + 1));
1048 format.push('' + date.getUTCDate());
1049 format.push('' + date.getUTCHours());
1050 format.push('' + date.getUTCMinutes());
1051 format.push('' + date.getUTCSeconds());
1052
1053 // ensure 2 digits are used for each format entry
1054 for(var i = 0; i < format.length; ++i) {
1055 if(format[i].length < 2) {
1056 rval += '0';
1057 }
1058 rval += format[i];
1059 }
1060 rval += 'Z';
1061
1062 return rval;
1063};
1064
1065/**
1066 * Converts a javascript integer to a DER-encoded byte buffer to be used
1067 * as the value for an INTEGER type.
1068 *
1069 * @param x the integer.
1070 *
1071 * @return the byte buffer.
1072 */
1073asn1.integerToDer = function(x) {
1074 var rval = forge.util.createBuffer();
1075 if(x >= -0x80 && x < 0x80) {
1076 return rval.putSignedInt(x, 8);
1077 }
1078 if(x >= -0x8000 && x < 0x8000) {
1079 return rval.putSignedInt(x, 16);
1080 }
1081 if(x >= -0x800000 && x < 0x800000) {
1082 return rval.putSignedInt(x, 24);
1083 }
1084 if(x >= -0x80000000 && x < 0x80000000) {
1085 return rval.putSignedInt(x, 32);
1086 }
1087 var error = new Error('Integer too large; max is 32-bits.');
1088 error.integer = x;
1089 throw error;
1090};
1091
1092/**
1093 * Converts a DER-encoded byte buffer to a javascript integer. This is
1094 * typically used to decode the value of an INTEGER type.
1095 *
1096 * @param bytes the byte buffer.
1097 *
1098 * @return the integer.
1099 */
1100asn1.derToInteger = function(bytes) {
1101 // wrap in buffer if needed
1102 if(typeof bytes === 'string') {
1103 bytes = forge.util.createBuffer(bytes);
1104 }
1105
1106 var n = bytes.length() * 8;
1107 if(n > 32) {
1108 throw new Error('Integer too large; max is 32-bits.');
1109 }
1110 return bytes.getSignedInt(n);
1111};
1112
1113/**
1114 * Validates that the given ASN.1 object is at least a super set of the
1115 * given ASN.1 structure. Only tag classes and types are checked. An
1116 * optional map may also be provided to capture ASN.1 values while the
1117 * structure is checked.
1118 *
1119 * To capture an ASN.1 value, set an object in the validator's 'capture'
1120 * parameter to the key to use in the capture map. To capture the full
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'.
1125 *
1126 * Objects in the validator may set a field 'optional' to true to indicate
1127 * that it isn't necessary to pass validation.
1128 *
1129 * @param obj the ASN.1 object to validate.
1130 * @param v the ASN.1 structure validator.
1131 * @param capture an optional map to capture values in.
1132 * @param errors an optional array for storing validation errors.
1133 *
1134 * @return true on success, false on failure.
1135 */
1136asn1.validate = function(obj, v, capture, errors) {
1137 var rval = false;
1138
1139 // ensure tag class and type are the same if specified
1140 if((obj.tagClass === v.tagClass || typeof(v.tagClass) === 'undefined') &&
1141 (obj.type === v.type || typeof(v.type) === 'undefined')) {
1142 // ensure constructed flag is the same if specified
1143 if(obj.constructed === v.constructed ||
1144 typeof(v.constructed) === 'undefined') {
1145 rval = true;
1146
1147 // handle sub values
1148 if(v.value && forge.util.isArray(v.value)) {
1149 var j = 0;
1150 for(var i = 0; rval && i < v.value.length; ++i) {
1151 rval = v.value[i].optional || false;
1152 if(obj.value[j]) {
1153 rval = asn1.validate(obj.value[j], v.value[i], capture, errors);
1154 if(rval) {
1155 ++j;
1156 } else if(v.value[i].optional) {
1157 rval = true;
1158 }
1159 }
1160 if(!rval && errors) {
1161 errors.push(
1162 '[' + v.name + '] ' +
1163 'Tag class "' + v.tagClass + '", type "' +
1164 v.type + '" expected value length "' +
1165 v.value.length + '", got "' +
1166 obj.value.length + '"');
1167 }
1168 }
1169 }
1170
1171 if(rval && capture) {
1172 if(v.capture) {
1173 capture[v.capture] = obj.value;
1174 }
1175 if(v.captureAsn1) {
1176 capture[v.captureAsn1] = obj;
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 }
1195 }
1196 } else if(errors) {
1197 errors.push(
1198 '[' + v.name + '] ' +
1199 'Expected constructed "' + v.constructed + '", got "' +
1200 obj.constructed + '"');
1201 }
1202 } else if(errors) {
1203 if(obj.tagClass !== v.tagClass) {
1204 errors.push(
1205 '[' + v.name + '] ' +
1206 'Expected tag class "' + v.tagClass + '", got "' +
1207 obj.tagClass + '"');
1208 }
1209 if(obj.type !== v.type) {
1210 errors.push(
1211 '[' + v.name + '] ' +
1212 'Expected type "' + v.type + '", got "' + obj.type + '"');
1213 }
1214 }
1215 return rval;
1216};
1217
1218// regex for testing for non-latin characters
1219var _nonLatinRegex = /[^\\u0000-\\u00ff]/;
1220
1221/**
1222 * Pretty prints an ASN.1 object to a string.
1223 *
1224 * @param obj the object to write out.
1225 * @param level the level in the tree.
1226 * @param indentation the indentation to use.
1227 *
1228 * @return the string.
1229 */
1230asn1.prettyPrint = function(obj, level, indentation) {
1231 var rval = '';
1232
1233 // set default level and indentation
1234 level = level || 0;
1235 indentation = indentation || 2;
1236
1237 // start new line for deep levels
1238 if(level > 0) {
1239 rval += '\n';
1240 }
1241
1242 // create indent
1243 var indent = '';
1244 for(var i = 0; i < level * indentation; ++i) {
1245 indent += ' ';
1246 }
1247
1248 // print class:type
1249 rval += indent + 'Tag: ';
1250 switch(obj.tagClass) {
1251 case asn1.Class.UNIVERSAL:
1252 rval += 'Universal:';
1253 break;
1254 case asn1.Class.APPLICATION:
1255 rval += 'Application:';
1256 break;
1257 case asn1.Class.CONTEXT_SPECIFIC:
1258 rval += 'Context-Specific:';
1259 break;
1260 case asn1.Class.PRIVATE:
1261 rval += 'Private:';
1262 break;
1263 }
1264
1265 if(obj.tagClass === asn1.Class.UNIVERSAL) {
1266 rval += obj.type;
1267
1268 // known types
1269 switch(obj.type) {
1270 case asn1.Type.NONE:
1271 rval += ' (None)';
1272 break;
1273 case asn1.Type.BOOLEAN:
1274 rval += ' (Boolean)';
1275 break;
1276 case asn1.Type.INTEGER:
1277 rval += ' (Integer)';
1278 break;
1279 case asn1.Type.BITSTRING:
1280 rval += ' (Bit string)';
1281 break;
1282 case asn1.Type.OCTETSTRING:
1283 rval += ' (Octet string)';
1284 break;
1285 case asn1.Type.NULL:
1286 rval += ' (Null)';
1287 break;
1288 case asn1.Type.OID:
1289 rval += ' (Object Identifier)';
1290 break;
1291 case asn1.Type.ODESC:
1292 rval += ' (Object Descriptor)';
1293 break;
1294 case asn1.Type.EXTERNAL:
1295 rval += ' (External or Instance of)';
1296 break;
1297 case asn1.Type.REAL:
1298 rval += ' (Real)';
1299 break;
1300 case asn1.Type.ENUMERATED:
1301 rval += ' (Enumerated)';
1302 break;
1303 case asn1.Type.EMBEDDED:
1304 rval += ' (Embedded PDV)';
1305 break;
1306 case asn1.Type.UTF8:
1307 rval += ' (UTF8)';
1308 break;
1309 case asn1.Type.ROID:
1310 rval += ' (Relative Object Identifier)';
1311 break;
1312 case asn1.Type.SEQUENCE:
1313 rval += ' (Sequence)';
1314 break;
1315 case asn1.Type.SET:
1316 rval += ' (Set)';
1317 break;
1318 case asn1.Type.PRINTABLESTRING:
1319 rval += ' (Printable String)';
1320 break;
1321 case asn1.Type.IA5String:
1322 rval += ' (IA5String (ASCII))';
1323 break;
1324 case asn1.Type.UTCTIME:
1325 rval += ' (UTC time)';
1326 break;
1327 case asn1.Type.GENERALIZEDTIME:
1328 rval += ' (Generalized time)';
1329 break;
1330 case asn1.Type.BMPSTRING:
1331 rval += ' (BMP String)';
1332 break;
1333 }
1334 } else {
1335 rval += obj.type;
1336 }
1337
1338 rval += '\n';
1339 rval += indent + 'Constructed: ' + obj.constructed + '\n';
1340
1341 if(obj.composed) {
1342 var subvalues = 0;
1343 var sub = '';
1344 for(var i = 0; i < obj.value.length; ++i) {
1345 if(obj.value[i] !== undefined) {
1346 subvalues += 1;
1347 sub += asn1.prettyPrint(obj.value[i], level + 1, indentation);
1348 if((i + 1) < obj.value.length) {
1349 sub += ',';
1350 }
1351 }
1352 }
1353 rval += indent + 'Sub values: ' + subvalues + sub;
1354 } else {
1355 rval += indent + 'Value: ';
1356 if(obj.type === asn1.Type.OID) {
1357 var oid = asn1.derToOid(obj.value);
1358 rval += oid;
1359 if(forge.pki && forge.pki.oids) {
1360 if(oid in forge.pki.oids) {
1361 rval += ' (' + forge.pki.oids[oid] + ') ';
1362 }
1363 }
1364 }
1365 if(obj.type === asn1.Type.INTEGER) {
1366 try {
1367 rval += asn1.derToInteger(obj.value);
1368 } catch(ex) {
1369 rval += '0x' + forge.util.bytesToHex(obj.value);
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 }
1388 } else if(obj.type === asn1.Type.OCTETSTRING) {
1389 if(!_nonLatinRegex.test(obj.value)) {
1390 rval += '(' + obj.value + ') ';
1391 }
1392 rval += '0x' + forge.util.bytesToHex(obj.value);
1393 } else if(obj.type === asn1.Type.UTF8) {
1394 rval += forge.util.decodeUtf8(obj.value);
1395 } else if(obj.type === asn1.Type.PRINTABLESTRING ||
1396 obj.type === asn1.Type.IA5String) {
1397 rval += obj.value;
1398 } else if(_nonLatinRegex.test(obj.value)) {
1399 rval += '0x' + forge.util.bytesToHex(obj.value);
1400 } else if(obj.value.length === 0) {
1401 rval += '[null]';
1402 } else {
1403 rval += obj.value;
1404 }
1405 }
1406
1407 return rval;
1408};
Note: See TracBrowser for help on using the repository browser.