Open-Source Wikis

/

OpenSSL

/

Subsystems

/

ASN.1

openssl/openssl

ASN.1

Active contributors: Tomas Mraz, Pauli, Dr. David von Oheimb, Matt Caswell, Richard Levitte

Purpose

OpenSSL's ASN.1 subsystem encodes and decodes ASN.1 types in DER (and the BER/CER variants where needed). It is the substrate beneath every X.509 certificate, every PKCS structure, every CMS / OCSP / CRL / CMP / TS message in the toolkit. The subsystem provides:

  • A type system — ASN1_INTEGER, ASN1_STRING, ASN1_OBJECT, ASN1_TYPE, ASN1_BIT_STRING, ASN1_SEQUENCE, ASN1_SET, ASN1_TIME, …
  • A template macro language so domain-specific types (e.g. X509_NAME_ENTRY) can be declared once and get encode/decode/new/free for free.
  • A bytestream parser/serializer (d2i_* and i2d_* family).
  • A streaming variant for big inputs (SMIME_ASN1_*, BIO_* integration).

Directory layout

crypto/asn1/
├── asn1_lib.c             -- the bytestream encoder/decoder primitives
├── asn1_par.c, asn1_gen.c -- "parse" / "generate" structured pretty-printers
├── tasn_dec.c             -- template-driven decoder
├── tasn_enc.c             -- template-driven encoder
├── tasn_fre.c             -- template-driven free
├── tasn_new.c             -- template-driven allocator
├── tasn_typ.c             -- the IMPLEMENT_ASN1_TYPE machinery
├── tasn_utl.c             -- template helpers
├── tasn_prn.c             -- pretty-printer
├── x_*.c                  -- type-specific encoders (x_int.c, x_bignum.c, x_long.c, x_int64.c, x_pkey.c, x_pubkey.c, x_name.c, x_algor.c, x_attrib.c, x_info.c, x_spki.c, x_val.c, x_sig.c, x_x509.c via crypto/x509/, …)
├── a_*.c                  -- ASN1_TYPE primitive support (a_int.c, a_bitstr.c, a_object.c, a_strex.c, a_strnid.c, a_print.c, a_d2i_fp.c, a_dup.c, a_gentm.c, a_utctm.c, a_time.c, …)
├── ameth_lib.c            -- legacy EVP_PKEY_ASN1_METHOD glue (deprecated)
├── bio_asn1.c, bio_ndef.c -- BIO filters for ASN.1 streaming
├── d2i_param.c, d2i_pr.c, d2i_pu.c, i2d_evp.c, p8_pkey.c, p5_pbev2.c, p5_pbe.c, …
├── nsseq.c                -- Netscape sequence (legacy)
├── n_pkey.c               -- old Netscape private-key wrapping (deprecated)
└── asn_*.c, charmap.h, evp_asn1.c, asn1_err.c, asn_pack.c, asn_mime.c, asn_moid.c

How templates work

The hallmark of OpenSSL's ASN.1 system is the macro DSL. A schema is declared once with ASN1_SEQUENCE/ASN1_CHOICE/ASN1_SET_OF macros, and a parallel IMPLEMENT_ASN1_FUNCTIONS macro emits encode/decode/new/free.

ASN1_SEQUENCE(X509_NAME_ENTRY) = {
    ASN1_SIMPLE(X509_NAME_ENTRY, object, ASN1_OBJECT),
    ASN1_SIMPLE(X509_NAME_ENTRY, value,  ASN1_PRINTABLE)
} ASN1_SEQUENCE_END(X509_NAME_ENTRY)

IMPLEMENT_ASN1_FUNCTIONS(X509_NAME_ENTRY)

After macro expansion the file gets:

  • A static ASN1_ITEM describing the schema.
  • i2d_X509_NAME_ENTRY, d2i_X509_NAME_ENTRY, X509_NAME_ENTRY_new, X509_NAME_ENTRY_free functions.

The runtime walks the ASN1_ITEM recursively. The encoder is tasn_enc.c; the decoder tasn_dec.c; allocator tasn_new.c; free tasn_fre.c. The ASN1_TEMPLATE substructure says how each member is encoded — simple, optional, default, sequence-of, set-of, choice, etc.

Schema declarations are spread across the codebase, near the data type they describe:

  • crypto/x509/x_*.c — X.509 schema (X509, X509_NAME, X509_EXTENSION, …).
  • crypto/cms/cms_asn1.c, cms_pwri.c — CMS schema.
  • crypto/cmp/cmp_asn.c — CMP schema.
  • crypto/crmf/crmf_asn.c — CRMF schema.
  • crypto/ocsp/ocsp_asn.c — OCSP schema.
  • crypto/ts/ts_asn1.c — TS schema.
  • crypto/pkcs7/pk7_asn1.c, crypto/pkcs12/p12_*.c — PKCS family schemas.
  • crypto/ess/ess_asn1.c — ESS extensions.
  • crypto/asn1/p8_pkey.c — PKCS#8 PrivateKeyInfo.

