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
2,230 changes: 2,230 additions & 0 deletions .github/workflows/windows-cert-store-test.yml

Large diffs are not rendered by default.

315 changes: 314 additions & 1 deletion apps/wolfsshd/configuration.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,24 @@ struct WOLFSSHD_CONFIG {
char* hostKeyFile;
char* hostCertFile;
char* userCAKeysFile;
#ifdef USE_WINDOWS_API
#ifdef WOLFSSH_CERTS
char* hostKeyStore;
char* hostKeyStoreSubject;
char* hostKeyStoreFlags;
#endif /* WOLFSSH_CERTS */
#endif /* USE_WINDOWS_API */
char* hostKeyAlgos;
char* kekAlgos;
char* listenAddress;
char* authKeysFile;
char* forceCmd;
char* pidFile;
#ifdef USE_WINDOWS_API
char* winUserStores;
char* winUserDwFlags;
char* winUserPvPara;
#endif /* USE_WINDOWS_API */
WOLFSSHD_CONFIG* next; /* next config in list */
long loginTimer;
word16 port;
Expand All @@ -89,6 +101,8 @@ struct WOLFSSHD_CONFIG {
byte permitRootLogin:1;
byte permitEmptyPasswords:1;
byte authKeysFileSet:1; /* if not set then no explicit authorized keys */
byte useSystemCA:1;
byte useUserCAStore:1;
};

int CountWhitespace(const char* in, int inSz, byte inv);
Expand Down Expand Up @@ -311,7 +325,19 @@ void wolfSSHD_ConfigFree(WOLFSSHD_CONFIG* conf)
FreeString(&current->authKeysFile, heap);
FreeString(&current->hostKeyFile, heap);
FreeString(&current->hostCertFile, heap);
#ifdef USE_WINDOWS_API
#ifdef WOLFSSH_CERTS
FreeString(&current->hostKeyStore, heap);
FreeString(&current->hostKeyStoreSubject, heap);
FreeString(&current->hostKeyStoreFlags, heap);
#endif /* WOLFSSH_CERTS */
#endif /* USE_WINDOWS_API */
FreeString(&current->pidFile, heap);
#ifdef USE_WINDOWS_API
FreeString(&current->winUserStores, heap);
FreeString(&current->winUserDwFlags, heap);
FreeString(&current->winUserPvPara, heap);
#endif /* USE_WINDOWS_API */

WFREE(current, heap, DYNTYPE_SSHD);
current = next;
Expand All @@ -338,6 +364,13 @@ enum {
OPT_PROTOCOL = 9,
OPT_LOGIN_GRACE_TIME = 10,
OPT_HOST_KEY = 11,
#ifdef USE_WINDOWS_API
#ifdef WOLFSSH_CERTS
OPT_HOST_KEY_STORE = 50,
OPT_HOST_KEY_STORE_SUBJECT = 51,
OPT_HOST_KEY_STORE_FLAGS = 52,
#endif /* WOLFSSH_CERTS */
#endif /* USE_WINDOWS_API */
OPT_PASSWORD_AUTH = 12,
OPT_PORT = 13,
OPT_PERMIT_ROOT = 14,
Expand All @@ -350,9 +383,22 @@ enum {
OPT_TRUSTED_USER_CA_KEYS = 21,
OPT_PIDFILE = 22,
OPT_BANNER = 23,
OPT_TRUSTED_SYSTEM_CA_KEYS = 24,
OPT_TRUSTED_USER_CA_STORE = 25,
#ifdef USE_WINDOWS_API
OPT_WIN_USER_STORES = 26,
OPT_WIN_USER_DW_FLAGS = 27,
OPT_WIN_USER_PV_PARA = 28,
#endif /* USE_WINDOWS_API */
};
enum {
NUM_OPTIONS = 24
NUM_OPTIONS = 26
#ifdef USE_WINDOWS_API
+ 3
#ifdef WOLFSSH_CERTS
+ 3
#endif /* WOLFSSH_CERTS */
#endif /* USE_WINDOWS_API */
};

static const CONFIG_OPTION options[NUM_OPTIONS] = {
Expand All @@ -367,6 +413,17 @@ static const CONFIG_OPTION options[NUM_OPTIONS] = {
{OPT_ACCEPT_ENV, "AcceptEnv"},
{OPT_PROTOCOL, "Protocol"},
{OPT_LOGIN_GRACE_TIME, "LoginGraceTime"},
/* The config parser uses strncmp with the option-name length, so longer
* option names that share a common prefix MUST appear before the shorter
* one. HostKeyStoreSubject/HostKeyStoreFlags before HostKeyStore,
* and all HostKeyStore* before HostKey. */
#ifdef USE_WINDOWS_API
#ifdef WOLFSSH_CERTS
{OPT_HOST_KEY_STORE_SUBJECT, "HostKeyStoreSubject"},
{OPT_HOST_KEY_STORE_FLAGS, "HostKeyStoreFlags"},
{OPT_HOST_KEY_STORE, "HostKeyStore"},
#endif /* WOLFSSH_CERTS */
#endif /* USE_WINDOWS_API */
{OPT_HOST_KEY, "HostKey"},
{OPT_PASSWORD_AUTH, "PasswordAuthentication"},
{OPT_PORT, "Port"},
Expand All @@ -380,6 +437,13 @@ static const CONFIG_OPTION options[NUM_OPTIONS] = {
{OPT_TRUSTED_USER_CA_KEYS, "TrustedUserCAKeys"},
{OPT_PIDFILE, "PidFile"},
{OPT_BANNER, "Banner"},
{OPT_TRUSTED_SYSTEM_CA_KEYS, "wolfSSH_TrustedSystemCAKeys"},
{OPT_TRUSTED_USER_CA_STORE, "wolfSSH_TrustedUserCaStore"},
#ifdef USE_WINDOWS_API
{OPT_WIN_USER_STORES, "wolfSSH_WinUserStores"},
{OPT_WIN_USER_DW_FLAGS, "wolfSSH_WinUserDwFlags"},
{OPT_WIN_USER_PV_PARA, "wolfSSH_WinUserPvPara"},
#endif /* USE_WINDOWS_API */
};

/* returns WS_SUCCESS on success */
Expand Down Expand Up @@ -1021,12 +1085,50 @@ static int HandleConfigOption(WOLFSSHD_CONFIG** conf, int opt,
/* TODO: Add logic to check if file exists? */
ret = wolfSSHD_ConfigSetUserCAKeysFile(*conf, value);
break;
case OPT_TRUSTED_SYSTEM_CA_KEYS:
ret = wolfSSHD_ConfigSetSystemCA(*conf, value);
break;
case OPT_PIDFILE:
ret = SetFileString(&(*conf)->pidFile, value, (*conf)->heap);
break;
case OPT_BANNER:
ret = SetFileString(&(*conf)->banner, value, (*conf)->heap);
break;
case OPT_TRUSTED_USER_CA_STORE:
ret = wolfSSHD_ConfigSetUserCAStore(*conf, value);
break;
#ifdef USE_WINDOWS_API
case OPT_WIN_USER_STORES:
ret = wolfSSHD_ConfigSetWinUserStores(*conf, value);
break;
case OPT_WIN_USER_DW_FLAGS:
ret = wolfSSHD_ConfigSetWinUserDwFlags(*conf, value);
break;
case OPT_WIN_USER_PV_PARA:
ret = wolfSSHD_ConfigSetWinUserPvPara(*conf, value);
break;
#endif /* USE_WINDOWS_API */
#ifdef USE_WINDOWS_API
#ifdef WOLFSSH_CERTS
case OPT_HOST_KEY_STORE:
wolfSSH_Log(WS_LOG_INFO,
"[SSHD] Parsed HostKeyStore = '%s'", value);
ret = SetFileString(&(*conf)->hostKeyStore, value, (*conf)->heap);
break;
case OPT_HOST_KEY_STORE_SUBJECT:
wolfSSH_Log(WS_LOG_INFO,
"[SSHD] Parsed HostKeyStoreSubject = '%s'", value);
ret = SetFileString(&(*conf)->hostKeyStoreSubject, value,
(*conf)->heap);
break;
case OPT_HOST_KEY_STORE_FLAGS:
wolfSSH_Log(WS_LOG_INFO,
"[SSHD] Parsed HostKeyStoreFlags = '%s'", value);
ret = SetFileString(&(*conf)->hostKeyStoreFlags, value,
(*conf)->heap);
break;
#endif /* WOLFSSH_CERTS */
#endif /* USE_WINDOWS_API */
default:
break;
}
Expand Down Expand Up @@ -1309,6 +1411,178 @@ char* wolfSSHD_ConfigGetHostCertFile(const WOLFSSHD_CONFIG* conf)
return ret;
}


/* getter function for if using system CAs
* return 1 if true and 0 if false */
int wolfSSHD_ConfigGetSystemCA(const WOLFSSHD_CONFIG* conf)
{
if (conf != NULL) {
return conf->useSystemCA;
}
return 0;
}


/* setter function for if using system CAs
* 'yes' if true and 'no' if false
* returns WS_SUCCESS on success */
int wolfSSHD_ConfigSetSystemCA(WOLFSSHD_CONFIG* conf, const char* value)
{
int ret = WS_SUCCESS;

if (conf != NULL) {
if (WSTRCMP(value, "yes") == 0) {
wolfSSH_Log(WS_LOG_INFO, "[SSHD] System CAs enabled");
conf->useSystemCA = 1;
}
else if (WSTRCMP(value, "no") == 0) {
wolfSSH_Log(WS_LOG_INFO, "[SSHD] System CAs disabled");
conf->useSystemCA = 0;
}
else {
wolfSSH_Log(WS_LOG_INFO, "[SSHD] System CAs unexpected flag");
ret = WS_FATAL_ERROR;
}
}

return ret;
}

/* getter function for if using user CA store
* return 1 if true and 0 if false */
int wolfSSHD_ConfigGetUserCAStore(const WOLFSSHD_CONFIG* conf)
{
if (conf != NULL) {
return conf->useUserCAStore;
}
return 0;
}


/* setter function for if using user CA store
* 'yes' if true and 'no' if false
* returns WS_SUCCESS on success */
int wolfSSHD_ConfigSetUserCAStore(WOLFSSHD_CONFIG* conf, const char* value)
{
int ret = WS_SUCCESS;

if (conf != NULL) {
if (WSTRCMP(value, "yes") == 0) {
wolfSSH_Log(WS_LOG_INFO, "[SSHD] User CA store enabled. Note this "
"is currently only supported on Windows.");
conf->useUserCAStore = 1;
}
else if (WSTRCMP(value, "no") == 0) {
wolfSSH_Log(WS_LOG_INFO, "[SSHD] User CA store disabled");
conf->useUserCAStore = 0;
}
else {
wolfSSH_Log(WS_LOG_INFO, "[SSHD] User CA store unexpected flag");
ret = WS_FATAL_ERROR;
}
}

return ret;
}

#ifdef USE_WINDOWS_API
char* wolfSSHD_ConfigGetWinUserStores(WOLFSSHD_CONFIG* conf)
{
if (conf != NULL) {
if (conf->winUserStores == NULL) {
/* If no value was specified, default to CERT_STORE_PROV_SYSTEM */
CreateString(&conf->winUserStores, "CERT_STORE_PROV_SYSTEM",
(int)WSTRLEN("CERT_STORE_PROV_SYSTEM"), conf->heap);
}

return conf->winUserStores;
}

return NULL;
}

int wolfSSHD_ConfigSetWinUserStores(WOLFSSHD_CONFIG* conf, const char* value)
{
int ret = WS_SUCCESS;

if (conf == NULL) {
ret = WS_BAD_ARGUMENT;
}

if (ret == WS_SUCCESS) {
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These setters assign a newly allocated string via CreateString() without freeing any previously set value, which leaks memory if the config option is specified more than once (or if config structs are reused). Consider freeing conf->winUserStores first (e.g., FreeString) or using the existing SetFileString() helper which handles replacement safely.

Suggested change
if (ret == WS_SUCCESS) {
if (ret == WS_SUCCESS) {
if (conf->winUserStores != NULL) {
WFREE(conf->winUserStores, conf->heap, DYNTYPE_STRING);
conf->winUserStores = NULL;
}

Copilot uses AI. Check for mistakes.
ret = CreateString(&conf->winUserStores, value,
(int)WSTRLEN(value), conf->heap);
}

return ret;
}

char* wolfSSHD_ConfigGetWinUserDwFlags(WOLFSSHD_CONFIG* conf)
{
if (conf != NULL) {
if (conf->winUserDwFlags == NULL) {
/* If no value was specified, default to
* CERT_SYSTEM_STORE_CURRENT_USER */
CreateString(&conf->winUserDwFlags,
"CERT_SYSTEM_STORE_CURRENT_USER",
(int)WSTRLEN("CERT_SYSTEM_STORE_CURRENT_USER"),
conf->heap);
}

return conf->winUserDwFlags;
}

return NULL;
}

int wolfSSHD_ConfigSetWinUserDwFlags(WOLFSSHD_CONFIG* conf, const char* value)
{
int ret = WS_SUCCESS;

if (conf == NULL) {
ret = WS_BAD_ARGUMENT;
}

if (ret == WS_SUCCESS) {
ret = CreateString(&conf->winUserDwFlags, value,
(int)WSTRLEN(value), conf->heap);
}

return ret;
}

char* wolfSSHD_ConfigGetWinUserPvPara(WOLFSSHD_CONFIG* conf)
{
if (conf != NULL) {
if (conf->winUserPvPara == NULL) {
/* If no value was specified, default to MY */
CreateString(&conf->winUserPvPara, "MY",
(int)WSTRLEN("MY"), conf->heap);
}

return conf->winUserPvPara;
}

return NULL;
}

int wolfSSHD_ConfigSetWinUserPvPara(WOLFSSHD_CONFIG* conf, const char* value)
{
int ret = WS_SUCCESS;

if (conf == NULL) {
ret = WS_BAD_ARGUMENT;
}

if (ret == WS_SUCCESS) {
ret = CreateString(&conf->winUserPvPara, value,
(int)WSTRLEN(value), conf->heap);
}

return ret;
}
#endif /* USE_WINDOWS_API */

char* wolfSSHD_ConfigGetUserCAKeysFile(const WOLFSSHD_CONFIG* conf)
{
char* ret = NULL;
Expand Down Expand Up @@ -1342,6 +1616,45 @@ int SetFileString(char** dst, const char* src, void* heap)
return ret;
}

#ifdef USE_WINDOWS_API
#ifdef WOLFSSH_CERTS
char* wolfSSHD_ConfigGetHostKeyStore(const WOLFSSHD_CONFIG* conf)
{
char* ret = NULL;

if (conf != NULL) {
ret = conf->hostKeyStore;
}

return ret;
}


char* wolfSSHD_ConfigGetHostKeyStoreSubject(const WOLFSSHD_CONFIG* conf)
{
char* ret = NULL;

if (conf != NULL) {
ret = conf->hostKeyStoreSubject;
}

return ret;
}


char* wolfSSHD_ConfigGetHostKeyStoreFlags(const WOLFSSHD_CONFIG* conf)
{
char* ret = NULL;

if (conf != NULL) {
ret = conf->hostKeyStoreFlags;
}

return ret;
}
#endif /* WOLFSSH_CERTS */
#endif /* USE_WINDOWS_API */

int wolfSSHD_ConfigSetHostKeyFile(WOLFSSHD_CONFIG* conf, const char* file)
{
int ret = WS_SUCCESS;
Expand Down
Loading
Loading