ASN.1 Overview

The ASN.1 family of standards define a number of ways to encode data, including byte-oriented (e.g., BER), bit-oriented (e.g., PER), and textual (e.g., XER). Some encoding variants (e.g., DER) are just stricter variants of the more general encodings (e.g., BER).

This variant of the asn1c compiler provides automatic Python bindings for:

  • Basic ASN.1 types (INTEGER, BOOLEAN, REAL, etc.)

  • Enumerated types

  • Named bit string (flags) types

  • CHOICE types (unions)

  • SEQUENCE types (structs)

  • SET types (special structs) and

  • SEQUENCE OF / SET OF (collections)

ASN.1 Base Type

Each generated class follows a schema that can be represented by the following conceptual base class.

Warning

This class although not present in the actual module file can be used as the base class for all generated ASN.1 types, due to the shared interface.

class _Asn1Type

Each type alias, enumerated or constructed type WILL generate its own class. Each class will implement the methods described in this base class (TYPING ONLY!).

There are several terms used to annotate each function. Their meaning is as follows:

  • Required: These methods MUST be impleented by the subclass

  • Optional: Only some types implement these methods

  • Configurable: Methods annotated with this term are implemented based on compiler options.

__repr__(self) str

Required.

Returns a string with the class name, without the internal value.

__str__(self) str

Optional.

Returns the value of the ASN.1 object, if set, as a human-readable string. This method MAY be implemented by subtypes. Refer to each ASN.1 documentation to see whether the type implements this behavior.

Note

This method will simply call value.__str__() after converting it internally and if supported.

Validation and Constraint Checking

All generated types implement validation methods to check ASN.1 constraints as defined in the schema.

is_valid(self) bool

Required.

Checks whether the current value satisfies all constraints without raising an exception. Returns True if valid, False otherwise.

check_constraints(self) None

Required.

Validates the current value against ASN.1 constraints and raises a ValueError if any are violated.

Encoding and decoding methods are generated only if the corresponding encoding rule was enabled at compile time.

Basic Encoding Rules (BER)

The Basic Encoding Rules (X.690) describe the most widely used (by the ASN.1 community) way to encode and decode a given structure in a machine-independent way.

ber_encode(self) bytes

Configurable.

Encodes the value in BER format.

static ber_decode(data: bytes | Buffer) _Asn1Type

Configurable.

Decodes BER-encoded bytes into a new instance.

Canonical Encoding Rules (CER)

The Canonical Encoding Rules are a restricted form of BER that ensures a unique encoding for any given value.

Warning

The current implementation uses the BER encoder under the hood and no validation is performed.

cer_encode(self) bytes

Configurable.

Encodes the value in CER format.

static cer_decode(data: bytes | Buffer) _Asn1Type

Configurable.

Decodes CER-encoded bytes into a new instance.

Distinguished Encoding Rules (DER)

The Distinguished Encoding Rules are another restricted subset of BER (canonical BER), similar to CER, but optimized for certain cryptographic applications.

der_encode(self) bytes

Configurable.

Encodes the value in DER format.

static der_decode(data: bytes | Buffer) _Asn1Type

Configurable.

Decodes DER-encoded bytes into a new instance.

XML Encoding Rules (XER)

The XML Encoding Rules (X.693) define how ASN.1 structures are represented in XML. XER provides a human-readable form of the data and may be canonicalized to ensure deterministic output.

xer_encode(self, /, *, canonical: bool = ...) bytes

Configurable.

Encodes the value in XER format. If canonical is True, produces canonical XML form.

static xer_decode(data: bytes | Buffer, /, *, canonical: bool = ...) _Asn1Type

Configurable.

Decodes XER-encoded bytes into a new instance. If canonical is True, enforces canonical XML parsing.

JSON Encoding Rules (JER)

The JSON Encoding Rules (X.697) map ASN.1 structures to JSON format for use in web-based APIs and systems. Output may be either compact (minified) or human-readable.

