#!/usr/bin/env bash set -uo pipefail # CASAN Plan-16 SEC-02 (H-02) — no local key auto-generation in enforced mode. # # The tamper-evidence of the audit chain rests on the head signature. If the # signer auto-generates a private key next to the data (as dev convenience does), # then any actor who can write the log can also mint a key and re-sign a forged # head. In enforced mode the signer must NOT auto-generate — the key is provisioned # out-of-band (KMS/HSM). This proves: # * permissive mode still auto-generates a local key (dev convenience), # * enforced mode does NOT create a key when none is provisioned, and the # resulting unsigned head then FAILS strict verification (fail-closed). # # Deterministic; hermetic (temp key dir + backup/restore of audit + gov dirs). SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/../scripts/bash/casan-paths.sh" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" BASH_DIR="$CASAN_HARNESS_ROOT/scripts/bash" WORK="$(mktemp -d)" BK="$WORK/bak"; mkdir -p "$BK" cp -a "$CASAN_STATE_ROOT/logs/audit" "$BK/audit" 2>/dev/null || true cp -a "$CASAN_GOVERNANCE_ROOT" "$BK/cg" 2>/dev/null || true restore() { rm -rf "$CASAN_STATE_ROOT/logs/audit"; cp -a "$BK/audit" "$CASAN_STATE_ROOT/logs/audit" 2>/dev/null || true rm -rf "$CASAN_GOVERNANCE_ROOT"; cp -a "$BK/cg" "$CASAN_GOVERNANCE_ROOT" 2>/dev/null || true } trap 'restore; rm -rf "$WORK"' EXIT PASS=0; FAIL=0 pass() { echo "PASS: $1"; PASS=$((PASS + 1)); } fail() { echo "FAIL: $1"; FAIL=$((FAIL + 1)); } rc_of() { set +e; "$@" >/dev/null 2>&1; echo $?; set -e 2>/dev/null || true; } echo "===== Plan-16 SEC-02: no local key auto-gen in enforced mode =====" echo "benign input" > "$WORK/in.txt" # 1) Permissive mode: a fresh key dir auto-generates a local key (dev convenience). KD1="$WORK/keys-permissive" env CASAN_AUDIT_KEY_DIR="$KD1" bash "$BASH_DIR/governance-check.sh" "$WORK/in.txt" "$WORK/out1.txt" agent_step >/dev/null 2>&1 [[ -f "$KD1/audit-private.pem" ]] \ && pass "permissive mode auto-generates a local signing key" \ || fail "permissive mode did not auto-generate a key (dev convenience broken)" # 2) Enforced mode: a fresh key dir must NOT auto-generate a key. KD2="$WORK/keys-enforced" env CASAN_VERIFY_STRICT=1 CASAN_AUDIT_KEY_DIR="$KD2" bash "$BASH_DIR/governance-check.sh" "$WORK/in.txt" "$WORK/out2.txt" agent_step >/dev/null 2>&1 [[ ! -f "$KD2/audit-private.pem" ]] \ && pass "enforced mode does NOT auto-generate a local key (H-02 closed)" \ || fail "enforced mode auto-generated a local key (attacker could re-sign forgery)" # 3) The unsigned head produced in enforced mode fails strict verification. [[ "$(rc_of env CASAN_VERIFY_STRICT=1 bash "$BASH_DIR/verify-audit-chain.sh")" -ne 0 ]] \ && pass "unsigned head from enforced run FAILS strict verify (fail-closed)" \ || fail "unsigned head passed strict verify" echo "" echo "===== SEC-02 SUMMARY: PASS=$PASS FAIL=$FAIL =====" [[ "$FAIL" -eq 0 ]] || exit 1