#!/usr/bin/env python3 """Read one public PEM certificate; compare a proposed revisit interval. No keys, network, certificate installation, CA validation, or renewal requests. Exit 0: interval is shorter than both lifetime and remaining time (not a safety verdict). Exit 1: revisit reaches expiry. Exit 2: invalid or unsupported input. """ import argparse import datetime as dt import math import subprocess import sys parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('certificate', help='one PEM public certificate') parser.add_argument('revisit_days', type=float) args = parser.parse_args() if not math.isfinite(args.revisit_days) or args.revisit_days <= 0: parser.error('revisit_days must be finite and greater than zero') try: dates = subprocess.check_output(['openssl','x509','-in',args.certificate, '-noout','-startdate','-enddate'], text=True) fields = dict(line.split('=',1) for line in dates.strip().splitlines()) def parse(value): return dt.datetime.strptime(value, '%b %d %H:%M:%S %Y %Z').replace(tzinfo=dt.timezone.utc) start, end = parse(fields['notBefore']), parse(fields['notAfter']) now = dt.datetime.now(dt.timezone.utc) lifetime = (end-start).total_seconds()/86400 remaining = (end-now).total_seconds()/86400 if start > now or lifetime <= 0: raise ValueError('certificate is not valid now or dates are invalid') except (OSError, ValueError, KeyError, subprocess.CalledProcessError) as exc: print('UNCLASSIFIED: invalid or unsupported certificate input', file=sys.stderr) sys.exit(2) print(f'lifetime_days={lifetime:.2f} remaining_days={remaining:.2f} revisit_days={args.revisit_days:g}') if args.revisit_days >= min(lifetime, remaining): print('FAIL: this revisit interval reaches or passes expiry') sys.exit(1) print('INTERVAL ONLY: revisit precedes expiry; renewal, retries and deployment are untested')