Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions apps/wolfsshd/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -783,9 +783,15 @@ int wolfSSHD_OpenSecureFile(const char* path, WUID_T ownerUid,
#endif
}

#if defined(WOLFSSHD_UNIT_TEST) && !defined(_WIN32)
int SearchForPubKey(const char* path, const char* authKeysFile,
const WS_UserAuthData_PublicKey* pubKeyCtx,
WUID_T uid, int strictModes)
#else
static int SearchForPubKey(const char* path, const char* authKeysFile,
const WS_UserAuthData_PublicKey* pubKeyCtx,
WUID_T uid, int strictModes)
#endif
{
int ret = WSSHD_AUTH_SUCCESS;
char authKeysPath[MAX_PATH_SZ];
Expand Down
3 changes: 3 additions & 0 deletions apps/wolfsshd/auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ extern int (*wsshd_setreuid_cb)(WUID_T, WUID_T);
int wolfSSHD_GetUserGroupNames(void* heap, const char* usr, WGID_T primaryGid,
char*** outNames, word32* outCount);
void wolfSSHD_FreeUserGroupNames(void* heap, char** names, word32 count);
int SearchForPubKey(const char* path, const char* authKeysFile,
const WS_UserAuthData_PublicKey* pubKeyCtx,
WUID_T uid, int strictModes);
#endif
#if defined(WOLFSSH_HAVE_LIBCRYPT) || defined(WOLFSSH_HAVE_LIBLOGIN)
int CheckPasswordHashUnix(const char* input, char* stored);
Expand Down
123 changes: 123 additions & 0 deletions apps/wolfsshd/test/test_configuration.c
Original file line number Diff line number Diff line change
Expand Up @@ -1408,6 +1408,126 @@ static int test_CheckAuthKeysLine(void)

return ret;
}

#ifndef _WIN32
/* Drive SearchForPubKey against a temp authorized_keys file to cover the
* "no line matched -> WSSHD_AUTH_FAILURE" gate: the authorized key kills a
* condition inversion, the unauthorized key kills a deletion of the gate. */
static int test_SearchForPubKey(void)
{
int ret = WS_SUCCESS;
static const char keyAStr[] = "wolfssh-auth-key-test-A-AAAAAAA";
static const char keyBStr[] = "wolfssh-auth-key-test-B-BBBBBBB";
const byte* keyA = (const byte*)keyAStr;
const byte* keyB = (const byte*)keyBStr;
const word32 keySz = (word32)(sizeof(keyAStr) - 1);
char base[] = "/tmp/wolfsshd_pkXXXXXX";
char keysPath[64] = "";
char missPath[64] = "";
char line[256];
WS_UserAuthData_PublicKey pubKeyCtx;
WUID_T uid = getuid();
FILE* f = NULL;
int rc;

if (mkdtemp(base) == NULL) {
Log(" mkdtemp failed.\n");
ret = WS_FATAL_ERROR;
}

if (ret == WS_SUCCESS) {
snprintf(keysPath, sizeof(keysPath), "%s/authorized_keys", base);
snprintf(missPath, sizeof(missPath), "%s/absent_keys", base);
ret = BuildAuthKeysLine(keyA, keySz, line, sizeof(line));
}

if (ret == WS_SUCCESS) {
f = fopen(keysPath, "w");
if (f == NULL) {
Log(" fopen of authorized_keys failed.\n");
ret = WS_FATAL_ERROR;
}
else {
fputs(line, f);
fputs("\n", f);
fclose(f);
}
}

/* Force 0600 so the StrictModes secure-open is not tripped by a permissive
* umask leaving the file group or world writable. */
if (ret == WS_SUCCESS && chmod(keysPath, S_IRUSR | S_IWUSR) != 0) {
Log(" chmod of authorized_keys failed.\n");
ret = WS_FATAL_ERROR;
}

WMEMSET(&pubKeyCtx, 0, sizeof(pubKeyCtx));
pubKeyCtx.publicKeySz = keySz;

/* StrictModes disabled so the check stays hermetic (no ownership gate). */
if (ret == WS_SUCCESS) {
Log(" Testing scenario: authorized key is accepted.");
pubKeyCtx.publicKey = keyA;
rc = SearchForPubKey(base, keysPath, &pubKeyCtx, uid, 0);
if (rc == WSSHD_AUTH_SUCCESS) {
Log(" PASSED.\n");
}
else {
Log(" FAILED (rc=%d).\n", rc);
ret = WS_FATAL_ERROR;
}
}

/* The temp file is user-owned with safe perms, so the StrictModes
* secure-open branch must also accept the authorized key. */
if (ret == WS_SUCCESS) {
Log(" Testing scenario: authorized key accepted under StrictModes.");
pubKeyCtx.publicKey = keyA;
rc = SearchForPubKey(base, keysPath, &pubKeyCtx, uid, 1);
if (rc == WSSHD_AUTH_SUCCESS) {
Log(" PASSED.\n");
}
else {
Log(" FAILED (rc=%d).\n", rc);
ret = WS_FATAL_ERROR;
}
}

if (ret == WS_SUCCESS) {
Log(" Testing scenario: unauthorized key is rejected.");
pubKeyCtx.publicKey = keyB;
rc = SearchForPubKey(base, keysPath, &pubKeyCtx, uid, 0);
if (rc == WSSHD_AUTH_FAILURE) {
Log(" PASSED.\n");
}
else {
Log(" FAILED (rc=%d).\n", rc);
ret = WS_FATAL_ERROR;
}
}

/* A missing authorized_keys file is an error, not a silent accept. */
if (ret == WS_SUCCESS) {
Log(" Testing scenario: missing keys file returns an error.");
pubKeyCtx.publicKey = keyA;
rc = SearchForPubKey(base, missPath, &pubKeyCtx, uid, 0);
if (rc < 0) {
Log(" PASSED.\n");
}
else {
Log(" FAILED (rc=%d).\n", rc);
ret = WS_FATAL_ERROR;
}
}

if (keysPath[0] != '\0') {
unlink(keysPath);
}
rmdir(base);

return ret;
}
#endif /* !_WIN32 */
#endif /* WOLFSSL_BASE64_ENCODE */

#ifndef _WIN32
Expand Down Expand Up @@ -1924,6 +2044,9 @@ const TEST_CASE testCases[] = {
#ifdef WOLFSSL_BASE64_ENCODE
TEST_DECL(test_CheckAuthKeysLine),
#endif
#if defined(WOLFSSL_BASE64_ENCODE) && !defined(_WIN32)
TEST_DECL(test_SearchForPubKey),
#endif
#ifndef _WIN32
TEST_DECL(test_GetUserGroupNames),
TEST_DECL(test_AuthReducePermissionsUser_ok),
Expand Down
Loading