Skip to content

Instantly share code, notes, and snippets.

@dreness
Created November 2, 2019 08:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dreness/645d014b6a11e69dca15639e1ebe4092 to your computer and use it in GitHub Desktop.
Save dreness/645d014b6a11e69dca15639e1ebe4092 to your computer and use it in GitHub Desktop.
Extract x509 certificates found in xar table of contents
#!/usr/bin/env python3
from xml.etree import ElementTree as ET
from os.path import abspath
from os import getenv
import subprocess
import textwrap
import zlib
import sys
if len(sys.argv) != 2:
print("Please supply the path to a .pkg file as the only argument.")
exit(1)
path = sys.argv[1]
if abspath(path) is None:
print(f"Couldn't find a file at {arg}...")
exit(1)
TMP = getenv("TMPDIR")
if TMP is None:
TMP = "/tmp"
f = open(path, "rb")
# the size of the xar file's zlib-compressed table of contents
# (an xml document) is stored as an 8 byte integer at offset 8.
f.seek(8)
toc_s = int.from_bytes(f.read(8), byteorder="big")
print(f"Compressed table of contents is {toc_s} bytes.")
# The table of contents data begins at offset 28
f.seek(0)
f.seek(28)
z = f.read(toc_s)
xml_s = zlib.decompress(z)
toc = ET.fromstring(xml_s)
i = 0
found = 0
for e in toc.iter():
i += 1
# certificate data is in the 'text' attribute of an element
# whose tag name includes 'X509Certificate'
if "X509Certificate" in e.tag:
# The certificate data would be in the 'text' attribute of this element
if e.text is not None:
fn = f"{TMP}/cert-{i}.crt"
out = open(fn, "w")
out.write("-----BEGIN CERTIFICATE-----\n")
out.write(e.text)
out.write("-----END CERTIFICATE-----\n")
out.close()
print(f"Wrote {abspath(fn)}")
found += 1
if found > 0:
subprocess.run(["open", TMP])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment