[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