summaryrefslogtreecommitdiff
path: root/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/decoders/der.js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/node/polyfills/_crypto/crypto_browserify/asn1.js/decoders/der.js')
-rw-r--r--ext/node/polyfills/_crypto/crypto_browserify/asn1.js/decoders/der.js386
1 files changed, 386 insertions, 0 deletions
diff --git a/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/decoders/der.js b/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/decoders/der.js
new file mode 100644
index 000000000..9ab811507
--- /dev/null
+++ b/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/decoders/der.js
@@ -0,0 +1,386 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright 2017 Fedor Indutny. All rights reserved. MIT license.
+
+import bignum from "internal:deno_node/polyfills/_crypto/crypto_browserify/bn.js/bn.js";
+import { DecoderBuffer } from "internal:deno_node/polyfills/_crypto/crypto_browserify/asn1.js/base/buffer.js";
+import { Node } from "internal:deno_node/polyfills/_crypto/crypto_browserify/asn1.js/base/node.js";
+import * as der from "internal:deno_node/polyfills/_crypto/crypto_browserify/asn1.js/constants/der.js";
+
+export function DERDecoder(entity) {
+ this.enc = "der";
+ this.name = entity.name;
+ this.entity = entity;
+
+ // Construct base tree
+ this.tree = new DERNode();
+ this.tree._init(entity.body);
+}
+
+DERDecoder.prototype.decode = function decode(data, options) {
+ if (!DecoderBuffer.isDecoderBuffer(data)) {
+ data = new DecoderBuffer(data, options);
+ }
+ return this.tree._decode(data, options);
+};
+
+// Tree methods
+
+function DERNode(parent) {
+ Node.call(this, "der", parent);
+}
+// inherits(DERNode, Node);
+DERNode.prototype = Object.create(Node.prototype, {
+ constructor: {
+ value: DERNode,
+ enumerable: false,
+ writable: true,
+ configurable: true,
+ },
+});
+
+DERNode.prototype._peekTag = function peekTag(buffer, tag, any) {
+ if (buffer.isEmpty()) {
+ return false;
+ }
+
+ const state = buffer.save();
+ const decodedTag = derDecodeTag(buffer, 'Failed to peek tag: "' + tag + '"');
+ if (buffer.isError(decodedTag)) {
+ return decodedTag;
+ }
+
+ buffer.restore(state);
+
+ return decodedTag.tag === tag || decodedTag.tagStr === tag ||
+ (decodedTag.tagStr + "of") === tag || any;
+};
+
+DERNode.prototype._decodeTag = function decodeTag(buffer, tag, any) {
+ const decodedTag = derDecodeTag(
+ buffer,
+ 'Failed to decode tag of "' + tag + '"',
+ );
+ if (buffer.isError(decodedTag)) {
+ return decodedTag;
+ }
+
+ let len = derDecodeLen(
+ buffer,
+ decodedTag.primitive,
+ 'Failed to get length of "' + tag + '"',
+ );
+
+ // Failure
+ if (buffer.isError(len)) {
+ return len;
+ }
+
+ if (
+ !any &&
+ decodedTag.tag !== tag &&
+ decodedTag.tagStr !== tag &&
+ decodedTag.tagStr + "of" !== tag
+ ) {
+ return buffer.error('Failed to match tag: "' + tag + '"');
+ }
+
+ if (decodedTag.primitive || len !== null) {
+ return buffer.skip(len, 'Failed to match body of: "' + tag + '"');
+ }
+
+ // Indefinite length... find END tag
+ const state = buffer.save();
+ const res = this._skipUntilEnd(
+ buffer,
+ 'Failed to skip indefinite length body: "' + this.tag + '"',
+ );
+ if (buffer.isError(res)) {
+ return res;
+ }
+
+ len = buffer.offset - state.offset;
+ buffer.restore(state);
+ return buffer.skip(len, 'Failed to match body of: "' + tag + '"');
+};
+
+DERNode.prototype._skipUntilEnd = function skipUntilEnd(buffer, fail) {
+ for (;;) {
+ const tag = derDecodeTag(buffer, fail);
+ if (buffer.isError(tag)) {
+ return tag;
+ }
+ const len = derDecodeLen(buffer, tag.primitive, fail);
+ if (buffer.isError(len)) {
+ return len;
+ }
+
+ let res;
+ if (tag.primitive || len !== null) {
+ res = buffer.skip(len);
+ } else {
+ res = this._skipUntilEnd(buffer, fail);
+ }
+
+ // Failure
+ if (buffer.isError(res)) {
+ return res;
+ }
+
+ if (tag.tagStr === "end") {
+ break;
+ }
+ }
+};
+
+DERNode.prototype._decodeList = function decodeList(
+ buffer,
+ _tag,
+ decoder,
+ options,
+) {
+ const result = [];
+ while (!buffer.isEmpty()) {
+ const possibleEnd = this._peekTag(buffer, "end");
+ if (buffer.isError(possibleEnd)) {
+ return possibleEnd;
+ }
+
+ const res = decoder.decode(buffer, "der", options);
+ if (buffer.isError(res) && possibleEnd) {
+ break;
+ }
+ result.push(res);
+ }
+ return result;
+};
+
+DERNode.prototype._decodeStr = function decodeStr(buffer, tag) {
+ if (tag === "bitstr") {
+ const unused = buffer.readUInt8();
+ if (buffer.isError(unused)) {
+ return unused;
+ }
+ return { unused: unused, data: buffer.raw() };
+ } else if (tag === "bmpstr") {
+ const raw = buffer.raw();
+ if (raw.length % 2 === 1) {
+ return buffer.error("Decoding of string type: bmpstr length mismatch");
+ }
+
+ let str = "";
+ for (let i = 0; i < raw.length / 2; i++) {
+ str += String.fromCharCode(raw.readUInt16BE(i * 2));
+ }
+ return str;
+ } else if (tag === "numstr") {
+ const numstr = buffer.raw().toString("ascii");
+ if (!this._isNumstr(numstr)) {
+ return buffer.error(
+ "Decoding of string type: " +
+ "numstr unsupported characters",
+ );
+ }
+ return numstr;
+ } else if (tag === "octstr") {
+ return buffer.raw();
+ } else if (tag === "objDesc") {
+ return buffer.raw();
+ } else if (tag === "printstr") {
+ const printstr = buffer.raw().toString("ascii");
+ if (!this._isPrintstr(printstr)) {
+ return buffer.error(
+ "Decoding of string type: " +
+ "printstr unsupported characters",
+ );
+ }
+ return printstr;
+ } else if (/str$/.test(tag)) {
+ return buffer.raw().toString();
+ } else {
+ return buffer.error("Decoding of string type: " + tag + " unsupported");
+ }
+};
+
+DERNode.prototype._decodeObjid = function decodeObjid(
+ buffer,
+ values,
+ relative,
+) {
+ let result;
+ const identifiers = [];
+ let ident = 0;
+ let subident = 0;
+ while (!buffer.isEmpty()) {
+ subident = buffer.readUInt8();
+ ident <<= 7;
+ ident |= subident & 0x7f;
+ if ((subident & 0x80) === 0) {
+ identifiers.push(ident);
+ ident = 0;
+ }
+ }
+ if (subident & 0x80) {
+ identifiers.push(ident);
+ }
+
+ const first = (identifiers[0] / 40) | 0;
+ const second = identifiers[0] % 40;
+
+ if (relative) {
+ result = identifiers;
+ } else {
+ result = [first, second].concat(identifiers.slice(1));
+ }
+
+ if (values) {
+ let tmp = values[result.join(" ")];
+ if (tmp === undefined) {
+ tmp = values[result.join(".")];
+ }
+ if (tmp !== undefined) {
+ result = tmp;
+ }
+ }
+
+ return result;
+};
+
+DERNode.prototype._decodeTime = function decodeTime(buffer, tag) {
+ const str = buffer.raw().toString();
+
+ let year;
+ let mon;
+ let day;
+ let hour;
+ let min;
+ let sec;
+ if (tag === "gentime") {
+ year = str.slice(0, 4) | 0;
+ mon = str.slice(4, 6) | 0;
+ day = str.slice(6, 8) | 0;
+ hour = str.slice(8, 10) | 0;
+ min = str.slice(10, 12) | 0;
+ sec = str.slice(12, 14) | 0;
+ } else if (tag === "utctime") {
+ year = str.slice(0, 2) | 0;
+ mon = str.slice(2, 4) | 0;
+ day = str.slice(4, 6) | 0;
+ hour = str.slice(6, 8) | 0;
+ min = str.slice(8, 10) | 0;
+ sec = str.slice(10, 12) | 0;
+ if (year < 70) {
+ year = 2000 + year;
+ } else {
+ year = 1900 + year;
+ }
+ } else {
+ return buffer.error("Decoding " + tag + " time is not supported yet");
+ }
+
+ return Date.UTC(year, mon - 1, day, hour, min, sec, 0);
+};
+
+DERNode.prototype._decodeNull = function decodeNull() {
+ return null;
+};
+
+DERNode.prototype._decodeBool = function decodeBool(buffer) {
+ const res = buffer.readUInt8();
+ if (buffer.isError(res)) {
+ return res;
+ } else {
+ return res !== 0;
+ }
+};
+
+DERNode.prototype._decodeInt = function decodeInt(buffer, values) {
+ // Bigint, return as it is (assume big endian)
+ const raw = buffer.raw();
+ let res = new bignum(raw);
+
+ if (values) {
+ res = values[res.toString(10)] || res;
+ }
+
+ return res;
+};
+
+DERNode.prototype._use = function use(entity, obj) {
+ if (typeof entity === "function") {
+ entity = entity(obj);
+ }
+ return entity._getDecoder("der").tree;
+};
+
+// Utility methods
+
+function derDecodeTag(buf, fail) {
+ let tag = buf.readUInt8(fail);
+ if (buf.isError(tag)) {
+ return tag;
+ }
+
+ const cls = der.tagClass[tag >> 6];
+ const primitive = (tag & 0x20) === 0;
+
+ // Multi-octet tag - load
+ if ((tag & 0x1f) === 0x1f) {
+ let oct = tag;
+ tag = 0;
+ while ((oct & 0x80) === 0x80) {
+ oct = buf.readUInt8(fail);
+ if (buf.isError(oct)) {
+ return oct;
+ }
+
+ tag <<= 7;
+ tag |= oct & 0x7f;
+ }
+ } else {
+ tag &= 0x1f;
+ }
+ const tagStr = der.tag[tag];
+
+ return {
+ cls: cls,
+ primitive: primitive,
+ tag: tag,
+ tagStr: tagStr,
+ };
+}
+
+function derDecodeLen(buf, primitive, fail) {
+ let len = buf.readUInt8(fail);
+ if (buf.isError(len)) {
+ return len;
+ }
+
+ // Indefinite form
+ if (!primitive && len === 0x80) {
+ return null;
+ }
+
+ // Definite form
+ if ((len & 0x80) === 0) {
+ // Short form
+ return len;
+ }
+
+ // Long form
+ const num = len & 0x7f;
+ if (num > 4) {
+ return buf.error("length octect is too long");
+ }
+
+ len = 0;
+ for (let i = 0; i < num; i++) {
+ len <<= 8;
+ const j = buf.readUInt8(fail);
+ if (buf.isError(j)) {
+ return j;
+ }
+ len |= j;
+ }
+
+ return len;
+}