Skip to content

Instantly share code, notes, and snippets.

@kissgyorgy
Created July 2, 2022 17:20
Show Gist options
  • Save kissgyorgy/a78da25495e0ac6e736dec92dac19627 to your computer and use it in GitHub Desktop.
Save kissgyorgy/a78da25495e0ac6e736dec92dac19627 to your computer and use it in GitHub Desktop.
Python: Parse X.509 DER certificate with extra data at the end
from pathlib import Path
from cryptography import x509
ASN1_SEQUENCE_TAG = 0x30
def get_der_cert_length(cert_bytes: bytes) -> int:
if cert_bytes[0] != ASN1_SEQUENCE_TAG:
raise ValueError("Not a DER certificate")
first_size_octet = cert_bytes[1]
# https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/#length
# The short form is a single byte, between 0 and 127.
if first_size_octet < 128:
size_start = 1
size_length = 1
sequence_length = first_size_octet
# The long form is at least two bytes long, and has bit 8 of the first byte set to 1.
elif first_size_octet > 128:
size_start = 2
# Bits 7-1 of the first byte indicate how many more bytes are in the length field itself.
# Then the remaining bytes specify the length itself, as a multi-byte integer.
size_length = first_size_octet & 0x7f
size_end = size_start + size_length
sequence_length = 0
for length_octet in cert_bytes[size_start:size_end]:
sequence_length <<= 8
sequence_length |= length_octet
else: # 128 means indefinite
raise ValueError("Indefinite length encoding not supported")
return size_start + size_length + sequence_length
def main():
cert_bytes = Path("mkcert.der").read_bytes()
length = get_der_cert_length(cert_bytes)
print(length)
cert_only_bytes = cert_bytes[:length]
cert = x509.load_der_x509_certificate(cert_only_bytes)
print(cert)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment