UNPKG

asn1-ts

Version:

ASN.1 encoding and decoding, including BER, CER, and DER.

112 lines (111 loc) 3.9 kB
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); } }