Reading and writing

Caller intent Function family
Parse a DER blob d2i_<TYPE>(NULL, &bytes, len)
Parse from a BIO d2i_<TYPE>_bio(bio, NULL) or ASN1_d2i_bio(...)
Encode to memory i2d_<TYPE>(obj, NULL) (returns length); call again with a buffer
Encode to a BIO i2d_<TYPE>_bio(bio, obj)
PEM read/write PEM_read_bio_<TYPE> / PEM_write_bio_<TYPE> (in crypto/pem/)

For new code, OSSL_DECODER and OSSL_ENCODER (in features/encoders-decoders) are the recommended provider-routed APIs. The i2d_*/d2i_* family is preserved for backward compatibility and is the only path for non-key types like X509, X509_CRL, etc.

Strings

ASN.1 string types map onto a single ASN1_STRING C type with a type discriminator (V_ASN1_PRINTABLESTRING, V_ASN1_UTF8STRING, V_ASN1_BMPSTRING, …). Conversion utilities live in a_strex.c, a_strnid.c, a_print.c. The ASN1_STRING_TABLE machinery knows the per-OID expected string types so e.g. commonName is encoded sensibly.

Time

ASN.1 has two main time types: UTCTime (YYMMDDHHMMSSZ) and GeneralizedTime (YYYYMMDDHHMMSS[.fff]Z). Per X.509 rules, certificates use UTCTime through 2049 and GeneralizedTime thereafter. OpenSSL's ASN1_TIME is a tagged union; conversion helpers in a_time.c, a_gentm.c, a_utctm.c. Common pitfall: comparing ASN1_TIME values requires ASN1_TIME_compare, not direct string comparison.

OIDs

Object Identifiers are stored in ASN1_OBJECT. The big static OID table is in crypto/objects/obj_dat.c (with header obj_dat.h, 7,200 lines, autogenerated from crypto/objects/objects.txt). The corresponding NID enum and macros are emitted into include/openssl/obj_mac.h (6,700 lines). Look up by OID string with OBJ_txt2nid, by name with OBJ_sn2nid/OBJ_ln2nid.

To add a new OID, edit crypto/objects/objects.txt and run make update.

Error handling

ASN.1 errors push onto the OpenSSL error stack with ASN1err() / ERR_raise(ERR_LIB_ASN1, ...). Common reasons (ASN1_R_*):

  • ASN1_R_DATA_IS_WRONG, _BAD_TAG, _INVALID_OBJECT_ENCODING, _HEADER_TOO_LONG, _TOO_LONG.
  • ASN1_R_NESTED_ASN1_STRING — defends against deeply nested attacker inputs.
  • ASN1_R_UNKNOWN_FORMAT — the type discriminator didn't match a known string family.

The decoder enforces depth and length limits (ASN1_MAX_STRING_NEST, ASN1_MAX_CONSTRUCTED_NEST) by default to mitigate parsing-time DoS.

Streaming

For multi-megabyte CMS/PKCS#7 signed-data blobs, the _stream family in asn_mime.c and bio_asn1.c does indefinite-length BER encoding/decoding through a chain of BIOs. The classic example: signing a 1 GB tarball into a .p7s without buffering the entire input. The bio_ndef.c filter handles indefinite-length detection.

Integration points

  • Every certificate parser in crypto/x509/ calls into the ASN.1 templates.
  • CMS/PKCS#7/OCSP/CMP/TS bring their own templates but share the same encoder/decoder runtime.
  • OSSL_ENCODER / OSSL_DECODER in providers/implementations/encode_decode/ ultimately produce the same DER bytes; they are a thin layer on top of the ASN.1 system for keys.

Entry points for modification

  • New ASN.1 type: declare with ASN1_SEQUENCE / IMPLEMENT_ASN1_FUNCTIONS in the appropriate crypto/<area>/<area>_asn.c. Add i2d_*, d2i_*, *_new, *_free to a public header (with the new symbols also added to util/libcrypto.num via make update).
  • New OID: crypto/objects/objects.txt, then make update.
  • Tightening parser limits: crypto/asn1/asn1_local.h and tasn_dec.c.

Documentation

  • doc/man3/d2i_X509.pod — covers the d2i_*/i2d_* family.
  • doc/man3/ASN1_*.pod — type accessors.
  • doc/man7/x509.pod — overview of the X.509 stack that ASN.1 underpins.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

ASN.1 – OpenSSL wiki | Factory