Skip to content

Commit 36e2765

Browse files
ejohnstownpadelsbach
authored andcommitted
Fix sshd test flakiness and orphan daemon
- term size test: poll tmux output with retries instead of fixed sleeps, re-sending the size query each pass in case the shell was not yet ready - term close test: scope netstat checks to the test port so unrelated host CLOSE_WAIT/TIME_WAIT sockets don't fail the test - run_all_sshd_tests.sh: validate --match before starting wolfSSHd - renewcerts.sh: build the per-user cert from a throwaway config copy so the tracked renewcerts.cnf is never modified in place
1 parent 69f7799 commit 36e2765

5 files changed

Lines changed: 108 additions & 49 deletions

File tree

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ apps/wolfsshd/wolfsshd
7070
apps/wolfsshd/test/test_configuration
7171
apps/wolfsshd/test/log.txt
7272
apps/wolfsshd/test/sshd_config_*
73+
apps/wolfsshd/test/authorized_keys_test
74+
apps/wolfsshd/test/stdout.txt
75+
76+
# Test-run generated certs/keys and scratch data
77+
keys/root-*
78+
keys/*.csr
79+
keys/renewcerts-*.cnf
80+
random-test.txt
81+
random-test-result.txt
82+
test.dat
7383

7484
# test output
7585
tests/*.test

apps/wolfsshd/test/run_all_sshd_tests.sh

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,26 @@ done
6161
TOTAL=0
6262
SKIPPED=0
6363

64+
# validate the requested test before any setup so a bad name does not leave
65+
# a wolfSSHd running
66+
if [[ -n "$MATCH" ]]; then
67+
MATCH_FOUND=0
68+
for test in "${test_cases[@]}"; do
69+
if [[ "$test" == "$MATCH" ]]; then
70+
MATCH_FOUND=1
71+
break
72+
fi
73+
done
74+
if [[ "$MATCH_FOUND" -eq 0 ]]; then
75+
echo "Error: Test '$MATCH' not found."
76+
echo "All test cases:"
77+
for test in "${test_cases[@]}"; do
78+
echo " $test"
79+
done
80+
exit 1
81+
fi
82+
fi
83+
6484
# setup
6585
set -e
6686
./create_authorized_test_file.sh
@@ -106,13 +126,8 @@ run_test() {
106126

107127
# Run the tests
108128
if [[ -n "$MATCH" ]]; then
109-
if [[ " ${test_cases[*]} " =~ " $MATCH " ]]; then
110-
echo "Running test: $MATCH"
111-
run_test "$MATCH"
112-
else
113-
echo "Error: Test '$MATCH' not found."
114-
exit 1
115-
fi
129+
echo "Running test: $MATCH"
130+
run_test "$MATCH"
116131

117132
if [ "$USING_LOCAL_HOST" == 1 ]; then
118133
printf "Shutting down test wolfSSHd\n"

apps/wolfsshd/test/sshd_term_close_test.sh

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ if [ "$WOLFSSHD_PID_COUNT" = "$WOLFSSHD_PID_COUNT_AFTER" ]; then
2828
exit 1
2929
fi
3030

31-
netstat -nt | grep ESTABLISHED
31+
# Only consider sockets for the test port so unrelated host traffic
32+
# (other CLOSE_WAIT/TIME_WAIT connections) does not skew the result.
33+
netstat -nt | grep ":$2 " | grep ESTABLISHED
3234
RESULT=$?
3335
if [ "$RESULT" != "0" ]; then
3436
echo "Expecting to find the TCP connection established"
@@ -37,14 +39,14 @@ fi
3739

3840
sleep 2
3941

40-
netstat -nt | grep CLOSE_WAIT
42+
netstat -nt | grep ":$2 " | grep CLOSE_WAIT
4143
RESULT=$?
4244
if [ "$RESULT" = "0" ]; then
4345
echo "Found close wait and was not expecting it"
4446
exit 1
4547
fi
4648

47-
netstat -nt | grep TIME_WAIT
49+
netstat -nt | grep ":$2 " | grep TIME_WAIT
4850
RESULT=$?
4951
if [ "$RESULT" != "0" ]; then
5052
echo "Did not find timed wait for TCP close down"

apps/wolfsshd/test/sshd_term_size_test.sh

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -23,34 +23,63 @@ if [ ${RESULT} = 1 ]; then
2323
exit 1
2424
fi
2525

26+
# tear down the tmux session on any exit, so a timeout failure does not
27+
# leave a stale session that breaks the next run with "duplicate session"
28+
trap 'tmux kill-session -t test 2>/dev/null || true' EXIT
29+
30+
# Wait until the remote shell produces some output (i.e. a prompt), so the
31+
# SSH session is known to be up before keys are sent to it. CI runners can
32+
# take several seconds to get through key exchange and login.
33+
wait_for_session() {
34+
for _ in $(seq 1 10); do
35+
if tmux capture-pane -p -t test | grep -q '[^[:space:]]'; then
36+
return 0
37+
fi
38+
sleep 1
39+
done
40+
echo "Timed out waiting for SSH session output"
41+
tmux capture-pane -p -t test
42+
return 1
43+
}
44+
45+
# Ask the remote shell for its size and poll the pane until a line of the
46+
# form "<columns> <rows>" shows up. The result is left in SIZE_LINE.
47+
get_size_line() {
48+
SIZE_LINE=""
49+
for _ in $(seq 1 10); do
50+
# Re-send the query each pass in case the shell was not yet ready to
51+
# read input on an earlier pass; tail -n 1 below tolerates the extra
52+
# numeric line a repeat can produce.
53+
tmux send-keys -t test 'echo;echo $COLUMNS $LINES;echo'
54+
tmux send-keys -t test 'ENTER'
55+
sleep 1
56+
SIZE_LINE=$(tmux capture-pane -p -t test | tr -d '\r' | \
57+
grep -E '^[0-9]+[[:space:]]+[0-9]+[[:space:]]*$' | tail -n 1)
58+
if [ -n "$SIZE_LINE" ]; then
59+
return 0
60+
fi
61+
done
62+
echo "Timed out waiting for terminal size output"
63+
tmux capture-pane -p -t test
64+
return 1
65+
}
66+
2667
echo "Creating tmux session at $PWD with command :"
2768
echo "tmux new-session -d -s test \"$TEST_CLIENT -q -t -u $USER -i $PRIVATE_KEY -j $PUBLIC_KEY -h \"$1\" -p \"$2\"\""
2869
tmux new-session -d -s test "$TEST_CLIENT -q -t -u $USER -i $PRIVATE_KEY -j $PUBLIC_KEY -h \"$1\" -p \"$2\""
2970
echo "Result of tmux new-session = $?"
3071

31-
# give the command a second to establish SSH connection
32-
sleep 1
72+
wait_for_session || exit 1
3373

3474
COL=`tmux display -p -t test '#{pane_width}'`
3575
ROW=`tmux display -p -t test '#{pane_height}'`
3676
echo "tmux 'test' session has COL = ${COL} and ROW = ${ROW}"
3777

3878
# get the terminals columns and lines
39-
tmux send-keys -t test 'echo;echo $COLUMNS $LINES;echo'
40-
tmux send-keys -t test 'ENTER'
41-
42-
# give the command a second to run
43-
sleep 1
44-
45-
tmux capture-pane -t test
46-
RESULT=$(tmux show-buffer | grep '^[0-9]* [0-9]*$')
47-
tmux show-buffer
79+
get_size_line || exit 1
80+
echo "Captured terminal size line: '$SIZE_LINE'"
4881

49-
echo "$RESULT"
50-
echo ""
51-
echo ""
52-
ROW_FOUND=$(echo "$RESULT" | sed -e 's/[0-9]* \([0-9]*\)/\1/')
53-
COL_FOUND=$(echo "$RESULT" | sed -e 's/\([0-9]*\) [0-9]*/\1/')
82+
read -r COL_FOUND ROW_FOUND <<< "$SIZE_LINE"
5483

