PYTHON-ASN1(1)

NAME
python-asn1 - Python-ASN1 3.3.0 [image: GitHub Actions] [image]
 <https://github.com/andrivet/python-asn1> [image: PyPI Package latest release] [image]
 <https://pypi.org/project/asn1/> [image: PyPI Wheel] [image]
 <https://pypi.org/project/asn1/> [image: Supported versions] [image]
 <https://pypi.org/project/asn1/> [image: Supported implementations] [image]
 <https://pypi.org/project/asn1/>

OVERVIEW

Python-ASN1 is a simple ASN.1 encoder and decoder for Python 2.7 and 3.5+.

  Features

•   Support BER (parser) and DER (parser and generator) encoding (including indefinite lengths)

•   100% python, compatible with version 2.7, 3.5 and higher

•   Can be integrated by just including a file into your project

•   Support most common ASN.1 types including REAL (encoding and decoding).

  Dependencies

Python-ASN1 relies on Python-Future <https://python-future.org> for Python 2 and 3 compatibility. To install Python-Future:

    pip install future

Python-ASN1 relies on type hints <https://docs.python.org/3/library/typing.html>. For Python 2.7, a backport of the standard library typing module has to be installed:

    pip install typing

This is not necessary for Python 3.5 and higher since it is part of the standard library.

  How to install Python-asn1

Install from PyPi with the following:

    pip install asn1

or download the repository from GitHub <https://github.com/andrivet/python-asn1> and install with the following:

    python setup.py install

You can also simply include asn1.py into your project.

  How to use Python-asn1

Note: You can find more detailed documentation on the Usage <usage.rst> page.

  Encoding

If you want to encode data and retrieve its DER-encoded representation, use code such as:

    import asn1
    encoder = asn1.Encoder()
    encoder.start()
    encoder.write('1.2.3', asn1.Numbers.ObjectIdentifier)
    encoded_bytes = encoder.output()

  Decoding

If you want to decode ASN.1 from DER or BER encoded bytes, use code such as:

    import asn1
    decoder = asn1.Decoder()
    decoder.start(encoded_bytes)
    tag, value = decoder.read()

  Documentation

The complete documentation is available on Read The Docs:

python-asn1.readthedocs.io <https://python-asn1.readthedocs.io/en/latest/>

  Contributing

Contributions to Python-ASN1 are welcome. If you want to contribute, please fork the repository on GitHub, make your changes and submit a pull request (PR). Please make sure that your code is properly tested and that all tests pass. In particular, tests should pass for old versions of Python (2.7 and from 3.5 to 3.14). You can use the provided Docker file to test your code on all those versions of Python.

  License

Python-ASN1 is free software that is made available under the MIT license. Consult the file LICENSE that is distributed together with this library for the exact licensing terms.

  Copyright

The following people have contributed to Python-ASN1. Collectively they own the copyright of this software.

•   Geert Jansen (<geert@boskant.nl>): original implementation <https://github.com/geertj/python-asn1>.

•   Sebastien Andrivet (<sebastien@andrivet.com>)

•   Filippo Santovito (<filippo.santovito@gmail.com>)

INSTALLATION

Install from PyPi <https://pypi.org/project/asn1/> with the following:

    pip install asn1

or download the repository from GitHub <https://github.com/andrivet/python-asn1> and install with the following:

    python setup.py install

You can also simply include asn1.py into your project.

USAGE

Note: You can find a complete example in Examples <>.

The Python-ASN1 API is exposed by a single Python module named asn1 <#module-asn1>. The main interface is provided by the following classes:

•   Encoder <#asn1.Encoder>: Used to encode ASN.1.

•   Decoder <#asn1.Decoder>: Used to decode ASN.1.

•   Error <#asn1.Error>: Exception used to signal errors.

  Type Mapping

The Python-ASN1 encoder and decoder make a difference between primitive and constructed data types. Primitive data types can be encoded and decoded directly with read() <#asn1.Decoder.read> and write() <#asn1.Encoder.write> methods. For these types, ASN.1 types are mapped directly to Python types and vice versa, as per the table below:
ASN.1 type | Tag Number | Decoding | Encoding
Boolean | 0x01 | bool | bool
Integer | 0x02 | int | int
Null | 0x05 | None | None
ObjectIdentifier | 0x06 | str |
Real | 0x09 | float | float
Enumerated | 0x0A | int |

Because ASN.1 has more data types than Python, the situation arises that one Python type corresponds to multiple ASN.1 types. In this situation, the to be encoded ASN.1 type cannot be determined from the Python type. The solution implemented in Python-ASN1 is that the most frequently used type will be the implicit default. This is indicated in the Encoding column. If another type is desired than that must be specified explicitly through the API.

