import { type Asn1Node, decodeAsn1, isConstructed, UNIVERSAL_TAGS, } from "../asn1/index.js"; import { X509_CODES, X509Error } from "../errors/error-codes.js"; import type { BasicConstraints } from "./extension.types.js"; function bad(reason: string): X509Error { return new X509Error( X509_CODES.EXTENSION_MALFORMED, "error.x509.basic-constraints-malformed", { context: { reason } } ); } /** OID for the basic constraints extension. */ export const OID_BASIC_CONSTRAINTS = "2.5.29.19"; export function decodeBasicConstraints(value: Uint8Array): BasicConstraints { const outer = decodeAsn1(value); if ( !isConstructed(outer) || outer.tag.tagNumber !== UNIVERSAL_TAGS.SEQUENCE ) { throw bad("not-sequence"); } let cA = false; let pathLenConstraint: number | undefined; let idx = 0; const first = outer.children[idx]; if ( first !== undefined && !isConstructed(first) && first.tag.tagNumber === UNIVERSAL_TAGS.BOOLEAN ) { if (first.content.length !== 1) { throw bad("bool-len"); } cA = (first.content[0] as number) !== 0x00; idx += 1; } const second = outer.children[idx]; if ( second !== undefined && !isConstructed(second) && second.tag.tagNumber === UNIVERSAL_TAGS.INTEGER ) { if (second.content.length === 0 || second.content.length > 4) { throw bad("pathlen-len"); } let n = 0; for (let i = 0; i < second.content.length; i++) { n = (n << 8) | (second.content[i] as number); } if (n < 0) { throw bad("pathlen-negative"); } pathLenConstraint = n; idx += 1; } if (idx !== outer.children.length) { throw bad("extra-fields"); } return pathLenConstraint === undefined ? { cA } : { cA, pathLenConstraint }; } // Silence unused-import warning when only types are referenced here. export type { Asn1Node };