- Bundle current root certificates (Let's Encrypt, GTS, Sectigo, DigiCert G2, Amazon, ...) missing from Android 2.x's store (Roots.java, tools/gen_roots.py) - Ask once for unknown certificates, showing the SHA-256 fingerprint, and remember the answer; replaces "accept any certificate" (Trust*, Settings) - Local streaming proxy so Android 2.x's MediaPlayer can play https:// servers, with seeking and a fresh token per request (StreamProxy.java) - Tests over real TLS with good, expired, wrong-host, forged and self-signed certificates (test/make_pki.sh, TrustTest.java) - README: server setup for a legacy TLS 1.0 port Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
70 lines
3.3 KiB
Bash
Executable File
70 lines
3.3 KiB
Bash
Executable File
#!/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
|