jer_encode(self, /, *, minified: bool = ...) bytes

Configurable.

Encodes the value in JSON format. If minified is True, outputs a compact single-line JSON representation.

static jer_decode(data: bytes | Buffer, /, *, minified: bool = ...) _Asn1Type

Configurable.

Decodes JSON-formatted bytes into a new instance. If minified is True, expects compact JSON input.

Octet Encoding Rules (OER)

The Octet Encoding Rules (X.696) provide a compact binary representation optimized for environments with limited resources.

oer_encode(self, /, *, canonical: bool = ...) bytes

Configurable.

Encodes the value in OER format. If canonical is True, produces canonical octet output.

static oer_decode(data: bytes | Buffer, /, *, canonical: bool = ...) _Asn1Type

Configurable.

Decodes OER-encoded bytes into a new instance.

Packed Encoding Rules (PER)

The Packed Encoding Rules (X.691) are a highly efficient binary encoding that omits most length and type metadata. Data may be aligned (byte-padded) or unaligned (bit-packed).

per_encode(self, /, *, canonical: bool = ..., aligned: bool = ...) bytes

Configurable.

Encodes the value in PER format. If aligned is True, aligns data to byte boundaries. If canonical is True, enforces canonical PER output.

static per_decode(data: bytes | Buffer, /, *, canonical: bool = ..., aligned: bool = ...) _Asn1Type

Configurable.

Decodes PER-encoded bytes into a new instance. If aligned is True, expects byte-aligned PER input.

Non-standard textual representation

Some types support an additional non-standard, human-oriented textual form, primarily for debugging or logging.

to_text(self) bytes

Configurable.

Returns a textual representation of the value.

ASN.1 Conceptual BASIC Type

The Abstract Syntax Notation One (ASN.1) standard defines a set of basic types such as INTEGER, BOOLEAN, REAL, OCTET STRING, and others. These basic types are mapped to native Python types where possible for ease of use. A high-level conversion matrix is given below:

ASN.1 Type

Python Equivalent

INTEGER

int

BOOLEAN

bool

REAL

float

OCTET STRING

bytes

UTF8String

str

BIT STRING

bitarray (external)

NULL

None

OID

str

Each new basic type definition in an ASN.1 module will generate a corresponding Python class. For example, defining a new INTEGER type:

MyInteger ::= INTEGER

will generate a Python class:

class MyInteger(_Asn1BasicType[int]):
    pass

Important

When a basic type is used inside a SEQUENCE, CHOICE, or other constructed type with or without being given its own type name, it is inlined, meaning the type wrapper won’t be used and conversion from the value type is incorporated directly.

All generated Python classes — excluding those with named values (e.g. ENUMERATED types) — follow the conceptual API defined by the _Asn1BasicType class below.

class _Asn1BasicType[_PY_T]

Inherits from _Asn1Type.

A conceptual base class for all ASN.1 basic types. Each basic type stores its underlying value in a property called value.

__init__(self, value: _PY_T | None = None) None

Required.

Initializes a new ASN.1 basic type instance. If value is provided, it is assigned to the value property after validation and (if necessary) conversion to the appropriate internal representation.

If value is None, the instance is created in an unset state.

Note

Initialization with a Python type other than the target type is allowed if the type supports automatic conversion. For example, an OCTET STRING type may accept both bytes and bytearray at initialization.

property value: _PY_T

Required.

The current value of the ASN.1 object, represented as the mapped Python type.

This property may be reassigned after initialization, and assignments will be validated against the ASN.1 type conversion constraints. Type constrains defined in the ASN.1 file won’t be checked after the assignment.

Note

Directly setting a value that violates the type (e.g., assigning a string to an INTEGER type) will raise a TypeError or ValueError.

ASN.1 Conceptual Enumerated Type

