react / wstein / node_modules / browserify / node_modules / crypto-browserify / node_modules / public-encrypt / node_modules / parse-asn1 / node_modules / asn1.js / lib / asn1 / base / node.js
80647 viewsvar Reporter = require('../base').Reporter;1var EncoderBuffer = require('../base').EncoderBuffer;2var assert = require('minimalistic-assert');34// Supported tags5var tags = [6'seq', 'seqof', 'set', 'setof', 'octstr', 'bitstr', 'objid', 'bool',7'gentime', 'utctime', 'null_', 'enum', 'int', 'ia5str'8];910// Public methods list11var methods = [12'key', 'obj', 'use', 'optional', 'explicit', 'implicit', 'def', 'choice',13'any'14].concat(tags);1516// Overrided methods list17var overrided = [18'_peekTag', '_decodeTag', '_use',19'_decodeStr', '_decodeObjid', '_decodeTime',20'_decodeNull', '_decodeInt', '_decodeBool', '_decodeList',2122'_encodeComposite', '_encodeStr', '_encodeObjid', '_encodeTime',23'_encodeNull', '_encodeInt', '_encodeBool'24];2526function Node(enc, parent) {27var state = {};28this._baseState = state;2930state.enc = enc;3132state.parent = parent || null;33state.children = null;3435// State36state.tag = null;37state.args = null;38state.reverseArgs = null;39state.choice = null;40state.optional = false;41state.any = false;42state.obj = false;43state.use = null;44state.useDecoder = null;45state.key = null;46state['default'] = null;47state.explicit = null;48state.implicit = null;4950// Should create new instance on each method51if (!state.parent) {52state.children = [];53this._wrap();54}55}56module.exports = Node;5758var stateProps = [59'enc', 'parent', 'children', 'tag', 'args', 'reverseArgs', 'choice',60'optional', 'any', 'obj', 'use', 'alteredUse', 'key', 'default', 'explicit',61'implicit'62];6364Node.prototype.clone = function clone() {65var state = this._baseState;66var cstate = {};67stateProps.forEach(function(prop) {68cstate[prop] = state[prop];69});70var res = new this.constructor(cstate.parent);71res._baseState = cstate;72return res;73};7475Node.prototype._wrap = function wrap() {76var state = this._baseState;77methods.forEach(function(method) {78this[method] = function _wrappedMethod() {79var clone = new this.constructor(this);80state.children.push(clone);81return clone[method].apply(clone, arguments);82};83}, this);84};8586Node.prototype._init = function init(body) {87var state = this._baseState;8889assert(state.parent === null);90body.call(this);9192// Filter children93state.children = state.children.filter(function(child) {94return child._baseState.parent === this;95}, this);96assert.equal(state.children.length, 1, 'Root node can have only one child');97};9899Node.prototype._useArgs = function useArgs(args) {100var state = this._baseState;101102// Filter children and args103var children = args.filter(function(arg) {104return arg instanceof this.constructor;105}, this);106args = args.filter(function(arg) {107return !(arg instanceof this.constructor);108}, this);109110if (children.length !== 0) {111assert(state.children === null);112state.children = children;113114// Replace parent to maintain backward link115children.forEach(function(child) {116child._baseState.parent = this;117}, this);118}119if (args.length !== 0) {120assert(state.args === null);121state.args = args;122state.reverseArgs = args.map(function(arg) {123if (typeof arg !== 'object' || arg.constructor !== Object)124return arg;125126var res = {};127Object.keys(arg).forEach(function(key) {128if (key == (key | 0))129key |= 0;130var value = arg[key];131res[value] = key;132});133return res;134});135}136};137138//139// Overrided methods140//141142overrided.forEach(function(method) {143Node.prototype[method] = function _overrided() {144var state = this._baseState;145throw new Error(method + ' not implemented for encoding: ' + state.enc);146};147});148149//150// Public methods151//152153tags.forEach(function(tag) {154Node.prototype[tag] = function _tagMethod() {155var state = this._baseState;156var args = Array.prototype.slice.call(arguments);157158assert(state.tag === null);159state.tag = tag;160161this._useArgs(args);162163return this;164};165});166167Node.prototype.use = function use(item) {168var state = this._baseState;169170assert(state.use === null);171state.use = item;172173return this;174};175176Node.prototype.optional = function optional() {177var state = this._baseState;178179state.optional = true;180181return this;182};183184Node.prototype.def = function def(val) {185var state = this._baseState;186187assert(state['default'] === null);188state['default'] = val;189state.optional = true;190191return this;192};193194Node.prototype.explicit = function explicit(num) {195var state = this._baseState;196197assert(state.explicit === null && state.implicit === null);198state.explicit = num;199200return this;201};202203Node.prototype.implicit = function implicit(num) {204var state = this._baseState;205206assert(state.explicit === null && state.implicit === null);207state.implicit = num;208209return this;210};211212Node.prototype.obj = function obj() {213var state = this._baseState;214var args = Array.prototype.slice.call(arguments);215216state.obj = true;217218if (args.length !== 0)219this._useArgs(args);220221return this;222};223224Node.prototype.key = function key(newKey) {225var state = this._baseState;226227assert(state.key === null);228state.key = newKey;229230return this;231};232233Node.prototype.any = function any() {234var state = this._baseState;235236state.any = true;237238return this;239};240241Node.prototype.choice = function choice(obj) {242var state = this._baseState;243244assert(state.choice === null);245state.choice = obj;246this._useArgs(Object.keys(obj).map(function(key) {247return obj[key];248}));249250return this;251};252253//254// Decoding255//256257Node.prototype._decode = function decode(input) {258var state = this._baseState;259260// Decode root node261if (state.parent === null)262return input.wrapResult(state.children[0]._decode(input));263264var result = state['default'];265var present = true;266267var prevKey;268if (state.key !== null)269prevKey = input.enterKey(state.key);270271// Check if tag is there272if (state.optional) {273present = this._peekTag(274input,275state.explicit !== null ? state.explicit :276state.implicit !== null ? state.implicit :277state.tag || 0,278state.any279);280if (input.isError(present))281return present;282}283284// Push object on stack285var prevObj;286if (state.obj && present)287prevObj = input.enterObject();288289if (present) {290// Unwrap explicit values291if (state.explicit !== null) {292var explicit = this._decodeTag(input, state.explicit);293if (input.isError(explicit))294return explicit;295input = explicit;296}297298// Unwrap implicit and normal values299if (state.use === null && state.choice === null) {300if (state.any)301var save = input.save();302var body = this._decodeTag(303input,304state.implicit !== null ? state.implicit : state.tag,305state.any306);307if (input.isError(body))308return body;309310if (state.any)311result = input.raw(save);312else313input = body;314}315316// Select proper method for tag317if (state.any)318result = result;319else if (state.choice === null)320result = this._decodeGeneric(state.tag, input);321else322result = this._decodeChoice(input);323324if (input.isError(result))325return result;326327// Decode children328if (!state.any && state.choice === null && state.children !== null) {329var fail = state.children.some(function decodeChildren(child) {330// NOTE: We are ignoring errors here, to let parser continue with other331// parts of encoded data332child._decode(input);333});334if (fail)335return err;336}337}338339// Pop object340if (state.obj && present)341result = input.leaveObject(prevObj);342343// Set key344if (state.key !== null && (result !== null || present === true))345input.leaveKey(prevKey, state.key, result);346347return result;348};349350Node.prototype._decodeGeneric = function decodeGeneric(tag, input) {351var state = this._baseState;352353if (tag === 'seq' || tag === 'set')354return null;355if (tag === 'seqof' || tag === 'setof')356return this._decodeList(input, tag, state.args[0]);357else if (tag === 'octstr' || tag === 'bitstr' || tag === 'ia5str')358return this._decodeStr(input, tag);359else if (tag === 'objid' && state.args)360return this._decodeObjid(input, state.args[0], state.args[1]);361else if (tag === 'objid')362return this._decodeObjid(input, null, null);363else if (tag === 'gentime' || tag === 'utctime')364return this._decodeTime(input, tag);365else if (tag === 'null_')366return this._decodeNull(input);367else if (tag === 'bool')368return this._decodeBool(input);369else if (tag === 'int' || tag === 'enum')370return this._decodeInt(input, state.args && state.args[0]);371else if (state.use !== null)372return this._getUse(state.use, input._reporterState.obj)._decode(input);373else374return input.error('unknown tag: ' + tag);375376return null;377};378379Node.prototype._getUse = function _getUse(entity, obj) {380381var state = this._baseState;382// Create altered use decoder if implicit is set383state.useDecoder = this._use(entity, obj);384assert(state.useDecoder._baseState.parent === null);385state.useDecoder = state.useDecoder._baseState.children[0];386if (state.implicit !== state.useDecoder._baseState.implicit) {387state.useDecoder = state.useDecoder.clone();388state.useDecoder._baseState.implicit = state.implicit;389}390return state.useDecoder;391};392393Node.prototype._decodeChoice = function decodeChoice(input) {394var state = this._baseState;395var result = null;396var match = false;397398Object.keys(state.choice).some(function(key) {399var save = input.save();400var node = state.choice[key];401try {402var value = node._decode(input);403if (input.isError(value))404return false;405406result = { type: key, value: value };407match = true;408} catch (e) {409input.restore(save);410return false;411}412return true;413}, this);414415if (!match)416return input.error('Choice not matched');417418return result;419};420421//422// Encoding423//424425Node.prototype._createEncoderBuffer = function createEncoderBuffer(data) {426return new EncoderBuffer(data, this.reporter);427};428429Node.prototype._encode = function encode(data, reporter, parent) {430var state = this._baseState;431if (state['default'] !== null && state['default'] === data)432return;433434var result = this._encodeValue(data, reporter, parent);435if (result === undefined)436return;437438if (this._skipDefault(result, reporter, parent))439return;440441return result;442};443444Node.prototype._encodeValue = function encode(data, reporter, parent) {445var state = this._baseState;446447// Decode root node448if (state.parent === null)449return state.children[0]._encode(data, reporter || new Reporter());450451var result = null;452var present = true;453454// Set reporter to share it with a child class455this.reporter = reporter;456457// Check if data is there458if (state.optional && data === undefined) {459if (state['default'] !== null)460data = state['default']461else462return;463}464465// For error reporting466var prevKey;467468// Encode children first469var content = null;470var primitive = false;471if (state.any) {472// Anything that was given is translated to buffer473result = this._createEncoderBuffer(data);474} else if (state.choice) {475result = this._encodeChoice(data, reporter);476} else if (state.children) {477content = state.children.map(function(child) {478if (child._baseState.tag === 'null_')479return child._encode(null, reporter, data);480481if (child._baseState.key === null)482return reporter.error('Child should have a key');483var prevKey = reporter.enterKey(child._baseState.key);484485if (typeof data !== 'object')486return reporter.error('Child expected, but input is not object');487488var res = child._encode(data[child._baseState.key], reporter, data);489reporter.leaveKey(prevKey);490491return res;492}, this).filter(function(child) {493return child;494});495496content = this._createEncoderBuffer(content);497} else {498if (state.tag === 'seqof' || state.tag === 'setof') {499// TODO(indutny): this should be thrown on DSL level500if (!(state.args && state.args.length === 1))501return reporter.error('Too many args for : ' + state.tag);502503if (!Array.isArray(data))504return reporter.error('seqof/setof, but data is not Array');505506var child = this.clone();507child._baseState.implicit = null;508content = this._createEncoderBuffer(data.map(function(item) {509var state = this._baseState;510511return this._getUse(state.args[0], data)._encode(item, reporter);512}, child));513} else if (state.use !== null) {514result = this._getUse(state.use, parent)._encode(data, reporter);515} else {516content = this._encodePrimitive(state.tag, data);517primitive = true;518}519}520521// Encode data itself522var result;523if (!state.any && state.choice === null) {524var tag = state.implicit !== null ? state.implicit : state.tag;525var cls = state.implicit === null ? 'universal' : 'context';526527if (tag === null) {528if (state.use === null)529reporter.error('Tag could be ommited only for .use()');530} else {531if (state.use === null)532result = this._encodeComposite(tag, primitive, cls, content);533}534}535536// Wrap in explicit537if (state.explicit !== null)538result = this._encodeComposite(state.explicit, false, 'context', result);539540return result;541};542543Node.prototype._encodeChoice = function encodeChoice(data, reporter) {544var state = this._baseState;545546var node = state.choice[data.type];547if (!node) {548assert(549false,550data.type + ' not found in ' +551JSON.stringify(Object.keys(state.choice)));552}553return node._encode(data.value, reporter);554};555556Node.prototype._encodePrimitive = function encodePrimitive(tag, data) {557var state = this._baseState;558559if (tag === 'octstr' || tag === 'bitstr' || tag === 'ia5str')560return this._encodeStr(data, tag);561else if (tag === 'objid' && state.args)562return this._encodeObjid(data, state.reverseArgs[0], state.args[1]);563else if (tag === 'objid')564return this._encodeObjid(data, null, null);565else if (tag === 'gentime' || tag === 'utctime')566return this._encodeTime(data, tag);567else if (tag === 'null_')568return this._encodeNull();569else if (tag === 'int' || tag === 'enum')570return this._encodeInt(data, state.args && state.reverseArgs[0]);571else if (tag === 'bool')572return this._encodeBool(data);573else574throw new Error('Unsupported tag: ' + tag);575};576577578