Created
July 2, 2022 17:20
-
-
Save kissgyorgy/a78da25495e0ac6e736dec92dac19627 to your computer and use it in GitHub Desktop.
Python: Parse X.509 DER certificate with extra data at the end
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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