# `asn1/strings` — typed-string decoders ## Purpose Decodes and encodes the typed ASN.1 string types used inside X.509 Names and SubjectAltName entries: `UTF8String`, `PrintableString`, `IA5String`, `TeletexString`, `BMPString`, `UniversalString`. The encoder picks the most-restrictive form that holds the input value per RFC 5280 paragraph 7. Decoder is strict about character-set membership — invalid `PrintableString` characters are rejected as `ASN1_MALFORMED`. ## Features - UTF-8 decode via `TextDecoder` with `fatal: true`, so invalid UTF-8 is rejected (not replaced). - `PrintableString` alphabet check per ITU-T X.520 — letters, digits, space, and the eleven punctuation characters allowed. - `IA5String` 0x00-0x7F check. - `BMPString` (UCS-2 big-endian) and `UniversalString` (UCS-4 big-endian) decode. - `TeletexString` pragmatically decoded as Latin-1; sufficient for the rare legacy CAs that still emit it. - Encoder picks `PrintableString` when valid, falling back to `UTF8String` — matches RFC 5280 paragraph 7.1 "most-restrictive" rule. ## Usage: Basic Example ```ts import { decodeAsn1String, encodeAsn1String, UNIVERSAL_TAGS } from "@suaveplan/x509/asn1"; const s = decodeAsn1String(UNIVERSAL_TAGS.UTF8_STRING, new Uint8Array([0x68, 0x69])); // "hi" const { tagNumber, body } = encodeAsn1String("Example CA"); // tagNumber === UNIVERSAL_TAGS.PRINTABLE_STRING ``` ## Usage: Advanced Example ```ts import { decodeAsn1, decodeAsn1String, UNIVERSAL_TAGS } from "@suaveplan/x509/asn1"; // Decode a Name attribute value where the tag depends on the CA's choice: const attrNode = decodeAsn1(attrBytes); if (!("content" in attrNode)) throw new Error("expected primitive"); const cn = decodeAsn1String(attrNode.tag.tagNumber, attrNode.content); ``` ## API Reference - `decodeAsn1String(tagNumber: number, body: Uint8Array): string` — dispatches on the universal tag; throws `X509Error(ASN1_MALFORMED)` on unsupported tag or character-set violation. - `encodeAsn1String(value: string): { tagNumber, body }` — returns the most-restrictive choice that holds the value. ## Implementation Notes - `PrintableString` regex covers ITU-T X.520 paragraph 6.1 — letters, digits, space, and the eleven allowed punctuation marks. - `TeletexString` (T.61) is technically a 7/8-bit ISO 2022 escape system with national variants; decoding as Latin-1 is the de-facto industry practice (BoringSSL, OpenSSL). - `BMPString` and `UniversalString` are byte-order strict — the BMP form is UCS-2 big-endian (2 bytes per char), Universal is UCS-4 big-endian (4 bytes per char). - The encoder does not pick `IA5String`, `TeletexString`, `BMPString`, or `UniversalString` — these are accepted when reading legacy certs but every newly-encoded value defaults to `UTF8String` (the modern X.509 recommendation per RFC 5280 paragraph 4.1.2.4).