Parsing Certificate Transparency Logs
The Itch
import struct
from enum import Enum
from OpenSSL import crypto
class LogEntryType(Enum):
uninitialized = -1 # Not set
X509LogEntryType = 0
PrecertLogEntryType = 1
# MerkleTreeHeader = Struct(
# "Version" / Byte,
# "MerkleLeafType" / Byte,
# "Timestamp" / Int64ub,
# "LogEntryType" / Enum(Int16ub, X509LogEntryType=0, PrecertLogEntryType=1),
# "Entry" / GreedyBytes
# )
class MerkleTreeParser:
Version = 0
MerkleLeafType = 0
Timestamp = 0
LogEntryType = LogEntryType.uninitialized
Entry = b''
def __init__(self, data):
FORMAT = f'>BBQH'
unpacked = struct.unpack(FORMAT, data[:struct.calcsize(FORMAT)])
self.Version = unpacked[0]
self.MerkleLeafType = unpacked[1]
self.Timestamp = unpacked[2]
self.LogEntryType = LogEntryType(unpacked[3])
self.Entry = data[struct.calcsize(FORMAT):]
def __str__(self) -> str:
return f"Version: {self.Version}, MerkleLeafType: {self.MerkleLeafType}, Timestamp: {self.Timestamp}, LogEntryType: {self.LogEntryType}, Entry: {self.Entry}"
# Certificate = Struct(
# "Length" / Int24ub,
# "CertData" / Bytes(this.Length)
# )
class Certificate:
Length = 0
CertData = b''
def __init__(self, data):
if len(data) == 0:
return
FORMAT = f'>I'
unpacked = struct.unpack(FORMAT, b'\x00' + data[:3])
self.Length = unpacked[0]
self.CertData = data[3:]
def __str__(self) -> str:
return f"Length: {self.Length}, CertData: {self.CertData}"
# CertificateChain = Struct(
# "ChainLength" / Int24ub,
# "Chain" / GreedyRange(Certificate),
# )
class CertificateChain:
ChainLength : int = 0
Chain:list = []
def __init__(self, data):
if len(data) == 0:
return
FORMAT = f'>I'
unpacked = struct.unpack(FORMAT, b'\x00' + data[:3])
self.ChainLength = unpacked[0]
data = data[3:]
while len(data) > 0:
length = struct.unpack(FORMAT, b'\x00' + data[:3])[0]
cert_data = data[:3+length]
cert = Certificate(cert_data)
self.Chain.append(cert)
data = data[3+length:]
def __str__(self) -> str:
return f"ChainLength: {self.ChainLength}, Chain: {self.Chain}"
# PreCertEntry = Struct(
# "LeafCert" / Certificate,
# Embedded(CertificateChain),
# Terminated
# )
class PreCertEntry:
LeafCert = Certificate(b'')
Chain = CertificateChain(b'')
def __init__(self, data):
if len(data) == 0:
return
FORMAT = f'>I'
leafcert_length = struct.unpack(FORMAT, b'\x00' + data[:3])[0]
self.LeafCert = Certificate(data[:3+leafcert_length])
data = data[3+leafcert_length:]
self.Chain = CertificateChain(data)
def __str__(self) -> str:
return f"LeafCert: {self.LeafCert}, Chain: {self.Chain}"The Itch Part II
Thanks
Last updated