Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 198 additions & 7 deletions lib/encoding/asn1.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,18 @@ const classesByVal = {
3: 'PRIVATE'
};

// ASN.1 type
const TARGET = 0xff;

// flags
const OPTIONAL = 1 << 8;
const MODE = 0xff << 9;
const NORMAL = 0 << 9;
const EXPLICIT = 1 << 9;
const IMPLICIT = 2 << 9;
const FORCE = 1 << 9;

// mode
const MODE = 0xff << 10;
const NORMAL = 0 << 10;
const EXPLICIT = 1 << 10;
const IMPLICIT = 1 << 11;

/**
* Node
Expand Down Expand Up @@ -154,6 +160,17 @@ class Node extends bio.Struct {
this.flags &= ~OPTIONAL;
}

get force() {
return (this.flags & FORCE) !== 0;
}

set force(value) {
if (value)
this.flags |= FORCE;
else
this.flags &= ~FORCE;
}

get target() {
return this.flags & TARGET;
}
Expand Down Expand Up @@ -239,7 +256,7 @@ class Node extends bio.Struct {
}

getSize(extra) {
if (this.opt && this.clean())
if (this.opt && this.clean() && !this.force)
return 0;

const body = this.getBodySize(extra);
Expand All @@ -256,7 +273,7 @@ class Node extends bio.Struct {
}

write(bw, extra) {
if (this.opt && this.clean())
if (this.opt && this.clean() && !this.force)
return bw;

const body = this.getBodySize();
Expand Down Expand Up @@ -490,6 +507,13 @@ class Any extends Node {
const Node = typeToClass(hdr.type);

this.node = new Node();

// If a Null node was present when reading,
// respect the preference and include the node
// when writing as well.
if (this.opt)
this.force = true;

this.node.flags = this.flags;
this.node.read(br, extra);

Expand Down Expand Up @@ -535,6 +559,32 @@ class Any extends Node {
node: this.node
};
}

getJSON() {
if (this.opt && !this.force)
return null;

return {
type: this.node.constructor.name,
node: this.node.getJSON()
};
}

fromJSON(json) {
if (!json)
return null;

if (this.opt)
this.force = true;

const type = types[json.type.toUpperCase()];
const Node = typeToClass(type);
this.node = new Node();
this.node.fromJSON(json.node);
this.node.flags = this.flags;

return this.node;
}
}

/**
Expand All @@ -547,6 +597,7 @@ class Choice extends Node {
assert(node instanceof Node);
this.node = node;
this.from(...options);
this.types = types;
}

get type() {
Expand All @@ -557,6 +608,10 @@ class Choice extends Node {
throw new Error('Unimplemented.');
}

typeToClass(type) {
return typeToClass(type);
}

getSize(extra) {
return this.node.getSize(extra);
}
Expand Down Expand Up @@ -584,7 +639,7 @@ class Choice extends Node {
if (choices.indexOf(hdr.type) === -1)
throw new Error(`Could not satisfy choice for: ${hdr.type}.`);

const Node = typeToClass(hdr.type);
const Node = this.typeToClass(hdr.type);
const el = new Node();
el.flags = this.flags;

Expand Down Expand Up @@ -621,6 +676,23 @@ class Choice extends Node {
node: this.node
};
}

getJSON() {
return {
type: this.node.constructor.name,
node: this.node.getJSON()
};
}

fromJSON(json) {
const type = this.types[json.type.toUpperCase()];
const Node = this.typeToClass(type);
this.node = new Node();
this.node.fromJSON(json.node);
this.node.flags = this.flags;

return this.node;
}
}

/**
Expand Down Expand Up @@ -693,6 +765,17 @@ const Str = class String extends Node {
format() {
return `<${this.constructor.name}: ${this.value}>`;
}

getJSON() {
return this.value;
}

fromJSON(json) {
assert(typeof json === 'string');
this.value = json;

return this;
}
};

/**
Expand Down Expand Up @@ -751,6 +834,17 @@ const Bool = class Boolean extends Node {
format() {
return `<${this.constructor.name}: ${this.value}>`;
}

getJSON() {
return this.value;
}

fromJSON(json) {
assert(typeof json === 'boolean');
this.value = json;

return this;
}
};

/**
Expand Down Expand Up @@ -954,6 +1048,21 @@ class Integer extends Node {

return `<${name}: ${sign}0x${hex}>`;
}

getJSON() {
return {
value: this.value.toString('hex'),
negative: this.negative
};
}

fromJSON(json) {
assert(typeof json.negative === 'boolean');
this.value = Buffer.from(json.value, 'hex');
this.negative = json.negative;

return this;
}
}

/**
Expand Down Expand Up @@ -995,6 +1104,14 @@ class Unsigned extends Integer {
assert(!this.negative);
return this;
}

getJSON() {
return this.toNumber();
}

fromJSON(json) {
return this.fromNumber(json);
}
}

/**
Expand Down Expand Up @@ -1121,6 +1238,21 @@ class BitString extends Node {

return `<${this.constructor.name}: ${this.bits}:${value.toString('hex')}>`;
}

getJSON() {
return {
bits: this.bits,
value: this.value.toString('hex')
};
}

fromJSON(json) {
assert(typeof json.bits === 'number');
this.bits = json.bits;
this.value = Buffer.from(json.value, 'hex');

return this;
}
}

/**
Expand Down Expand Up @@ -1175,6 +1307,16 @@ class OctString extends Node {

return `<${this.constructor.name}: ${value.toString('hex')}>`;
}

getJSON() {
return this.value.toString('hex');
}

fromJSON(json) {
this.value = Buffer.from(json, 'hex');

return this;
}
}

/**
Expand Down Expand Up @@ -1213,6 +1355,14 @@ class Null extends Node {
format() {
return `<${this.constructor.name}>`;
}

getJSON() {
return null;
}

fromJSON(json) {
return this;
}
}

/**
Expand Down Expand Up @@ -1368,6 +1518,10 @@ class OID extends Node {
str = objects.hashes[str];
else if (objects.curves.hasOwnProperty(str))
str = objects.curves[str];
else if (objects.sigAlgs.hasOwnProperty(str))
str = objects.sigAlgs[str];
else if (objects.extensions.hasOwnProperty(str))
str = objects.extensions[str];

const parts = str.split('.');
const out = new Uint32Array(parts.length);
Expand Down Expand Up @@ -1415,19 +1569,40 @@ class OID extends Node {
return objects.curvesByVal[this.toString()] || null;
}

getExtensionName() {
return objects.extensionsByVal[this.toString()] || null;
}

format() {
const oid = this.toString();
const name = objects.attrsByVal[oid]
|| objects.sigAlgsByVal[oid]
|| objects.keyAlgsByVal[oid]
|| objects.hashesByVal[oid]
|| objects.curvesByVal[oid]
|| objects.extensionsByVal[oid]
|| 'UNKNOWN';

const str = `${oid} (${name})`;

return `<${this.constructor.name}: ${str}>`;
}

getJSON() {
const oid = this.toString();
const name = objects.attrsByVal[oid]
|| objects.sigAlgsByVal[oid]
|| objects.keyAlgsByVal[oid]
|| objects.hashesByVal[oid]
|| objects.curvesByVal[oid]
|| objects.extensionsByVal[oid]
|| this.toString();
return name;
}

fromJSON(json) {
return this.fromString(json);
}
}

/**
Expand Down Expand Up @@ -1548,6 +1723,14 @@ class RawSequence extends Node {
format() {
return this.toArray();
}

getJSON() {
throw new Error('Not implemented.');
}

fromJSON(json) {
throw new Error('Not implemented.');
}
}

/**
Expand Down Expand Up @@ -1695,6 +1878,14 @@ class Time extends Node {

return `<${name}: ${value}${off} (${this.toString()})>`;
}

getJSON() {
return this.toString();
}

fromJSON(json) {
return this.fromString(json);
}
}

/**
Expand Down
Loading