Skip to content

Instantly share code, notes, and snippets.

@markscottwright
Created July 2, 2023 20:37
Show Gist options
  • Save markscottwright/2a5fc5fb64bce674d8b4c70210801921 to your computer and use it in GitHub Desktop.
Save markscottwright/2a5fc5fb64bce674d8b4c70210801921 to your computer and use it in GitHub Desktop.
How to parse a JKS in Python
from pprint import pprint
import dataclasses
import struct
from datetime import datetime
import cryptography.x509
from cryptography.x509 import Certificate
def next_long(f):
return struct.unpack(">Q", f.read(8))[0]
def next_int(f):
return struct.unpack(">I", f.read(4))[0]
def next_short(f):
return struct.unpack(">H", f.read(2))[0]
def next_string(f):
string_length = next_short(f)
return f.read(string_length).decode("utf8")
def next_timestamp(f):
return datetime.fromtimestamp(next_long(f) / 1000.0)
def next_cert(f):
cert_type = next_string(f)
cert_length = next_int(f)
cert_bytes = f.read(cert_length)
return cryptography.x509.load_der_x509_certificate(cert_bytes)
@dataclasses.dataclass
class CertificateEntry:
alias: str
timestamp: datetime
certificate: Certificate
@dataclasses.dataclass
class KeyAndCertificatesEntry:
alias: str
timestamp: datetime
certificates: list[Certificate]
key: bytes # PKCS8
def parse_jks(jks_path: str) -> list[CertificateEntry | KeyAndCertificatesEntry]:
entries = []
with open(jks_path, 'rb') as f:
magic = next_int(f)
version = next_int(f)
assert magic == 0xfeedfeed
assert version == 2
num_entries = next_int(f)
for entry in range(num_entries):
entry_type = next_int(f)
alias = next_string(f)
timestamp = next_timestamp(f)
if entry_type == 2:
cert = next_cert(f)
entries.append(CertificateEntry(alias, timestamp, cert))
else:
private_key_length = next_int(f)
private_key = f.read(private_key_length)
num_certs = next_int(f)
certs = []
for i in range(num_certs):
certs.append(next_cert(f))
entries.append(CertificateEntry(alias, timestamp, certs, private_key))
return entries
jks_entries = parse_jks(r"C:\Tools\java\jdk-17.0.1+12\lib\security\cacerts")
pprint(jks_entries)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment