Files
fips/testing/static/scripts/ping-test.sh
T
Johnathan Corgan bf117df0ca Add periodic Noise rekey with fresh DH for forward secrecy (FMP + FSP)
Implement periodic full rekey at both protocol layers using fresh DH
key exchanges. Uses the existing K-bit flag (FLAG_KEY_EPOCH /
FSP_FLAG_K) to coordinate cutover between peers.

FMP layer (IK pattern):
- ActivePeer gains rekey state: pending/previous sessions, K-bit epoch
  tracking, drain window, dampening timer
- Handshake state stored on ActivePeer with msg1 sent on existing link
- Encrypted frame handler detects K-bit flips, promotes pending
  sessions, falls back to previous session during drain
- Handshake handlers distinguish rekey from new connections using
  addr_to_link lookup with identity-based fallback
- Free all session indices (current, rekey, pending, previous) on
  peer removal

FSP layer (XK pattern):
- SessionEntry gains parallel rekey fields with XK-specific state
  for the 3-message handshake
- Route availability check before FSP rekey initiation
- Encrypted session handler adds K-bit flip detection and dual-session
  decrypt fallback
- SessionSetup/Ack/Msg3 handlers extended for rekey paths

Defense-in-depth:
- Consecutive decryption failure detector (threshold=20) triggers
  forced peer removal instead of waiting for link-dead timeout
- Identity-based rekey detection as fallback when addr_to_link
  doesn't match (e.g., TCP ephemeral ports)

Configuration: RekeyConfig with enabled flag, after_secs (default 120),
and after_messages (default 65536) thresholds.

Logging: info for successful K-bit cutover completions, warn for
failures, debug for intermediate handshake steps, trace for routine
operations (resends, drain cleanup).

Rekey lifecycle:
1. Timer/counter fires -> initiator starts new handshake
2. Old session continues handling traffic during handshake
3. Handshake completes -> initiator cuts over, flips K-bit
4. Responder sees flipped K-bit -> promotes new session
5. Both keep old session for 10s drain window
6. After drain, old session discarded

Integration test: Docker-based multi-phase test exercising both FMP
and FSP rekey with aggressive timers (35s). Verifies connectivity
across all 20 directed pairs survives two consecutive rekey cycles.
Includes rekey topology, docker-compose profile, and CI matrix entry.

Increase ping test convergence wait from 3s to 5s for CI reliability.
2026-03-07 18:33:27 +00:00

116 lines
3.1 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# End-to-end ping test between FIPS nodes via DNS resolution.
# Usage: ./ping-test.sh [mesh|chain]
#
# Requires containers to be running:
# docker compose --profile mesh up -d
# ./scripts/ping-test.sh mesh
set -e
# Exit entire script on Ctrl+C
trap 'echo ""; echo "Test interrupted"; exit 130' INT
PROFILE="${1:-mesh}"
COUNT=1
TIMEOUT=5
PASSED=0
FAILED=0
# Node identities (from generated env file)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ENV_FILE="$SCRIPT_DIR/../generated-configs/npubs.env"
if [ ! -f "$ENV_FILE" ]; then
echo "Error: $ENV_FILE not found. Run generate-configs.sh first." >&2
exit 1
fi
# shellcheck source=../generated-configs/npubs.env
source "$ENV_FILE"
ping_test() {
local from="$1"
local to_npub="$2"
local label="$3"
echo -n " $label ... "
local output
if output=$(docker exec "fips-$from" ping6 -c "$COUNT" -W "$TIMEOUT" "${to_npub}.fips" 2>&1); then
# Extract round-trip time from ping output
local rtt=$(echo "$output" | grep -oE 'time=[0-9.]+' | cut -d= -f2)
if [ -n "$rtt" ]; then
echo "OK (${rtt}ms)"
else
echo "OK"
fi
PASSED=$((PASSED + 1))
else
echo "FAIL"
FAILED=$((FAILED + 1))
fi
}
echo "=== FIPS Ping Test ($PROFILE topology) ==="
echo ""
# Wait for nodes to converge
echo "Waiting 5s for mesh convergence..."
sleep 5
if [ "$PROFILE" = "mesh" ] || [ "$PROFILE" = "mesh-public" ]; then
# Sparse mesh topology: A-B, B-C, C-D, D-E, E-A, A-D
# Test all 20 directed pairs (5 nodes × 4 targets each)
echo ""
echo "From node-a:"
ping_test node-a "$NPUB_B" "A → B"
ping_test node-a "$NPUB_C" "A → C"
ping_test node-a "$NPUB_D" "A → D"
ping_test node-a "$NPUB_E" "A → E"
echo ""
echo "From node-b:"
ping_test node-b "$NPUB_A" "B → A"
ping_test node-b "$NPUB_C" "B → C"
ping_test node-b "$NPUB_D" "B → D"
ping_test node-b "$NPUB_E" "B → E"
echo ""
echo "From node-c:"
ping_test node-c "$NPUB_A" "C → A"
ping_test node-c "$NPUB_B" "C → B"
ping_test node-c "$NPUB_D" "C → D"
ping_test node-c "$NPUB_E" "C → E"
echo ""
echo "From node-d:"
ping_test node-d "$NPUB_A" "D → A"
ping_test node-d "$NPUB_B" "D → B"
ping_test node-d "$NPUB_C" "D → C"
ping_test node-d "$NPUB_E" "D → E"
echo ""
echo "From node-e:"
ping_test node-e "$NPUB_A" "E → A"
ping_test node-e "$NPUB_B" "E → B"
ping_test node-e "$NPUB_C" "E → C"
ping_test node-e "$NPUB_D" "E → D"
elif [ "$PROFILE" = "chain" ]; then
echo ""
echo "Adjacent peer tests:"
ping_test node-a "$NPUB_B" "A → B (1 hop)"
ping_test node-b "$NPUB_C" "B → C (1 hop)"
echo ""
echo "Multi-hop tests:"
ping_test node-a "$NPUB_C" "A → C (2 hops)"
ping_test node-a "$NPUB_D" "A → D (3 hops)"
ping_test node-a "$NPUB_E" "A → E (4 hops)"
echo ""
echo "Reverse multi-hop:"
ping_test node-e "$NPUB_A" "E → A (4 hops)"
fi
echo ""
echo "=== Results: $PASSED passed, $FAILED failed ==="
[ "$FAILED" -eq 0 ] && exit 0 || exit 1