PEM Decoder and Encoder

Often times DER-encoded data is wrapped in PEM encoding. This allows the binary DER data to be identified and reliably sent over various communication channels.

The asn1crypto.pem module includes three functions:

  • detect(byte_string)
  • unarmor(pem_bytes, multiple=False)
  • armor(type_name, der_bytes, headers=None)

detect()

The detect() function accepts a byte string and looks for a BEGIN block line. This is useful to determine in a byte string needs to be PEM-decoded before parsing.

from asn1crypto import pem, x509

with open('/path/to/cert', 'rb') as f:
    der_bytes = f.read()
    if pem.detect(der_bytes):
        _, _, der_bytes = pem.unarmor(der_bytes)

unarmor()

The unarmor() function accepts a byte string and the flag to indicates if more than one PEM block may be contained in the byte string. The result is a three-element tuple.

  • The first element is a unicode string of the type of PEM block. Examples include: CERTIFICATE, PRIVATE KEY, PUBLIC KEY.
  • The second element is a dict of PEM block headers. Headers are typically only used by encrypted OpenSSL private keys, and are in the format Name: Value.
  • The third element is a byte string of the decoded block contents.
from asn1crypto import pem, x509

with open('/path/to/cert', 'rb') as f:
    der_bytes = f.read()
    if pem.detect(der_bytes):
        type_name, headers, der_bytes = pem.unarmor(der_bytes)

cert = x509.Certificate.load(der_bytes)

If the multiple keyword argument is set to True, a generator will be returned.

from asn1crypto import pem, x509

certs = []
with open('/path/to/ca_certs', 'rb') as f:
    for type_name, headers, der_bytes in pem.unarmor(f.read(), multiple=True):
        certs.append(x509.Certificate.load(der_bytes))

armor()

The armor() function accepts three parameters: a unicode string of the block type name, a byte string to encode and an optional keyword argument headers, that should be a dict of headers to add after the BEGIN line. Headers are typically only used by encrypted OpenSSL private keys.

from asn1crypto import pem, x509

# cert is an instance of x509.Certificate

with open('/path/to/cert', 'wb') as f:
    der_bytes = cert.dump()
    pem_bytes = pem.armor('CERTIFICATE', der_bytes)
    f.write(pem_bytes)