From 487c48caf2bb2c36735e766b79bf190e3dfe33ed Mon Sep 17 00:00:00 2001 From: Emma Stensland Date: Wed, 16 Sep 2026 15:39:40 -0600 Subject: [PATCH] test_configuration: Gate composites and restore type discrimination --- apps/wolfsshd/test/test_configuration.c | 95 +++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 6 deletions(-) diff --git a/apps/wolfsshd/test/test_configuration.c b/apps/wolfsshd/test/test_configuration.c index 9de5b64fd..088ad838e 100644 --- a/apps/wolfsshd/test/test_configuration.c +++ b/apps/wolfsshd/test/test_configuration.c @@ -63,6 +63,18 @@ void Log(const char *const fmt, ...) va_end(vlist); } +/* The default library callback writes to stdout, which interleaves badly with + * the buffered test output above; send library logs to stderr too. Debug lines + * are dropped: tests that drive expected rejections emit one per failure, + * splicing into the scenario lines this file leaves open until the verdict. */ +static void TestLoggingCb(enum wolfSSH_LogLevel level, + const char *const msgStr) +{ + if (level > WS_LOG_DEBUG) { + fprintf(stderr, "[%d] %s\n", (int)level, msgStr); + } +} + static void CleanupWildcardTest(void) { WDIR dir; @@ -2995,6 +3007,10 @@ static word32 BuildWireKeyBlob(const char* type, const byte* payload, return blobSz; } +/* OpenSSH maps these RSA SHA-2 signature names onto ssh-rsa; mirrors + * AuthKeysTokenKeyType() in apps/wolfsshd/auth.c. */ +static const char* const rsaAliases[] = { "rsa-sha2-256", "rsa-sha2-512" }; + /* Build a mutable " " line; WSTRTOK mutates in place. */ static int BuildAuthKeysLineType(const char* type, const byte* key, word32 keySz, char* lineOut, word32 lineOutSz) @@ -3082,6 +3098,7 @@ static int test_CheckAuthKeysLineTypes(void) #endif #endif #endif + #ifndef WOLFSSH_NO_MLDSA_COMPOSITES #ifndef WOLFSSH_NO_MLDSA44_ES256 "ssh-mldsa44-es256@wolfssl.com", #endif @@ -3100,6 +3117,7 @@ static int test_CheckAuthKeysLineTypes(void) #ifndef WOLFSSH_NO_MLDSA87_ED448 "ssh-mldsa87-ed448@wolfssl.com", #endif + #endif /* !WOLFSSH_NO_MLDSA_COMPOSITES */ }; static const char keyAStr[] = "wolfssh-auth-key-test-A-AAAAAAA"; const byte* keyA = (const byte*)keyAStr; @@ -3109,11 +3127,14 @@ static int test_CheckAuthKeysLineTypes(void) word32 blobSz; char line[256]; char lineCopy[256]; - word32 i; + const word32 numTypes = (word32)(sizeof(types) / sizeof(types[0])); + const word32 numAliases = (word32)(sizeof(rsaAliases) + / sizeof(rsaAliases[0])); + word32 i, j; int ret = WS_SUCCESS; int rc; - for (i = 0; i < (word32)(sizeof(types) / sizeof(types[0])); i++) { + for (i = 0; i < numTypes; i++) { blobSz = BuildWireKeyBlob(types[i], keyA, keySz, blob, sizeof(blob)); if (blobSz == 0) { Log(" CheckAuthKeysLine type %s: blob build failed.\n", @@ -3139,13 +3160,75 @@ static int test_CheckAuthKeysLineTypes(void) Log(" FAILED (rc=%d).\n", rc); return WS_FATAL_ERROR; } + + /* Other types must reject this blob to catch prefix collisions. */ + if (numTypes < 2) { + Log(" Skipping scenario: only one key type built, nothing to " + "reject %s blob against.\n", types[i]); + continue; + } + Log(" Testing scenario: all other types rejected " + "against %s blob.", types[i]); + for (j = 0; j < numTypes; j++) { + if (i == j) { + continue; + } + ret = BuildAuthKeysLineType(types[j], blob, blobSz, line, + sizeof(line)); + if (ret != WS_SUCCESS) { + Log(" build of %s FAILED (ret=%d).\n", types[j], ret); + return ret; + } + WMEMCPY(lineCopy, line, WSTRLEN(line) + 1); + rc = CheckAuthKeysLine(lineCopy, (word32)WSTRLEN(lineCopy), + blob, blobSz, 0); + if (rc != WSSHD_AUTH_FAILURE) { + Log(" %s not rejected FAILED (rc=%d).\n", types[j], rc); + return WS_FATAL_ERROR; + } + } + Log(" PASSED.\n"); } - /* Reject line token naming a different key type. */ + /* The alias maps to ssh-rsa only: a non-RSA blob must still be rejected. */ + blobSz = BuildWireKeyBlob("ecdsa-sha2-nistp256", keyA, keySz, blob, + sizeof(blob)); + if (blobSz == 0) { + return WS_BUFFER_E; + } + for (i = 0; i < numAliases; i++) { + const char* sigType = rsaAliases[i]; + + ret = BuildAuthKeysLineType(sigType, blob, blobSz, line, + sizeof(line)); + if (ret != WS_SUCCESS) { + Log(" CheckAuthKeysLine type %s: build failed.\n", sigType); + return ret; + } + Log(" Testing scenario: %s token rejects an " + "ecdsa-sha2-nistp256 blob.", sigType); + WMEMCPY(lineCopy, line, WSTRLEN(line) + 1); + rc = CheckAuthKeysLine(lineCopy, (word32)WSTRLEN(lineCopy), + blob, blobSz, 0); + if (rc == WSSHD_AUTH_FAILURE) { + Log(" PASSED.\n"); + } + else { + Log(" FAILED (rc=%d).\n", rc); + return WS_FATAL_ERROR; + } + } + + /* The acceptance direction of the alias is covered by + * test_CheckAuthKeysLine(). */ + + /* Used by the mismatched-token case below. */ blobSz = BuildWireKeyBlob("ssh-rsa", keyA, keySz, blob, sizeof(blob)); if (blobSz == 0) { return WS_BUFFER_E; } + + /* Reject line token naming a different key type. */ ret = BuildAuthKeysLineType("ssh-bogus-type", blob, blobSz, line, sizeof(line)); if (ret != WS_SUCCESS) { @@ -3395,9 +3478,7 @@ static int test_CheckAuthKeysLine(void) } if (ret == WS_SUCCESS) { - /* OpenSSH maps an RSA SHA-2 signature name onto ssh-rsa, so these - * lines authenticate an ssh-rsa key there and must here too. */ - static const char* rsaAliases[] = { "rsa-sha2-256", "rsa-sha2-512" }; + /* An RSA SHA-2 alias line authenticates an ssh-rsa key. */ word32 i; for (i = 0; i < (word32)(sizeof(rsaAliases) / sizeof(rsaAliases[0])); @@ -7281,6 +7362,8 @@ int main(int argc, char** argv) (void)argc; (void)argv; + wolfSSH_SetLoggingCb(TestLoggingCb); + CleanupWildcardTest(); ret = SetupWildcardTest();