Skip to content

Commit 2cb2edb

Browse files
wolfsshd: mark AuthorizedKeysFile as explicitly set in public setter
1 parent 1efd647 commit 2cb2edb

2 files changed

Lines changed: 71 additions & 6 deletions

File tree

apps/wolfsshd/configuration.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,7 +1064,6 @@ static int HandleConfigOption(WOLFSSHD_CONFIG** conf, int opt,
10641064

10651065
switch (opt) {
10661066
case OPT_AUTH_KEYS_FILE:
1067-
(*conf)->authKeysFileSet = 1;
10681067
ret = wolfSSHD_ConfigSetAuthKeysFile(*conf, value);
10691068
break;
10701069
case OPT_PRIV_SEP:
@@ -1381,21 +1380,29 @@ int wolfSSHD_ConfigGetAuthKeysFileSet(const WOLFSSHD_CONFIG* conf)
13811380
int wolfSSHD_ConfigSetAuthKeysFile(WOLFSSHD_CONFIG* conf, const char* file)
13821381
{
13831382
int ret = WS_SUCCESS;
1383+
char* newFile = NULL;
13841384

13851385
if (conf == NULL) {
13861386
ret = WS_BAD_ARGUMENT;
13871387
}
13881388

1389+
/* allocate the replacement string first so a failure leaves the existing
1390+
* authKeysFile and authKeysFileSet untouched rather than half updated */
1391+
if (ret == WS_SUCCESS && file != NULL) {
1392+
ret = CreateString(&newFile, file, (int)WSTRLEN(file), conf->heap);
1393+
}
1394+
13891395
if (ret == WS_SUCCESS) {
13901396
if (conf->authKeysFile != NULL) {
13911397
FreeString(&conf->authKeysFile, conf->heap);
13921398
conf->authKeysFile = NULL;
13931399
}
13941400

1395-
if (file != NULL) {
1396-
ret = CreateString(&conf->authKeysFile, file,
1397-
(int)WSTRLEN(file), conf->heap);
1398-
}
1401+
/* swap in the new file and keep authKeysFileSet consistent with it:
1402+
* set when a file is explicitly configured so certificate public-key
1403+
* logins are still checked against it, cleared when removed */
1404+
conf->authKeysFile = newFile;
1405+
conf->authKeysFileSet = (file != NULL) ? 1 : 0;
13991406
}
14001407

14011408
return ret;

apps/wolfsshd/test/test_configuration.c

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,8 @@ static int test_ConfigCopy(void)
305305
ret = wolfSSHD_ConfigSetHostCertFile(head, "/etc/ssh/host_cert.pub");
306306
if (ret == WS_SUCCESS)
307307
ret = wolfSSHD_ConfigSetUserCAKeysFile(head, "/etc/ssh/ca.pub");
308-
/* AuthorizedKeysFile must go through PCL so authKeysFileSet flag is set */
308+
/* AuthorizedKeysFile via PCL to also exercise the config-parse path; the
309+
* authKeysFileSet flag is set either way and must survive the copy */
309310
if (ret == WS_SUCCESS) ret = PCL("AuthorizedKeysFile .ssh/authorized_keys");
310311

311312
/* scalar fields */
@@ -651,6 +652,62 @@ static int test_IncludeRecursionBound(void)
651652
return ret;
652653
}
653654

655+
/* The public wolfSSHD_ConfigSetAuthKeysFile setter must mark the authorized
656+
* keys file as explicitly configured, otherwise certificate public-key logins
657+
* skip the authorized-keys check and rely on CA validation alone. */
658+
static int test_ConfigSetAuthKeysFile(void)
659+
{
660+
int ret = WS_SUCCESS;
661+
WOLFSSHD_CONFIG* conf;
662+
663+
conf = wolfSSHD_ConfigNew(NULL);
664+
if (conf == NULL)
665+
ret = WS_MEMORY_E;
666+
667+
/* fresh config has no explicit authorized keys file */
668+
if (ret == WS_SUCCESS) {
669+
if (wolfSSHD_ConfigGetAuthKeysFileSet(conf) != 0)
670+
ret = WS_FATAL_ERROR;
671+
}
672+
673+
/* configuring a file through the public setter must set the flag */
674+
if (ret == WS_SUCCESS)
675+
ret = wolfSSHD_ConfigSetAuthKeysFile(conf, ".ssh/authorized_keys");
676+
if (ret == WS_SUCCESS) {
677+
if (wolfSSHD_ConfigGetAuthKeysFileSet(conf) == 0)
678+
ret = WS_FATAL_ERROR;
679+
}
680+
681+
/* a failed update must leave the existing configuration intact: an
682+
* all-whitespace file makes CreateString fail, and both the previously
683+
* configured file and the flag must be untouched, not half cleared */
684+
if (ret == WS_SUCCESS) {
685+
if (wolfSSHD_ConfigSetAuthKeysFile(conf, " ") == WS_SUCCESS)
686+
ret = WS_FATAL_ERROR; /* the bad value should have been rejected */
687+
}
688+
if (ret == WS_SUCCESS) {
689+
if (wolfSSHD_ConfigGetAuthKeysFile(conf) == NULL ||
690+
XSTRCMP(wolfSSHD_ConfigGetAuthKeysFile(conf),
691+
".ssh/authorized_keys") != 0)
692+
ret = WS_FATAL_ERROR;
693+
}
694+
if (ret == WS_SUCCESS) {
695+
if (wolfSSHD_ConfigGetAuthKeysFileSet(conf) == 0)
696+
ret = WS_FATAL_ERROR;
697+
}
698+
699+
/* removing the file must clear the flag again */
700+
if (ret == WS_SUCCESS)
701+
ret = wolfSSHD_ConfigSetAuthKeysFile(conf, NULL);
702+
if (ret == WS_SUCCESS) {
703+
if (wolfSSHD_ConfigGetAuthKeysFileSet(conf) != 0)
704+
ret = WS_FATAL_ERROR;
705+
}
706+
707+
wolfSSHD_ConfigFree(conf);
708+
return ret;
709+
}
710+
654711
/* Verifies ConfigFree releases all string fields - most useful under ASan. */
655712
static int test_ConfigFree(void)
656713
{
@@ -1013,6 +1070,7 @@ const TEST_CASE testCases[] = {
10131070
TEST_DECL(test_MatchUnsupportedSelector),
10141071
TEST_DECL(test_CAKeysFileDiffers),
10151072
TEST_DECL(test_IncludeRecursionBound),
1073+
TEST_DECL(test_ConfigSetAuthKeysFile),
10161074
TEST_DECL(test_ConfigFree),
10171075
#ifdef WOLFSSL_BASE64_ENCODE
10181076
TEST_DECL(test_CheckAuthKeysLine),

0 commit comments

Comments
 (0)