The ASN.1 ENUMERATED type (or named INTEGER) defines a finite set of named integer values. In the generated Python bindings, these are represented as classes that:

  • Contain an embedded VALUES enumeration (a subclass of enum.IntEnum).

  • Store their current value as one of these VALUES members (or its integer equivalent).

  • Provide both integer and enum-based semantics for assignment and comparison.

For example:

MyEnum ::= ENUMERATED {
    firstOption (0),
    secondOption(1),
    thirdOption (2)
}

will generate a Python class:

class MyEnum(_BasicAsn1EnumType):
    class VALUES(enum.IntEnum):
        V_firstOption  = 0
        V_secondOption = 1
        V_thirdOption  = 2

Note

Unlike simple INTEGER aliases, ENUMERATED and name INTEGER types always produce a dedicated Python class with its own VALUES inner enumeration.

All generated Python ENUMERATED classes conform to the following conceptual API:

class _Asn1EnumType

Inherits from _Asn1Type.

Conceptual base class for all ASN.1 ENUMERATED types.

class VALUES(enum.IntEnum)

Required.

Inner enumeration containing all named values defined in the ASN.1 type. Each member is prefixed with V_ to avoid name clashes with class-level constants or methods.

Example:

class VALUES(enum.IntEnum):
    V_firstOption = 0
    V_secondOption = 1
    V_thirdOption = 2
property value: _BasicAsn1EnumType.VALUES

Required.

Holds the current value of the enumeration as a VALUES member.

This property accepts assignment using either:

  • A member of VALUES (e.g., MyEnum.VALUES.V_firstOption)

  • An integer corresponding to a valid VALUES member

Warning

Assigning an integer that does not correspond to any member of VALUES will raise a ValueError when accessing the value, NOT when assigning it.

__init__(self, value: _BasicAsn1EnumType.VALUES | int | None = None) None

Required.

Initializes a new ENUMERATED instance with the given value. If None is provided, the instance is created in an unset state.

ASN.1 Conceptual Named BIT STRING Type

The ASN.1 BIT STRING type can be defined with named bit positions, often used to represent a set of boolean flags. In the generated Python bindings, these named BIT STRING types are represented by classes that:

  • Contain an embedded VALUES enumeration (a subclass of enum.IntEnum).

  • Store their current value internally as a bitarray.bitarray.

  • Use little-endian alignment by default, while exposing a value_BE property to query or assign the big-endian aligned variant.

Note

Both value and value_BE return the raw bitarray.bitarray instance rather than an integer mask or enumeration.

Warning

Big-endian representation is only available via value_BE. The internal storage is always little-endian. Big-endian representation is not supported for anonymous inner named BIT STRING types.

Example:

MyFlags ::= BIT STRING {
    read(0),
    write(1),
    execute(2)
}

will generate a Python class:

class MyFlags(_BasicAsn1FlagType):
    class VALUES(enum.IntFlag):
        V_read      = 0
        V_write     = 1
        V_execute   = 2

Because the generated VALUES enumeration now stores the bit position directly (rather than the full mask), checking whether a flag is set is done by indexing into the underlying bitarray:

obj = MyFlags()

# Check if the 'read' flag is set
bool(obj.value[MyFlags.VALUES.V_read])  # True or False

All generated Python named BIT STRING classes conform to the following conceptual API:

class _Asn1FlagType

Inherits from _Asn1Type.

Conceptual base class for all ASN.1 named BIT STRING types.

class VALUES(enum.IntFlag)

Required.

Inner enumeration containing all named flag values defined in the ASN.1 type. Each member is prefixed with V_ to avoid name clashes.

Each flag’s value is the bit index in the underlying bitarray.

property value: bitarray.bitarray

Required.

Holds the current flag state as a little-endian bitarray.bitarray.

This property accepts assignment using:

  • A bitarray.bitarray object (must be little-endian aligned)

  • A bytes object containing the encoded BIT STRING

Accessing individual flags is done by indexing with a VALUES member.

Warning

