ilusm.dev

asn

ASN.1 DER parser - tag/length/value decoding, OID strings, X.509 certificate parsing, PEM decoding, RSA public key extraction. Pure ilusm.

Load with: use asn

What this module does

asn parses binary ASN.1 DER data entirely in ilusm - no native bindings needed. You can feed it raw DER bytes or a PEM string and walk the tree of TLV (tag-length-value) nodes, decode OIDs to dotted notation, extract X.509 certificate fields (subject, issuer, serial number, validity dates, public key), and pull RSA modulus and exponent out of a certificate's public key.

DER tags are described by three fields: cls (class: universal/application/context/private), pc (primitive or constructed), and num (the tag number). Long-form tags (tag number >= 0x1F) are not supported and will error.

Quick example

use asn

# Parse a PEM certificate
cert = asncr(pem_string)

prn(cert.subj)   # "/CN=example.com/O=Acme Ltd"
prn(cert.iss)    # "/CN=Let's Encrypt..."
prn(cert.sn)     # serial number as integer
prn(cert.notb)   # not-before validity string
prn(cert.nota)   # not-after validity string

# Extract RSA public key integers
rsa = asnrs(cert)
prn(rsa.n)  # modulus
prn(rsa.e)  # exponent

Functions

Tag constants

Defined as constants for use when inspecting tag classes and primitive/constructed bits.

asnclsuniversal = 0x00, asnclsapp = 0x40, asnclscxt = 0x80, asnclspriv = 0xC0

The four ASN.1 tag classes as constants.

asnpcpri = 0x00, asnpccon = 0x20

Primitive (0x00) and constructed (0x20) bit constants for the P/C flag in a tag byte.

Low-level parsing

asnta(d, i)

Reads a tag byte from byte string d at position i. Returns {cls, pc, num, pos} - class bits, primitive/constructed bit, tag number, and the position after the tag byte. Errors on out-of-bounds or long-form tags.

asnle(d, i)

Reads the length field from d at position i. Handles both short form (single byte) and long form (length-of-length prefix, up to 4 bytes). Returns {len, pos}. Errors on indefinite-length (n == 0) or lengths needing more than 4 bytes.

asntl(d, i)

Parses one complete TLV (tag-length-value) starting at position i. Returns {tag, val, raw, pos} - val is the value bytes, raw includes the full TLV bytes, pos is where the next TLV starts.

asnpa(d, i)

Recursively parses a DER structure starting at i. For constructed nodes, recursively parses all children into a kids list. For primitive nodes, returns the raw value bytes. Returns {tag, raw, kids?} or {tag, raw, val}.

PEM decoding

asnpe(s)

Strips PEM armour (-----BEGIN ...----- / -----END ...----- lines) from a string, concatenates the base64 body lines, and decodes to raw DER bytes via enc.encub.

Value decoders

asnoi(b)

Decodes OID bytes to a dotted decimal string like "1.2.840.113549.1.1.11". The first byte encodes the first two arcs as first/40 and first%40. Subsequent bytes use base-128 variable-length encoding.

asnin(b)

Decodes a big-endian signed integer from DER bytes. Handles negative values (high bit set on first byte means two's complement). Returns 0 for empty input.

Tree navigation

asnfi(n, path)

Finds a descendant node by walking a path of tag numbers. Each element in path is a tag number to match against children. Returns the found node or errors with the missing tag number.

X.509 certificates

asncr(d)

Parses an X.509 certificate from raw DER bytes. Returns {subj, iss, pub, sn, notb, nota} - subject name, issuer name (both as /CN=.../O=... strings), raw public key bytes, serial number as integer, and the not-before/not-after validity strings.

asncr(s)

Overload that accepts a PEM string. Calls asnpe to strip armour first, then parses the DER.

Distinguished name formatting

asnna(n)

Converts an X.500 RelativeDistinguishedName node to an /attr=value string. Recognises the following OIDs: 2.5.4.6 → C, 2.5.4.8 → ST, 2.5.4.7 → L, 2.5.4.10 → O, 2.5.4.11 → OU, 2.5.4.3 → CN, 2.5.4.5 → SN. Unknown OIDs are used as-is.

RSA public key extraction

asnrs(c)

Extracts the RSA public key from a parsed cert object (c.pub). Parses the SubjectPublicKeyInfo structure, skips the BIT STRING wrapper byte, and returns {n, e} - modulus and public exponent as large integers decoded by asnin.

Notes

  • Long-form tags (tag number >= 31 / 0x1F) are not supported - asnta will error.
  • Length fields requiring more than 4 bytes are rejected.
  • asncr is overloaded: one signature takes DER bytes, the other takes a PEM string.
  • The module relies on enc for byte-level access and base64 decoding.