Some ASN.1 types can be either primitive or constructed. They can be encoded and decoded like primitive types. The following table shows the mapping between ASN.1 types and Python types.
ASN.1 type | Tag Number | Decoding | Encoding
BitString | 0x03 | bytes |
OctetString | 0x04 | bytes | bytes
UTF8String | 0x0C | str |
NumericString | 0x12 | str |
PrintableString | 0x13 | str | str
T61String | 0x14 | str |
VideotextString | 0x15 | str |
IA5String | 0x16 | str |
GraphicString | 0x19 | str |
VisibleString | 0x1A | str |
GeneralString | 0x1B | str |
UniversalString | 0x1C | str |
CharacterString | 0x1D | str |
UnicodeString | 0x1E | str |

For constructed types, there are two possibilities. The first is to treat them as a sequence of types. In this case, the encoder and decoder will automatically map the ASN.1 types to Python types and vice versa.
ASN.1 type | Tag Number | Decoding | Encoding
Sequence | 0x10 | list | list
Set | 0x11 | list |

The second possibility is to treat them as a stack of types. In this approach, the user needs to explicitly enter/leave the constructed type using the Encoder.enter() <#asn1.Encoder.enter> and Encoder.leave() <#asn1.Encoder.leave> methods of the encoder and the Decoder.enter() <#asn1.Decoder.enter> and Decoder.leave() <#asn1.Decoder.leave> methods of the decoder.

  Encoding

If you want to encode data and retrieve its DER-encoded representation, use code such as:

    import asn1
    encoder = asn1.Encoder()
    encoder.start()
    encoder.write('1.2.3', asn1.Numbers.ObjectIdentifier)
    encoded_bytes = encoder.output()

or using the new context manager api:

    import asn1
    with asn1.Encoder() as encoder:
        encoder.write('1.2.3', asn1.Numbers.ObjectIdentifier)
        encoded_bytes = encoder.output()

It is also possible to encode data directly to a file or any stream:

    import asn1
    with open('output.der', 'wb') as f:
      encoder = asn1.Encoder()
      encoder.start(f)
      encoder.write('1.2.3', asn1.Numbers.ObjectIdentifier)

or using the new context manager api:

    import asn1
    with open('output.der', 'wb') as f:
      with asn1.Encoder(stream=f) as encoder:
          encoder.write('1.2.3', asn1.Numbers.ObjectIdentifier)

You can encode complex data structures such as sequences and sets:

    import asn1
    with open('output.der', 'wb') as f:
          encoder = asn1.Encoder()
          encoder.start(f)
          encoder.write(['test1', 'test2', [
              1,
              0.125,
              b'\x01\x02\x03'
          ]])

ASN.1 types are automatically mapped to Python types. If you want to precisely specify the ASN.1 type, you have to use the Encoder.enter() <#asn1.Encoder.enter> and Encoder.leave() <#asn1.Encoder.leave> methods:

    import asn1
    with open('output.der', 'wb') as f:
          encoder = asn1.Encoder()
          encoder.start(f)
          encoder.enter(asn1.Numbers.Sequence)
          encoder.write('test1', asn1.Numbers.PrintableString)
          encoder.write('test2', asn1.Numbers.PrintableString)
          encoder.enter(asn1.Numbers.Sequence)
          encoder.write(1, asn1.Numbers.Integer)
          encoder.write(0.125, asn1.Numbers.Real)
          encoder.write(b'\x01\x02\x03', asn1.Numbers.OctetString)
          encoder.leave()
          encoder.leave()

or using the new context manager api:

    import asn1
    with open('output.der', 'wb') as f:
          with asn1.Encoder(stream=f) as encoder:
              with encoder.sequence():
                  encoder.write('test1', asn1.Numbers.PrintableString)
                  encoder.write('test2', asn1.Numbers.PrintableString)
                  with encoder.sequence():
                      encoder.write(1, asn1.Numbers.Integer)
                      encoder.write(0.125, asn1.Numbers.Real)
                      encoder.write(b'\x01\x02\x03', asn1.Numbers.OctetString)

This also allows to encode data progressively, without having to keep everything in memory.

A value can be encoded with an explicit Number, Type or Class:

    import asn1
    encoder = asn1.Encoder()
    encoder.start()
    enc.write(55, nr=asn1.Numbers.Integer, typ=asn1.Types.Primitive, cls=asn1.Classes.Application)
    encoded_bytes = encoder.output()

  DER and CER

The encoder uses DER (Distinguished Encoding Rules) encoding by default. If you want to use CER (Canonical Encoding Rules) encoding, you can do so by calling the Encoder.start() <#asn1.Encoder.start> method with a stream as argument:

    stream = open('output.cer', 'wb')
    encoder = asn1.Encoder()
    encoder.start(stream)

You can explicitly specify the CER encoding without using a stream:

    encoder = asn1.Encoder()
    encoder.start(Encoder.CER)

You can explicitly specify the DER encoding when using a stream:

    stream = open('output.cer', 'wb')
    encoder = asn1.Encoder()
    encoder.start(stream, Encoder.DER)

