#!/usr/bin/env python3 # MIT License # Copyright (c) 2026 Sławomir Koszewski import subprocess import sys from pathlib import Path import pytest SCRIPT = Path(__file__).parent / "simple-ca.py" def py(*args, check=True): return subprocess.run( [sys.executable, str(SCRIPT), *args], capture_output=True, text=True, check=check, ) def openssl(*args, check=True): return subprocess.run(["openssl", *args], capture_output=True, text=True, check=check) def cert_serial(cert_path): out = openssl("x509", "-in", str(cert_path), "-noout", "-serial").stdout return out.strip().split("=", 1)[-1].upper() def verify_cert(cert_path, bundle_path): result = openssl("verify", "-CAfile", str(bundle_path), str(cert_path), check=False) assert result.returncode == 0, f"Certificate verification failed:\n{result.stderr}" @pytest.fixture def dirs(tmp_path): ca = tmp_path / "ca" ca.mkdir() return ca # --------------------------------------------------------------------------- # Standalone CA # --------------------------------------------------------------------------- def test_standalone_ca(dirs): ca = dirs py("make-ca", "--ca-dir", str(ca), "Test CA") assert (ca / "ca_cert.pem").exists() assert (ca / "ca_bundle.pem").exists() assert (ca / "simple-ca.json").exists() verify_cert(ca / "ca_cert.pem", ca / "ca_bundle.pem") py("make-cert", "--ca-dir", str(ca), "test", "test.example.com", "127.0.0.1") assert (ca / "test_cert.pem").exists() verify_cert(ca / "test_cert.pem", ca / "ca_bundle.pem") # --------------------------------------------------------------------------- # Two-level CA # --------------------------------------------------------------------------- def test_two_level_ca(dirs): ca = dirs py("make-ca", "--ca-dir", str(ca), "Test Root CA") py("make-ca", "--ca-dir", str(ca), "--issuing-ca", "issuing_ca", "Issuing CA") assert (ca / "issuing_ca" / "ca_cert.pem").exists() verify_cert(ca / "issuing_ca" / "ca_cert.pem", ca / "ca_bundle.pem") py("make-cert", "--ca-dir", str(ca), "--issuing-ca", "issuing_ca", "test", "test.example.com", "127.0.0.1") verify_cert(ca / "issuing_ca" / "test_cert.pem", ca / "ca_bundle.pem") py("make-pfx", "--ca-dir", str(ca), "--issuing-ca", "issuing_ca", "--password", "s3cr3t", str(ca / "issuing_ca" / "test_cert.pem")) assert (ca / "issuing_ca" / "test.pfx").exists() result = openssl("pkcs12", "-in", str(ca / "issuing_ca" / "test.pfx"), "-noout", "-info", "-password", "pass:s3cr3t") assert result.returncode == 0 # --------------------------------------------------------------------------- # PFX algorithm variants # --------------------------------------------------------------------------- def test_pfx_modern(dirs): ca = dirs py("make-ca", "--ca-dir", str(ca), "PFX Test CA") py("make-ca", "--ca-dir", str(ca), "--issuing-ca", "issuing_ca", "Issuing CA") py("make-cert", "--ca-dir", str(ca), "--issuing-ca", "issuing_ca", "test", "test.example.com", "127.0.0.1") py("make-pfx", "--ca-dir", str(ca), "--issuing-ca", "issuing_ca", "--password", "s3cr3t", str(ca / "issuing_ca" / "test_cert.pem")) info = openssl("pkcs12", "-in", str(ca / "issuing_ca" / "test.pfx"), "-noout", "-info", "-password", "pass:s3cr3t") assert "PBES2" in (info.stdout + info.stderr), "Expected modern PBES2 encryption" @pytest.mark.skipif(sys.platform != "darwin", reason="macOS only") def test_pfx_apple_openssl(dirs): ca = dirs py("make-ca", "--ca-dir", str(ca), "PFX Test CA") py("make-ca", "--ca-dir", str(ca), "--issuing-ca", "issuing_ca", "Issuing CA") py("make-cert", "--ca-dir", str(ca), "--issuing-ca", "issuing_ca", "test", "test.example.com", "127.0.0.1") py("make-pfx", "--apple-openssl", "--ca-dir", str(ca), "--issuing-ca", "issuing_ca", "--password", "s3cr3t", str(ca / "issuing_ca" / "test_cert.pem")) result = subprocess.run( ["/usr/bin/openssl", "pkcs12", "-in", str(ca / "issuing_ca" / "test.pfx"), "-noout", "-info", "-password", "pass:s3cr3t"], capture_output=True, text=True, ) assert result.returncode == 0 combined = result.stdout + result.stderr assert "PBES2" not in combined, "Expected Apple-compatible (non-PBES2) format" # --------------------------------------------------------------------------- # CRL and revocation # --------------------------------------------------------------------------- def test_crl(dirs): ca = dirs py("make-ca", "--ca-dir", str(ca), "CRL Test CA") py("make-ca", "--ca-dir", str(ca), "--issuing-ca", "issuing_ca", "Issuing CA") py("make-cert", "--ca-dir", str(ca), "--issuing-ca", "issuing_ca", "alice", "alice.example.com") py("make-cert", "--ca-dir", str(ca), "--issuing-ca", "issuing_ca", "bob", "bob.example.com") issuing_dir = ca / "issuing_ca" alice_serial = cert_serial(issuing_dir / "alice_cert.pem") bob_serial = cert_serial(issuing_dir / "bob_cert.pem") py("revoke-cert", "--ca-dir", str(ca), "--issuing-ca", "issuing_ca", str(issuing_dir / "alice_cert.pem")) py("make-crl", "--ca-dir", str(ca), "--issuing-ca", "issuing_ca") issuing_crl = issuing_dir / "crl.pem" assert issuing_crl.exists() crl_text = openssl("crl", "-in", str(issuing_crl), "-noout", "-text").stdout.upper() assert alice_serial in crl_text, f"Alice's serial {alice_serial} not found in issuing CA CRL" assert bob_serial not in crl_text, f"Bob's serial {bob_serial} unexpectedly found in issuing CA CRL" py("make-crl", "--ca-dir", str(ca)) root_crl = ca / "crl.pem" assert root_crl.exists() root_crl_text = openssl("crl", "-in", str(root_crl), "-noout", "-text").stdout assert "No Revoked Certificates" in root_crl_text, "Root CA CRL should be empty" def test_crl_number_increments(dirs): ca = dirs py("make-ca", "--ca-dir", str(ca), "CRL Test CA") numbers = [] for _ in range(2): py("make-crl", "--ca-dir", str(ca)) numbers.append(openssl("crl", "-in", str(ca / "crl.pem"), "-noout", "-crlnumber").stdout.strip()) assert numbers == ["crlNumber=0x01", "crlNumber=0x02"], numbers # --------------------------------------------------------------------------- # User certificate and SAN handling # --------------------------------------------------------------------------- def test_user_cert(dirs): ca = dirs py("make-ca", "--ca-dir", str(ca), "Test CA") py("make-ca", "--ca-dir", str(ca), "--issuing-ca", "issuing_ca", "Issuing CA") py("make-cert", "--ca-dir", str(ca), "--issuing-ca", "issuing_ca", "--type", "user", "Alice Example", "alice@example.com") cert = ca / "issuing_ca" / "Alice Example_cert.pem" verify_cert(cert, ca / "ca_bundle.pem") text = openssl("x509", "-in", str(cert), "-noout", "-text").stdout for eku in ("TLS Web Client Authentication", "E-mail Protection", "Code Signing"): assert eku in text, f"EKU {eku!r} not found" assert "email:alice@example.com" in text assert "TLS Web Server Authentication" not in text def test_invalid_ip_san(dirs): ca = dirs py("make-ca", "--ca-dir", str(ca), "Test CA") result = py("make-cert", "--ca-dir", str(ca), "test", "999.1.1.1", check=False) assert result.returncode != 0 assert not (ca / "test_cert.pem").exists() def test_make_ca_root_exists(dirs): ca = dirs py("make-ca", "--ca-dir", str(ca), "Test CA") result = py("make-ca", "--ca-dir", str(ca), "Test CA", check=False) assert result.returncode == 0 assert "Traceback" not in result.stderr def test_pfx_bare_filename(dirs): ca = dirs py("make-ca", "--ca-dir", str(ca), "Test CA") py("make-cert", "--ca-dir", str(ca), "test", "test.example.com") result = subprocess.run( [sys.executable, str(SCRIPT), "make-pfx", "--ca-dir", str(ca), "test_cert.pem"], capture_output=True, text=True, cwd=ca, ) assert result.returncode == 0, result.stderr assert (ca / "test.pfx").exists()