Assigning a value containing bits that are not defined in VALUES will not raise an error, but those bits will be preserved and treated as unnamed flags.

property value_BE: bitarray.bitarray

Required.

Holds the current flag state as a big-endian bitarray.bitarray.

Similar to value, but the bit ordering is reversed. Assigning or querying this property transparently handles the endian conversion.

__init__(self, value: _BasicAsn1FlagType.VALUES | int | bytes | bitarray.bitarray | None = None) None

Required.

Initializes a new BIT STRING instance with the given value. If None is provided, the instance is created in an unset state.

ASN.1 Conceptual CHOICE Type

The ASN.1 CHOICE type represents a union-like structure where only one of several possible fields can be set at any given time. This constraint is enforced in the generated Python classes to ensure data integrity and correct encoding.

Each CHOICE class exposes an internal enumeration PRESENT that tracks which field is currently active.

class _Asn1ChoiceType

Inherits from _Asn1Type.

class PRESENT(enum.IntEnum)

This enumeration contains all possible states corresponding to each member of the CHOICE. By convention, members are named PR_<member_name>. The default state PR_NOTHING indicates that no field is currently set.

__init__(self, /, **members: Any) None

Required.

Initializes a new CHOICE instance by setting exactly one field using keyword arguments. For example:

choice = MyChoice(field1=value1)

Attempting to set multiple fields simultaneously is disallowed.

present: _BasicAsn1ChoiceType.PRESENT

Required.

Reflects the currently active field of the CHOICE. Reading this property returns the corresponding PRESENT enum member, indicating which field is set.

Behavioral Notes

  • Only one field can be set at a time. Setting a new field automatically clears any previously set field.

  • Accessing an unset field returns None instead of raising an exception.

  • The CHOICE type behaves conceptually like a C union, but with Pythonic safety checks and clear state tracking.

ASN.1 Conceptual List Type

The _Asn1ListType class is the conceptual base for all generated Python classes that represent ASN.1 SEQUENCE OF and SET OF types.

These ASN.1 types hold an ordered or unordered collection of elements of the same type:

  • SEQUENCE OF preserves the element order.

  • SET OF does not guarantee ordering in ASN.1 semantics (although Python will typically maintain insertion order internally).

In Python, the generated classes behave like mutable sequences (similar to lists) and implement part of Python’s mapping protocol, allowing index-based access and assignment. To convert such an ASN.1 list to a native Python list, use list(my_obj).

Example ASN.1 definition:

MySequenceOfIntegers ::= SEQUENCE OF INTEGER

which generates a Python class roughly equivalent to:

class MySequenceOfIntegers(_Asn1ListType[int]):
    pass

Each generated Python class conforms to the conceptual list type specified below. However, there are some constrains when using this type:

  • Deletion is supported with del my_obj[index], but there is no direct remove(value) method.

  • Values assigned to the collection are converted to the target ASN.1 Python type automatically (see the conversion model).

  • Mutating the returned Python element directly will not update the internal ASN.1 representation unless explicitly re-assigned.

class _Asn1ListType[_PY_T]

Inherits from _Asn1Type.

Represents a SEQUENCE OF or SET OF ASN.1 type containing elements of type _PY_T.

__init__(self, values: Iterable[_PY_T] | None = None) None

Required.

Initializes the collection with an optional iterable of elements.

__len__(self) int

Required.

Returns the number of elements in the collection.

__getitem__(self, index: int) _PY_T

Required.

Retrieves the element at the specified index.

__setitem__(self, index: int, value: _PY_T) None

Required.

Replaces the element at the specified index with value.

__delitem__(self, index: int) None

Required.

Removes the element at the specified index.

add(self, value: _PY_T) None

Required.

Appends a single element to the end of the collection.

extend(self, values: Iterable[_PY_T]) None

Required.

Appends multiple elements from the iterable values.

clear(self) None

Required.

Removes all elements from the collection.