import assert from "node:assert/strict"; import test from "node:test"; import { exploreCertificateDer } from "../src/der-explorer.js"; test("DER explorer extracts Basic Constraints and Key Usage with offsets", () => { const basicConstraints = extension("551d13", "30030101ff"); const keyUsage = extension("551d0f", "03020106", true); const extensions = tlv("30", basicConstraints + keyUsage); const tbs = tlv("30", tlv("a3", extensions)); const certificate = bytes(tlv("30", tbs)); const result = exploreCertificateDer(certificate); assert.equal(result.byteLength, certificate.length); assert.equal(result.derived.isCa, true); assert.deepEqual(result.derived.keyUsages, ["keyCertSign", "crlSign"]); assert.equal(result.extensions[1].critical, true); assert.deepEqual(result.derived.unsupportedCriticalExtensions, []); assert.ok(result.extensions.every((item) => item.offset < item.valueOffset)); }); test("DER explorer rejects indefinite, truncated, and excessively nested input", () => { assert.throws(() => exploreCertificateDer(bytes("30800000")), /Indefinite length/); assert.throws(() => exploreCertificateDer(bytes("300301")), /exceeds its container/); let nested = "0500"; for (let index = 0; index < 34; index++) nested = tlv("30", nested); assert.throws(() => exploreCertificateDer(bytes(nested)), /nesting limit/); }); test("an understood name does not make an unsupported critical extension safe", () => { const policies = extension("551d20", "3000", true); const certificate = bytes(tlv("30", tlv("30", tlv("a3", tlv("30", policies))))); const result = exploreCertificateDer(certificate); assert.equal(result.extensions[0].name, "Certificate Policies"); assert.equal(result.extensions[0].known, true); assert.equal(result.extensions[0].supported, false); assert.deepEqual(result.derived.unsupportedCriticalExtensions, ["2.5.29.32"]); }); function extension(oidHex, valueHex, critical = false) { return tlv("30", tlv("06", oidHex) + (critical ? "0101ff" : "") + tlv("04", valueHex)); } function tlv(tag, value) { const length = value.length / 2; if (length >= 128) throw new Error("test helper supports short lengths only"); return `${tag}${length.toString(16).padStart(2, "0")}${value}`; } function bytes(hex) { return Uint8Array.from(hex.match(/../g).map((pair) => Number.parseInt(pair, 16))); }