Files
suaveplan/packages/security-stack/security/x509/src/extensions/basic-constraints.ts
2026-05-27 23:47:53 +01:00

71 lines
2.0 KiB
TypeScript

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 };