asn1-ts
Version:
ASN.1 encoding and decoding, including BER, CER, and DER.
112 lines (111 loc) • 3.9 kB
JavaScript
import encodeRelativeObjectIdentifier from "../codecs/x690/encoders/encodeRelativeObjectIdentifier.mjs";
import decodeRelativeObjectIdentifier from "../codecs/x690/decoders/decodeRelativeObjectIdentifier.mjs";
import { Buffer } from "node:buffer";
import * as errors from "../errors.mjs";
const PERIOD = ".".charCodeAt(0);
export default class ObjectIdentifier {
constructor() {
this.encoding = new Uint8Array(0);
}
static fromParts(nodes, prefix) {
let _nodes = typeof prefix === "number" ? [prefix, ...nodes] : nodes;
if (!prefix || typeof prefix === "number") {
if (_nodes.length < 2) {
throw new Error("Cannot construct an OID with less than two nodes!");
}
if ((_nodes[0] < 0) || (_nodes[0] > 2)) {
throw new Error("OIDs first node must be 0, 1, or 2!");
}
if (((_nodes[0] < 2) && (_nodes[1] > 39))) {
throw new Error(`OID Node #2 cannot exceed 39 if node #1 is 0 or 1. Received these nodes: ${_nodes}.`);
}
}
const oid = new ObjectIdentifier();
if (prefix && typeof prefix !== "number") {
oid.encoding = Buffer.concat([prefix.encoding, encodeRelativeObjectIdentifier(_nodes)]);
}
else {
oid.encoding = encodeRelativeObjectIdentifier([
(_nodes[0] * 40) + _nodes[1],
..._nodes.slice(2),
]);
}
return oid;
}
get nodes() {
const subcomponents = decodeRelativeObjectIdentifier(this.encoding);
return [
Math.min(2, Math.floor(subcomponents[0] / 40)),
((subcomponents[0] >= 80)
? (subcomponents[0] - 80)
: (subcomponents[0] % 40)),
...subcomponents.slice(1),
];
}
get dotDelimitedNotation() {
return this.nodes.join(".");
}
get asn1Notation() {
return `{ ${Array.from(this.nodes).map((node) => node.toString()).join(" ")} }`;
}
toString() {
return this.dotDelimitedNotation;
}
toJSON() {
return this.dotDelimitedNotation;
}
toBytes() {
return Buffer.from(this.encoding);
}
static fromString(str) {
const arcs = [];
let last = 0;
let i = 0;
while (i < str.length) {
if (str.charCodeAt(i) === PERIOD) {
const arc = Number.parseInt(str.slice(last, i), 10);
arcs.push(arc);
last = i + 1;
}
i++;
}
const arc = Number.parseInt(str.slice(last, i), 10);
arcs.push(arc);
return ObjectIdentifier.fromParts(arcs);
}
static fromBytes(bytes) {
if (bytes.length === 0) {
throw new errors.ASN1TruncationError("Encoded value was too short to be an OBJECT IDENTIFIER!");
}
if (bytes[bytes.length - 1] & 0b10000000) {
throw new errors.ASN1TruncationError("OID was truncated.");
}
let current_node = 0;
for (let i = 1; i < bytes.length; i++) {
const byte = bytes[i];
if ((current_node === 0) && (byte === 0x80)) {
throw new errors.ASN1PaddingError("Prohibited padding on OBJECT IDENTIFIER node.");
}
if (byte < 0x80) {
current_node = 0;
}
else {
current_node++;
}
}
const oid = new ObjectIdentifier();
oid.encoding = bytes;
return oid;
}
static fromBytesUnsafe(bytes) {
const oid = new ObjectIdentifier();
oid.encoding = bytes;
return oid;
}
static compare(a, b) {
return Buffer.compare(a.encoding, b.encoding) === 0;
}
isEqualTo(other) {
return ObjectIdentifier.compare(this, other);
}
}