From 057a756f3339b1513d5f7fd6244eb49bf252a2ea Mon Sep 17 00:00:00 2001 From: John Safranek Date: Wed, 21 Oct 2026 09:20:01 -0700 Subject: [PATCH] examples: compare auth secrets in constant time The echoserver and tpmcertserver userauth callbacks compare the stored digest or password with wolfSSH_ConstantCompare(). The echoserver callback now wipes its digest buffer on every return. Issue: F-8858, F-12630 --- examples/echoserver/echoserver.c | 32 ++++++++++++++++++++------ examples/tpmcertserver/tpmcertserver.c | 5 ++-- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index dc879f09..98d094d9 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -3598,13 +3598,14 @@ static int wsUserAuthResult(byte res, static int userAuthWouldBlock = 0; -static int wsUserAuth(byte authType, - WS_UserAuthData* authData, - void* ctx) +/* authHash is WC_SHA256_DIGEST_SIZE bytes of scratch for the digest of the + * offered secret; the caller wipes it. */ +static int wsUserAuthCheck(byte authType, + WS_UserAuthData* authData, + void* ctx, byte* authHash) { PwMapList* list; PwMap* map; - byte authHash[WC_SHA256_DIGEST_SIZE] = {0}; int userFound = 0; if (ctx == NULL) { @@ -3727,14 +3728,16 @@ static int wsUserAuth(byte authType, if (authData->type == WOLFSSH_USERAUTH_PUBLICKEY) { userFound = 1; - if (WMEMCMP(map->p, authHash, WC_SHA256_DIGEST_SIZE) == 0) { + if (wolfSSH_ConstantCompare(map->p, authHash, + WC_SHA256_DIGEST_SIZE) == 0) { return WOLFSSH_USERAUTH_SUCCESS; } /* Hash mismatch: continue checking other registered keys * for this user (a user may have multiple public keys). */ } else if (authData->type == WOLFSSH_USERAUTH_PASSWORD) { - if (WMEMCMP(map->p, authHash, WC_SHA256_DIGEST_SIZE) == 0) { + if (wolfSSH_ConstantCompare(map->p, authHash, + WC_SHA256_DIGEST_SIZE) == 0) { return WOLFSSH_USERAUTH_SUCCESS; } else { @@ -3754,7 +3757,8 @@ static int wsUserAuth(byte authType, } /* do keyboard auth prompts */ - if (WMEMCMP(map->p, authHash, WC_SHA256_DIGEST_SIZE) == 0) { + if (wolfSSH_ConstantCompare(map->p, authHash, + WC_SHA256_DIGEST_SIZE) == 0) { return WOLFSSH_USERAUTH_SUCCESS; } else { @@ -3780,6 +3784,20 @@ static int wsUserAuth(byte authType, } +static int wsUserAuth(byte authType, + WS_UserAuthData* authData, + void* ctx) +{ + byte authHash[WC_SHA256_DIGEST_SIZE] = {0}; + int ret; + + ret = wsUserAuthCheck(authType, authData, ctx, authHash); + wc_ForceZero(authHash, sizeof(authHash)); + + return ret; +} + + #ifdef WOLFSSH_SFTP /* * Sets the WOLFSSH object's default SFTP path to the value provided by diff --git a/examples/tpmcertserver/tpmcertserver.c b/examples/tpmcertserver/tpmcertserver.c index ae78ea2b..2a3c1396 100644 --- a/examples/tpmcertserver/tpmcertserver.c +++ b/examples/tpmcertserver/tpmcertserver.c @@ -64,11 +64,12 @@ static int TpmCsUserAuth(byte authType, WS_UserAuthData* authData, void* ctx) WOLFSSH_UNUSED(ctx); if (authType == WOLFSSH_USERAUTH_PASSWORD) { - const char* pw = (const char*)authData->sf.password.password; + const byte* pw = authData->sf.password.password; word32 pwSz = authData->sf.password.passwordSz; if (pwSz == (word32)XSTRLEN(TPMCS_PASSWORD) - && XMEMCMP(pw, TPMCS_PASSWORD, pwSz) == 0) { + && wolfSSH_ConstantCompare(pw, + (const byte*)TPMCS_PASSWORD, pwSz) == 0) { ret = WOLFSSH_USERAUTH_SUCCESS; } }