DER has the advantage to be predicatable: there is one and only one way to encode a message using DER. DER is commonly used in security-related applications such as X.509 digital certificates. DER uses definite lengths for all encoded messages. This means that the length of the encoded message is known in advance. This is useful for encoding messages that are fixed in size or that do not change in size over time. The disadvantage of DER is that the encoded binary data are kept in memory until the encoding is finished. This can be a problem for very large messages.

CER is similar to DER, but it uses indefinite lengths. This means that the length of the encoded message is not known in advance. This is useful for encoding messages that may be very large or that may change in size over time. The advantage of CER is that the encoded binary data are not kept in memory until the encoding is finished. This means that the encoder can start writing the encoded message to a file or a stream as soon as it is available.

IMPORTANT: There was a mistake in version 3.0.0 of Python-ASN1 where the encoder used CER encoding by default contrary to the previous versions that were using DER. This was fixed in version 3.0.1: CER is the default encoding when using a stream. Otherwise, DER is the default encoding.

  Decoding

If you want to decode ASN.1 from BER (DER, CER, ...) encoded bytes, use code such as:

    import asn1
    decoder = asn1.Decoder()
    decoder.start(encoded_bytes)
    tag, value = decoder.read()

or using the new context manager api:

    import asn1
    with asn1.Decoder(stream=encoded_bytes) as decoder:
        tag, value = decoder.read()

It is also possible to decode data directly from a file or any stream:

    import asn1
    with open('input.der', 'rb') as f:
      decoder = asn1.Decoder()
      decoder.start(f)
      tag, value = decoder.read()

You can decode complex data structures. The decoder will automatically map ASN.1 types to Python types:

    import asn1
    with open('example7.der', 'rb') as f:
        decoder = asn1.Decoder()
        decoder.start(f)
        tag, value = decoder.read()
        print(tag)
        pprint.pprint(value)

You can ask the decoder to return the number of unused bits when decoding a BitString:

    import asn1
    encoded = b'\x23\x0C\x03\x02\x00\x0B\x03\x02\x00\x0B\x03\x02\x04\x0F'
    decoder = asn1.Decoder()
    decoder.start(encoded)
    tag, (value, unused) = decoder.read(asn1.ReadFlags.WithUnused)
    print('Tag: ', tag)
    print('Value: ', value)
    print('Unused bits: ', unused)

The flag ReadFlags.WithUnused can be used with any ASN.1 type. When used, the read method will return a tuple with the value and the number of unused bits. If the type is not a BitString, the number of unused bits is always 0.

  Constants

A few constants are defined in the asn1 <#module-asn1> module. The constants immediately below correspond to ASN.1 tag numbers. They can be used as the nr parameter of the Encoder.write() <#asn1.Encoder.write> method, and are returned as the first part of a (nr, typ, cls) tuple as returned by Decoder.peek() <#asn1.Decoder.peek> and Decoder.read() <#asn1.Decoder.read>.
Constant | Value (hex)
Numbers.Boolean | 0x01
Numbers.Integer | 0x02
Numbers.BitString | 0x03
Numbers.OctetString | 0x04
Numbers.Null | 0x05
Numbers.ObjectIdentifier | 0x06
Numbers.ObjectDescriptor | 0x07
Numbers.External | 0x08
Numbers.Real | 0x09
Numbers.Enumerated | 0x0a
Numbers.EmbeddedPDV | 0x0b
Numbers.UTF8String | 0x0c
Numbers.RelativeOID | 0x0d
Numbers.Time | 0x0e
Numbers.Sequence | 0x10
Numbers.Set | 0x11
Numbers.NumericString | 0x12
Numbers.PrintableString | 0x13
Numbers.T61String | 0x14
Numbers.VideotextString | 0x15
Numbers.IA5String | 0x16
Numbers.UTCTime | 0x17
Numbers.GeneralizedTime | 0x18
Numbers.GraphicString | 0x19
Numbers.VisibleString | 0x1a
Numbers.GeneralString | 0x1b
Numbers.UniversalString | 0x1c
Numbers.CharacterString | 0x1d
Numbers.UnicodeString | 0x1e
Numbers.Date | 0x1f
Numbers.TimeOfDay | 0x20
Numbers.DateTime | 0x21
Numbers.Duration | 0x22
Numbers.OIDinternationalized | 0x23
Numbers.RelativeOIDinternationalized | 0x24

The following constants define the two available encoding types (primitive and constructed) for ASN.1 data types. As above they can be used with the Encoder.write() <#asn1.Encoder.write> and are returned by Decoder.peek() <#asn1.Decoder.peek> and Decoder.read() <#asn1.Decoder.read>.
Constant | Value (hex)
Types.Constructed | 0x20
Types.Primitive | 0x00

Finally the constants below define the different ASN.1 classes. As above they can be used with the Encoder.write() <#asn1.Encoder.write> and are returned by Decoder.peek() <#asn1.Decoder.peek> and Decoder.read() <#asn1.Decoder.read>.
Constant | Value (hex)
Classes.Universal | 0x00
Classes.Application | 0x40
Classes.Context | 0x80
Classes.Private | 0xc0

EXAMPLES

  Dump

