Bug 1608278 - Export DER as DERDecoder to avoid duplicate DER global in DER.jsm r=keeler

We need to stop relying on the global `this` in order to support ES Modules.
In this case we have `this.DER` (which is exported) and `class DER` in the
same module.

Because of this, changing `this.DER` to `const DER` would lead to an error.
So this change renames the class to avoid the conflict.

Differential Revision: https://phabricator.services.mozilla.com/D60078

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Brian Grinstead 2020-01-16 18:20:41 +00:00
Родитель 238012c70a
Коммит d8480acf44
3 изменённых файлов: 68 добавлений и 46 удалений

Просмотреть файл

@ -10,8 +10,8 @@
// Intended to be used like so: // Intended to be used like so:
// //
// let bytes = <an array of bytes describing a SEQUENCE OF INTEGER>; // let bytes = <an array of bytes describing a SEQUENCE OF INTEGER>;
// let der = new DER.DER(bytes); // let der = new DER.DERDecoder(bytes);
// let contents = new DER.DER(der.readTagAndGetContents(DER.SEQUENCE)); // let contents = new DER.DERDecoder(der.readTagAndGetContents(DER.SEQUENCE));
// while (!contents.atEnd()) { // while (!contents.atEnd()) {
// let integerBytes = contents.readTagAndGetContents(DER.INTEGER); // let integerBytes = contents.readTagAndGetContents(DER.INTEGER);
// <... do something with integerBytes ...> // <... do something with integerBytes ...>
@ -83,7 +83,7 @@ class BitString {
} }
/** Class representing DER-encoded data. Provides methods for decoding it. */ /** Class representing DER-encoded data. Provides methods for decoding it. */
class DER { class DERDecoder {
/** /**
* @param {Number[]} bytes an array of bytes representing the encoded data * @param {Number[]} bytes an array of bytes representing the encoded data
*/ */
@ -299,7 +299,7 @@ class DER {
} }
} }
this.DER = { const DER = {
UNIVERSAL, UNIVERSAL,
CONSTRUCTED, CONSTRUCTED,
CONTEXT_SPECIFIC, CONTEXT_SPECIFIC,
@ -315,6 +315,6 @@ this.DER = {
UTF8String, UTF8String,
SEQUENCE, SEQUENCE,
SET, SET,
DER, DERDecoder,
}; };
this.EXPORTED_SYMBOLS = ["DER"]; var EXPORTED_SYMBOLS = ["DER"];

Просмотреть файл

@ -4,7 +4,7 @@
"use strict"; "use strict";
var { DER } = ChromeUtils.import("resource://gre/modules/psm/DER.jsm", null); var { DER } = ChromeUtils.import("resource://gre/modules/psm/DER.jsm");
const ERROR_UNSUPPORTED_ASN1 = "unsupported asn.1"; const ERROR_UNSUPPORTED_ASN1 = "unsupported asn.1";
const ERROR_TIME_NOT_VALID = "Time not valid"; const ERROR_TIME_NOT_VALID = "Time not valid";
@ -118,7 +118,7 @@ class DecodedDER {
* @param {Number[]} bytes encoded DER to be decoded * @param {Number[]} bytes encoded DER to be decoded
*/ */
parse(bytes) { parse(bytes) {
this._der = new DER.DER(bytes); this._der = new DER.DERDecoder(bytes);
try { try {
this.parseOverride(); this.parseOverride();
} catch (e) { } catch (e) {
@ -134,7 +134,7 @@ class DecodedDER {
* @return {DER} the contents of the SEQUENCE * @return {DER} the contents of the SEQUENCE
*/ */
function readSEQUENCEAndMakeDER(der) { function readSEQUENCEAndMakeDER(der) {
return new DER.DER(der.readTagAndGetContents(DER.SEQUENCE)); return new DER.DERDecoder(der.readTagAndGetContents(DER.SEQUENCE));
} }
/** /**
@ -145,7 +145,7 @@ function readSEQUENCEAndMakeDER(der) {
* @return {DER} the contents of the tag * @return {DER} the contents of the tag
*/ */
function readTagAndMakeDER(der, tag) { function readTagAndMakeDER(der, tag) {
return new DER.DER(der.readTagAndGetContents(tag)); return new DER.DERDecoder(der.readTagAndGetContents(tag));
} }
// Certificate ::= SEQUENCE { // Certificate ::= SEQUENCE {

Просмотреть файл

@ -7,41 +7,41 @@
// Until DER.jsm is actually used in production code, this is where we have to // Until DER.jsm is actually used in production code, this is where we have to
// import it from. // import it from.
var { DER } = ChromeUtils.import("resource://gre/modules/psm/DER.jsm", null); var { DER } = ChromeUtils.import("resource://gre/modules/psm/DER.jsm");
function run_simple_tests() { function run_simple_tests() {
throws( throws(
() => new DER.DER("this is not an array"), () => new DER.DERDecoder("this is not an array"),
/invalid input/, /invalid input/,
"should throw given non-array input" "should throw given non-array input"
); );
throws( throws(
() => new DER.DER([0, "invalid input", 1]), () => new DER.DERDecoder([0, "invalid input", 1]),
/invalid input/, /invalid input/,
"should throw given non-byte data (string case)" "should throw given non-byte data (string case)"
); );
throws( throws(
() => new DER.DER([31, 1, {}]), () => new DER.DERDecoder([31, 1, {}]),
/invalid input/, /invalid input/,
"should throw given non-byte data (object case)" "should throw given non-byte data (object case)"
); );
throws( throws(
() => new DER.DER([0.1, 3, 1]), () => new DER.DERDecoder([0.1, 3, 1]),
/invalid input/, /invalid input/,
"should throw given non-byte data (non-integer case)" "should throw given non-byte data (non-integer case)"
); );
throws( throws(
() => new DER.DER([1, 3, -1]), () => new DER.DERDecoder([1, 3, -1]),
/invalid input/, /invalid input/,
"should throw given non-byte data (negative integer case)" "should throw given non-byte data (negative integer case)"
); );
throws( throws(
() => new DER.DER([1, 300, 79]), () => new DER.DERDecoder([1, 300, 79]),
/invalid input/, /invalid input/,
"should throw given non-byte data (large integer case)" "should throw given non-byte data (large integer case)"
); );
let testReadByte = new DER.DER([0x0a, 0x0b]); let testReadByte = new DER.DERDecoder([0x0a, 0x0b]);
equal(testReadByte.readByte(), 0x0a, "should read 0x0a"); equal(testReadByte.readByte(), 0x0a, "should read 0x0a");
equal(testReadByte.readByte(), 0x0b, "should read 0x0b"); equal(testReadByte.readByte(), 0x0b, "should read 0x0b");
throws( throws(
@ -50,35 +50,35 @@ function run_simple_tests() {
"reading more data than is available should fail" "reading more data than is available should fail"
); );
let testReadBytes = new DER.DER([0x0c, 0x0d, 0x0e]); let testReadBytes = new DER.DERDecoder([0x0c, 0x0d, 0x0e]);
deepEqual( deepEqual(
testReadBytes.readBytes(3), testReadBytes.readBytes(3),
[0x0c, 0x0d, 0x0e], [0x0c, 0x0d, 0x0e],
"should read correct sequence of bytes" "should read correct sequence of bytes"
); );
let testReadNegativeBytes = new DER.DER([0xff, 0xaf]); let testReadNegativeBytes = new DER.DERDecoder([0xff, 0xaf]);
throws( throws(
() => testReadNegativeBytes.readBytes(-4), () => testReadNegativeBytes.readBytes(-4),
/invalid length/, /invalid length/,
"reading a negative number of bytes should fail" "reading a negative number of bytes should fail"
); );
let testReadZeroBytes = new DER.DER([]); let testReadZeroBytes = new DER.DERDecoder([]);
equal( equal(
testReadZeroBytes.readBytes(0).length, testReadZeroBytes.readBytes(0).length,
0, 0,
"reading zero bytes should result in a zero-length array" "reading zero bytes should result in a zero-length array"
); );
let testReadTooManyBytes = new DER.DER([0xab, 0xcd, 0xef]); let testReadTooManyBytes = new DER.DERDecoder([0xab, 0xcd, 0xef]);
throws( throws(
() => testReadTooManyBytes.readBytes(4), () => testReadTooManyBytes.readBytes(4),
/data truncated/, /data truncated/,
"reading too many bytes should fail" "reading too many bytes should fail"
); );
let testSEQUENCE = new DER.DER([0x30, 0x01, 0x01]); let testSEQUENCE = new DER.DERDecoder([0x30, 0x01, 0x01]);
let content = testSEQUENCE.readTagAndGetContents(DER.SEQUENCE); let content = testSEQUENCE.readTagAndGetContents(DER.SEQUENCE);
equal(content.length, 1, "content should have length 1"); equal(content.length, 1, "content should have length 1");
equal(content[0], 1, "value of content should be [1]"); equal(content[0], 1, "value of content should be [1]");
@ -86,7 +86,7 @@ function run_simple_tests() {
testSEQUENCE.assertAtEnd(); testSEQUENCE.assertAtEnd();
// The length purports to be 4 bytes, but there are only 2 available. // The length purports to be 4 bytes, but there are only 2 available.
let truncatedSEQUENCE = new DER.DER([0x30, 0x04, 0x00, 0x00]); let truncatedSEQUENCE = new DER.DERDecoder([0x30, 0x04, 0x00, 0x00]);
throws( throws(
() => truncatedSEQUENCE.readTagAndGetContents(DER.SEQUENCE), () => truncatedSEQUENCE.readTagAndGetContents(DER.SEQUENCE),
/data truncated/, /data truncated/,
@ -94,7 +94,7 @@ function run_simple_tests() {
); );
// With 2 bytes of content, there is 1 remaining after reading the content. // With 2 bytes of content, there is 1 remaining after reading the content.
let extraDataSEQUENCE = new DER.DER([0x30, 0x02, 0xab, 0xcd, 0xef]); let extraDataSEQUENCE = new DER.DERDecoder([0x30, 0x02, 0xab, 0xcd, 0xef]);
content = extraDataSEQUENCE.readTagAndGetContents(DER.SEQUENCE); content = extraDataSEQUENCE.readTagAndGetContents(DER.SEQUENCE);
equal(content.length, 2, "content should have length 2"); equal(content.length, 2, "content should have length 2");
deepEqual(content, [0xab, 0xcd], "value of content should be [0xab, 0xcd]"); deepEqual(content, [0xab, 0xcd], "value of content should be [0xab, 0xcd]");
@ -110,7 +110,7 @@ function run_simple_tests() {
// The length of 0x81 0x01 is invalid because it could be encoded as just // The length of 0x81 0x01 is invalid because it could be encoded as just
// 0x01, which is shorter. // 0x01, which is shorter.
let invalidLengthSEQUENCE1 = new DER.DER([0x30, 0x81, 0x01, 0x00]); let invalidLengthSEQUENCE1 = new DER.DERDecoder([0x30, 0x81, 0x01, 0x00]);
throws( throws(
() => invalidLengthSEQUENCE1.readTagAndGetContents(DER.SEQUENCE), () => invalidLengthSEQUENCE1.readTagAndGetContents(DER.SEQUENCE),
/invalid length/, /invalid length/,
@ -118,7 +118,13 @@ function run_simple_tests() {
); );
// Similarly, 0x82 0x00 0x01 could be encoded as just 0x01, which is shorter. // Similarly, 0x82 0x00 0x01 could be encoded as just 0x01, which is shorter.
let invalidLengthSEQUENCE2 = new DER.DER([0x30, 0x82, 0x00, 0x01, 0x00]); let invalidLengthSEQUENCE2 = new DER.DERDecoder([
0x30,
0x82,
0x00,
0x01,
0x00,
]);
throws( throws(
() => invalidLengthSEQUENCE2.readTagAndGetContents(DER.SEQUENCE), () => invalidLengthSEQUENCE2.readTagAndGetContents(DER.SEQUENCE),
/invalid length/, /invalid length/,
@ -126,7 +132,13 @@ function run_simple_tests() {
); );
// Lengths requiring 4 bytes to encode are not supported. // Lengths requiring 4 bytes to encode are not supported.
let unsupportedLengthSEQUENCE = new DER.DER([0x30, 0x83, 0x01, 0x01, 0x01]); let unsupportedLengthSEQUENCE = new DER.DERDecoder([
0x30,
0x83,
0x01,
0x01,
0x01,
]);
throws( throws(
() => unsupportedLengthSEQUENCE.readTagAndGetContents(DER.SEQUENCE), () => unsupportedLengthSEQUENCE.readTagAndGetContents(DER.SEQUENCE),
/unsupported length/, /unsupported length/,
@ -134,21 +146,27 @@ function run_simple_tests() {
); );
// Indefinite lengths are not supported (and aren't DER anyway). // Indefinite lengths are not supported (and aren't DER anyway).
let unsupportedASN1SEQUENCE = new DER.DER([0x30, 0x80, 0x01, 0x00, 0x00]); let unsupportedASN1SEQUENCE = new DER.DERDecoder([
0x30,
0x80,
0x01,
0x00,
0x00,
]);
throws( throws(
() => unsupportedASN1SEQUENCE.readTagAndGetContents(DER.SEQUENCE), () => unsupportedASN1SEQUENCE.readTagAndGetContents(DER.SEQUENCE),
/unsupported asn.1/, /unsupported asn.1/,
"should get 'unsupported asn.1' error" "should get 'unsupported asn.1' error"
); );
let unexpectedTag = new DER.DER([0x31, 0x01, 0x00]); let unexpectedTag = new DER.DERDecoder([0x31, 0x01, 0x00]);
throws( throws(
() => unexpectedTag.readTagAndGetContents(DER.SEQUENCE), () => unexpectedTag.readTagAndGetContents(DER.SEQUENCE),
/unexpected tag/, /unexpected tag/,
"should get 'unexpected tag' error" "should get 'unexpected tag' error"
); );
let readTLVTestcase = new DER.DER([0x02, 0x03, 0x45, 0x67, 0x89]); let readTLVTestcase = new DER.DERDecoder([0x02, 0x03, 0x45, 0x67, 0x89]);
let bytes = readTLVTestcase.readTLV(); let bytes = readTLVTestcase.readTLV();
deepEqual( deepEqual(
bytes, bytes,
@ -156,7 +174,7 @@ function run_simple_tests() {
"bytes read with readTLV should be equal to expected value" "bytes read with readTLV should be equal to expected value"
); );
let peekTagTestcase = new DER.DER([0x30, 0x01, 0x00]); let peekTagTestcase = new DER.DERDecoder([0x30, 0x01, 0x00]);
ok( ok(
peekTagTestcase.peekTag(DER.SEQUENCE), peekTagTestcase.peekTag(DER.SEQUENCE),
"peekTag should return true for peeking with a SEQUENCE at a SEQUENCE" "peekTag should return true for peeking with a SEQUENCE at a SEQUENCE"
@ -171,7 +189,7 @@ function run_simple_tests() {
"peekTag should return false for peeking at a DER with no more data" "peekTag should return false for peeking at a DER with no more data"
); );
let tlvChoiceTestcase = new DER.DER([0x31, 0x02, 0xaa, 0xbb]); let tlvChoiceTestcase = new DER.DERDecoder([0x31, 0x02, 0xaa, 0xbb]);
let tlvChoiceContents = tlvChoiceTestcase.readTLVChoice([DER.NULL, DER.SET]); let tlvChoiceContents = tlvChoiceTestcase.readTLVChoice([DER.NULL, DER.SET]);
deepEqual( deepEqual(
tlvChoiceContents, tlvChoiceContents,
@ -179,7 +197,7 @@ function run_simple_tests() {
"readTLVChoice should return expected bytes" "readTLVChoice should return expected bytes"
); );
let tlvChoiceNoMatchTestcase = new DER.DER([0x30, 0x01, 0xff]); let tlvChoiceNoMatchTestcase = new DER.DERDecoder([0x30, 0x01, 0xff]);
throws( throws(
() => tlvChoiceNoMatchTestcase.readTLVChoice([DER.NULL, DER.SET]), () => tlvChoiceNoMatchTestcase.readTLVChoice([DER.NULL, DER.SET]),
/unexpected tag/, /unexpected tag/,
@ -188,7 +206,7 @@ function run_simple_tests() {
} }
function run_bit_string_tests() { function run_bit_string_tests() {
let bitstringDER = new DER.DER([0x03, 0x04, 0x03, 0x01, 0x02, 0xf8]); let bitstringDER = new DER.DERDecoder([0x03, 0x04, 0x03, 0x01, 0x02, 0xf8]);
let bitstring = bitstringDER.readBIT_STRING(); let bitstring = bitstringDER.readBIT_STRING();
equal(bitstring.unusedBits, 3, "BIT STRING should have 3 unused bits"); equal(bitstring.unusedBits, 3, "BIT STRING should have 3 unused bits");
deepEqual( deepEqual(
@ -197,7 +215,7 @@ function run_bit_string_tests() {
"BIT STRING should have expected contents" "BIT STRING should have expected contents"
); );
let bitstringTooManyUnusedBits = new DER.DER([0x03, 0x02, 0x08, 0x00]); let bitstringTooManyUnusedBits = new DER.DERDecoder([0x03, 0x02, 0x08, 0x00]);
throws( throws(
() => bitstringTooManyUnusedBits.readBIT_STRING(), () => bitstringTooManyUnusedBits.readBIT_STRING(),
/invalid BIT STRING encoding/, /invalid BIT STRING encoding/,
@ -206,7 +224,7 @@ function run_bit_string_tests() {
// A BIT STRING must have the unused bits byte, and so its length must be at // A BIT STRING must have the unused bits byte, and so its length must be at
// least one. // least one.
let bitstringMissingUnusedBits = new DER.DER([0x03, 0x00]); let bitstringMissingUnusedBits = new DER.DERDecoder([0x03, 0x00]);
throws( throws(
() => bitstringMissingUnusedBits.readBIT_STRING(), () => bitstringMissingUnusedBits.readBIT_STRING(),
/invalid BIT STRING encoding/, /invalid BIT STRING encoding/,
@ -215,7 +233,7 @@ function run_bit_string_tests() {
// The minimal BIT STRING is 03 01 00 (zero bits of padding and zero bytes of // The minimal BIT STRING is 03 01 00 (zero bits of padding and zero bytes of
// content). // content).
let minimalBitstringDER = new DER.DER([0x03, 0x01, 0x00]); let minimalBitstringDER = new DER.DERDecoder([0x03, 0x01, 0x00]);
let minimalBitstring = minimalBitstringDER.readBIT_STRING(); let minimalBitstring = minimalBitstringDER.readBIT_STRING();
equal( equal(
minimalBitstring.unusedBits, minimalBitstring.unusedBits,
@ -230,7 +248,7 @@ function run_bit_string_tests() {
// However, a BIT STRING with zero bytes of content can't have any padding, // However, a BIT STRING with zero bytes of content can't have any padding,
// because that makes no sense. // because that makes no sense.
let noContentsPaddedBitstringDER = new DER.DER([0x03, 0x01, 0x03]); let noContentsPaddedBitstringDER = new DER.DERDecoder([0x03, 0x01, 0x03]);
throws( throws(
() => noContentsPaddedBitstringDER.readBIT_STRING(), () => noContentsPaddedBitstringDER.readBIT_STRING(),
/invalid BIT STRING encoding/, /invalid BIT STRING encoding/,
@ -269,8 +287,8 @@ function run_compound_tests() {
0x05, 0x05,
0x00, 0x00,
]; // NULL ]; // NULL
let der = new DER.DER(derBytes); let der = new DER.DERDecoder(derBytes);
let contents = new DER.DER(der.readTagAndGetContents(DER.SEQUENCE)); let contents = new DER.DERDecoder(der.readTagAndGetContents(DER.SEQUENCE));
let firstINTEGER = contents.readTagAndGetContents(DER.INTEGER); let firstINTEGER = contents.readTagAndGetContents(DER.INTEGER);
deepEqual( deepEqual(
firstINTEGER, firstINTEGER,
@ -284,7 +302,9 @@ function run_compound_tests() {
"OBJECT IDENTIFIER should have expected value" "OBJECT IDENTIFIER should have expected value"
); );
let firstNested = new DER.DER(contents.readTagAndGetContents(DER.SEQUENCE)); let firstNested = new DER.DERDecoder(
contents.readTagAndGetContents(DER.SEQUENCE)
);
let firstNestedNULL = firstNested.readTagAndGetContents(DER.NULL); let firstNestedNULL = firstNested.readTagAndGetContents(DER.NULL);
equal( equal(
firstNestedNULL.length, firstNestedNULL.length,
@ -299,7 +319,9 @@ function run_compound_tests() {
); );
firstNested.assertAtEnd(); firstNested.assertAtEnd();
let secondNested = new DER.DER(contents.readTagAndGetContents(DER.SEQUENCE)); let secondNested = new DER.DERDecoder(
contents.readTagAndGetContents(DER.SEQUENCE)
);
let secondNestedINTEGER = secondNested.readTagAndGetContents(DER.INTEGER); let secondNestedINTEGER = secondNested.readTagAndGetContents(DER.INTEGER);
deepEqual( deepEqual(
secondNestedINTEGER, secondNestedINTEGER,
@ -329,11 +351,11 @@ function run_compound_tests() {
0x00, 0x00,
0x00, 0x00,
]; // (extra data) ]; // (extra data)
let invalidDER = new DER.DER(invalidDERBytes); let invalidDER = new DER.DERDecoder(invalidDERBytes);
let invalidContents = new DER.DER( let invalidContents = new DER.DERDecoder(
invalidDER.readTagAndGetContents(DER.SEQUENCE) invalidDER.readTagAndGetContents(DER.SEQUENCE)
); );
let invalidContentsContents = new DER.DER( let invalidContentsContents = new DER.DERDecoder(
invalidContents.readTagAndGetContents(DER.SEQUENCE) invalidContents.readTagAndGetContents(DER.SEQUENCE)
); );
throws( throws(