micro509/der
DER reading and writing primitives.
The building blocks every other entrypoint is made of, for the cases the typed APIs do not cover:
- decoding a private extension's
extnValueinside anExtensionDecoder - encoding the bytes a
CustomExtensioncarries - inspecting a structure this library does not model
Reading accepts definite lengths and minimal length encodings, rejects the high-tag-number form, and applies a nesting-depth guard capped at DEFAULT_MAX_DER_DEPTH. BER-only constructs fail.
Readers and decoders take untrusted bytes, so each one comes as a pair:
decodeDerIntegerreturns aDecodeDerResultdecodeDerIntegerOrThrowthrows
Writers take typed input and throw, matching encodeName and pemEncode.
All operations are synchronous.
DecodeDerErrorCode
Machine-readable failure reason for the DER readers and decoders.
type DecodeDerErrorCode = malformedDecodeDerFailure
Structured failure payload for DER reading and decoding.
interface DecodeDerFailure extends Micro509Error<DecodeDerErrorCode> {
readonly ok: false;
}Properties
readonlyok:false— Alwaysfalsefor failures.
DecodeDerResult
Success-or-failure result from a DER reader or decoder.
type DecodeDerResult<TValue> = {
readonly ok: true;
readonly value: TValue
} | ErrorResult<DecodeDerErrorCode, Record<never, never>, DecodeDerFailure>decodeDerBitString
Decodes a BIT STRING element (tag 0x03) into a DerBitString.
Unused trailing bits are returned as encoded, with a violation of X.690 §11.2.1 reported through DerBitString.nonZeroPadding, since certificates in the wild carry them.
function decodeDerBitString(
element: DerElement,
): DecodeDerResult<DerBitString>Parameters
element:DerElement
decodeDerBitStringOrThrow
Decodes a BIT STRING element (tag 0x03) into a DerBitString.
Unused trailing bits are returned as encoded, with a violation of X.690 §11.2.1 reported through DerBitString.nonZeroPadding, since certificates in the wild carry them.
function decodeDerBitStringOrThrow(
element: DerElement,
): DerBitStringParameters
element:DerElement
Throws
- if
elementis mis-tagged, or claims more than seven unused bits.
decodeDerBoolean
Decodes a BOOLEAN element (tag 0x01).
function decodeDerBoolean(
element: DerElement,
): DecodeDerResult<boolean>Parameters
element:DerElement
decodeDerBooleanOrThrow
Decodes a BOOLEAN element (tag 0x01).
function decodeDerBooleanOrThrow(
element: DerElement,
): booleanParameters
element:DerElement
Throws
- if
elementis mis-tagged, or holds anything but0x00or0xff.
decodeDerInteger
Decodes an INTEGER element (tag 0x02) into a number.
function decodeDerInteger(
element: DerElement,
): DecodeDerResult<number>Parameters
element:DerElement
decodeDerIntegerOrThrow
Decodes an INTEGER element (tag 0x02) into a number.
function decodeDerIntegerOrThrow(
element: DerElement,
): numberParameters
element:DerElement
Throws
- if
elementis mis-tagged, negative, non-minimally encoded, or exceedsNumber.MAX_SAFE_INTEGER.
decodeDerOctetString
Decodes an OCTET STRING element (tag 0x04) into its payload bytes.
function decodeDerOctetString(
element: DerElement,
): DecodeDerResult<Uint8Array>Parameters
element:DerElement
decodeDerOctetStringOrThrow
Decodes an OCTET STRING element (tag 0x04) into its payload bytes.
function decodeDerOctetStringOrThrow(
element: DerElement,
): Uint8ArrayParameters
element:DerElement
Throws
- if
elementis mis-tagged.
decodeDerOid
Decodes an OBJECT IDENTIFIER element (tag 0x06) into dotted-decimal form.
function decodeDerOid(
element: DerElement,
): DecodeDerResult<string>Parameters
element:DerElement
decodeDerOidOrThrow
Decodes an OBJECT IDENTIFIER element (tag 0x06) into dotted-decimal form.
function decodeDerOidOrThrow(
element: DerElement,
): stringParameters
element:DerElement
Throws
- if
elementis mis-tagged, or holds a malformed sub-identifier.
decodeDerString
Decodes a string element into text, dispatching on its tag.
Supports UTF8String, PrintableString, IA5String, UniversalString, and BMPString.
function decodeDerString(
element: DerElement,
): DecodeDerResult<string>Parameters
element:DerElement
decodeDerStringOrThrow
Decodes a string element into text, dispatching on its tag.
Supports UTF8String, PrintableString, IA5String, UniversalString, and BMPString.
function decodeDerStringOrThrow(
element: DerElement,
): stringParameters
element:DerElement
Throws
- on TeletexString, and on every other string tag.
decodeDerTime
Decodes a UTCTime (tag 0x17) or GeneralizedTime (tag 0x18) element into a Date.
function decodeDerTime(
element: DerElement,
): DecodeDerResult<Date>Parameters
element:DerElement
decodeDerTimeOrThrow
Decodes a UTCTime (tag 0x17) or GeneralizedTime (tag 0x18) element into a Date.
function decodeDerTimeOrThrow(
element: DerElement,
): DateParameters
element:DerElement
Throws
- if
elementcarries any other tag, or a malformed time value.
derChildren
Reads the direct children of a constructed parent within source.
function derChildren(
source: Uint8Array,
parent: DerElement,
): DecodeDerResult<DerElement[]>Parameters
source:Uint8Arrayparent:DerElement
derChildrenOrThrow
Reads the direct children of a constructed parent within source.
function derChildrenOrThrow(
source: Uint8Array,
parent: DerElement,
): DerElement[]Parameters
source:Uint8Arrayparent:DerElement
Throws
- if a child overflows
parent, or data is left between the last child and its end.
readDerElement
Reads one TLV element from bytes starting at offset.
function readDerElement(
bytes: Uint8Array,
offset: number,
): DecodeDerResult<DerElement>Parameters
bytes:Uint8Arrayoffset:number— Byte position of the tag octet. Defaults to 0.
readDerElementOrThrow
Reads one TLV element from bytes starting at offset.
function readDerElementOrThrow(
bytes: Uint8Array,
offset: number,
): DerElementParameters
bytes:Uint8Arrayoffset:number— Byte position of the tag octet. Defaults to 0.
Throws
- if the element is truncated, indefinite-length, or non-minimally encoded.
readDerRoot
Reads the single top-level TLV element from bytes.
function readDerRoot(
bytes: Uint8Array,
options?: ReadRootElementOptions,
): DecodeDerResult<DerElement>Parameters
bytes:Uint8Arrayoptions?:ReadRootElementOptions
readDerRootOrThrow
Reads the single top-level TLV element from bytes.
function readDerRootOrThrow(
bytes: Uint8Array,
options?: ReadRootElementOptions,
): DerElementParameters
bytes:Uint8Arrayoptions?:ReadRootElementOptions
Throws
- if
bytescarries trailing data, or nesting exceeds the depth guard.
readDerSequence
Reads a DER-encoded SEQUENCE from bytes and returns its direct children.
function readDerSequence(
bytes: Uint8Array,
options?: ReadSequenceChildrenOptions,
): DecodeDerResult<DerElement[]>Parameters
bytes:Uint8Arrayoptions?:ReadSequenceChildrenOptions
readDerSequenceOrThrow
Reads a DER-encoded SEQUENCE from bytes and returns its direct children.
function readDerSequenceOrThrow(
bytes: Uint8Array,
options?: ReadSequenceChildrenOptions,
): DerElement[]Parameters
bytes:Uint8Arrayoptions?:ReadSequenceChildrenOptions
Throws
- if the root element is not a SEQUENCE, or if child boundaries are inconsistent.
DerBitString
A BIT STRING payload and the number of unused trailing bits in its final byte.
interface DerBitString {
readonly bytes: Uint8Array;
readonly unusedBits: number;
readonly nonZeroPadding: boolean;
}Properties
readonlybytes:Uint8Array— Payload bytes, excluding the leading unused-bit count octet.readonlyunusedBits:number— Unused trailing bits in the final byte, 0 through 7.readonlynonZeroPadding:boolean—truewhen the original encoding had non-zero padding bits (DER violation).
hexToBytes
Converts a hex string (even or odd length) to a Uint8Array. Odd-length strings are left-padded with a zero nibble.
function hexToBytes(
value: string,
): Uint8ArrayParameters
value:string
toHex
Converts raw bytes to a lowercase hex string with no separator.
function toHex(
bytes: Uint8Array,
): stringParameters
bytes:Uint8Array
DerElement
A single parsed ASN.1 TLV element with byte-range metadata.
interface DerElement {
readonly tag: number;
readonly headerLength: number;
readonly length: number;
readonly start: number;
readonly end: number;
readonly value: Uint8Array;
}Properties
readonlytag:number— ASN.1 tag byte (e.g.0x30for SEQUENCE,0x02for INTEGER).readonlyheaderLength:number— Number of bytes occupied by the tag + length octets.readonlylength:number— Byte length of the value portion (excluding tag and length octets).readonlystart:number— Byte offset where the value portion begins in the source buffer.readonlyend:number— Byte offset one past the last value byte. Equals the next element's header offset.readonlyvalue:Uint8Array— The raw value bytes (slice of the source buffer).
ReadRootElementOptions
Options for readRootElement.
interface ReadRootElementOptions {
readonly maxDepth?: number;
readonly allowOpaqueConstructedTags?: readonly number[];
}Properties
readonlymaxDepth?:number— Maximum nesting depth for the DER depth check. @defaultDEFAULT_MAX_DER_DEPTH.readonlyallowOpaqueConstructedTags?:readonlynumber``[]— Constructed tags whose inner bytes may not parse as valid TLV children (e.g. opaque extension values).
ReadSequenceChildrenOptions
Options for readSequenceChildren.
interface ReadSequenceChildrenOptions {
readonly maxDepth?: number;
readonly allowOpaqueConstructedTags?: readonly number[];
}Properties
readonlymaxDepth?:number— Maximum nesting depth for the DER depth check. @defaultDEFAULT_MAX_DER_DEPTH.readonlyallowOpaqueConstructedTags?:readonlynumber``[]— Constructed tags whose inner bytes may not parse as valid TLV children (e.g. opaque extension values).
assertDerMaxDepth
Walks the full DER tree rooted in bytes.
Constructed tags with content that cannot be parsed as valid children are tolerated when listed in allowOpaqueConstructedTags.
function assertDerMaxDepth(
bytes: Uint8Array,
maxDepth: number,
options?: {
readonly allowOpaqueConstructedTags?: readonly number[]
},
): voidParameters
bytes:Uint8ArraymaxDepth:numberoptions?: {readonlyallowOpaqueConstructedTags?:readonlynumber``[]}
Throws
- if nesting exceeds
maxDepth.
derBitString
Encodes a DER BIT STRING (tag 0x03).
The value is prefixed with a single octet indicating how many trailing bits in the last byte are unused.
function derBitString(
value: Uint8Array,
unusedBits: number,
): Uint8ArrayParameters
value:Uint8ArrayunusedBits:number— Number of unused trailing bits (0–7). Defaults to 0.
derBmpString
Encodes a DER BMPString (tag 0x1e) as big-endian UTF-16.
function derBmpString(
value: string,
): Uint8ArrayParameters
value:string
Throws
- on lone surrogates and on code points above the Basic Multilingual Plane.
derBoolean
Encodes a DER BOOLEAN (tag 0x01): true → 0xff, false → 0x00.
function derBoolean(
value: boolean,
): Uint8ArrayParameters
value:boolean
concatBytes
Concatenates multiple byte arrays into a single Uint8Array.
function concatBytes(
parts: readonly Uint8Array[],
): Uint8ArrayParameters
parts:readonlyUint8Array``[]
DEFAULT_MAX_DER_DEPTH
Maximum nesting depth allowed when recursively walking a DER structure.
Guards against stack exhaustion from pathologically nested input.
const DEFAULT_MAX_DER_DEPTH: 64derExplicitContext
Wraps a value in an explicit context-specific constructed tag (0xa0 + tag).
Used for optional SEQUENCE fields tagged with [tag] EXPLICIT.
function derExplicitContext(
tag: number,
value: Uint8Array,
): Uint8ArrayParameters
tag:numbervalue:Uint8Array
derGeneralizedTime
Encodes a Date as a DER GeneralizedTime (tag 0x18), format YYYYMMDDHHMMSSZ.
Uses a four-digit year; required for dates outside the 1950–2049 range.
function derGeneralizedTime(
date: Date,
): Uint8ArrayParameters
date:Date
derIa5String
Encodes a DER IA5String (tag 0x16).
function derIa5String(
value: string,
): Uint8ArrayParameters
value:string
Throws
- if the input contains any non-ASCII character (code point > 0x7f).
derImplicitConstructedContext
Wraps a value in an implicit context-specific constructed tag (0xa0 + tag).
Used for [tag] IMPLICIT fields whose underlying type is constructed (e.g. SEQUENCE).
function derImplicitConstructedContext(
tag: number,
value: Uint8Array,
): Uint8ArrayParameters
tag:numbervalue:Uint8Array
derImplicitPrimitiveContext
Wraps a value in an implicit context-specific primitive tag (0x80 + tag).
Used for [tag] IMPLICIT fields whose underlying type is primitive (e.g. OCTET STRING).
function derImplicitPrimitiveContext(
tag: number,
value: Uint8Array,
): Uint8ArrayParameters
tag:numbervalue:Uint8Array
derInteger
Encodes raw big-endian bytes as a DER INTEGER (tag 0x02).
Strips leading zero bytes for minimal encoding and prepends a zero byte when the high bit is set to keep the value non-negative.
function derInteger(
bytes: Uint8Array,
): Uint8ArrayParameters
bytes:Uint8Array
derIntegerFromNumber
Encodes a non-negative JavaScript number as a DER INTEGER.
function derIntegerFromNumber(
value: number,
): Uint8ArrayParameters
value:number
Throws
- if the value is not a non-negative safe integer.
derNull
Produces a DER NULL element (tag 0x05, zero-length value).
function derNull(): Uint8ArrayderOid
Encodes a dotted-decimal OID string as a DER OBJECT IDENTIFIER (tag 0x06).
Validates arc constraints per X.660: first arc must be 0–2, second < 40 for arcs 0 and 1.
Sub-identifiers are encoded with base-128 continuation.
function derOid(
oid: string,
): Uint8ArrayParameters
oid:string
derOctetString
Wraps raw bytes in an OCTET STRING element (tag 0x04).
function derOctetString(
value: Uint8Array,
): Uint8ArrayParameters
value:Uint8Array
derPrintableString
Encodes a DER PrintableString (tag 0x13).
function derPrintableString(
value: string,
): Uint8ArrayParameters
value:string
Throws
- if the input contains characters outside the X.520 PrintableString set.
derSequence
Wraps concatenated children in a SEQUENCE (tag 0x30).
function derSequence(
parts: readonly Uint8Array[],
): Uint8ArrayParameters
parts:readonlyUint8Array``[]
derSet
Wraps children in a SET (tag 0x31) after DER-sorting them lexicographically by encoded bytes, as required by X.690 DER.
function derSet(
parts: readonly Uint8Array[],
): Uint8ArrayParameters
parts:readonlyUint8Array``[]
derTime
Encodes a Date as the appropriate DER time type per RFC 5280.
utcTimefor 1950–2049generalizedTimeotherwise
function derTime(
date: Date,
): Uint8ArrayParameters
date:Date
derTlv
Builds a complete DER TLV (tag-length-value) element:
- one tag octet,
- the DER-encoded length, then
- the raw value bytes.
function derTlv(
tag: number,
value: Uint8Array,
): Uint8ArrayParameters
tag:numbervalue:Uint8Array
derUniversalString
Encodes a DER UniversalString (tag 0x1c) as big-endian UTF-32.
function derUniversalString(
value: string,
): Uint8ArrayParameters
value:string
Throws
- on lone surrogates.
derUtcTime
Encodes a Date as a DER UTCTime (tag 0x17), format YYMMDDHHMMSSZ.
Only the two-digit year is stored; suitable for dates in 1950–2049.
function derUtcTime(
date: Date,
): Uint8ArrayParameters
date:Date
derUtf8String
Encodes a DER UTF8String (tag 0x0c).
function derUtf8String(
value: string,
): Uint8ArrayParameters
value:string