summaryrefslogtreecommitdiff
path: root/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/base/node.js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/node/polyfills/_crypto/crypto_browserify/asn1.js/base/node.js')
-rw-r--r--ext/node/polyfills/_crypto/crypto_browserify/asn1.js/base/node.js734
1 files changed, 734 insertions, 0 deletions
diff --git a/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/base/node.js b/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/base/node.js
new file mode 100644
index 000000000..027778155
--- /dev/null
+++ b/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/base/node.js
@@ -0,0 +1,734 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright 2017 Fedor Indutny. All rights reserved. MIT license.
+
+import { Reporter } from "internal:deno_node/polyfills/_crypto/crypto_browserify/asn1.js/base/reporter.js";
+import {
+ DecoderBuffer,
+ EncoderBuffer,
+} from "internal:deno_node/polyfills/_crypto/crypto_browserify/asn1.js/base/buffer.js";
+import { assert } from "internal:deno_node/polyfills/_util/asserts.ts";
+
+// Supported tags
+const tags = [
+ "seq",
+ "seqof",
+ "set",
+ "setof",
+ "objid",
+ "bool",
+ "gentime",
+ "utctime",
+ "null_",
+ "enum",
+ "int",
+ "objDesc",
+ "bitstr",
+ "bmpstr",
+ "charstr",
+ "genstr",
+ "graphstr",
+ "ia5str",
+ "iso646str",
+ "numstr",
+ "octstr",
+ "printstr",
+ "t61str",
+ "unistr",
+ "utf8str",
+ "videostr",
+];
+
+// Public methods list
+const methods = [
+ "key",
+ "obj",
+ "use",
+ "optional",
+ "explicit",
+ "implicit",
+ "def",
+ "choice",
+ "any",
+ "contains",
+].concat(tags);
+
+// Overrided methods list
+const overrided = [
+ "_peekTag",
+ "_decodeTag",
+ "_use",
+ "_decodeStr",
+ "_decodeObjid",
+ "_decodeTime",
+ "_decodeNull",
+ "_decodeInt",
+ "_decodeBool",
+ "_decodeList",
+
+ "_encodeComposite",
+ "_encodeStr",
+ "_encodeObjid",
+ "_encodeTime",
+ "_encodeNull",
+ "_encodeInt",
+ "_encodeBool",
+];
+
+export function Node(enc, parent, name) {
+ const state = {};
+ this._baseState = state;
+
+ state.name = name;
+ state.enc = enc;
+
+ state.parent = parent || null;
+ state.children = null;
+
+ // State
+ state.tag = null;
+ state.args = null;
+ state.reverseArgs = null;
+ state.choice = null;
+ state.optional = false;
+ state.any = false;
+ state.obj = false;
+ state.use = null;
+ state.useDecoder = null;
+ state.key = null;
+ state["default"] = null;
+ state.explicit = null;
+ state.implicit = null;
+ state.contains = null;
+
+ // Should create new instance on each method
+ if (!state.parent) {
+ state.children = [];
+ this._wrap();
+ }
+}
+
+const stateProps = [
+ "enc",
+ "parent",
+ "children",
+ "tag",
+ "args",
+ "reverseArgs",
+ "choice",
+ "optional",
+ "any",
+ "obj",
+ "use",
+ "alteredUse",
+ "key",
+ "default",
+ "explicit",
+ "implicit",
+ "contains",
+];
+
+Node.prototype.clone = function clone() {
+ const state = this._baseState;
+ const cstate = {};
+ stateProps.forEach(function (prop) {
+ cstate[prop] = state[prop];
+ });
+ const res = new this.constructor(cstate.parent);
+ res._baseState = cstate;
+ return res;
+};
+
+Node.prototype._wrap = function wrap() {
+ const state = this._baseState;
+ methods.forEach(function (method) {
+ this[method] = function _wrappedMethod() {
+ const clone = new this.constructor(this);
+ state.children.push(clone);
+ return clone[method].apply(clone, arguments);
+ };
+ }, this);
+};
+
+Node.prototype._init = function init(body) {
+ const state = this._baseState;
+
+ assert(state.parent === null);
+ body.call(this);
+
+ // Filter children
+ state.children = state.children.filter(function (child) {
+ return child._baseState.parent === this;
+ }, this);
+ assert(state.children.length === 1, "Root node can have only one child");
+};
+
+Node.prototype._useArgs = function useArgs(args) {
+ const state = this._baseState;
+
+ // Filter children and args
+ const children = args.filter(function (arg) {
+ return arg instanceof this.constructor;
+ }, this);
+ args = args.filter(function (arg) {
+ return !(arg instanceof this.constructor);
+ }, this);
+
+ if (children.length !== 0) {
+ assert(state.children === null);
+ state.children = children;
+
+ // Replace parent to maintain backward link
+ children.forEach(function (child) {
+ child._baseState.parent = this;
+ }, this);
+ }
+ if (args.length !== 0) {
+ assert(state.args === null);
+ state.args = args;
+ state.reverseArgs = args.map(function (arg) {
+ if (typeof arg !== "object" || arg.constructor !== Object) {
+ return arg;
+ }
+
+ const res = {};
+ Object.keys(arg).forEach(function (key) {
+ if (key == (key | 0)) {
+ key |= 0;
+ }
+ const value = arg[key];
+ res[value] = key;
+ });
+ return res;
+ });
+ }
+};
+
+//
+// Overrided methods
+//
+
+overrided.forEach(function (method) {
+ Node.prototype[method] = function _overrided() {
+ const state = this._baseState;
+ throw new Error(method + " not implemented for encoding: " + state.enc);
+ };
+});
+
+//
+// Public methods
+//
+
+tags.forEach(function (tag) {
+ Node.prototype[tag] = function _tagMethod() {
+ const state = this._baseState;
+ const args = Array.prototype.slice.call(arguments);
+
+ assert(state.tag === null);
+ state.tag = tag;
+
+ this._useArgs(args);
+
+ return this;
+ };
+});
+
+Node.prototype.use = function use(item) {
+ assert(item);
+ const state = this._baseState;
+
+ assert(state.use === null);
+ state.use = item;
+
+ return this;
+};
+
+Node.prototype.optional = function optional() {
+ const state = this._baseState;
+
+ state.optional = true;
+
+ return this;
+};
+
+Node.prototype.def = function def(val) {
+ const state = this._baseState;
+
+ assert(state["default"] === null);
+ state["default"] = val;
+ state.optional = true;
+
+ return this;
+};
+
+Node.prototype.explicit = function explicit(num) {
+ const state = this._baseState;
+
+ assert(state.explicit === null && state.implicit === null);
+ state.explicit = num;
+
+ return this;
+};
+
+Node.prototype.implicit = function implicit(num) {
+ const state = this._baseState;
+
+ assert(state.explicit === null && state.implicit === null);
+ state.implicit = num;
+
+ return this;
+};
+
+Node.prototype.obj = function obj() {
+ const state = this._baseState;
+ const args = Array.prototype.slice.call(arguments);
+
+ state.obj = true;
+
+ if (args.length !== 0) {
+ this._useArgs(args);
+ }
+
+ return this;
+};
+
+Node.prototype.key = function key(newKey) {
+ const state = this._baseState;
+
+ assert(state.key === null);
+ state.key = newKey;
+
+ return this;
+};
+
+Node.prototype.any = function any() {
+ const state = this._baseState;
+
+ state.any = true;
+
+ return this;
+};
+
+Node.prototype.choice = function choice(obj) {
+ const state = this._baseState;
+
+ assert(state.choice === null);
+ state.choice = obj;
+ this._useArgs(
+ Object.keys(obj).map(function (key) {
+ return obj[key];
+ }),
+ );
+
+ return this;
+};
+
+Node.prototype.contains = function contains(item) {
+ const state = this._baseState;
+
+ assert(state.use === null);
+ state.contains = item;
+
+ return this;
+};
+
+//
+// Decoding
+//
+
+Node.prototype._decode = function decode(input, options) {
+ const state = this._baseState;
+
+ // Decode root node
+ if (state.parent === null) {
+ return input.wrapResult(state.children[0]._decode(input, options));
+ }
+
+ let result = state["default"];
+ let present = true;
+
+ let prevKey = null;
+ if (state.key !== null) {
+ prevKey = input.enterKey(state.key);
+ }
+
+ // Check if tag is there
+ if (state.optional) {
+ let tag = null;
+ if (state.explicit !== null) {
+ tag = state.explicit;
+ } else if (state.implicit !== null) {
+ tag = state.implicit;
+ } else if (state.tag !== null) {
+ tag = state.tag;
+ }
+
+ if (tag === null && !state.any) {
+ // Trial and Error
+ const save = input.save();
+ try {
+ if (state.choice === null) {
+ this._decodeGeneric(state.tag, input, options);
+ } else {
+ this._decodeChoice(input, options);
+ }
+ present = true;
+ } catch (_e) {
+ present = false;
+ }
+ input.restore(save);
+ } else {
+ present = this._peekTag(input, tag, state.any);
+
+ if (input.isError(present)) {
+ return present;
+ }
+ }
+ }
+
+ // Push object on stack
+ let prevObj;
+ if (state.obj && present) {
+ prevObj = input.enterObject();
+ }
+
+ if (present) {
+ // Unwrap explicit values
+ if (state.explicit !== null) {
+ const explicit = this._decodeTag(input, state.explicit);
+ if (input.isError(explicit)) {
+ return explicit;
+ }
+ input = explicit;
+ }
+
+ const start = input.offset;
+
+ // Unwrap implicit and normal values
+ if (state.use === null && state.choice === null) {
+ let save;
+ if (state.any) {
+ save = input.save();
+ }
+ const body = this._decodeTag(
+ input,
+ state.implicit !== null ? state.implicit : state.tag,
+ state.any,
+ );
+ if (input.isError(body)) {
+ return body;
+ }
+
+ if (state.any) {
+ result = input.raw(save);
+ } else {
+ input = body;
+ }
+ }
+
+ if (options && options.track && state.tag !== null) {
+ options.track(input.path(), start, input.length, "tagged");
+ }
+
+ if (options && options.track && state.tag !== null) {
+ options.track(input.path(), input.offset, input.length, "content");
+ }
+
+ // Select proper method for tag
+ if (state.any) {
+ // no-op
+ } else if (state.choice === null) {
+ result = this._decodeGeneric(state.tag, input, options);
+ } else {
+ result = this._decodeChoice(input, options);
+ }
+
+ if (input.isError(result)) {
+ return result;
+ }
+
+ // Decode children
+ if (!state.any && state.choice === null && state.children !== null) {
+ state.children.forEach(function decodeChildren(child) {
+ // NOTE: We are ignoring errors here, to let parser continue with other
+ // parts of encoded data
+ child._decode(input, options);
+ });
+ }
+
+ // Decode contained/encoded by schema, only in bit or octet strings
+ if (state.contains && (state.tag === "octstr" || state.tag === "bitstr")) {
+ const data = new DecoderBuffer(result);
+ result = this._getUse(state.contains, input._reporterState.obj)
+ ._decode(data, options);
+ }
+ }
+
+ // Pop object
+ if (state.obj && present) {
+ result = input.leaveObject(prevObj);
+ }
+
+ // Set key
+ if (state.key !== null && (result !== null || present === true)) {
+ input.leaveKey(prevKey, state.key, result);
+ } else if (prevKey !== null) {
+ input.exitKey(prevKey);
+ }
+
+ return result;
+};
+
+Node.prototype._decodeGeneric = function decodeGeneric(tag, input, options) {
+ const state = this._baseState;
+
+ if (tag === "seq" || tag === "set") {
+ return null;
+ }
+ if (tag === "seqof" || tag === "setof") {
+ return this._decodeList(input, tag, state.args[0], options);
+ } else if (/str$/.test(tag)) {
+ return this._decodeStr(input, tag, options);
+ } else if (tag === "objid" && state.args) {
+ return this._decodeObjid(input, state.args[0], state.args[1], options);
+ } else if (tag === "objid") {
+ return this._decodeObjid(input, null, null, options);
+ } else if (tag === "gentime" || tag === "utctime") {
+ return this._decodeTime(input, tag, options);
+ } else if (tag === "null_") {
+ return this._decodeNull(input, options);
+ } else if (tag === "bool") {
+ return this._decodeBool(input, options);
+ } else if (tag === "objDesc") {
+ return this._decodeStr(input, tag, options);
+ } else if (tag === "int" || tag === "enum") {
+ return this._decodeInt(input, state.args && state.args[0], options);
+ }
+
+ if (state.use !== null) {
+ return this._getUse(state.use, input._reporterState.obj)
+ ._decode(input, options);
+ } else {
+ return input.error("unknown tag: " + tag);
+ }
+};
+
+Node.prototype._getUse = function _getUse(entity, obj) {
+ const state = this._baseState;
+ // Create altered use decoder if implicit is set
+ state.useDecoder = this._use(entity, obj);
+ assert(state.useDecoder._baseState.parent === null);
+ state.useDecoder = state.useDecoder._baseState.children[0];
+ if (state.implicit !== state.useDecoder._baseState.implicit) {
+ state.useDecoder = state.useDecoder.clone();
+ state.useDecoder._baseState.implicit = state.implicit;
+ }
+ return state.useDecoder;
+};
+
+Node.prototype._decodeChoice = function decodeChoice(input, options) {
+ const state = this._baseState;
+ let result = null;
+ let match = false;
+
+ Object.keys(state.choice).some(function (key) {
+ const save = input.save();
+ const node = state.choice[key];
+ try {
+ const value = node._decode(input, options);
+ if (input.isError(value)) {
+ return false;
+ }
+
+ result = { type: key, value: value };
+ match = true;
+ } catch (_e) {
+ input.restore(save);
+ return false;
+ }
+ return true;
+ }, this);
+
+ if (!match) {
+ return input.error("Choice not matched");
+ }
+
+ return result;
+};
+
+//
+// Encoding
+//
+
+Node.prototype._createEncoderBuffer = function createEncoderBuffer(data) {
+ return new EncoderBuffer(data, this.reporter);
+};
+
+Node.prototype._encode = function encode(data, reporter, parent) {
+ const state = this._baseState;
+ if (state["default"] !== null && state["default"] === data) {
+ return;
+ }
+
+ const result = this._encodeValue(data, reporter, parent);
+ if (result === undefined) {
+ return;
+ }
+
+ if (this._skipDefault(result, reporter, parent)) {
+ return;
+ }
+
+ return result;
+};
+
+Node.prototype._encodeValue = function encode(data, reporter, parent) {
+ const state = this._baseState;
+
+ // Decode root node
+ if (state.parent === null) {
+ return state.children[0]._encode(data, reporter || new Reporter());
+ }
+
+ let result = null;
+
+ // Set reporter to share it with a child class
+ this.reporter = reporter;
+
+ // Check if data is there
+ if (state.optional && data === undefined) {
+ if (state["default"] !== null) {
+ data = state["default"];
+ } else {
+ return;
+ }
+ }
+
+ // Encode children first
+ let content = null;
+ let primitive = false;
+ if (state.any) {
+ // Anything that was given is translated to buffer
+ result = this._createEncoderBuffer(data);
+ } else if (state.choice) {
+ result = this._encodeChoice(data, reporter);
+ } else if (state.contains) {
+ content = this._getUse(state.contains, parent)._encode(data, reporter);
+ primitive = true;
+ } else if (state.children) {
+ content = state.children.map(function (child) {
+ if (child._baseState.tag === "null_") {
+ return child._encode(null, reporter, data);
+ }
+
+ if (child._baseState.key === null) {
+ return reporter.error("Child should have a key");
+ }
+ const prevKey = reporter.enterKey(child._baseState.key);
+
+ if (typeof data !== "object") {
+ return reporter.error("Child expected, but input is not object");
+ }
+
+ const res = child._encode(data[child._baseState.key], reporter, data);
+ reporter.leaveKey(prevKey);
+
+ return res;
+ }, this).filter(function (child) {
+ return child;
+ });
+ content = this._createEncoderBuffer(content);
+ } else {
+ if (state.tag === "seqof" || state.tag === "setof") {
+ // TODO(indutny): this should be thrown on DSL level
+ if (!(state.args && state.args.length === 1)) {
+ return reporter.error("Too many args for : " + state.tag);
+ }
+
+ if (!Array.isArray(data)) {
+ return reporter.error("seqof/setof, but data is not Array");
+ }
+
+ const child = this.clone();
+ child._baseState.implicit = null;
+ content = this._createEncoderBuffer(data.map(function (item) {
+ const state = this._baseState;
+
+ return this._getUse(state.args[0], data)._encode(item, reporter);
+ }, child));
+ } else if (state.use !== null) {
+ result = this._getUse(state.use, parent)._encode(data, reporter);
+ } else {
+ content = this._encodePrimitive(state.tag, data);
+ primitive = true;
+ }
+ }
+
+ // Encode data itself
+ if (!state.any && state.choice === null) {
+ const tag = state.implicit !== null ? state.implicit : state.tag;
+ const cls = state.implicit === null ? "universal" : "context";
+
+ if (tag === null) {
+ if (state.use === null) {
+ reporter.error("Tag could be omitted only for .use()");
+ }
+ } else {
+ if (state.use === null) {
+ result = this._encodeComposite(tag, primitive, cls, content);
+ }
+ }
+ }
+
+ // Wrap in explicit
+ if (state.explicit !== null) {
+ result = this._encodeComposite(state.explicit, false, "context", result);
+ }
+
+ return result;
+};
+
+Node.prototype._encodeChoice = function encodeChoice(data, reporter) {
+ const state = this._baseState;
+
+ const node = state.choice[data.type];
+ if (!node) {
+ assert(
+ false,
+ data.type + " not found in " +
+ JSON.stringify(Object.keys(state.choice)),
+ );
+ }
+ return node._encode(data.value, reporter);
+};
+
+Node.prototype._encodePrimitive = function encodePrimitive(tag, data) {
+ const state = this._baseState;
+
+ if (/str$/.test(tag)) {
+ return this._encodeStr(data, tag);
+ } else if (tag === "objid" && state.args) {
+ return this._encodeObjid(data, state.reverseArgs[0], state.args[1]);
+ } else if (tag === "objid") {
+ return this._encodeObjid(data, null, null);
+ } else if (tag === "gentime" || tag === "utctime") {
+ return this._encodeTime(data, tag);
+ } else if (tag === "null_") {
+ return this._encodeNull();
+ } else if (tag === "int" || tag === "enum") {
+ return this._encodeInt(data, state.args && state.reverseArgs[0]);
+ } else if (tag === "bool") {
+ return this._encodeBool(data);
+ } else if (tag === "objDesc") {
+ return this._encodeStr(data, tag);
+ } else {
+ throw new Error("Unsupported tag: " + tag);
+ }
+};
+
+Node.prototype._isNumstr = function isNumstr(str) {
+ return /^[0-9 ]*$/.test(str);
+};
+
+Node.prototype._isPrintstr = function isPrintstr(str) {
+ return /^[A-Za-z0-9 '()+,-./:=?]*$/.test(str);
+};