5584
if [ "$COL" != "$COL_FOUND" ]; then
5685
echo "Col found was $COL_FOUND which does not match expected $COL"
@@ -80,22 +109,13 @@ echo "Starting another session with a smaller window size"
80109
echo "tmux new-session -d -x 50 -y 10 -s test \"$TEST_CLIENT -q -t -u $USER -i $PRIVATE_KEY -j $PUBLIC_KEY -h \"$1\" -p \"$2\"\""
81110
tmux new-session -d -x 50 -y 10 -s test "$TEST_CLIENT -q -t -u $USER -i $PRIVATE_KEY -j $PUBLIC_KEY -h \"$1\" -p \"$2\""
82111

83-
# give the command a second to establish SSH connection
84-
sleep 1
112+
wait_for_session || exit 1
85113

86114
echo "Sending keys to tmux session for displaying column/rows"
87-
tmux send-keys -t test 'echo;echo $COLUMNS $LINES;echo'
88-
tmux send-keys -t test 'ENTER'
89-
tmux capture-pane -t test
90-
RESULT=$(tmux show-buffer | grep '^[0-9]* [0-9]*$')
91-
92-
ROW_FOUND=$( echo "$RESULT" | sed -e 's/[0-9]* \([0-9]*\)/\1/' )
93-
COL_FOUND=$( echo "$RESULT" | sed -e 's/\([0-9]*\) [0-9]*/\1/' )
94-
95-
#remove any newlines, tabs, or returns
96-
ROW_FOUND=$( tr -d '\n\t\r ' <<<"$ROW_FOUND" )
97-
COL_FOUND=$( tr -d '\n\t\r ' <<<"$COL_FOUND" )
115+
get_size_line || exit 1
116+
echo "Captured terminal size line: '$SIZE_LINE'"
98117

118+
read -r COL_FOUND ROW_FOUND <<< "$SIZE_LINE"
99119

