#!/bin/sh # Test certificates: a root CA, an intermediate CA, and server certificates, good and bad. set -e D=${1:-build/pki} rm -rf "$D" && mkdir -p "$D" && cd "$D" q() { openssl "$@" > /dev/null 2>err.log || { cat err.log; exit 1; }; } cat > ca.ext <<'EOF' basicConstraints=critical,CA:TRUE keyUsage=critical,keyCertSign,cRLSign EOF cat > leaf.ext <<'EOF' basicConstraints=CA:FALSE keyUsage=critical,digitalSignature,keyEncipherment extendedKeyUsage=serverAuth subjectAltName=DNS:localhost,IP:127.0.0.1 EOF cat > other.ext <<'EOF' basicConstraints=CA:FALSE keyUsage=critical,digitalSignature,keyEncipherment extendedKeyUsage=serverAuth subjectAltName=DNS:other.example EOF q req -x509 -newkey rsa:2048 -nodes -keyout root.key -out root.crt -days 3650 -subj "/CN=Test Root CA" -addext "basicConstraints=critical,CA:TRUE" -addext "keyUsage=critical,keyCertSign,cRLSign" q req -newkey rsa:2048 -nodes -keyout int.key -out int.csr -subj "/CN=Test Intermediate R1" q x509 -req -in int.csr -CA root.crt -CAkey root.key -CAcreateserial -out int.crt -days 1825 -extfile ca.ext # good server certificate q req -newkey rsa:2048 -nodes -keyout leaf.key -out leaf.csr -subj "/CN=localhost" q x509 -req -in leaf.csr -CA int.crt -CAkey int.key -CAcreateserial -out leaf.crt -days 90 -extfile leaf.ext cat leaf.crt int.crt > good.chain # certificate for a different host, same CA q req -newkey rsa:2048 -nodes -keyout other.key -out other.csr -subj "/CN=other.example" q x509 -req -in other.csr -CA int.crt -CAkey int.key -CAcreateserial -out other.crt -days 90 -extfile other.ext cat other.crt int.crt > wronghost.chain # forgery: an attacker uses their own valid (non-CA) certificate to sign one for localhost q req -newkey rsa:2048 -nodes -keyout forged.key -out forged.csr -subj "/CN=localhost" q x509 -req -in forged.csr -CA other.crt -CAkey other.key -CAcreateserial -out forged.crt -days 90 -extfile leaf.ext cat forged.crt other.crt int.crt > forged.chain cp forged.key forged.chain.key # expired certificate q req -newkey rsa:2048 -nodes -keyout old.key -out old.csr -subj "/CN=localhost" python3 - <<'PY' import datetime from cryptography import x509 from cryptography.hazmat.primitives import hashes, serialization ca = x509.load_pem_x509_certificate(open("int.crt", "rb").read()) ca_key = serialization.load_pem_private_key(open("int.key", "rb").read(), None) csr = x509.load_pem_x509_csr(open("old.csr", "rb").read()) cert = (x509.CertificateBuilder().subject_name(csr.subject).issuer_name(ca.subject) .public_key(csr.public_key()).serial_number(x509.random_serial_number()) .not_valid_before(datetime.datetime(2020, 1, 1)).not_valid_after(datetime.datetime(2021, 1, 1)) .add_extension(x509.BasicConstraints(ca=False, path_length=None), critical=False) .add_extension(x509.SubjectAlternativeName([x509.DNSName("localhost")]), critical=False) .sign(ca_key, hashes.SHA256())) open("old.crt", "wb").write(cert.public_bytes(serialization.Encoding.PEM)) PY cat old.crt int.crt > expired.chain # self-signed server q req -x509 -newkey rsa:2048 -nodes -keyout self.key -out self.crt -days 365 -subj "/CN=localhost" -addext "subjectAltName=DNS:localhost,IP:127.0.0.1" cp self.crt self.chain cp leaf.key good.chain.key; cp other.key wronghost.chain.key; cp old.key expired.chain.key; cp self.key self.chain.key ls *.chain