diff --git a/.github/scripts/check-workflow-result.sh b/.github/scripts/check-workflow-result.sh index 53326c55..bd2a7053 100755 --- a/.github/scripts/check-workflow-result.sh +++ b/.github/scripts/check-workflow-result.sh @@ -296,6 +296,22 @@ if [ "$WOLFPROV_FORCE_FAIL" = "WOLFPROV_FORCE_FAIL=1" ]; then echo "FAIL: iperf exited $TEST_RESULT but iperf-test.log is missing or does not show the credential encryption failure" exit 1 fi + # ----- GIT-SSH-DR ----- + elif [ "$TEST_SUITE" = "git-ssh-dr" ]; then + # Every client operation must fail on wolfProvider's RNG + if [ "$TEST_RESULT" -ne 0 ] \ + && [ -f "git-ssh-dr-test.log" ] \ + && grep -Eq '^Result: 0 succeeded, [1-9][0-9]* failed on the RNG, 0 failed otherwise, 0 skipped$' \ + git-ssh-dr-test.log; then + echo "PASS: every git over SSH operation failed on the RNG as expected with force fail enabled" + exit 0 + elif [ "$TEST_RESULT" -eq 0 ]; then + echo "FAIL: git over SSH tests unexpectedly succeeded with force fail enabled" + exit 1 + else + echo "FAIL: git-ssh-dr exited $TEST_RESULT but git-ssh-dr-test.log is missing or shows operations that did not fail on the RNG" + exit 1 + fi else if [ $TEST_RESULT -eq 0 ]; then echo "$TEST_SUITE tests unexpectedly succeeded with force fail enabled" diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 3cd5e204..eb6af695 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -143,7 +143,7 @@ exercised, with and without `WOLFPROV_FORCE_FAIL=1`. | `pam-pkcs11.yml` | PAM PKCS#11 module | smartcard login via PKCS#11 token + wolfprov-backed verify | | `opensc.yml` | OpenSC smartcard middleware | PKCS#15 / pkcs11-tool cert + key ops | | `sscep.yml` | SCEP enrollment client | CSR signing + SCEP message envelope decrypt/encrypt | -| `git-ssh-dr.yml` | git over SSH (wolfSSL custom) | ed25519/RSA host key + signing path through OpenSSH stack | +| `git-ssh-dr.yml` | git over SSH to a local sshd (wolfSSL custom) | RNG, SHA-2 and AES in Debian's OpenSSH: `aes-ctr` (RSA, DH group14, aes128-ctr, hmac-sha2-256) and `aes-gcm` (ECDSA P-521, ECDH P-256, aes256-gcm) suites | | `libfido2.yml` | FIDO2 / WebAuthn | CTAP2 ECDSA signatures, HMAC-secret extension | #### TPM, disk crypto, hashing diff --git a/.github/workflows/git-ssh-dr.yml b/.github/workflows/git-ssh-dr.yml index 2a2a4419..3d5e63e2 100644 --- a/.github/workflows/git-ssh-dr.yml +++ b/.github/workflows/git-ssh-dr.yml @@ -47,8 +47,8 @@ jobs: openssl_ref: ${{ fromJson(needs.discover_versions.outputs.openssl_ref_array) }} fips_ref: [ 'FIPS', 'non-FIPS' ] replace_default: [ true ] - key_type: [ 'rsa', 'ecdsa', 'ed25519', 'chacha20-poly1305' ] - iterations: [ 10 ] # Total of 80 runs + suite: [ 'aes-ctr', 'aes-gcm' ] + iterations: [ 10 ] force_fail: ['WOLFPROV_FORCE_FAIL=1', ''] env: WOLFSSL_PACKAGES_PATH: /tmp/wolfssl-packages @@ -94,16 +94,11 @@ jobs: - name: Run git + replace default + ssh test shell: bash run: | - echo "=== Running Git + replace default + ssh Test ===" - echo "Using the local test script for consistent testing" - # Run the test with the matrix parameters - echo "Testing with key type: ${{ matrix.key_type }}" - echo "Running ${{ matrix.iterations }} iterations" - - # Run the scripts test + set +o pipefail ${{ matrix.force_fail }} ./scripts/test-git-ssh-dr.sh \ - --key-types "${{ matrix.key_type }}" \ + --suite "${{ matrix.suite }}" \ --iterations "${{ matrix.iterations }}" \ - --verbose + --verbose 2>&1 | tee git-ssh-dr-test.log + TEST_RESULT=${PIPESTATUS[0]} - echo "=== Test completed for ${{ matrix.key_type }} ===" + $GITHUB_WORKSPACE/.github/scripts/check-workflow-result.sh $TEST_RESULT ${{ matrix.force_fail }} git-ssh-dr diff --git a/scripts/test-git-ssh-dr.sh b/scripts/test-git-ssh-dr.sh index 08ce4789..494e3540 100755 --- a/scripts/test-git-ssh-dr.sh +++ b/scripts/test-git-ssh-dr.sh @@ -17,32 +17,49 @@ # You should have received a copy of the GNU General Public License # along with wolfProvider. If not, see . # -# Local test script for wolfProvider git operations -# This script tests git operations with wolfProvider -# as the default replace provider - -echo "=== wolfProvider Git Operations Local Test ===" -echo "Testing git operations with wolfProvider default replace functionality" -echo "" +# Git over SSH with wolfProvider as the replace-default provider. +# +# Starts a local sshd and runs ssh-keygen and git clone, push, pull and fetch +# against it over ssh://. Client and server allow only the algorithms of one +# suite, and every git operation checks the negotiated algorithms: +# +# aes-ctr RSA 4096 keys (rsa-sha2-512), diffie-hellman-group14-sha256, +# aes128-ctr, hmac-sha2-256 +# aes-gcm ECDSA P-521 keys (ecdsa-sha2-nistp521), ecdh-sha2-nistp256, +# aes256-gcm@openssh.com +# +# OpenSSH gets its RNG, SHA-2 digests and AES ciphers from libcrypto, so +# from wolfProvider. With WOLFPROV_FORCE_FAIL=1 only the client operations +# run with force fail. The script exits 0 only when every operation succeeds, +# and its Result line counts the operations that failed with FORCE_FAIL_REASON. +# +# Force fail stops ssh and ssh-keygen in seed_rng(), before any key exchange +# or cipher, so only the normal runs show the AES and SHA-2 paths working. +# Ed25519, curve25519 and chacha20-poly1305, OpenSSH's defaults, are left +# out: OpenSSH computes them itself and asks wolfProvider only for RNG and +# SHA-2, which both suites already use. +# +# Runs as root with /usr/sbin/sshd, binds sshd to 127.0.0.1:2222, and works +# in a new mktemp directory under /tmp. -# Configuration -KEY_TYPES=("rsa" "ecdsa" "ed25519" "chacha20-poly1305") +SUITE="aes-ctr" ITERATIONS=10 -GITHUB_ITERATIONS=5 -TEST_BASE_DIR="/tmp/git-wolfprovider-test" -SSH_TEST_ENABLED=${SSH_TEST_ENABLED:-true} +VERBOSE_OUTPUT=false +WOLFPROV_FORCE_FAIL=${WOLFPROV_FORCE_FAIL:-0} -# Non-interactive settings -VERBOSE_OUTPUT=${VERBOSE_OUTPUT:-false} -QUIET_MODE=${QUIET_MODE:-false} -MAX_LOG_LINES=${MAX_LOG_LINES:-5} +# OpenSSH exits in seed_rng() when wolfProvider's RNG fails. +FORCE_FAIL_REASON="PRNG is not seeded" -# Force fail functionality -WOLFPROV_FORCE_FAIL=${WOLFPROV_FORCE_FAIL:-0} -FORCE_FAIL_PASSED=0 -FAIL=0 +SSH_PORT=2222 +# Seconds before a single setup step or client command is killed +OP_TIMEOUT=120 +# Set by init_workspace(), together with every path inside it +TEST_BASE_DIR="" +# Commit that the next pull or fetch must bring in, set by advance_remote() +REMOTE_HEAD="" -source "scripts/cmd-test/cmd-test-common.sh" +OPS=("keygen" "clone" "push" "pull" "fetch") +declare -A OK_COUNT RNG_COUNT FAIL_COUNT SKIP_COUNT # Colors for output RED='\033[0;31m' @@ -74,925 +91,461 @@ print_status() { esac } -# Function to handle force fail scenarios -check_force_fail() { - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - ((FORCE_FAIL_PASSED++)) - fi +is_force_fail() { + [ "${WOLFPROV_FORCE_FAIL}" = "1" ] } -# Function to setup git test environment -setup_git_environment() { - echo "=== Setting up Git Test Environment ===" +# Print the last lines of a log file, if it has any +show_log() { + local title=$1 + local file=$2 - # Clean up any existing test directory - rm -rf "$TEST_BASE_DIR" - mkdir -p "$TEST_BASE_DIR" - cd "$TEST_BASE_DIR" - - # Configure git - git config --global user.name "Test User" - git config --global user.email "test@example.com" - git config --global init.defaultBranch main - - # Create bare repository - git init --bare test-repo.git - print_status "SUCCESS" "Created bare repository at $TEST_BASE_DIR/test-repo.git" - - # Create workspace and initial commit - mkdir test-workspace - cd test-workspace - git init - echo "# Test Repository" > README.md - git add README.md - git commit -m "Initial commit" - git remote add origin "$TEST_BASE_DIR/test-repo.git" - git push origin main - print_status "SUCCESS" "Created initial commit and pushed to bare repository" - - cd "$TEST_BASE_DIR" - echo "" + if [ -s "$file" ]; then + echo "--- $title (last 20 lines of $file) ---" + tail -20 "$file" + fi } -# Function to verify repository setup -verify_repository() { - echo "=== Repository Setup Verification ===" - echo "Checking test repository:" - ls -la "$TEST_BASE_DIR/" - echo "" - echo "Repository contents:" - ls -la "$TEST_BASE_DIR/test-repo.git/" - echo "" - echo "Git log in bare repository:" - cd "$TEST_BASE_DIR/test-repo.git" && git log --oneline - echo "" - echo "Git branches in bare repository:" - cd "$TEST_BASE_DIR/test-repo.git" && git branch -a - echo "" - echo "Git refs in bare repository:" - cd "$TEST_BASE_DIR/test-repo.git" && git show-ref - echo "" - - echo "Git information:" - which git - git --version - echo "Git help (first 10 lines):" - git help -a | head -10 - echo "" +die() { + print_status "FAILURE" "$1" + show_log "setup log" "$SETUP_LOG" + show_log "sshd log" "$SSHD_LOG" + exit 1 } -# Function to verify SSH setup and algorithm negotiation -verify_ssh_setup() { - echo "=== SSH Setup and Algorithm Verification ===" - echo "" - - # Check for force fail mode and provide context - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - print_status "INFO" "Force fail mode enabled - testing SSH algorithm behavior" - echo "Note: SSH defaults to ed25519 and chacha20-poly1305" - echo "These algorithms use OpenSSH's inline crypto, not OpenSSL/wolfProvider" - echo "Force fail will pass for default behavior since wolfProvider is not used" - echo "" - echo "SSH-specific forced key generation tests will fail successfully as expected." - echo "Since openssl is used for trivial things surrounding the operation WPFF will" - echo "make the test fail. However, this DOES NOT mean that wolfProvider/openssl is" - echo "being used." - echo "" +# Run a setup step without force fail and stop the test if it fails +setup_run() { + if ! env -u WOLFPROV_FORCE_FAIL timeout "$OP_TIMEOUT" "$@" \ + >>"$SETUP_LOG" 2>&1; then + die "Setup step failed: $*" fi +} - # Git SSH environment variables - echo "=== Git SSH Environment ===" - echo "GIT_SSH: ${GIT_SSH:-not set}" - echo "GIT_SSH_COMMAND: ${GIT_SSH_COMMAND:-not set}" - echo "" +select_suite() { + case "$SUITE" in + "aes-ctr") + KEY_TYPE="rsa" + KEY_BITS=4096 + KEY_ALGO="rsa-sha2-512" + HOST_KEY_NAME="ssh-rsa" + KEX_ALGO="diffie-hellman-group14-sha256" + CIPHER="aes128-ctr" + MAC="hmac-sha2-256" + NEGOTIATED_MAC="hmac-sha2-256" + ;; + "aes-gcm") + KEY_TYPE="ecdsa" + KEY_BITS=521 + KEY_ALGO="ecdsa-sha2-nistp521" + HOST_KEY_NAME="ecdsa-sha2-nistp521" + KEX_ALGO="ecdh-sha2-nistp256" + CIPHER="aes256-gcm@openssh.com" + MAC="hmac-sha2-256" + NEGOTIATED_MAC="" + ;; + *) + echo "Unknown suite: $SUITE" + show_usage + exit 1 + ;; + esac +} - # SSH binary information - echo "=== SSH Binary Information ===" - local ssh_binary=$(which ssh) - echo "SSH binary: $ssh_binary" - echo "SSH version: $(ssh -V 2>&1)" - echo "" +ssh_command() { + local key=$1 - # Detect git remote host - local git_remote_url=$(git remote get-url origin 2>/dev/null || echo "") - local git_host="github.com" - if [[ -n "$git_remote_url" ]]; then - if [[ "$git_remote_url" =~ ^git@([^:]+): ]]; then - git_host="${BASH_REMATCH[1]}" - elif [[ "$git_remote_url" =~ ^ssh://([^/]+)/ ]]; then - git_host="${BASH_REMATCH[1]}" - elif [[ "$git_remote_url" =~ ^https?://([^/]+)/ ]]; then - git_host="${BASH_REMATCH[1]}" - fi - fi + echo "ssh -F /dev/null -i $key -o IdentitiesOnly=yes -o BatchMode=yes" \ + "-o StrictHostKeyChecking=yes -o UserKnownHostsFile=$KNOWN_HOSTS" \ + "-o GlobalKnownHostsFile=/dev/null -o ConnectTimeout=10" \ + "-o ServerAliveInterval=10 -o ServerAliveCountMax=3" \ + "-o HostKeyAlgorithms=$KEY_ALGO -o PubkeyAcceptedAlgorithms=$KEY_ALGO" \ + "-o KexAlgorithms=$KEX_ALGO -o Ciphers=$CIPHER -o MACs=$MAC" \ + "-v -E $SSH_LOG" +} - local ssh_host="git@$git_host" - echo "Target SSH host: $ssh_host" - echo "" +sshd_listening() { + (exec 3<>"/dev/tcp/127.0.0.1/$SSH_PORT") 2>/dev/null +} - # SSH algorithm negotiation test - echo "=== SSH Algorithm Negotiation Test ===" - local ssh_log="/tmp/ssh-negotiation.log" - local ssh_error_log="/tmp/ssh-negotiation-errors.log" +# Create a new workspace (mode 0700) and derive every test path from it +init_workspace() { + TEST_BASE_DIR=$(mktemp -d /tmp/git-wolfprovider-test.XXXXXX) || { + echo "Cannot create a workspace under /tmp" + exit 1 + } + KEY_DIR="$TEST_BASE_DIR/keys" + HOST_KEY="$KEY_DIR/host_key" + SETUP_KEY="$KEY_DIR/setup_key" + AUTH_KEYS="$KEY_DIR/authorized_keys" + KNOWN_HOSTS="$KEY_DIR/known_hosts" + SSHD_CONFIG="$TEST_BASE_DIR/sshd_config" + SSHD_PID="$TEST_BASE_DIR/sshd.pid" + SSHD_LOG="$TEST_BASE_DIR/sshd.log" + SETUP_LOG="$TEST_BASE_DIR/setup.log" + OP_LOG="$TEST_BASE_DIR/op.log" + SSH_LOG="$TEST_BASE_DIR/ssh.log" + BARE_REPO="$TEST_BASE_DIR/test-repo.git" + SETUP_CLONE="$TEST_BASE_DIR/setup-clone" + UPSTREAM_CLONE="$TEST_BASE_DIR/upstream-clone" +} - print_status "INFO" "Testing SSH connection with verbose output..." - if timeout 10 ssh -vvv -o ConnectTimeout=5 -o BatchMode=yes "$ssh_host" 2>"$ssh_error_log" >"$ssh_log" 2>&1; then - print_status "SUCCESS" "SSH connection test completed" - else - print_status "INFO" "SSH connection test completed (connection may have failed as expected)" +# Stop the sshd this run started and remove its workspace +cleanup() { + if [ -z "$TEST_BASE_DIR" ]; then + return fi + if [ -s "$SSHD_PID" ]; then + kill "$(cat "$SSHD_PID")" 2>/dev/null + fi + rm -rf "$TEST_BASE_DIR" +} - # Parse algorithm negotiation results - echo "=== Algorithm Negotiation Results ===" - if [ -f "$ssh_log" ] && [ -s "$ssh_log" ]; then - # Extract key algorithms - local kex_algo=$(grep "kex: algorithm:" "$ssh_log" | tail -1 | awk '{print $NF}' || echo "unknown") - local hostkey_algo=$(grep "kex: host key algorithm:" "$ssh_log" | tail -1 | awk '{print $NF}' || echo "unknown") - local cipher_sc=$(grep "server->client cipher:" "$ssh_log" | tail -1 | awk '{print $5}' || echo "unknown") - local cipher_cs=$(grep "client->server cipher:" "$ssh_log" | tail -1 | awk '{print $5}' || echo "unknown") - - echo "Key Exchange Algorithm: $kex_algo" - echo "Host Key Algorithm: $hostkey_algo" - echo "Server->Client Cipher: $cipher_sc" - echo "Client->Server Cipher: $cipher_cs" - echo "" - - # Check for ed25519 and chacha20-poly1305 usage - local uses_ed25519=false - local uses_chacha20=false - - if [[ "$hostkey_algo" == *"ed25519"* ]]; then - uses_ed25519=true - fi - if [[ "$cipher_sc" == *"chacha20"* ]] || [[ "$cipher_cs" == *"chacha20"* ]]; then - uses_chacha20=true - fi +# Check that ssh and openssl load the replace-default libcrypto +check_install() { + local version + local providers - if [ "$uses_ed25519" = true ] || [ "$uses_chacha20" = true ]; then - print_status "INFO" "Modern SSH algorithms detected" - if [ "$uses_ed25519" = true ]; then - echo " - ed25519 host key algorithm detected (OpenSSH inline crypto)" - fi - if [ "$uses_chacha20" = true ]; then - echo " - chacha20-poly1305 cipher detected (OpenSSH inline crypto)" - fi - echo " - These algorithms bypass OpenSSL/wolfProvider" - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - print_status "SUCCESS" "Force fail will pass - wolfProvider not used by default SSH algorithms" - fi - else - print_status "INFO" "Traditional SSH algorithms detected" - echo " - These algorithms may use OpenSSL/wolfProvider" - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - print_status "WARNING" "Force fail may not pass - wolfProvider may be used" - fi - fi - else - print_status "WARNING" "Could not parse SSH negotiation results" - echo "SSH log file: $ssh_log" - echo "SSH error log: $ssh_error_log" + echo "=== Installation Check ===" + version=$(env -u WOLFPROV_FORCE_FAIL ssh -V 2>&1) + echo "ssh -V: $version" + case "$version" in + *"+wolfProvider-replace-default"*) + ;; + *) + die "ssh is not linked with the wolfProvider replace-default libcrypto" + ;; + esac + + providers=$(env -u WOLFPROV_FORCE_FAIL openssl list -providers 2>&1) + echo "$providers" + case "$providers" in + *"wolfSSL Provider"*) + ;; + *) + die "wolfProvider is not the active provider" + ;; + esac + + if [ ! -x /usr/sbin/sshd ]; then + die "/usr/sbin/sshd not found" fi echo "" +} - # Library linkage analysis - echo "=== SSH Binary Library Analysis ===" - if command -v ldd >/dev/null 2>&1; then - echo "Library dependencies:" - ldd "$ssh_binary" | grep -E -i 'ssl|crypto|wolf|gnutls' || echo " No SSL/Crypto/Wolf/GnuTLS libraries linked" - else - echo "ldd not available for library analysis" +setup_sshd() { + echo "=== Starting sshd on 127.0.0.1:$SSH_PORT ($SUITE) ===" + + setup_run ssh-keygen -q -t "$KEY_TYPE" -b "$KEY_BITS" -N "" \ + -C "git-ssh-dr-host" -f "$HOST_KEY" + setup_run ssh-keygen -q -t "$KEY_TYPE" -b "$KEY_BITS" -N "" \ + -C "git-ssh-dr-setup" -f "$SETUP_KEY" + cp "$SETUP_KEY.pub" "$AUTH_KEYS" + echo "[127.0.0.1]:$SSH_PORT $(cut -d' ' -f1,2 "$HOST_KEY.pub")" \ + > "$KNOWN_HOSTS" + + cat > "$SSHD_CONFIG" < "$GIT_CONFIG_GLOBAL" < "$seed/README.md" + setup_run git -C "$seed" add README.md + setup_run git -C "$seed" commit -q -m "Initial commit" + setup_run git -C "$seed" push -q "$BARE_REPO" main + + # Clone over SSH: the server works, and force fail has a clone to use + setup_run env GIT_SSH_COMMAND="$(ssh_command "$SETUP_KEY")" \ + git clone -q "$REPO_URL" "$SETUP_CLONE" + print_status "SUCCESS" "Created $BARE_REPO and cloned it over SSH" + + # Local clone that adds commits for pull and fetch to download + setup_run git clone -q "$BARE_REPO" "$UPSTREAM_CLONE" echo "" +} - # Clean up temporary files - rm -f "$ssh_log" "$ssh_error_log" +# Require the suite's algorithms in the ssh client log of the last operation +check_negotiation() { + local want + + for want in "kex: algorithm: $KEX_ALGO" \ + "kex: host key algorithm: $KEY_ALGO" \ + "kex: server->client cipher: $CIPHER MAC: $NEGOTIATED_MAC" \ + "kex: client->server cipher: $CIPHER MAC: $NEGOTIATED_MAC" \ + "Server host key: $HOST_KEY_NAME" \ + "Authenticated to 127.0.0.1"; do + if ! grep -qF "$want" "$SSH_LOG"; then + echo "Not found in ssh log: $want" + return 1 + fi + done } -# Function to test GitHub SSH connectivity -test_github_ssh_connectivity() { - echo "=== Testing GitHub SSH Connectivity ===" - echo "Testing lightweight git operation to GitHub via SSH" - echo "" +# Require that ref in dir is the commit advance_remote() pushed last +check_ref() { + local dir=$1 + local ref=$2 + local id - local github_repo="git@github.com:wolfSSL/wolfProvider.git" - local test_iterations=${1:-1} # Default to 1 iteration for GitHub test - local success_count=0 - local failure_count=0 - local timing_log="/tmp/github-ssh-timing.log" - local error_log="/tmp/github-ssh-errors.log" + if [ -z "$REMOTE_HEAD" ]; then + return 0 + fi + id=$(git -C "$dir" rev-parse "$ref") || return 1 + if [ "$id" != "$REMOTE_HEAD" ]; then + echo "$ref is $id, expected $REMOTE_HEAD" + return 1 + fi +} - # Clear previous logs - > "$timing_log" - > "$error_log" +op_keygen() { + local key=$1 - echo "Testing git ls-remote to $github_repo" - echo "This tests SSH connectivity and crypto without heavy operations" - echo "" + timeout "$OP_TIMEOUT" ssh-keygen -q -t "$KEY_TYPE" -b "$KEY_BITS" -N "" \ + -C "git-ssh-dr-test" -f "$key" +} - # Ensure we're in a valid directory for git operations - local original_dir=$(pwd) - cd /tmp || cd / || cd "$HOME" || true - echo "Current directory: $(pwd)" - echo "" +op_clone() { + local key=$1 + local dir=$2 - for ((attempt=1; attempt<=test_iterations; attempt++)); do - echo "--- GitHub SSH Test $attempt ---" - - local start_time=$(date +%s.%N) - local status="UNKNOWN" - - echo "Attempting git ls-remote to GitHub..." - - # Test the lightweight git operation - if timeout 30 git ls-remote "$github_repo" HEAD 2>>"$error_log" | head -1 >/dev/null; then - local end_time=$(date +%s.%N) - local duration=$(echo "$end_time - $start_time" | bc -l) - - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "GitHub SSH operation successful (with WPFF=1" - check_force_fail - else - status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "GitHub SSH operation successful" - fi - - echo " GitHub SSH test: $status ($(printf "%.6f" "$duration")s)" - echo "$attempt,$status,$duration" >> "$timing_log" - else - local end_time=$(date +%s.%N) - local duration=$(echo "$end_time - $start_time" | bc -l) - - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - status="EXPECTED_FAIL" - print_status "SUCCESS" "GitHub SSH operation failed as expected (WPFF=1)" - else - status="FAILURE" - ((failure_count++)) - print_status "FAILURE" "GitHub SSH operation failed on attempt $attempt" - fi - - echo " GitHub SSH test: $status ($(printf "%.6f" "$duration")s)" - echo "$attempt,$status,$duration" >> "$timing_log" - fi - - echo "" - done + GIT_SSH_COMMAND="$(ssh_command "$key")" \ + timeout "$OP_TIMEOUT" git clone "$REPO_URL" "$dir" && + check_negotiation +} - # Summary - echo "=== GITHUB SSH TEST SUMMARY ===" - echo "Total operations: $((success_count + failure_count))" - echo "Successful operations: $success_count" - echo "Failed operations: $failure_count" - if [ $((success_count + failure_count)) -gt 0 ]; then - local failure_rate=$((failure_count * 100 / (success_count + failure_count))) - echo "Failure rate: ${failure_rate}%" - else - echo "Failure rate: 0%" +op_push() { + local key=$1 + local dir=$2 + local head + local remote + + GIT_SSH_COMMAND="$(ssh_command "$key")" \ + timeout "$OP_TIMEOUT" git -C "$dir" push origin main || return + check_negotiation || return 1 + + head=$(git -C "$dir" rev-parse HEAD) || return 1 + remote=$(GIT_SSH_COMMAND="$(ssh_command "$key")" \ + timeout "$OP_TIMEOUT" git -C "$dir" ls-remote origin refs/heads/main) || + return + if [ "${remote%%[[:space:]]*}" != "$head" ]; then + echo "Remote main is '$remote', expected $head" + return 1 fi - echo "" - echo "GitHub SSH timing data saved to: $timing_log" - echo "GitHub SSH error log saved to: $error_log" - echo "" +} - # Show error log summary if there were errors - if [ -s "$error_log" ]; then - echo "=== GITHUB SSH ERROR LOG SUMMARY ===" - head -20 "$error_log" - if [ $(wc -l < "$error_log") -gt 20 ]; then - echo "... (showing first 20 lines, see $error_log for full log)" - fi - echo "" - fi +op_pull() { + local key=$1 + local dir=$2 - # Return to original directory - cd "$original_dir" 2>/dev/null || true + GIT_SSH_COMMAND="$(ssh_command "$key")" \ + timeout "$OP_TIMEOUT" git -C "$dir" pull origin main && + check_negotiation && check_ref "$dir" HEAD } -# Function to test git operations -test_git_operations() { - local key_type=$1 - local iterations=$2 - - echo "=== Testing Git Operations for $key_type ===" - - local success_count=0 - local failure_count=0 - local timing_log="/tmp/git-timing-$key_type.log" - local error_log="/tmp/git-errors-$key_type.log" - - echo "Iteration,Operation,Status,Duration,Error" > "$timing_log" - - for attempt in $(seq 1 "$iterations"); do - echo "--- Attempt $attempt for $key_type ---" - local test_dir="$TEST_BASE_DIR/git-test-$attempt" - mkdir -p "$test_dir" - cd "$test_dir" - - for operation in "clone" "push" "pull" "fetch"; do - echo "Testing $operation operation..." - local start_time=$(date +%s.%N) - local status="UNKNOWN" - - case "$operation" in - "clone") - echo "Attempting to clone from $TEST_BASE_DIR/test-repo.git" - echo "Current directory: $(pwd)" - echo "Repository exists: $(test -d "$TEST_BASE_DIR/test-repo.git" && echo 'YES' || echo 'NO')" - - if git clone --verbose "$TEST_BASE_DIR/test-repo.git" cloned-repo 2>&1 | tee -a "$error_log"; then - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "Clone successful (with WPFF=1 - using OpenSSH inline crypto as expected)" - check_force_fail - else - status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "Clone successful" - fi - - # Verify the clone worked - if [ -d "cloned-repo" ]; then - echo "Cloned repository exists and contains:" - ls -la cloned-repo/ - echo "Git status in cloned repo:" - cd cloned-repo - if ! git status 2>/dev/null; then - echo "WARNING: Git status failed - potential wolfProvider interference" - print_status "WARNING" "Git status failed in cloned repo" - fi - echo "Git log in cloned repo:" - if ! git log --oneline | head -${MAX_LOG_LINES} 2>/dev/null; then - echo "WARNING: Git log failed - potential wolfProvider interference" - print_status "WARNING" "Git log failed in cloned repo" - fi - cd .. - else - print_status "FAILURE" "cloned-repo directory not found after successful clone" - status="FAILURE" - ((failure_count++)) - fi - else - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - status="EXPECTED_FAIL" - print_status "SUCCESS" "Clone failed as expected (WPFF=1 - wolfProvider IS being used!)" - else - status="FAILURE" - ((failure_count++)) - FAIL=1 - print_status "FAILURE" "Clone failed on attempt $attempt" - fi - fi - ;; - - "push") - if [ -d "cloned-repo" ]; then - echo "Entering cloned-repo directory..." - cd cloned-repo - echo "Test change $attempt" >> test-file.txt - git add test-file.txt - git commit -m "Test commit $attempt" || true - echo "Attempting git push..." - if timeout 30 git push origin main 2>>"$error_log"; then - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "Push successful (with WPFF=1 - using OpenSSH inline crypto as expected)" - check_force_fail - else - status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "Push successful" - fi - else - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - status="EXPECTED_FAIL" - print_status "SUCCESS" "Push failed as expected (WPFF=1 - wolfProvider IS being used!)" - else - status="FAILURE" - ((failure_count++)) - FAIL=1 - print_status "FAILURE" "Push failed on attempt $attempt" - fi - fi - cd .. - else - status="SKIPPED" - echo "Skipping push - clone failed" - fi - ;; - - "pull") - if [ -d "cloned-repo" ]; then - echo "Entering cloned-repo directory for pull..." - cd cloned-repo - echo "Attempting git pull..." - if timeout 30 git pull origin main 2>>"$error_log"; then - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "Pull successful (with WPFF=1 - using OpenSSH inline crypto as expected)" - check_force_fail - else - status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "Pull successful" - fi - else - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - status="EXPECTED_FAIL" - print_status "SUCCESS" "Pull failed as expected (WPFF=1 - wolfProvider IS being used!)" - else - status="FAILURE" - ((failure_count++)) - FAIL=1 - print_status "FAILURE" "Pull failed on attempt $attempt" - fi - fi - cd .. - else - status="SKIPPED" - echo "Skipping pull - clone failed" - fi - ;; - - "fetch") - if [ -d "cloned-repo" ]; then - echo "Entering cloned-repo directory for fetch..." - cd cloned-repo - echo "Attempting git fetch..." - if timeout 30 git fetch origin 2>>"$error_log"; then - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "Fetch successful (with WPFF=1 - using OpenSSH inline crypto as expected)" - check_force_fail - else - status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "Fetch successful" - fi - else - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - status="EXPECTED_FAIL" - print_status "SUCCESS" "Fetch failed as expected (WPFF=1 - wolfProvider IS being used!)" - else - status="FAILURE" - ((failure_count++)) - FAIL=1 - print_status "FAILURE" "Fetch failed on attempt $attempt" - fi - fi - cd .. - else - status="SKIPPED" - echo "Skipping fetch - clone failed" - fi - ;; - esac - - local end_time=$(date +%s.%N) - local duration=$(echo "$end_time - $start_time" | bc -l 2>/dev/null || echo "0") - echo "$attempt,$operation,$status,$duration," >> "$timing_log" - echo " $operation: $status (${duration}s)" - done - - rm -rf "$test_dir" - done - - # Print summary - echo "" - echo "=== SUMMARY FOR $key_type ===" - echo "Total operations: $((success_count + failure_count))" - echo "Successful operations: $success_count" - echo "Failed operations: $failure_count" - - if [ $failure_count -gt 0 ]; then - local failure_rate=$(echo "scale=2; $failure_count * 100 / ($success_count + failure_count)" | bc -l) - echo "Failure rate: ${failure_rate}%" - else - echo "Failure rate: 0%" - fi +op_fetch() { + local key=$1 + local dir=$2 - echo "" - echo "Timing data saved to: $timing_log" - echo "Error log saved to: $error_log" + GIT_SSH_COMMAND="$(ssh_command "$key")" \ + timeout "$OP_TIMEOUT" git -C "$dir" fetch origin && + check_negotiation && check_ref "$dir" origin/main +} - if [ -f "$error_log" ] && [ -s "$error_log" ]; then - echo "" - echo "=== ERROR LOG SUMMARY ===" - tail -20 "$error_log" +# Run one client operation, count its result and return its exit status +run_op() { + local op=$1 + local rc + local outcome + local expected + shift + + : > "$OP_LOG" + : > "$SSH_LOG" + "$@" >"$OP_LOG" 2>&1 + rc=$? + if [ $rc -eq 124 ]; then + echo "Timed out after ${OP_TIMEOUT}s" >> "$OP_LOG" fi - echo "" -} -# Function to test git operations with different SSH key types -test_ssh_key_operations() { - local key_type=$1 - local iterations=$2 + if [ "$VERBOSE_OUTPUT" = "true" ]; then + sed 's/^/ /' "$OP_LOG" + fi - echo "=== Testing Git Operations with $key_type SSH Keys ===" - echo "Investigating intermittent failures with wolfProvider + git + SSH keys" - echo "" + if [ $rc -eq 0 ]; then + ((OK_COUNT[$op]++)) + outcome="succeeded" + elif grep -qF "$FORCE_FAIL_REASON" "$OP_LOG" "$SSH_LOG"; then + ((RNG_COUNT[$op]++)) + outcome="failed on the RNG" + else + ((FAIL_COUNT[$op]++)) + outcome="failed" + fi - # Verify wolfProvider is still active (if available) - echo "Pre-SSH wolfProvider Verification:" - if openssl list -providers | grep -q "wolfSSL Provider"; then - print_status "SUCCESS" "wolfProvider is active before SSH key operations" + if is_force_fail; then + expected="failed on the RNG" else - print_status "INFO" "wolfProvider not detected - testing SSH keys without wolfProvider" + expected="succeeded" + fi + if [ "$outcome" = "$expected" ]; then + print_status "SUCCESS" "$op $outcome" + else + print_status "FAILURE" "$op $outcome" + show_log "$op output" "$OP_LOG" + show_log "ssh log" "$SSH_LOG" + show_log "sshd log" "$SSHD_LOG" fi - echo "" - local success_count=0 - local failure_count=0 - local timing_log="/tmp/ssh-key-timing-$key_type.log" - local error_log="/tmp/ssh-key-errors-$key_type.log" - - echo "Iteration,Operation,Status,Duration,Error" > "$timing_log" - - # Test SSH key generation and git operations - for attempt in $(seq 1 "$iterations"); do - echo "--- SSH Key Test $attempt for $key_type ---" - local test_dir="$TEST_BASE_DIR/ssh-key-test-$attempt" - mkdir -p "$test_dir" - cd "$test_dir" - - # Generate SSH key for this attempt - local ssh_key="/tmp/test_${key_type}_key_$attempt" - local ssh_pub_key="${ssh_key}.pub" - - echo "Generating $key_type SSH key (attempt $attempt)..." - local key_gen_start=$(date +%s.%N) - local key_gen_status="UNKNOWN" - - case "$key_type" in - "rsa") - if ssh-keygen -t rsa -b 4096 -f "$ssh_key" -N "" -C "test-rsa-key-$attempt" 2>/dev/null; then - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - key_gen_status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "RSA key generation successful (with WPFF=1 - using OpenSSH inline crypto as expected)" - check_force_fail - else - key_gen_status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "RSA key generation successful" - fi - else - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - key_gen_status="EXPECTED_FAIL" - print_status "SUCCESS" "RSA key generation failed as expected (WPFF=1 - wolfProvider IS being used!)" - else - key_gen_status="FAILURE" - ((failure_count++)) - FAIL=1 - print_status "FAILURE" "RSA key generation failed" - fi - fi - ;; - "ecdsa") - if ssh-keygen -t ecdsa -b 521 -f "$ssh_key" -N "" -C "test-ecdsa-key-$attempt" 2>/dev/null; then - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - key_gen_status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "ECDSA key generation successful (with WPFF=1 - using OpenSSH inline crypto as expected)" - check_force_fail - else - key_gen_status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "ECDSA key generation successful" - fi - else - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - key_gen_status="EXPECTED_FAIL" - print_status "SUCCESS" "ECDSA key generation failed as expected (WPFF=1 - wolfProvider IS being used!)" - else - key_gen_status="FAILURE" - ((failure_count++)) - FAIL=1 - print_status "FAILURE" "ECDSA key generation failed" - fi - fi - ;; - "ed25519") - if ssh-keygen -t ed25519 -f "$ssh_key" -N "" -C "test-ed25519-key-$attempt" 2>/dev/null; then - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - key_gen_status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "ED25519 key generation successful (with WPFF=1 - using OpenSSH inline crypto as expected)" - check_force_fail - else - key_gen_status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "ED25519 key generation successful" - fi - else - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - key_gen_status="EXPECTED_FAIL" - print_status "SUCCESS" "ED25519 key generation failed as expected (WPFF=1 - wolfProvider IS being used!)" - else - key_gen_status="FAILURE" - ((failure_count++)) - FAIL=1 - print_status "FAILURE" "ED25519 key generation failed" - fi - fi - ;; - "chacha20-poly1305") - # Use chacha20-poly1305 cipher for SSH key encryption (default cipher in SSH) - if ssh-keygen -t ed25519 -Z chacha20-poly1305@openssh.com -f "$ssh_key" -N "" -C "test-chacha20-poly1305-key-$attempt" 2>/dev/null; then - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - key_gen_status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "chacha20-poly1305 SSH key generation successful (with WPFF=1 - using OpenSSH inline crypto as expected)" - check_force_fail - else - key_gen_status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "chacha20-poly1305 SSH key generation successful" - fi - else - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - key_gen_status="EXPECTED_FAIL" - print_status "SUCCESS" "chacha20-poly1305 SSH key generation failed as expected (WPFF=1 - wolfProvider IS being used!)" - else - key_gen_status="FAILURE" - ((failure_count++)) - FAIL=1 - print_status "FAILURE" "chacha20-poly1305 SSH key generation failed" - fi - fi - ;; - esac + return $rc +} - local key_gen_end=$(date +%s.%N) - local key_gen_duration=$(echo "$key_gen_end - $key_gen_start" | bc -l 2>/dev/null || echo "0") - echo "$attempt,key_generation,$key_gen_status,$key_gen_duration," >> "$timing_log" - echo " Key generation: $key_gen_status (${key_gen_duration}s)" - - if [ "$key_gen_status" = "SUCCESS" ] && [ -f "$ssh_key" ]; then - echo "Key fingerprint: $(ssh-keygen -lf "$ssh_pub_key" 2>/dev/null | awk '{print $2}')" - echo "Key size: $(stat -c%s "$ssh_key") bytes" - - # Test git operations with this SSH key - for operation in "clone" "push" "pull" "fetch"; do - echo "Testing git $operation with $key_type SSH key..." - local start_time=$(date +%s.%N) - local status="UNKNOWN" - - case "$operation" in - "clone") - echo "Setting up SSH key for git operations..." - mkdir -p ~/.ssh - cp "$ssh_key" ~/.ssh/id_${key_type}_test - cp "$ssh_pub_key" ~/.ssh/id_${key_type}_test.pub - chmod 600 ~/.ssh/id_${key_type}_test - chmod 644 ~/.ssh/id_${key_type}_test.pub - - # Test git clone with SSH key (using local path but with SSH key setup) - if git clone --verbose "$TEST_BASE_DIR/test-repo.git" cloned-repo 2>&1 | tee -a "$error_log"; then - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "Git clone with $key_type key successful (with WPFF=1 - using OpenSSH inline crypto as expected)" - check_force_fail - else - status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "Git clone with $key_type key successful" - fi - - if [ -d "cloned-repo" ]; then - echo "Cloned repository exists and contains:" - ls -la cloned-repo/ - echo "Git status in cloned repo:" - cd cloned-repo - git status || echo "Git status failed (this may be normal)" - echo "Git log in cloned repo:" - git log --oneline | head -${MAX_LOG_LINES} || echo "Git log failed" - cd .. - fi - else - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - status="EXPECTED_FAIL" - print_status "SUCCESS" "Git clone with $key_type key failed as expected (WPFF=1 - wolfProvider IS being used!)" - else - status="FAILURE" - ((failure_count++)) - FAIL=1 - print_status "FAILURE" "Git clone with $key_type key failed" - fi - fi - ;; - - "push") - if [ -d "cloned-repo" ]; then - echo "Entering cloned-repo directory for git push..." - cd cloned-repo - echo "Test change $attempt with $key_type key" >> test-file.txt - git add test-file.txt - git commit -m "$key_type Test commit $attempt" || true - echo "Attempting git push..." - if timeout 30 git push origin main 2>>"$error_log"; then - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "Git push with $key_type key successful (with WPFF=1 - using OpenSSH inline crypto as expected)" - check_force_fail - else - status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "Git push with $key_type key successful" - fi - else - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - status="EXPECTED_FAIL" - print_status "SUCCESS" "Git push with $key_type key failed as expected (WPFF=1 - wolfProvider IS being used!)" - else - status="FAILURE" - ((failure_count++)) - FAIL=1 - print_status "FAILURE" "Git push with $key_type key failed" - fi - fi - cd .. - else - status="SKIPPED" - echo "Skipping push - clone failed" - fi - ;; - - "pull") - if [ -d "cloned-repo" ]; then - echo "Entering cloned-repo directory for git pull..." - cd cloned-repo - echo "Attempting git pull..." - if timeout 30 git pull origin main 2>>"$error_log"; then - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "Git pull with $key_type key successful (with WPFF=1 - using OpenSSH inline crypto as expected)" - check_force_fail - else - status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "Git pull with $key_type key successful" - fi - else - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - status="EXPECTED_FAIL" - print_status "SUCCESS" "Git pull with $key_type key failed as expected (WPFF=1 - wolfProvider IS being used!)" - else - status="FAILURE" - ((failure_count++)) - FAIL=1 - print_status "FAILURE" "Git pull with $key_type key failed" - fi - fi - cd .. - else - status="SKIPPED" - echo "Skipping pull - clone failed" - fi - ;; - - "fetch") - if [ -d "cloned-repo" ]; then - echo "Entering cloned-repo directory for git fetch..." - cd cloned-repo - echo "Attempting git fetch..." - if timeout 30 git fetch origin 2>>"$error_log"; then - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "Git fetch with $key_type key successful (with WPFF=1 - using OpenSSH inline crypto as expected)" - check_force_fail - else - status="SUCCESS" - ((success_count++)) - print_status "SUCCESS" "Git fetch with $key_type key successful" - fi - else - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - status="EXPECTED_FAIL" - print_status "SUCCESS" "Git fetch with $key_type key failed as expected (WPFF=1 - wolfProvider IS being used!)" - else - status="FAILURE" - ((failure_count++)) - FAIL=1 - print_status "FAILURE" "Git fetch with $key_type key failed" - fi - fi - cd .. - else - status="SKIPPED" - echo "Skipping fetch - clone failed" - fi - ;; - esac - - local end_time=$(date +%s.%N) - local duration=$(echo "$end_time - $start_time" | bc -l 2>/dev/null || echo "0") - echo "$attempt,git_${operation},$status,$duration," >> "$timing_log" - echo " Git $operation with $key_type: $status (${duration}s)" - done - - # Clean up SSH key for this attempt - rm -f ~/.ssh/id_${key_type}_test ~/.ssh/id_${key_type}_test.pub - fi +skip_op() { + local op=$1 - # Clean up test files - rm -f "$ssh_key" "$ssh_pub_key" - rm -rf "$test_dir" - done + ((SKIP_COUNT[$op]++)) + print_status "WARNING" "$op skipped" +} - # Print summary - echo "" - echo "=== SSH KEY TEST SUMMARY FOR $key_type ===" - echo "Total operations: $((success_count + failure_count))" - echo "Successful operations: $success_count" - echo "Failed operations: $failure_count" - - if [ $failure_count -gt 0 ]; then - local failure_rate=$(echo "scale=2; $failure_count * 100 / ($success_count + failure_count)" | bc -l) - echo "Failure rate: ${failure_rate}%" - else - echo "Failure rate: 0%" - fi +# Commit a change to push, without force fail +make_commit() { + local dir=$1 + local attempt=$2 - echo "" - echo "SSH Key timing data saved to: $timing_log" - echo "SSH Key error log saved to: $error_log" + echo "Test change $attempt" >> "$dir/test-file.txt" + setup_run git -C "$dir" add test-file.txt + setup_run git -C "$dir" commit -q -m "Test commit $attempt" +} - if [ -f "$error_log" ] && [ -s "$error_log" ]; then - echo "" - echo "=== SSH KEY ERROR LOG SUMMARY ===" - tail -20 "$error_log" - fi - echo "" +# Push a new commit from UPSTREAM_CLONE, without force fail +advance_remote() { + local label=$1 + + setup_run git -C "$UPSTREAM_CLONE" pull -q origin main + echo "Upstream change $label" >> "$UPSTREAM_CLONE/upstream-file.txt" + setup_run git -C "$UPSTREAM_CLONE" add upstream-file.txt + setup_run git -C "$UPSTREAM_CLONE" commit -q -m "Upstream commit $label" + setup_run git -C "$UPSTREAM_CLONE" push -q origin main + REMOTE_HEAD=$(git -C "$UPSTREAM_CLONE" rev-parse HEAD) || + die "Cannot read the upstream clone's HEAD" } -# Function to cleanup -cleanup() { - echo "=== Cleanup ===" +# Run keygen, clone, push, pull and fetch once. Under force fail, a step +# that fails uses the setup key or setup clone so the next step still runs. +run_iteration() { + local attempt=$1 + local iter_dir="$TEST_BASE_DIR/iter-$attempt" + local key="$iter_dir/id_$KEY_TYPE" + local clone_key="" + local work_dir="" + local op + + echo "--- Iteration $attempt of $ITERATIONS ($SUITE) ---" + mkdir -p "$iter_dir" + + if run_op "keygen" op_keygen "$key"; then + cat "$key.pub" >> "$AUTH_KEYS" + clone_key=$key + elif is_force_fail; then + clone_key=$SETUP_KEY + fi - # Stop SSH server if running - if pgrep -f "sshd.*2222" > /dev/null; then - echo "Stopping SSH test server..." - pkill -f "sshd.*2222" || true + if [ -z "$clone_key" ]; then + skip_op "clone" + elif run_op "clone" op_clone "$clone_key" "$iter_dir/clone"; then + work_dir="$iter_dir/clone" + elif is_force_fail; then + work_dir=$SETUP_CLONE fi - # Clean up test directory - rm -rf "$TEST_BASE_DIR" - print_status "SUCCESS" "Cleaned up test directory: $TEST_BASE_DIR" + for op in "push" "pull" "fetch"; do + if [ -z "$work_dir" ]; then + skip_op "$op" + continue + fi + if [ "$op" = "push" ]; then + make_commit "$work_dir" "$attempt" + elif ! is_force_fail; then + advance_remote "$attempt-$op" + fi + if ! run_op "$op" "op_$op" "$clone_key" "$work_dir" && + [ "$op" = "push" ] && ! is_force_fail; then + # Drop the unpushed commit so pull can still fast-forward + setup_run git -C "$work_dir" reset -q --hard origin/main + fi + done + + rm -rf "$iter_dir" echo "" } -# Function to show usage show_usage() { echo "Usage: $0 [OPTIONS]" echo "" echo "Options:" echo " -h, --help Show this help message" - echo " -v, --verbose Enable verbose debug output" - echo " -q, --quiet Enable quiet mode (minimal output)" - echo " -s, --ssh Enable SSH key testing (default: enabled)" - echo " -n, --no-ssh Disable SSH key testing" - echo " -i, --iterations N Number of iterations per test (default: 10)" - echo " -g, --github-iterations N Number of GitHub SSH test iterations (default: 5)" - echo " -k, --key-types TYPES Comma-separated key types (default: rsa,ecdsa,ed25519)" - echo " -l, --log-lines N Maximum git log lines to show (default: 5)" - echo "" - echo "Environment Variables:" - echo " VERBOSE_OUTPUT=true Enable verbose output" - echo " QUIET_MODE=true Enable quiet mode" - echo " SSH_TEST_ENABLED=false Disable SSH testing" - echo " MAX_LOG_LINES=10 Set maximum log lines" - echo " WOLFPROV_FORCE_FAIL=1 Test if wolfProvider is being used (operations should fail)" - echo "" - echo "Examples:" - echo " $0 # Run all tests with default settings" - echo " $0 --verbose # Run with verbose debug output" - echo " $0 --no-ssh # Skip SSH key testing" - echo " $0 --iterations 20 # Run 20 iterations per test" - echo " $0 --github-iterations 10 # Run 10 GitHub SSH tests" - echo " $0 --key-types rsa,ed25519 # Test only RSA and ED25519 keys" - echo " WOLFPROV_FORCE_FAIL=1 $0 # Test with force fail to verify wolfProvider usage" + echo " -v, --verbose Print the output of every operation" + echo " -i, --iterations N Number of iterations (default: 10)" + echo " -s, --suite SUITE aes-ctr or aes-gcm (default: aes-ctr)" echo "" } -# Function to parse command line arguments +# Exit unless the option in $1 is followed by a value +need_value() { + if [ $# -lt 2 ]; then + echo "Missing value for $1" + show_usage + exit 1 + fi +} + parse_args() { while [[ $# -gt 0 ]]; do case $1 in @@ -1004,32 +557,14 @@ parse_args() { VERBOSE_OUTPUT=true shift ;; - -q|--quiet) - QUIET_MODE=true - shift - ;; - -s|--ssh) - SSH_TEST_ENABLED=true - shift - ;; - -n|--no-ssh) - SSH_TEST_ENABLED=false - shift - ;; -i|--iterations) + need_value "$@" ITERATIONS="$2" shift 2 ;; - -g|--github-iterations) - GITHUB_ITERATIONS="$2" - shift 2 - ;; - -k|--key-types) - IFS=',' read -ra KEY_TYPES <<< "$2" - shift 2 - ;; - -l|--log-lines) - MAX_LOG_LINES="$2" + -s|--suite) + need_value "$@" + SUITE="$2" shift 2 ;; *) @@ -1039,94 +574,85 @@ parse_args() { ;; esac done + + if ! [[ "$ITERATIONS" =~ ^[1-9][0-9]*$ ]]; then + echo "Invalid iteration count: $ITERATIONS" + exit 1 + fi } -# Main execution main() { - # Parse command line arguments - parse_args "$@" + local op + local ok=0 + local rng=0 + local failed=0 + local skipped=0 - echo "Starting wolfProvider Git Operations Test" - echo "==========================================" + parse_args "$@" + select_suite + + echo "=== wolfProvider Git over SSH Test ===" + echo "Suite: $SUITE ($KEY_ALGO, $KEX_ALGO, $CIPHER, $MAC)" + echo "Iterations: $ITERATIONS" + if is_force_fail; then + echo "WOLFPROV_FORCE_FAIL=1: client operations are expected to fail" \ + "with '$FORCE_FAIL_REASON'" + fi echo "" - # Check if running as root - if [ "$EUID" -ne 0 ]; then - print_status "WARNING" "Not running as root. Some operations may fail due to permissions." - echo "Consider running with: sudo $0" - echo "" + if [ "$(id -u)" -ne 0 ]; then + echo "This test starts sshd and must run as root" + exit 1 fi - # Verify wolfProvider is properly installed - ./scripts/verify-debian.sh - - # Verify SSH setup and algorithm negotiation - verify_ssh_setup + trap cleanup EXIT + init_workspace + mkdir -m 700 "$KEY_DIR" - # Setup git environment - setup_git_environment + export GIT_CONFIG_GLOBAL="$TEST_BASE_DIR/gitconfig" + REPO_URL="ssh://$(id -un)@127.0.0.1:$SSH_PORT$BARE_REPO" - # Verify repository setup - verify_repository + check_install + setup_sshd + setup_repository - # Test git operations for each key type - for key_type in "${KEY_TYPES[@]}"; do - test_git_operations "$key_type" "$ITERATIONS" + for op in "${OPS[@]}"; do + OK_COUNT[$op]=0 + RNG_COUNT[$op]=0 + FAIL_COUNT[$op]=0 + SKIP_COUNT[$op]=0 done - # Test SSH key operations if enabled - if [ "$SSH_TEST_ENABLED" = "true" ]; then - echo "=== SSH Key Testing Enabled ===" - echo "Testing SSH key generation and validation with different key types" - echo "" - - for key_type in "${KEY_TYPES[@]}"; do - test_ssh_key_operations "$key_type" "$ITERATIONS" - done - else - echo "=== SSH Key Testing Disabled ===" - echo "Set SSH_TEST_ENABLED=true to enable SSH key testing" - echo "" - fi - - # Test GitHub SSH connectivity - test_github_ssh_connectivity "$GITHUB_ITERATIONS" + for attempt in $(seq 1 "$ITERATIONS"); do + run_iteration "$attempt" + done - # Final verification - echo "=== Final wolfProvider Verification ===" - if openssl list -providers | grep -q "wolfSSL Provider"; then - print_status "SUCCESS" "wolfProvider is still active after git operations" - else - print_status "WARNING" "wolfProvider may have been affected by git operations" - fi + echo "=== Summary ($SUITE, $ITERATIONS iterations) ===" + printf " %-7s %9s %12s %14s %8s\n" "" "succeeded" "RNG failure" \ + "other failure" "skipped" + for op in "${OPS[@]}"; do + printf " %-7s %9d %12d %14d %8d\n" "$op" "${OK_COUNT[$op]}" \ + "${RNG_COUNT[$op]}" "${FAIL_COUNT[$op]}" "${SKIP_COUNT[$op]}" + ok=$((ok + OK_COUNT[$op])) + rng=$((rng + RNG_COUNT[$op])) + failed=$((failed + FAIL_COUNT[$op])) + skipped=$((skipped + SKIP_COUNT[$op])) + done echo "" + # check-workflow-result.sh matches this line in force fail runs + echo "Result: $ok succeeded, $rng failed on the RNG, $failed failed" \ + "otherwise, $skipped skipped" - # Cleanup - cleanup - - # Handle force fail results like cmd tests - if [ "${WOLFPROV_FORCE_FAIL}" = "1" ]; then - if [ $FORCE_FAIL_PASSED -eq 1 ]; then - echo "" - print_status "FAILURE" "Git Tests Failed With Force Fail Enabled" - echo "ERROR: Some tests passed when they should have failed" - exit 1 - else - echo "" - print_status "SUCCESS" "Git Tests Passed With Force Fail Enabled" - echo "SUCCESS: All tests failed as expected" - exit 0 - fi - else - if [ $FAIL -eq 0 ]; then - print_status "SUCCESS" "wolfProvider Git Operations Test completed successfully!" - exit 0 - else - print_status "FAILURE" "wolfProvider Git Operations Test completed with failures!" - exit 1 - fi + if [ $rng -eq 0 ] && [ $failed -eq 0 ] && [ $skipped -eq 0 ] && + [ $ok -gt 0 ]; then + print_status "SUCCESS" "All $ok operations succeeded" + exit 0 + fi + if ! is_force_fail; then + show_log "sshd log" "$SSHD_LOG" + print_status "FAILURE" "Not every operation succeeded" fi + exit 1 } -# Run main function main "$@"