#!/usr/bin/env python3 from pathlib import Path import re from cryptography.x509 import ( load_pem_x509_certificate as load_cert, NameOID, ) CERT_DIR = Path('/etc/letsencrypt/live/jahschwa.com') FULLCHAIN = CERT_DIR / 'fullchain.pem' PROSODY = CERT_DIR / 'prosody.pem' REGEX_BEGIN = re.compile(b'^\s*-----\s*BEGIN *CERTIFICATE.*-----\s*$') REGEX_END = re.compile(b'^\s*-----\s*END *CERTIFICATE.*-----\s*$') REGEX_DST = re.compile('^DST Root CA X3$') SKIP = [ lambda cert: REGEX_DST.search(_get_issuer_cn(cert)), ] def main(): with open(PROSODY, 'wb') as f: for cert in _load_certs(FULLCHAIN, skip=SKIP): f.write(cert) def _get_issuer_cn(cert): vals = cert.issuer.get_attributes_for_oid(NameOID.COMMON_NAME) if len(vals) != 1: raise ValueError(f'{cert} has {len(vals)} issuer CNs') return vals[0].value def _load_certs(cert_file, skip): for text in _iter_cert_text(cert_file): cert = load_cert(text) if not any(func(cert) for func in skip): yield text def _iter_cert_text(cert_file): start = None lines = [] with open(cert_file, 'rb') as f: for (i, line) in enumerate(f): if not line.strip(): continue if start is None: if REGEX_BEGIN.search(line): start = i + 1 lines = [line] else: lines.append(line) if REGEX_END.search(line): start = None yield b''.join(lines) if start is not None: raise ValueError(f'no matching END for cert starting on line {start}') if __name__ == '__main__': main()