This command line utility reads a X509.v3 certificate (in DER or PEM encoding), decodes it and outputs a textual representation. It more or less mimics openssl asn1parse <https://docs.openssl.org/1.1.1/man1/openssl-asn1parse/>:

    $ python examples/dump.py examples/test.crt
    [U] SEQUENCE
      [U] SEQUENCE
        [C] 0x0
          [U] INTEGER: 2
        [U] INTEGER: 5424
        [U] SEQUENCE
          [U] OBJECT: 1.2.840.113549.1.1.5
          [U] NULL: None
        [U] SEQUENCE
          [U] SET
            [U] SEQUENCE
              [U] OBJECT: 2.5.4.6
              [U] PRINTABLESTRING: --
          [U] SET
            [U] SEQUENCE
              [U] OBJECT: 2.5.4.8
              [U] PRINTABLESTRING: SomeState
          [U] SET
            [U] SEQUENCE
              [U] OBJECT: 2.5.4.7
              [U] PRINTABLESTRING: SomeCity
          [U] SET
            [U] SEQUENCE
              [U] OBJECT: 2.5.4.10
              [U] PRINTABLESTRING: SomeOrganization
          [U] SET
            [U] SEQUENCE
              [U] OBJECT: 2.5.4.11
              [U] PRINTABLESTRING: SomeOrganizationalUnit
          [U] SET
            [U] SEQUENCE
              [U] OBJECT: 2.5.4.3
              [U] PRINTABLESTRING: localhost.localdomain
          [U] SET
            [U] SEQUENCE
              [U] OBJECT: 1.2.840.113549.1.9.1
              [U] IA5STRING: root@localhost.localdomain
        [U] SEQUENCE
          [U] UTCTIME: 080205092331Z
          [U] UTCTIME: 090204092331Z
        [U] SEQUENCE
          [U] SET
            [U] SEQUENCE
              [U] OBJECT: 2.5.4.6
              [U] PRINTABLESTRING: --
          [U] SET
            [U] SEQUENCE
              [U] OBJECT: 2.5.4.8
              [U] PRINTABLESTRING: SomeState
          [U] SET
            [U] SEQUENCE
              [U] OBJECT: 2.5.4.7
              [U] PRINTABLESTRING: SomeCity
          [U] SET
            [U] SEQUENCE
              [U] OBJECT: 2.5.4.10
              [U] PRINTABLESTRING: SomeOrganization
          [U] SET
            [U] SEQUENCE
              [U] OBJECT: 2.5.4.11
              [U] PRINTABLESTRING: SomeOrganizationalUnit
          [U] SET
            [U] SEQUENCE
              [U] OBJECT: 2.5.4.3
              [U] PRINTABLESTRING: localhost.localdomain
          [U] SET
            [U] SEQUENCE
              [U] OBJECT: 1.2.840.113549.1.9.1
              [U] IA5STRING: root@localhost.localdomain
        [U] SEQUENCE
          [U] SEQUENCE
            [U] OBJECT: 1.2.840.113549.1.1.1
            [U] NULL: None
          [U] BIT STRING: 0xb'0030818902818100D51...10610203010001'
        [C] BIT STRING
          [U] SEQUENCE
            [U] SEQUENCE
              [U] OBJECT: 2.5.29.14
              [U] OCTET STRING: 0xb'04140A4BFA8754177E30B4217156510FD291C3300236'
            [U] SEQUENCE
              [U] OBJECT: 2.5.29.35
              [U] OCTET STRING: 0xb'3081DE80140A4...D61696E82021530'
            [U] SEQUENCE
              [U] OBJECT: 2.5.29.19
              [U] OCTET STRING: 0xb'30030101FF'
      [U] SEQUENCE
        [U] OBJECT: 1.2.840.113549.1.1.5
        [U] NULL: None
      [U] BIT STRING: 0xb'004E124658A357C59AABFA3...8A6245C7FC58B45A'

The main function is pretty_print:

    def pretty_print(input_stream, output_stream, indent=0):
         """Pretty print ASN.1 data."""
         while not input_stream.eof():
             tag = input_stream.peek()
             if tag.typ == asn1.Types.Primitive:
                 tag, value = input_stream.read()
                 output_stream.write(' ' * indent)
                 output_stream.write('[{}] {}: {}\n'.format(class_id_to_string(tag.cls),
                     tag_id_to_string(tag.nr), value_to_string(tag.nr, value)))
             elif tag.typ == asn1.Types.Constructed:
                 output_stream.write(' ' * indent)
                 output_stream.write('[{}] {}\n'.format(class_id_to_string(tag.cls),
                     tag_id_to_string(tag.nr)))
                 input_stream.enter()
                 pretty_print(input_stream, output_stream, indent + 2)
                 input_stream.leave()

This code:

•   line 3: Loops until its reaches the end of the input stream (with Decoder.eof() <#asn1.Decoder.eof>).

•   line 4: Looks (with Decoder.peek() <#asn1.Decoder.peek>) at the current tag.

•   line 5: If the tag is primitive (TypePrimitive) ...

•   line 6: ... the code reads (with Decoder.read() <#asn1.Decoder.read>) the current tag.

•   line 8: Then it displays its number and value (after some mapping to be more user-fiendly).

•   line 10: If the tag is constructed (TypeConstructed) ...

•   line 12: ... the code displays its class and number.

•   line 14: Then it enters inside the tag and ...

•   line 15: ... calls itself recursively to decode the ASN.1 tags inside.

•   line 16: Leaves the current constructed tag (with Decoder.leave() <#asn1.Decoder.leave>) to continue the decoding of its siblings.

INTRODUCTION TO ASN.1

ASN.1 is short for Abstract Syntax Notation One <https://www.itu.int/en/ITU-T/studygroups/2017-2020/17/Pages/default.aspx>. It is a joint ISO/IEC and ITU-T standard for describing the syntax and encoding of data structures in a platform independent way. The syntax of data structures in ASN.1 is described by a syntax definiton language. This language is used to compose ever more complex data types from a few simple ones such as integer and string. Often you will see this language in other standards that define an application on top of ASN.1 (for example LDAP). It is outside the scope of this introduction to go any deeper into the ASN.1 syntax definition language.

The encoding of data structures in ASN.1 is defined by so-called encoding rules. Not just one but many encoding rules exist, and occasionally new ones are added. Each of the encoding rules is powerful enough to encode any data type specified by the ASN.1 language. Because of the multiple encoding rules, it also means that is it not enough to know that a piece of data is ASN.1 to decode it: you also need to know the encoding rules with which it was encoded.

ASN.1 was first conceived in 1984. Some people say it is old, other say it is mature. Fact is that many Internet protocols are built on top of ASN.1. Some of the most important of these protocols are:

•   LDAP (Lightweight Directory Access Protocol)

•   Kerberos (network authentication protocol

•   SNMP (Simple Network Management Protocol)

•   X.509 (public key infrastructure, known from e.g. SSL certificates)

    ASN.1 is not the only standard for defining the syntax and encoding of data structures. Other standards are Sun's XDR <https://datatracker.ietf.org/doc/html/rfc4506> (External Data Representation), and EBNF <https://standards.iso.org/ittf/PubliclyAvailableStandards/s026153_ISO_IEC_14977_1996(E).zip> (Extended Backus-Naur Form). XDR is used primarily for ONC-RPC applications such as NFS (the Network File System). EBNF is perhaps the most used standard of them all: HTTP and XML (and thereby all its applications) are specified in EBNF.

  ASN.1 Data Types or Tags

ASN.1 data types are either primitive data types such as integers and strings, or more complex ones built on them. Whatever the details of the data type, each of them has the following properties.

•   Its number.The number is a numerical identifier that identifies the data type uniquely amongst others in its class. For example, ASN.1 defines that the type integer has the number 2.

•   Its class. Four classes exist: universal, application, context, private. Each class defines the scope of the data type, i.e. how broad is the type available. Universal types are always available while the other ones are more restricted. All standard primitive types that are defined by ASN.1 are defined in the universal class.

•   Its encoding type (or just type). Two types exist: primitive and constructed. Primitively types contain just one data value such as a number or a string, while constructed types contain a collection of other primitive or constructed types.

    The three properties together (number, class, type) are also called the tag of a data type.

  ASN.1 Encoding

As mentioned above, the encoding of data structures is defined by ASN.1 encoding rules. The most well-known encodings rules are:

•   BER (Basic Encoding Rules)

•   DER (Distinguished Encoding Rules)

    The BER and DER encodings are very similar: BER is a looser format and sometimes allows a single value to be encoded in different ways. The DER is a subset of BER and defines in case multiple encodings are possible which one needs to be used. This means that a BER parser can read DER (because that is just a special form of BER), and a DER generator automatically generates valid BER (because all DER is also BER.)

    Python-ASN1 supports the DER and BER, and none of the other encoding rules. The vast majority of applications use these encoding rules, so at the moment no support for additional encoding rules is planned. When generating ASN.1, Python-ASN1 will output DER, while for parsing it supports BER. This arrangement complies with the practise of being forgiving on input, and strict on output.

    The DER and BER encodings work according the the TLV (Tag, Length, Value) principle. A stream of encoded ASN.1 data consists of a sequence of zero or more (tags, lenght, value) tuples, one after the other. These tuples are also called records in this manual, although this is not a term that is defined in the ASN.1 standard. For each data type, DER and BER define how to encode the tag (which we remember is a combination of its number, class and type), the length (in octets) of the data value, and the data value itself.

    Because DER encoding results in a truly binary representation of the encoded data, a format has been devised for being able to send these in an encoding of printable characters so you can actually mail these things.

•   PEM (Privacy Enhanced Mail) defined in RFC 1421. In essence PEM files are just base64 encoded versions of the DER encoded data. In order to distinguish from the outside what kind of data is inside the DER encoded string, a header and footer are present around the data.

  References

•   ASN.1 ITU-T Study Group 17 - Languages for Telecommunication Systems <https://www.itu.int/en/ITU-T/studygroups/2017-2020/17/Pages/default.aspx>

•   XDR External Data Representation Standard <https://datatracker.ietf.org/doc/html/rfc4506>

•   EBNF ISO/IEC 14977: Information technology -- Syntactic metalanguage -- Extended BNF <https://standards.iso.org/ittf/PubliclyAvailableStandards/s026153_ISO_IEC_14977_1996(E).zip>

REFERENCE

  asn1

class asn1.Classes(*values)
    ASN.1 tag classes.

class asn1.Decoder(stream: RawIOBase | BufferedIOBase | bytes | None = None)
    ASN.1 decoder. Understands BER (and DER which is a subset).

enter() -> None
    This method enters the constructed type that is at the current decoding offset.

    Note: It is an error to call Decoder.enter() if the to be decoded ASN.1 tag is not of a constructed type. It is no more necessary to call this method. It is kept only for compatibility with previous versions of the library.

Returns
    None

eof() -> bool
    Return True if we are at the end of input.

Returns
    bool -- True if all input has been decoded, and False otherwise.

leave() -> None
    This method leaves the last constructed type that was Decoder.enter()-ed.

    Note: It is an error to call Decoder.leave() if the current ASN.1 tag is not of a constructed type. It is no more necessary to call this method. It is kept only for compatibility with previous versions of the library.

Returns
    None

peek() -> Tag <#asn1.Tag> | None
    This method returns the current ASN.1 tag (i.e. the tag that a subsequent Decoder.read() call would return) without updating the decoding offset. In case no more data is available from the input, this method returns None to signal end-of-file.

    This method is useful if you don't know whether the next tag will be a primitive or a constructed tag. Depending on the return value of peek, you would decide to either issue a Decoder.read() in case of a primitive type, or an Decoder.enter() in case of a constructed type.

    Note: Because this method does not advance the current offset in the input, calling it multiple times in a row will return the same value for all calls.

Returns
    Tag -- The current ASN.1 tag.

Raises
    Error <#asn1.Error> --

read(flags: ReadFlags <#asn1.ReadFlags> = ReadFlags.OnlyValue) -> Tuple[Tag <#asn1.Tag> | None, Any]
    This method decodes one ASN.1 tag from the input and returns it as a (tag, value) tuple. tag is a 3-tuple (nr, typ, cls), while value is a Python object representing the ASN.1 value. The number of unused bits can be requested in the flags parameter. When ReadFlags.OnlyValue is specified, the method the tuple (tag, (value, unused)). unused is the number of unused bits removed from the value. The offset in the input is increased so that the next Decoder.read() call will return the next tag. In case no more data is available from the input, this method returns None to signal end-of-file.

Parameters
    flags (asn1.DecoderFlags) -- Return only the value or the value and the number of unused bits as a tuple.

Returns
    Tag, value -- The current ASN.1 tag, its value and the number of unused bits if requested in start.

Raises
    Error <#asn1.Error> --

start(stream: RawIOBase | BufferedIOBase | bytes) -> None
    This method instructs the decoder to start decoding an ASN.1 input. This method may be called at any time to start a new decoding job. If this method is called while currently decoding another input, that decoding context is discarded.

    Note: It is not necessary to specify the encoding because the decoder assumes the input is in BER or DER format.

Parameters
    stream (DecoderStream) -- ASN.1 input, in BER or DER format, to be decoded.

Returns
    None

Raises
    Error <#asn1.Error> --

class asn1.Encoder(stream: RawIOBase | BufferedWriter | None = None, encoding: Encoding <#asn1.Encoding> | None = None)
    ASN.1 encoder. Uses DER encoding.

construct(nr: int, cls: int | None = None) -> Generator[None, Any, None]
    This method is a context manager that calls the enter and leave methods for better code mapping.

    Usage:

        with encoder.construct(asn1.Numbers.Sequence):
            encoder.write(1)
            with encoder.construct(asn1.Numbers.Sequence):
                encoder.write('foo')
                encoder.write('bar')
            encoder.write(2)

    encoder.output() will result in the following structure:

        SEQUENCE:
            INTEGER: 1
            SEQUENCE:
                STRING: foo
                STRING: bar
            INTEGER: 2

Parameters

•   nr (int) -- The desired ASN.1 type. Use Numbers enumeration.

•   cls (int, optional) -- Specifies the class of the constructed type. The default class is the universal class. Use Classes enumeration.

Returns
    None

Raises
    Error <#asn1.Error> --

enter(nr: int, cls: int | None = None) -> None
    This method starts the construction of a constructed type.

Parameters

•   nr (int) -- The desired ASN.1 type. Use Numbers enumeration.

•   cls (int) -- This optional parameter specifies the class of the constructed type. The default class to use is the universal class. Use Classes enumeration.

Returns
    None

Raises
    Error <#asn1.Error> --

leave() -> None
    This method completes the construction of a constructed type and writes the encoded representation to the output stream.

output() -> bytes
    This method returns the encoded ASN.1 data as plain Python bytes. With DER encoding and a stream, this method has to be called when all data are encoded. Otherwise, the stream will contain partial data. With DER encoding and no stream, this method has to be called multiple times. The data that has been encoded so far is returned. When using CER encoding, you do not need to call it at all. With CER, this method can only be called when using a BytesIO stream or no stream.

    Note: It is an error to call this method if the encoder is still constructing a constructed type, i.e. if Encoder.enter() has been called more times that Encoder.leave().

Returns
    bytes -- The DER or CER encoded ASN.1 data.

Raises
    Error <#asn1.Error> --

start(stream: RawIOBase | BufferedWriter | None = None, encoding: Encoding <#asn1.Encoding> | None = None) -> None
    This method instructs the encoder to start encoding a new ASN.1 output. This method may be called at any time to reset the encoder and reset the current output (if any).

Parameters

•   stream (EncoderStream) -- The output stream or the encoding with no stream.

•   encoding (Encoding or None) -- The encoding (DER or CER) to use.

write(value: Any, nr: int | None = None, typ: int | None = None, cls: int | None = None) -> None
    This method encodes one ASN.1 tag and writes it to the output buffer.

    Note: Normally, value will be the only parameter to this method. In this case Python-ASN1 will autodetect the correct ASN.1 type from the type of value, and will output the encoded value based on this type.

Parameters

•   value (any) -- The value of the ASN.1 tag to write. Python-ASN1 will try to autodetect the correct ASN.1 type from the type of value.

•   nr (int) -- If the desired ASN.1 type cannot be autodetected or is autodetected wrongly, the nr parameter can be provided to specify the ASN.1 type to be used. Use Numbers enumeration.

•   typ (int) -- This optional parameter can be used to write constructed types to the output by setting it to indicate the constructed encoding type. In this case, value must already be valid ASN.1 encoded data as plain Python bytes. This is not normally how constructed types should be encoded though, see Encoder.enter() and Encoder.leave() for the recommended way of doing this. Use Types enumeration.

•   cls (int) -- This parameter can be used to override the class of the value. The default class is the universal class. Use Classes enumeration.

Returns
    None

Raises
    Error <#asn1.Error> --

class asn1.Encoding(*values)
    ASN.1 encoding types.

exception asn1.Error
    ASN.11 encoding or decoding error.

class asn1.Numbers(*values)
    ASN.1 tag numbers.

class asn1.ReadFlags(*values)
    How to read values that may have unused bits.

class asn1.Tag(nr, typ, cls)

cls Alias for field number 2

nr  Alias for field number 0

typ Alias for field number 1

class asn1.Types(*values)
    ASN.1 tag types.

CONTRIBUTING

Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given.

  Bug reports

When reporting a bug <https://github.com/andrivet/python-asn1/pulls> please include:

•   Your operating system name and version.

•   Any details about your local setup that might be helpful in troubleshooting.

•   Detailed steps to reproduce the bug.

  Documentation improvements

Python-ASN1 could always use more documentation, whether as part of the official Python-ASN1 docs, in docstrings, or even on the web in blog posts, articles, and such.

  Feature requests and feedback

The best way to send feedback is to file an issue at <https://github.com/andrivet/python-asn1/pulls>.

If you are proposing a feature:

•   Explain in detail how it would work.

•   Keep the scope as narrow as possible, to make it easier to implement.

•   Remember that this is a volunteer-driven project, and that code contributions are welcome :)

  Development

To set up Python-ASN1 for local development:

1.  Fork python-asn1 <https://github.com/andrivet/python-asn1> (look for the "Fork" button).

2.  Clone your fork locally:

        git clone git@github.com:your_name_here/python-asn1.git

3.  Create a branch for local development:

        git checkout -b name-of-your-bugfix-or-feature

    Now you can make your changes locally.

4.  When you're done making changes, run all the checks, doc builder and spell checker with tox <https://tox.wiki/en/latest/installation.html> one command:

        tox

5.  Commit your changes and push your branch to GitHub:

        git add .
        git commit -m "Your detailed description of your changes."
        git push origin name-of-your-bugfix-or-feature

6.  Submit a pull request through the GitHub website.

    To use the provided Docker file:

1.  Build the image:

        docker build -t python-asn1 .

2.  Run the tests:

        docker run --rm --name python-asn1 python-asn1

  Pull Request Guidelines

If you need some code review or feedback while you're developing the code just make the pull request.

For merging, you should:

1.  Include passing tests (run tox) [1].

2.  Update documentation when there's new API, functionality etc.

3.  Add a note to CHANGELOG.rst about the changes.

4.  Add yourself to AUTHORS.rst.

[1] If you don't have all the necessary python versions available locally you can rely on Travis - it will run the tests <https://app.travis-ci.com/andrivet/python-asn1/pull_requests> for each change you add in the pull request.

    It will be slower though ...

  Tips

To run a subset of tests:

    tox -e envname -- py.test -k test_myfeature

To run all the test environments in parallel (you need to pip install detox):

    detox

CREDITS

The following projects have provided inspiration for Python-ASN1:

•   pyasn1 <https://web.archive.org/web/20191231214902/http://snmplabs.com/pyasn1/index.html> This is another ASN1 encoder/decoder for Python.

•   Samba <https://github.com/samba-team/samba/tree/master/source3/libads> In particular libads for the stack based approach for building constructed types.

AUTHORS

The following people have contributed to Python-ASN1. Collectively they own the copyright of this software.

•   Geert Jansen <<geert@boskant.nl>>

•   Sebastien Andrivet <<sebastien@andrivet.com>>

•   Filippo Santovito <<filippo.santovito@gmail.com>>

LICENSE

Copyright (c) 2007-2026 the Python-ASN1 authors.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

CHANGELOG

  3.3.0 (2026-05-15)

•   Fix #298 - Incorrect handling of indefinite form length when using ENTER/LEAVE

•   Fix #296 - Support for writing IMPLICIT values

  3.2.0 (2026-02-06)

•

New API using a context manager

•   Support for using Encoder via context manager

•   Support for encoding sequences via context manager

•   Support for encoding sets via context manager

•   Support for using Decoder via context manager

•   Add support of Python 3.14

•   New way of installing old versions of Python in the Docker file. As a consequence, all versions of Python including 2.7 and from 3.5 to 3.14 are now properly tested.

  3.1.0 (2025-05-16)

•   #291 - Add support for mypy. As a consequence, the previous module has been migrated to a package.

  3.0.1 (2025-05-02)

•   Fix #288 - Use DER encoding by default as in previous versions

  3.0.0 (2025-03-03)

•   Encoding and decoding of the ASN.1 REAL type

•   Support of indefinite lengths

•   Encoding and decoding of complex data (lists, sets, ...)

•   Add support for streams (file-like objects) when encoding and decoding

•   Optionally return the number of unused bits when decoding a BitString (see also #276)

•   #286 - Add ASN.1:2008 compliance test suite

  2.8.0 (2025-02-20)

•   PR #285 - Use Enum with Tag for pretty representation (thanks to @Julien00859)

•   Make explicit that Python 3.12 and 3.13 are supported

•   Fix some links in the documentation

•   Add a Docker file for testing

  2.7.1 (2024-08-07)

•   Fix OID encoding/decoding for the first octet according to ITU-T X.690 (thanks to Ian Neal)

  2.7.0 (2023-01-17)

•   Add context manager support (thanks to Mastermind-U)

  2.6.0 (2022-07-15)

•   Add support for GeneralizedTime (thanks to vollkorntomate)

  2.5.0 (2022-03-03)

•   Fixes to BitString decoding and encoding of IA5String and UTCTime (thanks to 0xbf00)

  2.4.2 (2021-10-29)

•   Fix a minor mistake in the dump.py example

•   Add Python 3.9 and 3.10

  2.4.1 (2020-07-16)

•   Fix #89 - Replace explicit references to enum34 by enum-compat

  2.4.0 (2020-06-23)

•   Fix #21 - Invalid decoding in non-Universal classes

•   Fix #57 - Invalid encoding of non-Universal classes

  2.3.1 (2020-04-06)

•   No change in code, only in packaging and in texts (README, ...)

  2.3.0 (2020-04-05)

•   Tests: Replace nose by pytest

•   Add Python 3.8, remove Python 3.4 support

•   PR#26 (from rumbah): Add test for default (implicit) encoding types

•   PR#25 (from thomwiggers): Attempt to support BIT STRING

•   Fix wrong example code, see #27

•   (from jcrowgey) Makes the package usable with pip install

•   Remove support of Python 3.3 (some dependencies do not support 3.3)

•   PR#15 (from ThePlasmaRailgun) Fix parsing of object identifier

•   PR#10 (from robinleander): Allow user to determine decoding tagtype

  2.2.0 (2017-10-30)

•   Use "true" enums instead of classes. Use enun34 backport for old Python versions.

  2.1.1 (2017-10-30)

•   Fix a bug (#9): two's complement corner case with values such as -32769. Add new test cases to test them.

  2.1.0 (2016-12-18)

•   Add more documentation

•   Use (simulated) enumerations

•   Add Python 2.6 in automated checks and tests

•   Add type hints (for static checking) and fix some code

  2.0.0 (2016-12-16)

•   First public release by Sebastien Andrivet

•   Support both python 2 and 3 (with Python-Future)

•   All strings are now in unicode

•   Add more ASN.1 tags (like PrintableString)

•   Fix errors in the example (dump.py)

•   Code reorganization

  0.9 (2011-05-18)

•   Initial public release by Geert Jansen

INDICES AND TABLES

•   Index <>

•   Search Page <>

Author
Sebastien Andrivet

Copyright
2007-2026, Sebastien Andrivet