100120
if [ "50" != "$COL_FOUND" ]; then
101121
echo "Col found was $COL_FOUND which does not match expected 50"

keys/renewcerts.sh

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,40 @@
11
touch index.txt
22

3+
# The tracked renewcerts.cnf uses "fred" as the baseline user. When a
4+
# different user is requested we work from a throwaway copy with the name
5+
# substituted in, so the tracked config is never modified in place.
6+
CONFIG="renewcerts.cnf"
7+
38
if [ -z "$1" ]; then
49
USER_NAME="fred"
510
else
6-
USER_NAME=$1
7-
cp fred-key.der $USER_NAME-key.der
8-
cp fred-key.pem $USER_NAME-key.pem
9-
sed -i.bak "s/fred/$USER_NAME/g" renewcerts.cnf
11+
USER_NAME="$1"
12+
# Escape characters that are special in a sed replacement (\, /, &) so a
13+
# user name containing them substitutes literally instead of breaking sed.
14+
USER_NAME_SED=$(printf '%s' "$USER_NAME" | sed -e 's/[\/&]/\\&/g')
15+
cp fred-key.der "$USER_NAME-key.der"
16+
cp fred-key.pem "$USER_NAME-key.pem"
17+
CONFIG="renewcerts-$USER_NAME.cnf"
18+
sed "s/fred/$USER_NAME_SED/g" renewcerts.cnf > "$CONFIG"
1019
fi
1120

1221
# renew CA
13-
openssl req -subj '/C=US/ST=Washington/L=Seattle/O=wolfSSL/OU=Development/CN=www.wolfssl.com/emailAddress=ca@example.com' -key ca-key-ecc.pem -text -out ca-cert-ecc.pem -config renewcerts.cnf -new -nodes -x509 -extensions v3_ca -days 3650 -set_serial 6
22+
openssl req -subj '/C=US/ST=Washington/L=Seattle/O=wolfSSL/OU=Development/CN=www.wolfssl.com/emailAddress=ca@example.com' -key ca-key-ecc.pem -text -out ca-cert-ecc.pem -config "$CONFIG" -new -nodes -x509 -extensions v3_ca -days 3650 -set_serial 6
1423
openssl x509 -in ca-cert-ecc.pem -outform DER -out ca-cert-ecc.der
1524

1625
# renew user cert
17-
openssl req -subj "/C=US/ST=WA/L=Seattle/O=wolfSSL Inc/OU=Development/CN=$USER_NAME/emailAddress=fred@example.com" -key $USER_NAME-key.pem -out $USER_NAME-cert.csr -config renewcerts.cnf -new -nodes
26+
openssl req -subj "/C=US/ST=WA/L=Seattle/O=wolfSSL Inc/OU=Development/CN=$USER_NAME/emailAddress=$USER_NAME@example.com" -key "$USER_NAME-key.pem" -out "$USER_NAME-cert.csr" -config "$CONFIG" -new -nodes
1827

19-
openssl x509 -req -in $USER_NAME-cert.csr -days 3650 -extfile renewcerts.cnf -extensions v3_$USER_NAME -CA ca-cert-ecc.pem -CAkey ca-key-ecc.pem -text -out $USER_NAME-cert.pem -set_serial 7
20-
openssl x509 -in $USER_NAME-cert.pem -outform DER -out $USER_NAME-cert.der
28+
openssl x509 -req -in "$USER_NAME-cert.csr" -days 3650 -extfile "$CONFIG" -extensions "v3_$USER_NAME" -CA ca-cert-ecc.pem -CAkey ca-key-ecc.pem -text -out "$USER_NAME-cert.pem" -set_serial 7
29+
openssl x509 -in "$USER_NAME-cert.pem" -outform DER -out "$USER_NAME-cert.der"
2130

2231
# renew server-cert
23-
openssl req -subj '/C=US/ST=Washington/L=Seattle/O=Eliptic/OU=ECC/CN=www.wolfssl.com/emailAddress=server@example.com' -key server-key.pem -out server-cert.csr -config renewcerts.cnf -new -nodes
32+
openssl req -subj '/C=US/ST=Washington/L=Seattle/O=Eliptic/OU=ECC/CN=www.wolfssl.com/emailAddress=server@example.com' -key server-key.pem -out server-cert.csr -config "$CONFIG" -new -nodes
2433

25-
openssl x509 -req -in server-cert.csr -days 3650 -extfile renewcerts.cnf -extensions v3_server -CA ca-cert-ecc.pem -CAkey ca-key-ecc.pem -text -out server-cert.pem -set_serial 8
34+
openssl x509 -req -in server-cert.csr -days 3650 -extfile "$CONFIG" -extensions v3_server -CA ca-cert-ecc.pem -CAkey ca-key-ecc.pem -text -out server-cert.pem -set_serial 8
2635
openssl x509 -in server-cert.pem -outform DER -out server-cert.der
2736

2837
rm index.*
38+
if [ -n "$1" ]; then
39+
rm -f "$CONFIG"
40+
fi

0 commit comments

Comments
 (0)