[Pkg-javascript-commits] [node-asn1.js] 01/202: initial
Bastien Roucariès
rouca at moszumanska.debian.org
Thu Apr 20 19:18:48 UTC 2017
This is an automated email from the git hooks/post-receive script.
rouca pushed a commit to branch master
in repository node-asn1.js.
commit eb0009c45912dbe17e35b98b5e7fbe4d50160f03
Author: Fedor Indutny <fedor.indutny at gmail.com>
Date: Sun Dec 1 16:48:53 2013 +0400
initial
---
.gitignore | 2 +
lib/asn1.js | 7 +
lib/asn1/api.js | 43 ++++++
lib/asn1/base/buffer.js | 41 ++++++
lib/asn1/base/index.js | 4 +
lib/asn1/base/node.js | 331 +++++++++++++++++++++++++++++++++++++++++++++
lib/asn1/decoders/der.js | 230 +++++++++++++++++++++++++++++++
lib/asn1/decoders/index.js | 3 +
lib/asn1/encoders/index.js | 0
lib/modules/index.js | 2 +
lib/modules/rfc2560.js | 106 +++++++++++++++
lib/modules/rfc3280.js | 148 ++++++++++++++++++++
package.json | 26 ++++
test/basic-test.js | 35 +++++
14 files changed, 978 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1ca9571
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+node_modules/
+npm-debug.log
diff --git a/lib/asn1.js b/lib/asn1.js
new file mode 100644
index 0000000..d4a1ce5
--- /dev/null
+++ b/lib/asn1.js
@@ -0,0 +1,7 @@
+var asn1 = exports;
+
+asn1.define = require('./asn1/api').define;
+asn1.base = require('./asn1/base');
+asn1.decoders = require('./asn1/decoders');
+asn1.encoders = require('./asn1/encoders');
+asn1.modules = require('./modules');
diff --git a/lib/asn1/api.js b/lib/asn1/api.js
new file mode 100644
index 0000000..f154ff3
--- /dev/null
+++ b/lib/asn1/api.js
@@ -0,0 +1,43 @@
+var asn1 = require('../asn1');
+var util = require('util');
+var vm = require('vm');
+
+var api = exports;
+
+api.define = function define(name, body) {
+ return new Entity(name, body);
+};
+
+function Entity(name, body) {
+ this.name = name;
+ this.body = body;
+
+ this.decoders = {};
+ this.encoders = {};
+};
+
+Entity.prototype._createNamed = function createNamed(base) {
+ var named = vm.runInThisContext('(function ' + this.name + '(entity) {\n' +
+ ' this._initNamed(entity);\n' +
+ '})');
+ util.inherits(named, base);
+ named.prototype._initNamed = function initnamed(entity) {
+ base.call(this, entity);
+ };
+
+ return new named(this);
+};
+
+Entity.prototype.decode = function decode(data, enc) {
+ // Lazily create decoder
+ if (!this.decoders.hasOwnProperty(enc))
+ this.decoders[enc] = this._createNamed(asn1.decoders[enc]);
+ return this.decoders[enc].decode(data);
+};
+
+Entity.prototype.encode = function encode(data, enc) {
+ // Lazily create encoder
+ if (!this.encoders.hasOwnProperty(enc))
+ this.encoders[enc] = this._createNamed(asn1.encoders[enc]);
+ return this.encoders[enc].encode(data);
+};
diff --git a/lib/asn1/base/buffer.js b/lib/asn1/base/buffer.js
new file mode 100644
index 0000000..2c484e2
--- /dev/null
+++ b/lib/asn1/base/buffer.js
@@ -0,0 +1,41 @@
+var assert = require('assert');
+var Buffer = require('buffer').Buffer;
+
+function DecoderBuffer(base) {
+ assert(Buffer.isBuffer(base));
+
+ this.base = base;
+ this.offset = 0;
+ this.length = base.length;
+}
+module.exports = DecoderBuffer;
+
+DecoderBuffer.prototype.save = function save() {
+ return { offset: this.offset };
+};
+
+DecoderBuffer.prototype.restore = function restore(save) {
+ this.offset = save.offset;
+};
+
+DecoderBuffer.prototype.isEmpty = function isEmpty() {
+ return this.offset === this.length;
+};
+
+DecoderBuffer.prototype.readUInt8 = function readUInt8() {
+ assert(this.offset + 1 <= this.length);
+ return this.base.readUInt8(this.offset++, true);
+}
+
+DecoderBuffer.prototype.skip = function skip(bytes) {
+ assert(this.offset + bytes <= this.length);
+ var res = new DecoderBuffer(this.base);
+ res.offset = this.offset;
+ res.length = this.offset + bytes;
+ this.offset += bytes;
+ return res;
+}
+
+DecoderBuffer.prototype.raw = function raw() {
+ return this.base.slice(this.offset, this.length);
+}
diff --git a/lib/asn1/base/index.js b/lib/asn1/base/index.js
new file mode 100644
index 0000000..9a71ab1
--- /dev/null
+++ b/lib/asn1/base/index.js
@@ -0,0 +1,4 @@
+var base = exports;
+
+base.DecoderBuffer = require('./buffer');
+base.Node = require('./node');
diff --git a/lib/asn1/base/node.js b/lib/asn1/base/node.js
new file mode 100644
index 0000000..da081f6
--- /dev/null
+++ b/lib/asn1/base/node.js
@@ -0,0 +1,331 @@
+var assert = require('assert');
+
+// Supported tags
+var tags = [
+ 'seq', 'seqof', 'octstr', 'bitstr', 'objid',
+ 'gentime', 'utctime', 'null_', 'enum', 'int'
+];
+
+// Public methods list
+var methods = [
+ 'key', 'obj', 'use', 'optional', 'explicit', 'implicit', 'def', 'choice'
+].concat(tags);
+
+// Overrided methods list
+var overrided = [
+ '_peekTag', '_execTag', '_execUse',
+ '_execStr', '_execObjid', '_execTime', '_execNull', '_execInt', '_execBool',
+ '_execOf'
+];
+
+function Node(enc, type, parent) {
+ var state = {};
+ this._baseState = state;
+
+ state.enc = enc;
+ state.type = type;
+
+ state.parent = parent || null;
+ state.children = null;
+
+ // State
+ state.tag = null;
+ state.args = null;
+ state.choice = null;
+ state.optional = false;
+ state.any = false;
+ state.obj = false;
+ state.use = null;
+ state.key = null;
+ state['default'] = null;
+ state.explicit = null;
+ state.implicit = null;
+
+ // Should create new instance on each method
+ if (!state.parent) {
+ state.children = [];
+ this._wrap();
+ }
+}
+module.exports = Node;
+
+Node.prototype._wrap = function wrap() {
+ var state = this._baseState;
+ methods.forEach(function(method) {
+ this[method] = function _wrappedMethod() {
+ var clone = new this.constructor(this);
+ state.children.push(clone);
+ return clone[method].apply(clone, arguments);
+ };
+ }, this);
+};
+
+Node.prototype._init = function init(body) {
+ var 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.equal(state.children.length, 1, 'Root node can have only one child');
+};
+
+Node.prototype._useArgs = function useArgs(args) {
+ var state = this._baseState;
+
+ // Filter children and args
+ var 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;
+ }
+};
+
+// Execute node
+Node.prototype._exec = function exec(input, obj) {
+ var state = this._baseState;
+
+ // Exec root node
+ if (state.parent === null)
+ return state.children[0]._exec(input);
+
+ var result = state['default'];
+ var present = true;
+
+ // Check if tag is there
+ if (state.optional) {
+ present = this._peekTag(
+ input,
+ state.explicit !== null ? state.explicit :
+ state.implicit !== null ? state.implicit :
+ state.tag || 0
+ );
+ }
+
+ // Push object on stack
+ if (state.obj && present) {
+ var prevObj = obj;
+ obj = {};
+ }
+
+ if (present) {
+ // Unwrap explicit values
+ if (state.explicit !== null)
+ input = this._execTag(input, state.explicit);
+
+ // Unwrap implicit and normal values
+ if (state.use === null && !state.any && state.choice === null) {
+ input = this._execTag(
+ input,
+ state.implicit !== null ? state.implicit : state.tag,
+ state.any
+ );
+ }
+
+ // Select proper method for tag
+ if (state.any)
+ result = input.raw();
+ if (state.choice !== null)
+ result = this._execChoice(input, obj);
+ else
+ result = this._execByTag(state.tag, input);
+
+ // Execute children
+ if (!state.any && state.choice === null && state.children !== null) {
+ state.children.forEach(function execChildren(child) {
+ child._exec(input, obj);
+ });
+ }
+ }
+
+ // Pop object
+ if (state.obj && present) {
+ result = obj;
+ obj = prevObj;
+ }
+
+ // Set key
+ if (state.key !== null)
+ obj[state.key] = result;
+
+ return result;
+};
+
+Node.prototype._execChoice = function execChoice(input, obj) {
+ var state = this._baseState;
+ var result = null;
+ var match = false;
+
+ Object.keys(state.choice).some(function(key) {
+ var save = input.save();
+ var node = state.choice[key];
+ try {
+ result = node._exec(input, obj);
+ match = true;
+ } catch (e) {
+ input.restore(save);
+ return false;
+ }
+ return true;
+ }, this);
+
+ assert(match, 'Choice not matched');
+ return result;
+};
+
+Node.prototype._execByTag = function execByTag(tag, input) {
+ var state = this._baseState;
+
+ if (tag === 'seq' || tag === 'set')
+ return null;
+ if (tag === 'seqof' || tag === 'setof')
+ return this._execOf(input, tag, state.args[0]);
+ else if (tag === 'octstr' || tag === 'bitstr')
+ return this._execStr(input, tag);
+ else if (tag === 'objid' && state.args)
+ return this._execObjid(input, state.args[0], state.args[1]);
+ else if (tag === 'objid')
+ return this._execObjid(input, null, null);
+ else if (tag === 'gentime')
+ return this._execTime(input, tag);
+ else if (tag === 'null_')
+ return this._execNull(input);
+ else if (tag === 'bool')
+ return this._execBool(input);
+ else if (tag === 'int' || tag === 'enum')
+ return this._execInt(input, state.args && state.args[0]);
+ else if (state.use !== null)
+ return this._execUse(input, state.use);
+ else
+ assert(false, 'unknown tag: ' + tag);
+
+ return null;
+};
+
+// Overrided methods
+overrided.forEach(function(method) {
+ Node.prototype[method] = function _overrided() {
+ var state = this._baseState;
+ throw new Error(method + ' not implemented for encoding: ' + state.enc);
+ };
+});
+
+// Public methods
+
+tags.forEach(function(tag) {
+ Node.prototype[tag] = function _tagMethod() {
+ var state = this._baseState;
+ var args = Array.prototype.slice.call(arguments);
+
+ assert(state.tag === null);
+ state.tag = tag;
+
+ this._useArgs(args);
+
+ return this;
+ };
+});
+
+Node.prototype.use = function use(item) {
+ var state = this._baseState;
+
+ assert(state.use === null);
+ state.use = item;
+
+ return this;
+};
+
+Node.prototype.optional = function optional() {
+ var state = this._baseState;
+
+ state.optional = true;
+
+ return this;
+};
+
+Node.prototype.def = function def(val) {
+ var state = this._baseState;
+
+ assert(state['default'] === null);
+ state['default'] = val;
+ state.optional = true;
+
+ return this;
+};
+
+Node.prototype.explicit = function explicit(num) {
+ var state = this._baseState;
+
+ assert(state.explicit === null && state.implicit === null);
+ state.explicit = num;
+
+ return this;
+};
+
+Node.prototype.implicit = function implicit(num) {
+ var state = this._baseState;
+
+ assert(state.explicit === null && state.implicit === null);
+ state.implicit = num;
+
+ return this;
+};
+
+Node.prototype.obj = function obj() {
+ var state = this._baseState;
+ var args = Array.prototype.slice.call(arguments);
+
+ state.obj = true;
+
+ if (args.length !== 0)
+ this._useArgs(args);
+
+ return this;
+};
+
+Node.prototype.key = function key(key) {
+ var state = this._baseState;
+
+ assert(state.key === null);
+ state.key = key;
+
+ return this;
+};
+
+Node.prototype.any = function any() {
+ var state = this._baseState;
+
+ state.any = true;
+
+ return this;
+};
+
+Node.prototype.choice = function choice(obj) {
+ var state = this._baseState;
+
+ assert(state.choice === null);
+ state.choice = obj;
+ this._useArgs(Object.keys(obj).map(function(key) {
+ return obj[key];
+ }));
+
+ return this;
+};
diff --git a/lib/asn1/decoders/der.js b/lib/asn1/decoders/der.js
new file mode 100644
index 0000000..59e8c83
--- /dev/null
+++ b/lib/asn1/decoders/der.js
@@ -0,0 +1,230 @@
+var assert = require('assert');
+var util = require('util');
+
+var asn1 = require('../../asn1');
+var base = asn1.base;
+
+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);
+};
+module.exports = DERDecoder;
+
+DERDecoder.prototype.decode = function decode(data) {
+ if (!(data instanceof base.DecoderBuffer))
+ data = new base.DecoderBuffer(data);
+
+ return this.tree._exec(data);
+};
+
+// Tree methods
+
+function DERNode(parent) {
+ base.Node.call(this, 'der', 'decoder', parent);
+}
+util.inherits(DERNode, base.Node);
+
+DERNode.prototype._peekTag = function peekTag(buffer, tag) {
+ if (buffer.isEmpty())
+ return false;
+
+ var state = buffer.save();
+ var decodedTag = decodeTag(buffer);
+ buffer.restore(state);
+
+ return decodedTag.tag === tag || decodedTag.tagStr === tag;
+};
+
+DERNode.prototype._execTag = function execTag(buffer, tag, any) {
+ var decodedTag = decodeTag(buffer);
+ var len = decodeLen(buffer, decodedTag.primitive);
+
+ if (!any) {
+ assert(decodedTag.tag === tag ||
+ decodedTag.tagStr === tag ||
+ decodedTag.tagStr + 'of' === tag,
+ 'Failed to match tag: ' + tag);
+ }
+
+ if (decodedTag.primitive || len !== null)
+ return buffer.skip(len);
+
+ assert(0, 'Indefinite length not implemented yet');
+};
+
+DERNode.prototype._execOf = function execOf(buffer, tag, decoder) {
+ var result = [];
+ while (!buffer.isEmpty())
+ result.push(decoder.decode(buffer, 'der'));
+ return result;
+};
+
+DERNode.prototype._execStr = function execStr(buffer, tag) {
+ return buffer.raw();
+};
+
+DERNode.prototype._execObjid = function execObjid(buffer, values, relative) {
+ var identifiers = [];
+ var ident = 0;
+ while (!buffer.isEmpty()) {
+ var subident = buffer.readUInt8();
+ ident <<= 7;
+ ident |= subident & 0x7f;
+ if ((subident & 0x80) === 0) {
+ identifiers.push(ident);
+ ident = 0;
+ }
+ }
+ if (subident & 0x80)
+ identifiers.push(ident);
+
+ var first = (identifiers[0] / 40) | 0;
+ var second = identifiers[0] % 40;
+
+ if (relative)
+ result = identifiers;
+ else
+ result = [first, second].concat(identifiers.slice(1));
+
+ if (values)
+ result = values[result.join(' ')];
+
+ return result;
+};
+
+DERNode.prototype._execTime = function execTime(buffer, tag) {
+ assert.equal(tag, 'gentime');
+
+ var str = buffer.raw().toString();
+ var year = str.slice(0, 4) | 0;
+ var mon = str.slice(4, 6) | 0;
+ var day = str.slice(6, 8) | 0;
+ var hour = str.slice(8, 10) | 0;
+ var min = str.slice(10, 12) | 0;
+ var sec = str.slice(12, 14) | 0;
+
+ return Date.UTC(year, mon - 1, day, hour, min, sec, 0);
+};
+
+DERNode.prototype._execNull = function execNull(buffer) {
+ return null;
+};
+
+DERNode.prototype._execBool = function execBool(buffer) {
+ return buffer.readUInt8() !== 0;
+};
+
+DERNode.prototype._execInt = function execInt(buffer, values) {
+ var res = 0;
+ while (!buffer.isEmpty()) {
+ res <<= 8;
+ res |= buffer.readUInt8();
+ }
+
+ if (values)
+ res = values[res];
+ return res;
+};
+
+DERNode.prototype._execUse = function execUse(buffer, decoder) {
+ return decoder.decode(buffer, 'der');
+};
+
+// Utility methods
+
+var tagClasses = {
+ 0: 'universal',
+ 1: 'application',
+ 2: 'context',
+ 3: 'private'
+};
+
+var tags = {
+ 0x00: 'end',
+ 0x01: 'bool',
+ 0x02: 'int',
+ 0x03: 'bitstr',
+ 0x04: 'octstr',
+ 0x05: 'null',
+ 0x06: 'objid',
+ 0x07: 'objDesc',
+ 0x08: 'external',
+ 0x09: 'real',
+ 0x0a: 'enum',
+ 0x0b: 'embed',
+ 0x0c: 'utf8str',
+ 0x0d: 'relativeOid',
+ 0x10: 'seq',
+ 0x11: 'set',
+ 0x12: 'numstr',
+ 0x13: 'printstr',
+ 0x14: 't61str',
+ 0x15: 'videostr',
+ 0x16: 'ia5str',
+ 0x17: 'utctime',
+ 0x18: 'gentime',
+ 0x19: 'graphstr',
+ 0x1a: 'iso646str',
+ 0x1b: 'genstr',
+ 0x1c: 'unistr',
+ 0x1d: 'charstr',
+ 0x1e: 'bmpstr'
+};
+
+function decodeTag(buf) {
+ var tag = buf.readUInt8();
+
+ var cls = tagClasses[tag >> 6];
+ var primitive = (tag & 0x20) === 0;
+
+ // Multi-octet tag - load
+ if ((tag & 0x1f) === 0x1f) {
+ var oct = tag;
+ tag = 0;
+ while ((oct & 0x80) === 0x80) {
+ oct = buf.readUInt8();
+ tag <<= 7;
+ tag |= oct & 0x7f;
+ }
+ } else {
+ tag &= 0x1f;
+ }
+ var tagStr = tags[tag];
+
+ return {
+ cls: cls,
+ primitive: primitive,
+ tag: tag,
+ tagStr: tagStr
+ };
+}
+
+function decodeLen(buf, primitive) {
+ var len = buf.readUInt8();
+
+ // Indefinite form
+ if (!primitive && len === 0x80)
+ return null;
+
+ // Definite form
+ if ((len & 0x80) === 0) {
+ // Short form
+ return len;
+ }
+
+ // Long form
+ var num = len & 0x7f;
+ assert(num < 4, 'length octect is too long');
+ len = 0;
+ for (var i = 0; i < num; i++) {
+ len <<= 8;
+ len |= buf.readUInt8();
+ }
+
+ return len;
+}
diff --git a/lib/asn1/decoders/index.js b/lib/asn1/decoders/index.js
new file mode 100644
index 0000000..7f431ca
--- /dev/null
+++ b/lib/asn1/decoders/index.js
@@ -0,0 +1,3 @@
+var decoders = exports;
+
+decoders.der = require('./der');
diff --git a/lib/asn1/encoders/index.js b/lib/asn1/encoders/index.js
new file mode 100644
index 0000000..e69de29
diff --git a/lib/modules/index.js b/lib/modules/index.js
new file mode 100644
index 0000000..7932eae
--- /dev/null
+++ b/lib/modules/index.js
@@ -0,0 +1,2 @@
+exports.rfc3280 = require('./rfc3280');
+exports.rfc2560 = require('./rfc2560');
diff --git a/lib/modules/rfc2560.js b/lib/modules/rfc2560.js
new file mode 100644
index 0000000..2df3235
--- /dev/null
+++ b/lib/modules/rfc2560.js
@@ -0,0 +1,106 @@
+var asn1 = require('../asn1');
+var rfc3280 = require('./rfc3280');
+
+// Import
+var OCSPResponse = asn1.define('OCSPResponse', function() {
+ this.seq().obj(
+ this.key('responseStatus').use(ResponseStatus),
+ this.key('responseBytes').optional().explicit(0).seq().obj(
+ this.key('responseType').objid({
+ '1 3 6 1 5 5 7 48 1 1': 'id-pkix-ocsp-basic'
+ }),
+ this.key('response').octstr()
+ )
+ );
+});
+exports.OCSPResponse = OCSPResponse;
+
+var ResponseStatus = asn1.define('ResponseStatus', function() {
+ this.enum({
+ 0: 'successful',
+ 1: 'malformed_request',
+ 2: 'internal_error',
+ 3: 'try_later',
+ 5: 'sig_required',
+ 6: 'unauthorized'
+ });
+});
+exports.ResponseStatus = ResponseStatus;
+
+var BasicOCSPResponse = asn1.define('BasicOCSPResponse', function() {
+ this.seq().obj(
+ this.key('tbsResponseData').use(ResponseData),
+ this.key('signatureAlgorithm').use(rfc3280.AlgorithmIdentifier),
+ this.key('signature').bitstr(),
+ this.key('certs').optional().explicit(0).seqof(rfc3280.Certificate)
+ );
+});
+exports.BasicOCSPResponse = BasicOCSPResponse;
+
+var ResponseData = asn1.define('ResponseData', function() {
+ this.seq().obj(
+ this.key('version').def('v1').explicit(0).use(rfc3280.Version),
+ this.key('responderID').use(ResponderID),
+ this.key('producedAt').gentime(),
+ this.key('responses').seqof(SingleResponse),
+ this.key('responseExtensions').optional().explicit(0)
+ .use(rfc3280.Extensions)
+ );
+});
+exports.ResponseData = ResponseData;
+
+var ResponderID = asn1.define('ResponderId', function() {
+ this.choice({
+ byName: this.explicit(1).use(rfc3280.Name),
+ byKey: this.explicit(2).use(KeyHash)
+ });
+});
+exports.ResponderID = ResponderID;
+
+var KeyHash = asn1.define('KeyHash', function() {
+ this.octstr();
+});
+exports.KeyHash = KeyHash;
+
+var SingleResponse = asn1.define('SingleResponse', function() {
+ this.seq().obj(
+ this.key('certId').use(CertID),
+ this.key('certStatus').use(CertStatus),
+ this.key('thisUpdate').gentime(),
+ this.key('nextUpdate').optional().explicit(0).gentime(),
+ this.key('singleExtensions').optional().explicit(1).use(Extensions)
+ );
+});
+exports.SingleResponse = SingleResponse;
+
+var CertStatus = asn1.define('CertStatus', function() {
+ this.choice({
+ good: this.implicit(0).null_(),
+ revoked: this.implicit(1).use(RevokedInfo),
+ unknown: this.implicit(2).null_()
+ });
+});
+exports.CertStatus = CertStatus;
+
+var RevokedInfo = asn1.define('RevokedInfo', function() {
+ this.seq().obj(
+ this.key('revocationTime').gentime(),
+ this.key('revocationReason').optional().explicit(0).use(rfc3280.CRLReason)
+ );
+});
+exports.RevokedInfo = RevokedInfo;
+
+var CertID = asn1.define('CertID', function() {
+ this.seq().obj(
+ this.key('hashAlgorithm').use(rfc3280.AlgorithmIdentifier),
+ this.key('issuerNameHash').octstr(),
+ this.key('issuerKeyHash').octstr(),
+ this.key('serialNumber').use(rfc3280.CertificateSerialNumber)
+ );
+});
+exports.CertID = CertID;
+
+var Extensions = asn1.define('Extensions', function() {
+ this.any();
+});
+exports.Extensions = Extensions;
diff --git a/lib/modules/rfc3280.js b/lib/modules/rfc3280.js
new file mode 100644
index 0000000..44038fb
--- /dev/null
+++ b/lib/modules/rfc3280.js
@@ -0,0 +1,148 @@
+var asn1 = require('../asn1');
+
+var CRLReason = asn1.define('CRLReason', function() {
+ this.enum({
+ 0: 'unspecified',
+ 1: 'keyCompromise',
+ 2: 'CACompromise',
+ 3: 'affiliationChanged',
+ 4: 'superseded',
+ 5: 'cessationOfOperation',
+ 6: 'certificateHold',
+ 8: 'removeFromCRL',
+ 9: 'privilegeWithdrawn',
+ 10: 'AACompromise'
+ });
+});
+exports.CRLReason = CRLReason;
+
+var AlgorithmIdentifier = asn1.define('AlgorithmIdentifier', function() {
+ this.seq().obj(
+ this.key('algorithm').objid(),
+ this.key('parameters').optional().any()
+ );
+});
+exports.AlgorithmIdentifier = AlgorithmIdentifier;
+
+var Certificate = asn1.define('Certificate', function() {
+ this.seq().obj(
+ this.key('tbsCertificate').use(TBSCertificate),
+ this.key('signatureAlgorithm').use(AlgorithmIdentifier),
+ this.key('signature').bitstr()
+ );
+});
+exports.Certificate = Certificate;
+
+var TBSCertificate = asn1.define('TBSCertificate', function() {
+ this.seq().obj(
+ this.key('version').def('v1').explicit(0).use(Version),
+ this.key('serialNumber').use(CertificateSerialNumber),
+ this.key('signature').use(AlgorithmIdentifier),
+ this.key('issuer').use(Name),
+ this.key('validity').use(Validity),
+ this.key('subject').use(Name),
+ this.key('subjectPublicKeyInfo').use(SubjectPublicKeyInfo),
+
+ // TODO(indutny): validate that version is v2 or v3
+ this.key('issuerUniqueID').optional().implicit(1).use(UniqueIdentifier),
+ this.key('subjectUniqueID').optional().implicit(2).use(UniqueIdentifier),
+
+ // TODO(indutny): validate that version is v3
+ this.key('extensions').optional().implicit(3).use(Extensions)
+ );
+});
+exports.TBSCertificate = TBSCertificate;
+
+var Version = asn1.define('Version', function() {
+ this.int({
+ 0: 'v1',
+ 1: 'v2',
+ 2: 'v3'
+ });
+});
+exports.Version = Version;
+
+var CertificateSerialNumber = asn1.define('CertificateSerialNumber',
+ function() {
+ this.int();
+});
+exports.CertificateSerialNumber = CertificateSerialNumber;
+
+var Validity = asn1.define('Validity', function() {
+ this.seq().obj(
+ this.key('notBefore').use(Time),
+ this.key('notAfter').use(Time)
+ );
+});
+exports.Validity = Validity;
+
+var Time = asn1.define('Time', function() {
+ this.choice({
+ utcTime: this.utctime(),
+ genTime: this.gentime()
+ });
+});
+exports.Time = Time;
+
+var UniqueIdentifier = asn1.define('UniqueIdentifier', function() {
+ this.bitstr();
+});
+exports.UniqueIdentifier = UniqueIdentifier;
+
+var SubjectPublicKeyInfo = asn1.define('SubjectPublicKeyInfo', function() {
+ this.seq().obj(
+ this.key('algorithm').use(AlgorithmIdentifier),
+ this.key('subjectPublicKey').bitstr()
+ );
+});
+exports.SubjectPublicKeyInfo = SubjectPublicKeyInfo;
+
+var Extensions = asn1.define('Extensions', function() {
+ this.seqof(Extension);
+});
+exports.Extensions = Extensions;
+
+var Extension = asn1.define('Extension', function() {
+ this.seq().obj(
+ this.key('extnID').objid(),
+ this.key('critical').bool().def(false),
+ this.key('extnValue').octstr()
+ );
+});
+exports.Extension = Extension;
+
+var Name = asn1.define('Name', function() {
+ this.choice({
+ rdn: this.use(RDNSequence)
+ });
+});
+exports.Name = Name;
+
+var RDNSequence = asn1.define('RDNSequence', function() {
+ this.seqof(RelativeDistinguishedName);
+});
+exports.RDNSequence = RDNSequence;
+
+var RelativeDistinguishedName = asn1.define('RelativeDistinguishedName',
+ function() {
+ this.setof(AttributeTypeAndValue);
+});
+exports.RelativeDistinguishedName = RelativeDistinguishedName;
+
+var AttributeTypeAndValue = asn1.define('AttributeTypeAndValue', function() {
+ this.seq().obj(
+ this.key('type').use(AttributeType),
+ this.key('value').use(AttributeValue)
+ );
+});
+exports.AttributeTypeAndValue = AttributeTypeAndValue;
+
+var AttributeType = asn1.define('AttributeType', function() {
+ this.objid();
+});
+exports.AttributeType = AttributeType;
+
+var AttributeValue = asn1.define('AttributeValue', function() {
+ this.any();
+});
+exports.AttributeValue = AttributeValue;
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..002fa61
--- /dev/null
+++ b/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "asn1.js",
+ "version": "0.0.0",
+ "description": "ASN.1 encoder and decoder",
+ "main": "lib/asn1.js",
+ "scripts": {
+ "test": "mocha --reporter spec test/*-test.js"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git at github.com:indutny/asn1.js"
+ },
+ "keywords": [
+ "asn.1",
+ "der"
+ ],
+ "author": "Fedor Indutny",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/indutny/asn1.js/issues"
+ },
+ "homepage": "https://github.com/indutny/asn1.js",
+ "devDependencies": {
+ "mocha": "~1.14.0"
+ }
+}
diff --git a/test/basic-test.js b/test/basic-test.js
new file mode 100644
index 0000000..5cf4029
--- /dev/null
+++ b/test/basic-test.js
@@ -0,0 +1,35 @@
+var assert = require('assert');
+var asn1 = require('..');
+
+var Buffer = require('buffer').Buffer;
+
+describe('asn1.js', function() {
+ it('should decode OCSP response', function() {
+ var data = new Buffer(
+ '308201d40a0100a08201cd308201c906092b0601050507300101048201ba308201b630' +
+ '819fa216041499e4405f6b145e3e05d9ddd36354fc62b8f700ac180f32303133313133' +
+ '303037343531305a30743072304a300906052b0e03021a050004140226ee2f5fa28108' +
+ '34dacc3380e680ace827f604041499e4405f6b145e3e05d9ddd36354fc62b8f700ac02' +
+ '1100bb4f9a31232b1ba52a0b77af481800588000180f32303133313133303037343531' +
+ '305aa011180f32303133313230343037343531305a300d06092a864886f70d01010505' +
+ '00038201010027813333c9b46845dfe3d0cb6b19c03929cdfc9181c1ce823929bb911a' +
+ 'd9de05721790fcccbab43f9fbdec1217ab8023156d07bbcc3555f25e9e472fbbb5e019' +
+ '2835efcdc71b3dbc5e5c4c5939fc7a610fc6521d4ed7d2b685a812fa1a3a129ea87873' +
+ '972be3be54618ba4a4d96090d7f9aaa5f70d4f07cf5cf3611d8a7b3adafe0b319459ed' +
+ '40d456773d5f45f04c773711d86cc41d274f771a31c10d30cd6f846b587524bfab2445' +
+ '4bbb4535cff46f6b341e50f26a242dd78e246c8dea0e2fabcac9582e000c138766f536' +
+ 'd7f7bab81247c294454e62b710b07126de4e09685818f694df5783eb66f384ce5977f1' +
+ '2721ff38c709f3ec580d22ff40818dd17f',
+ 'hex');
+
+ var res = asn1.modules.rfc2560.OCSPResponse.decode(data, 'der');
+ assert.equal(res.responseStatus, 'successful');
+ assert.equal(res.responseBytes.responseType, 'id-pkix-ocsp-basic');
+
+ var basic = asn1.modules.rfc2560.BasicOCSPResponse.decode(
+ res.responseBytes.response,
+ 'der'
+ );
+ console.log(require('util').inspect(basic, false, 300));
+ });
+});
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-asn1.js.git
More information about the Pkg-javascript-commits
mailing list