Skip to content

Commit eef8281

Browse files
yosuke-wolfsslejohnstown
authored andcommitted
wolfsshd: bind certificate auth to user, fail closed without FPKI
1 parent cb9bb7a commit eef8281

2 files changed

Lines changed: 65 additions & 6 deletions

File tree

.github/workflows/x509-interop.yml

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
id: cache-wolfssl
2626
with:
2727
path: build-dir/
28-
key: wolfssh-x509-interop-wolfssl-${{ env.WOLFSSL_REF }}-ubuntu-latest
28+
key: wolfssh-x509-interop-wolfssl-${{ env.WOLFSSL_REF }}-all-ubuntu-latest
2929
lookup-only: true
3030

3131
- name: Checkout, build, and install wolfSSL
@@ -35,7 +35,18 @@ jobs:
3535
repository: wolfssl/wolfssl
3636
ref: ${{ env.WOLFSSL_REF }}
3737
path: wolfssl
38-
configure: --enable-ssh --enable-keygen --enable-ed25519 --enable-curve25519
38+
# --enable-all defines WOLFSSL_FPKI, which compiles the UPN-vs-username
39+
# binding in wolfSSHd (apps/wolfsshd/auth.c). The client cert carries
40+
# UPN:fred@example, so user "fred" is bound to the certificate. The
41+
# wolfSSHd build still passes -DWOLFSSH_NO_FPKI below so the strict
42+
# FPKI profile (FASCN) is not required of the fred test certificate.
43+
#
44+
# Coverage note: this FPKI build exercises only the WOLFSSL_FPKI
45+
# success/binding path of RequestAuthentication. The non-FPKI
46+
# fail-closed reject branch (apps/wolfsshd/auth.c) is intentionally
47+
# not run here; it is verified at compile time and would need a
48+
# separate non-FPKI build to exercise at runtime.
49+
configure: --enable-all
3950
check: false
4051
install: true
4152

@@ -86,7 +97,7 @@ jobs:
8697
uses: actions/cache@v5
8798
with:
8899
path: build-dir/
89-
key: wolfssh-x509-interop-wolfssl-${{ env.WOLFSSL_REF }}-ubuntu-latest
100+
key: wolfssh-x509-interop-wolfssl-${{ env.WOLFSSL_REF }}-all-ubuntu-latest
90101
fail-on-cache-miss: true
91102

92103
- name: Restore PKIX-SSH cache
@@ -199,6 +210,39 @@ jobs:
199210
exit
200211
EOF
201212
213+
- name: Negative test - fred cert must not authenticate as another user
214+
working-directory: ./wolfssh/
215+
run: |
216+
# Regression guard for the cert principal-binding fix: a certificate
217+
# issued for "fred" (UPN:fred@example) must not be accepted for a
218+
# different SSH username. PreferredAuthentications=publickey plus
219+
# BatchMode keep this to a single publickey attempt with no password
220+
# fallback. The preceding positive tests already proved connectivity
221+
# and that fred's cert works; here we additionally require the failure
222+
# to be an authentication denial, so an unrelated ssh error (transport,
223+
# host-key, option change) cannot masquerade as a passing negative test.
224+
sudo useradd -m otheruser
225+
set +e
226+
../build-dir/bin/ssh -o StrictHostKeyChecking=accept-new \
227+
-o PreferredAuthentications=publickey \
228+
-o BatchMode=yes -o NumberOfPasswordPrompts=0 \
229+
-p 22222 -F ssh-pkixssh-config \
230+
-i ./keys/fred-key.pem otheruser@127.0.0.1 exit \
231+
> ssh-neg.out 2> ssh-neg.err
232+
rc=$?
233+
set -e
234+
cat ssh-neg.err || true
235+
if [ "$rc" -eq 0 ]; then
236+
echo "SECURITY FAILURE: fred certificate authenticated as otheruser"
237+
exit 1
238+
fi
239+
if ! grep -qi "permission denied" ssh-neg.err; then
240+
echo "Negative test inconclusive: ssh failed but not with an auth"
241+
echo "denial (possible transport/config error, not a binding reject)"
242+
exit 1
243+
fi
244+
echo "OK: fred certificate correctly rejected for otheruser (auth denied)"
245+
202246
- name: Show wolfSSHd log on failure
203247
if: failure()
204248
working-directory: ./wolfssh/

apps/wolfsshd/auth.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,10 +1341,10 @@ static int RequestAuthentication(WS_UserAuthData* authData,
13411341
ret = WOLFSSH_USERAUTH_REJECTED;
13421342
}
13431343
else {
1344-
wolfSSH_Log(WS_LOG_INFO,
1345-
"[SSHD] Relying on CA for public key check");
13461344
#ifdef WIN32
13471345
/* Still need to get users token on Windows */
1346+
wolfSSH_Log(WS_LOG_INFO,
1347+
"[SSHD] Relying on CA for public key check");
13481348
rc = SetupUserTokenWin(usr, &authData->sf.publicKey,
13491349
wolfSSHD_ConfigGetUserCAKeysFile(usrConf), authCtx);
13501350
if (rc == WSSHD_AUTH_SUCCESS) {
@@ -1356,8 +1356,23 @@ static int RequestAuthentication(WS_UserAuthData* authData,
13561356
"[SSHD] Error getting users token.");
13571357
ret = WOLFSSH_USERAUTH_FAILURE;
13581358
}
1359-
#else
1359+
#elif defined(WOLFSSL_FPKI)
1360+
/* The UPN-vs-username check above already bound the certificate
1361+
* to the requested user, so the CA-verified chain is
1362+
* sufficient. */
1363+
wolfSSH_Log(WS_LOG_INFO,
1364+
"[SSHD] Relying on CA for public key check");
13601365
ret = WOLFSSH_USERAUTH_SUCCESS;
1366+
#else
1367+
/* Without FPKI the certificate UPN/principal cannot be read, so
1368+
* the requested user cannot be bound to the certificate. Fail
1369+
* closed: require AuthorizedKeysFile (per-user key/cert mapping)
1370+
* or a wolfSSL build with FPKI. */
1371+
wolfSSH_Log(WS_LOG_ERROR,
1372+
"[SSHD] Certificate authentication cannot bind the requested "
1373+
"user without FPKI or AuthorizedKeysFile; rejecting "
1374+
"(user=%s)", usr);
1375+
ret = WOLFSSH_USERAUTH_REJECTED;
13611376
#endif
13621377
}
13631378
}

0 commit comments

Comments
 (0)