|
83 | 83 | fi |
84 | 84 | fi |
85 | 85 |
|
| 86 | +# Self-contained check for the ownership and symlink gate in getBufferFromFile(). |
| 87 | +# The host key, host certificate, and user CA all load through the same |
| 88 | +# getBufferFromFile(..., 1) call, so exercising the gate via the host key covers |
| 89 | +# the identical code for the other two trust anchors. Starts a private wolfSSHd |
| 90 | +# with substituted host keys and asserts startup is refused for a symlink, a |
| 91 | +# group/world-writable file, and (when run as a non-root user with sudo) a file |
| 92 | +# owned by another user, and accepted for a proper mode-600 regular file. Does |
| 93 | +# not use the shared daemon, so it runs the same whether or not one was started. |
| 94 | +run_hostkey_perm_check() { |
| 95 | + printf "host key ownership/symlink gate ... " |
| 96 | + TOTAL=$((TOTAL+1)) |
| 97 | + |
| 98 | + HK_SSHD=../wolfsshd |
| 99 | + HK_KEY=../../../keys/server-key.pem |
| 100 | + HK_PORT=22399 |
| 101 | + if [ ! -x "$HK_SSHD" ] || [ ! -f "$HK_KEY" ]; then |
| 102 | + printf "SKIPPED\n" |
| 103 | + SKIPPED=$((SKIPPED+1)) |
| 104 | + return |
| 105 | + fi |
| 106 | + |
| 107 | + HK_WORK=$(mktemp -d 2>/dev/null) || HK_WORK=$(mktemp -d -t sshdperm) |
| 108 | + if [ -z "$HK_WORK" ] || [ ! -d "$HK_WORK" ]; then |
| 109 | + printf "SKIPPED (mktemp failed)\n" |
| 110 | + SKIPPED=$((SKIPPED+1)) |
| 111 | + return |
| 112 | + fi |
| 113 | + |
| 114 | + cp "$HK_KEY" "$HK_WORK/hostkey.pem" || { |
| 115 | + printf "SKIPPED (could not prepare hostkey)\n" |
| 116 | + SKIPPED=$((SKIPPED+1)) |
| 117 | + rm -rf "$HK_WORK" |
| 118 | + return |
| 119 | + } |
| 120 | + chmod 600 "$HK_WORK/hostkey.pem" |
| 121 | + touch "$HK_WORK/authorized_keys" |
| 122 | + hk_cfg() { |
| 123 | + cat > "$HK_WORK/cfg" <<EOF |
| 124 | +Port $HK_PORT |
| 125 | +Protocol 2 |
| 126 | +PermitRootLogin yes |
| 127 | +PasswordAuthentication yes |
| 128 | +UsePrivilegeSeparation no |
| 129 | +UseDNS no |
| 130 | +HostKey $1 |
| 131 | +AuthorizedKeysFile $HK_WORK/authorized_keys |
| 132 | +EOF |
| 133 | + } |
| 134 | + |
| 135 | + # Load happens during startup before the listener; start, poll the log |
| 136 | + # rather than sleeping a fixed time, then stop. Both the host key load and |
| 137 | + # the listener emit a line, so stop as soon as either appears (max ~15s). |
| 138 | + # $1 (optional): "sudo" to launch the daemon as root for the owner branch. |
| 139 | + hk_run() { |
| 140 | + HK_PRE="$1" |
| 141 | + $HK_PRE "$HK_SSHD" -D -d -f "$HK_WORK/cfg" -p $HK_PORT > "$HK_WORK/log.txt" 2>&1 & |
| 142 | + HK_PID=$! |
| 143 | + i=0 |
| 144 | + while [ $i -lt 15 ]; do |
| 145 | + if grep -qE "Listening on port|Refusing to load" "$HK_WORK/log.txt" 2>/dev/null; then |
| 146 | + break |
| 147 | + fi |
| 148 | + sleep 1 |
| 149 | + i=$((i+1)) |
| 150 | + done |
| 151 | + # When launched via sudo, $HK_PID is the sudo pid, not the daemon, and |
| 152 | + # sudo does not reliably forward the signal, so match the daemon by port. |
| 153 | + # This guarantees a regression cannot leave a root daemon bound to it. |
| 154 | + if [ -n "$HK_PRE" ]; then |
| 155 | + $HK_PRE pkill -f "$HK_SSHD.*$HK_PORT" 2>/dev/null |
| 156 | + else |
| 157 | + kill $HK_PID 2>/dev/null |
| 158 | + fi |
| 159 | + wait $HK_PID 2>/dev/null |
| 160 | + } |
| 161 | + |
| 162 | + hk_fail() { |
| 163 | + printf "FAILED!\n%s\n" "$1" |
| 164 | + cat "$HK_WORK/log.txt" |
| 165 | + rm -rf "$HK_WORK" |
| 166 | + if [ "$USING_LOCAL_HOST" == 1 ]; then |
| 167 | + printf "Shutting down test wolfSSHd\n" |
| 168 | + stop_wolfsshd |
| 169 | + fi |
| 170 | + exit 1 |
| 171 | + } |
| 172 | + |
| 173 | + # proper mode-600 regular file must load. The only gate failure here is the |
| 174 | + # daemon refusing a properly-owned key; any other reason the daemon does not |
| 175 | + # reach the listener (port in use, environment cannot run the daemon) is |
| 176 | + # unrelated to the gate, so skip rather than fail the whole suite. |
| 177 | + hk_cfg "$HK_WORK/hostkey.pem"; hk_run |
| 178 | + if grep -q "Refusing to load" "$HK_WORK/log.txt"; then |
| 179 | + hk_fail "valid host key was refused" |
| 180 | + fi |
| 181 | + if ! grep -q "Listening on port" "$HK_WORK/log.txt"; then |
| 182 | + printf "SKIPPED (daemon could not listen)\n" |
| 183 | + SKIPPED=$((SKIPPED+1)) |
| 184 | + rm -rf "$HK_WORK" |
| 185 | + return |
| 186 | + fi |
| 187 | + |
| 188 | + # symlink must be refused |
| 189 | + ln -s "$HK_WORK/hostkey.pem" "$HK_WORK/link.pem" |
| 190 | + hk_cfg "$HK_WORK/link.pem"; hk_run |
| 191 | + grep -q "Refusing to load" "$HK_WORK/log.txt" || hk_fail "symlinked host key was not refused" |
| 192 | + |
| 193 | + # non-regular file (FIFO) must be refused. Skip where mkfifo is unavailable. |
| 194 | + if mkfifo "$HK_WORK/fifo.pem" 2>/dev/null; then |
| 195 | + hk_cfg "$HK_WORK/fifo.pem"; hk_run |
| 196 | + grep -q "Refusing to load" "$HK_WORK/log.txt" || hk_fail "FIFO host key was not refused" |
| 197 | + fi |
| 198 | + |
| 199 | + # group/world-writable file must be refused |
| 200 | + cp "$HK_KEY" "$HK_WORK/ww.pem"; chmod 666 "$HK_WORK/ww.pem" |
| 201 | + hk_cfg "$HK_WORK/ww.pem"; hk_run |
| 202 | + grep -q "Refusing to load" "$HK_WORK/log.txt" || hk_fail "world-writable host key was not refused" |
| 203 | + |
| 204 | + # Owner-rejection branch (st_uid != 0 && st_uid != geteuid()): the primary |
| 205 | + # substitution vector. The mode-600 host key is owned by the invoking user, |
| 206 | + # so launching the daemon as root (euid 0) must refuse it. Needs a non-root |
| 207 | + # invoker and non-interactive sudo; skip the sub-case otherwise. |
| 208 | + if [ "`id -u`" -ne 0 ] && sudo -n true 2>/dev/null; then |
| 209 | + hk_cfg "$HK_WORK/hostkey.pem"; hk_run sudo |
| 210 | + grep -q "Refusing to load" "$HK_WORK/log.txt" || hk_fail "non-root-owned host key was not refused under root daemon" |
| 211 | + fi |
| 212 | + |
| 213 | + rm -rf "$HK_WORK" |
| 214 | + printf "PASSED\n" |
| 215 | +} |
| 216 | + |
86 | 217 | run_test() { |
87 | 218 | printf "$1 ... " |
88 | 219 | ./"$1" "$TEST_HOST" "$TEST_PORT" "$USER" &> stdout.txt |
|
137 | 268 | # add additional tests here, check on var USING_LOCAL_HOST if can make sshd |
138 | 269 | # server start/restart with changes |
139 | 270 |
|
| 271 | + run_hostkey_perm_check |
| 272 | + |
140 | 273 | if [ "$USING_LOCAL_HOST" == 1 ]; then |
141 | 274 | printf "Shutting down test wolfSSHd\n" |
142 | 275 | stop_wolfsshd |
|
0 commit comments