- tls-server-accept.sh: each probe pins openssl s_client's -ciphersuites — ec/ChaCha20-Poly1305, rsa/AES-128-GCM, plus openssl's default list whose first suite (AES-256-GCM) the server must skip — 5/0 - tls-accept.sh: the Python/OpenSSL stub prints the negotiated suite; the happy-path ok line carries it — 5/0 (ChaCha under the peer's server-preference default) - rv2 8 story: E landed (real-protocol interop replaces the infeasible `openssl enc` AEAD check); D (encrypted-cookie wrapper) re-homed to porch as the consumer's phase after porch 2 — fork auto-approved, review_pending; status: done - porch 2: the encrypted-cookie out-of-scope bullet now points at the landed primitives and names the wrapper as its follow-on - board row rv2 8: in-progress -> done Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> (cherry picked from commit ac3bf74da4f45f624d7d3b440c8bcf17f4aec3a9)
101 lines
5 KiB
Bash
Executable file
101 lines
5 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# scripts/tls-server-accept.sh — runtime-v2 9 phase G's gate: inbound TLS 1.3.
|
|
# The runtime suite proves the server FSM offline (loopback against the client
|
|
# driver); this proves interop with a real client — `openssl s_client`
|
|
# validating our hand-rolled server handshake and exchanging application data,
|
|
# for both an ECDSA-P256 and an RSA server certificate. Each probe pins the
|
|
# client's cipher suite, so both AEADs run against the reference peer over the
|
|
# wire (rv2 8 phase E's cross-check), plus one probe with openssl's default
|
|
# list, whose first entry we do not implement. Log: /tmp/tls-server.log.
|
|
set -uo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
WOC="$ROOT/compiler/_build/default/bin/woc"
|
|
WOVM="$ROOT/runtime/wovm"
|
|
APP="$ROOT/docs/examples/tls-server"
|
|
PORT="${TLS_SERVER_PORT:-18553}"
|
|
LOG=/tmp/tls-server.log
|
|
|
|
pass=0; fail=0
|
|
ok() { echo "ok $1"; pass=$((pass + 1)); }
|
|
bad() { echo "FAIL $1"; fail=$((fail + 1)); }
|
|
|
|
WORK="$(mktemp -d)"
|
|
SRV_PID=""
|
|
cleanup() { [[ -n "$SRV_PID" ]] && kill -KILL "$SRV_PID" 2>/dev/null; rm -rf "$WORK"; }
|
|
trap cleanup EXIT
|
|
mkdir -p "$WORK/data"
|
|
|
|
[[ -x "$WOVM" ]] || { echo "tls-server: wovm not built — run: make -C runtime wovm" >&2; exit 1; }
|
|
[[ -x "$WOC" ]] || { echo "tls-server: woc not built — run: just woc-build" >&2; exit 1; }
|
|
command -v openssl >/dev/null || { echo "tls-server: needs openssl" >&2; exit 1; }
|
|
python3 -c 'import cryptography' 2>/dev/null || { echo "tls-server: needs python3 cryptography" >&2; exit 1; }
|
|
|
|
# ---- 1. a test CA + an EC leaf and an RSA leaf (SAN localhost) ------------
|
|
cat > "$WORK/mk.py" <<'PY'
|
|
import datetime, sys
|
|
from cryptography import x509
|
|
from cryptography.x509.oid import NameOID, ExtendedKeyUsageOID
|
|
from cryptography.hazmat.primitives import hashes, serialization as ser
|
|
from cryptography.hazmat.primitives.asymmetric import ec, rsa
|
|
d = sys.argv[1]
|
|
NB = datetime.datetime(2020,1,1); NA = datetime.datetime(2035,1,1)
|
|
def nm(cn): return x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, cn)])
|
|
cak = ec.generate_private_key(ec.SECP256R1())
|
|
ca = (x509.CertificateBuilder().subject_name(nm("wo-test-ca")).issuer_name(nm("wo-test-ca"))
|
|
.public_key(cak.public_key()).serial_number(x509.random_serial_number())
|
|
.not_valid_before(NB).not_valid_after(NA)
|
|
.add_extension(x509.BasicConstraints(ca=True, path_length=None), True).sign(cak, hashes.SHA256()))
|
|
open(d+"/ca.pem","wb").write(ca.public_bytes(ser.Encoding.PEM))
|
|
def leaf(key, tag):
|
|
c = (x509.CertificateBuilder().subject_name(nm("localhost")).issuer_name(ca.subject)
|
|
.public_key(key.public_key()).serial_number(x509.random_serial_number())
|
|
.not_valid_before(NB).not_valid_after(NA)
|
|
.add_extension(x509.SubjectAlternativeName([x509.DNSName("localhost")]), False)
|
|
.add_extension(x509.ExtendedKeyUsage([ExtendedKeyUsageOID.SERVER_AUTH]), False)
|
|
.sign(cak, hashes.SHA256()))
|
|
open(d+"/"+tag+".pem","wb").write(c.public_bytes(ser.Encoding.PEM))
|
|
open(d+"/"+tag+".key","wb").write(key.private_bytes(ser.Encoding.PEM,
|
|
ser.PrivateFormat.PKCS8, ser.NoEncryption()))
|
|
leaf(ec.generate_private_key(ec.SECP256R1()), "ec")
|
|
leaf(rsa.generate_private_key(public_exponent=65537, key_size=2048), "rsa")
|
|
PY
|
|
python3 "$WORK/mk.py" "$WORK" || { bad "cert generation"; echo "tls-server: $fail failures"; exit 1; }
|
|
ok "test CA + EC leaf + RSA leaf (SAN localhost, EKU serverAuth) generated"
|
|
|
|
# ---- 2. build the server -------------------------------------------------
|
|
{ echo; echo "== tls-server-accept $(date -Is) port $PORT =="; } >>"$LOG"
|
|
if "$WOC" --emit "$APP" -o "$WORK/srv.wob" 2>"$WORK/cerr"; then
|
|
ok "build: tls-server compiles"
|
|
else
|
|
bad "build: $(head -3 "$WORK/cerr")"; echo "tls-server: $fail failures"; exit 1
|
|
fi
|
|
|
|
# ---- 3. openssl s_client interop, per key type ---------------------------
|
|
probe() { # $1 = tag (ec|rsa) ; $2 = port (distinct per probe — avoids a bind race) ; $3 = openssl -ciphersuites list
|
|
local p="$2"
|
|
kill -KILL "$SRV_PID" 2>/dev/null
|
|
WO_DATA="$WORK/data" "$WOVM" "$WORK/srv.wob" "$p" "$WORK/$1.pem" "$WORK/$1.key" >>"$LOG" 2>&1 &
|
|
SRV_PID=$!; disown "$SRV_PID" 2>/dev/null || true
|
|
for _ in $(seq 1 100); do
|
|
if ( exec 3<>"/dev/tcp/127.0.0.1/$p" ) 2>/dev/null; then break; fi
|
|
sleep 0.05
|
|
done
|
|
local out
|
|
out="$({ printf 'GET / HTTP/1.0\r\n\r\n'; sleep 1; } | \
|
|
timeout 12 openssl s_client -connect "127.0.0.1:$p" -CAfile "$WORK/ca.pem" \
|
|
-servername localhost -tls1_3 -ciphersuites "$3" -verify_return_error -quiet 2>/dev/null)"
|
|
if [[ "$out" == *"hello-wo-tls"* ]]; then
|
|
ok "$1 [$3]: openssl s_client validated the cert + got the reply"
|
|
else
|
|
bad "$1 [$3]: no reply (out: ${out:0:80})"
|
|
fi
|
|
}
|
|
probe ec "$PORT" TLS_CHACHA20_POLY1305_SHA256
|
|
probe rsa "$((PORT + 1))" TLS_AES_128_GCM_SHA256
|
|
# openssl's default order: the server must skip the AES-256 suite it does not
|
|
# implement and pick from the rest
|
|
probe ec "$((PORT + 2))" TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
|
|
|
|
echo "tls-server: $((pass + fail)) checks, $fail failures"
|
|
[[ $fail -eq 0 ]]
|