Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for OpenSSH-style certificates. #561

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ examples/scpclient/wolfscp

# applications
apps/wolfsshd/wolfsshd
apps/wolfsshd/test/test_configuration
apps/wolfsshd/test/test_configuration.test

# test output
tests/*.test
Expand Down
70 changes: 8 additions & 62 deletions apps/wolfsshd/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -477,8 +477,7 @@ static int ResolveAuthKeysPath(const char* homeDir, char* resolved)
}

static int CheckPublicKeyUnix(const char* name,
const WS_UserAuthData_PublicKey* pubKeyCtx,
const char* usrCaKeysFile)
const WS_UserAuthData_PublicKey* pubKeyCtx)
{
int ret = WSSHD_AUTH_SUCCESS;
int rc;
Expand All @@ -493,65 +492,14 @@ static int CheckPublicKeyUnix(const char* name,

#ifdef WOLFSSH_OSSH_CERTS
if (pubKeyCtx->isOsshCert) {
byte* caKey = NULL;
word32 caKeySz;
const byte* caKeyType = NULL;
word32 caKeyTypeSz;
byte fingerprint[WC_SHA256_DIGEST_SIZE];

if (pubKeyCtx->caKey == NULL ||
pubKeyCtx->caKeySz != WC_SHA256_DIGEST_SIZE) {
ret = WS_FATAL_ERROR;
}

if (ret == WSSHD_AUTH_SUCCESS) {
f = XFOPEN(usrCaKeysFile, "rb");
if (f == XBADFILE) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Unable to open %s",
usrCaKeysFile);
ret = WS_BAD_FILE_E;
}
}
if (ret == WSSHD_AUTH_SUCCESS) {
lineBuf = (char*)WMALLOC(MAX_LINE_SZ, NULL, DYNTYPE_BUFFER);
if (lineBuf == NULL) {
ret = WS_MEMORY_E;
}
}
while (ret == WSSHD_AUTH_SUCCESS &&
(current = XFGETS(lineBuf, MAX_LINE_SZ, f)) != NULL) {
currentSz = (word32)XSTRLEN(current);

/* remove leading spaces */
while (currentSz > 0 && current[0] == ' ') {
currentSz = currentSz - 1;
current = current + 1;
}

if (currentSz <= 1) {
continue; /* empty line */
}

if (current[0] == '#') {
continue; /* commented out line */
}

rc = wolfSSH_ReadKey_buffer((const byte*)current, currentSz,
WOLFSSH_FORMAT_SSH, &caKey, &caKeySz,
&caKeyType, &caKeyTypeSz, NULL);
if (rc == WS_SUCCESS) {
rc = wc_Hash(WC_HASH_TYPE_SHA256, caKey, caKeySz, fingerprint,
WC_SHA256_DIGEST_SIZE);
if (rc == 0 && WMEMCMP(fingerprint, pubKeyCtx->caKey,
WC_SHA256_DIGEST_SIZE) == 0) {
foundKey = 1;
break;
}
}
}
/*
* wolfSSH proper will have already verified the user's cert if we've
* made it this far. There's no further checking to do in this callback.
*/
foundKey = 1;
}
else
#endif /* WOLFSSH_OSSH_CERTS */
#endif /* WOLFSSH_OSSH_CERTS */
{
errno = 0;
pwInfo = getpwnam((const char*)name);
Expand Down Expand Up @@ -632,7 +580,6 @@ static int CheckPublicKeyUnix(const char* name,
WFREE(authKeysFile, NULL, DYNTYPE_STRING);
}

(void)usrCaKeysFile;
return ret;
}
#endif /* !_WIN32*/
Expand Down Expand Up @@ -750,8 +697,7 @@ static int RequestAuthentication(WS_UserAuthData* authData,
}
else {
/* if not a certificate then parse through authorized key file */
rc = authCtx->checkPublicKeyCb(usr, &authData->sf.publicKey,
wolfSSHD_ConfigGetUserCAKeysFile(authCtx->conf));
rc = authCtx->checkPublicKeyCb(usr, &authData->sf.publicKey);
if (rc == WSSHD_AUTH_SUCCESS) {
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Public key ok.");
ret = WOLFSSH_USERAUTH_SUCCESS;
Expand Down
3 changes: 1 addition & 2 deletions apps/wolfsshd/auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ typedef int (*CallbackCheckPassword)(const char* usr, const byte* psw,
* ok, and negative values if an error occurs during checking.
*/
typedef int (*CallbackCheckPublicKey)(const char* usr,
const WS_UserAuthData_PublicKey* pubKey,
const char* usrCaKeysFile);
const WS_UserAuthData_PublicKey* pubKey);

WOLFSSHD_AUTH* wolfSSHD_AuthCreateUser(void* heap, const WOLFSSHD_CONFIG* conf);
int wolfSSHD_AuthFreeUser(WOLFSSHD_AUTH* auth);
Expand Down
17 changes: 9 additions & 8 deletions apps/wolfsshd/configuration.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,16 +284,17 @@ void wolfSSHD_ConfigFree(WOLFSSHD_CONFIG* conf)
while (current != NULL) {
WOLFSSHD_CONFIG* next = current->next;
heap = current->heap;

FreeString(&current->banner, heap);
FreeString(&current->banner, heap);
FreeString(&current->chrootDir, heap);
FreeString(&current->ciphers, heap);
FreeString(&current->kekAlgos, heap);
FreeString(&current->hostKeyAlgos, heap);
FreeString(&current->ciphers, heap);
FreeString(&current->kekAlgos, heap);
FreeString(&current->hostKeyAlgos, heap);
FreeString(&current->listenAddress, heap);
FreeString(&current->authKeysFile, heap);
FreeString(&current->hostKeyFile, heap);
FreeString(&current->hostCertFile, heap);
FreeString(&current->authKeysFile, heap);
FreeString(&current->hostKeyFile, heap);
FreeString(&current->hostCertFile, heap);
FreeString(&current->userCAKeysFile, heap);

WFREE(current, heap, DYNTYPE_SSHD);
current = next;
Expand Down
14 changes: 8 additions & 6 deletions apps/wolfsshd/include.am
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ apps_wolfsshd_wolfsshd_SOURCES = apps/wolfsshd/wolfsshd.c \
apps_wolfsshd_wolfsshd_LDADD = src/libwolfssh.la
apps_wolfsshd_wolfsshd_DEPENDENCIES = src/libwolfssh.la

noinst_PROGRAMS += apps/wolfsshd/test/test_configuration
apps_wolfsshd_test_test_configuration_SOURCES = apps/wolfsshd/test/test_configuration.c \
noinst_PROGRAMS += apps/wolfsshd/test/test_configuration.test
check_PROGRAMS += apps/wolfsshd/test/test_configuration.test
apps_wolfsshd_test_test_configuration_test_SOURCES = apps/wolfsshd/test/test_configuration.c \
apps/wolfsshd/configuration.c \
apps/wolfsshd/auth.c
apps_wolfsshd_test_test_configuration_LDADD = src/libwolfssh.la
apps_wolfsshd_test_test_configuration_DEPENDENCIES = src/libwolfssh.la
apps_wolfsshd_test_test_configuration_CPPFLAGS = $(AM_CPPFLAGS) -DWOLFSSH_SSHD -DWOLFSSHD_UNIT_TEST -I$(srcdir)/apps/wolfsshd/

apps_wolfsshd_test_test_configuration_test_LDADD = src/libwolfssh.la
apps_wolfsshd_test_test_configuration_test_DEPENDENCIES = src/libwolfssh.la
apps_wolfsshd_test_test_configuration_test_CPPFLAGS = $(AM_CPPFLAGS) -DWOLFSSH_SSHD -DWOLFSSHD_UNIT_TEST -I$(srcdir)/apps/wolfsshd/

DISTCLEANFILES+= apps/wolfsshd/.libs/wolfsshd \
apps/wolfsshd/test/.libs/test_configuration
apps/wolfsshd/test/.libs/test_configuration.test

endif BUILD_SSHD
89 changes: 50 additions & 39 deletions apps/wolfsshd/wolfsshd.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ static void CleanupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx)
}

#ifndef NO_FILESYSTEM
static void freeBufferFromFile(byte* buf, void* heap)
static void FreeBufferFromFile(byte* buf, void* heap)
{
if (buf != NULL)
WFREE(buf, heap, DYNTYPE_SSHD);
Expand All @@ -198,7 +198,7 @@ static void freeBufferFromFile(byte* buf, void* heap)


/* set bufSz to size wanted if too small and buf is null */
static byte* getBufferFromFile(const char* fileName, word32* bufSz, void* heap)
static byte* GetBufferFromFile(const char* fileName, word32* bufSz, void* heap)
{
FILE* file;
byte* buf = NULL;
Expand Down Expand Up @@ -282,7 +282,7 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx)
byte* data;
word32 dataSz = 0;

data = getBufferFromFile(hostKey, &dataSz, heap);
data = GetBufferFromFile(hostKey, &dataSz, heap);
if (data == NULL) {
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Error reading host key file.");
Expand Down Expand Up @@ -311,22 +311,22 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx)
ret = WS_BAD_ARGUMENT;
}

freeBufferFromFile(data, heap);
FreeBufferFromFile(data, heap);
wc_FreeDer(&der);
}
}
}

#if defined(WOLFSSH_OSSH_CERTS) || defined(WOLFSSH_CERTS)
if (ret == WS_SUCCESS) {
/* TODO: Create a helper function that uses a file instead. */
char* hostCert = wolfSSHD_ConfigGetHostCertFile(conf);

if (hostCert != NULL) {
byte* data;
word32 dataSz = 0;

data = getBufferFromFile(hostCert, &dataSz, heap);
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Using host cert file %s",
hostCert);
data = GetBufferFromFile(hostCert, &dataSz, heap);
if (data == NULL) {
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Error reading host key file.");
Expand All @@ -335,44 +335,48 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx)
}

if (ret == WS_SUCCESS) {
#ifdef WOLFSSH_OPENSSH_CERTS
if (wolfSSH_CTX_UseOsshCert_buffer(*ctx, data, dataSz) < 0) {
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Failed to use host certificate.");
ret = WS_BAD_ARGUMENT;
}
#endif
#ifdef WOLFSSH_OSSH_CERTS
ret = wolfSSH_CTX_UseOsshCert_buffer(*ctx, data, dataSz);
/*
* If wolfSSH_CTX_UseOsshCert_buffer failed, the cert might be
* X.509. Try with wolfSSH_CTX_UseCert_buffer.
*/
if (ret != WS_SUCCESS)
#endif /* WOLFSSH_OSSH_CERTS */
{
#ifdef WOLFSSH_CERTS
if (ret == WS_SUCCESS || ret == WS_BAD_ARGUMENT) {
/* Try PEM first. */
ret = wolfSSH_CTX_UseCert_buffer(*ctx, data, dataSz,
WOLFSSH_FORMAT_PEM);
if (ret != WS_SUCCESS) {
/* Try DER (ASN.1) if it wasn't PEM. */
ret = wolfSSH_CTX_UseCert_buffer(*ctx, data, dataSz,
WOLFSSH_FORMAT_ASN1);
}
if (ret != WS_SUCCESS) {
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Failed to load in host certificate.");
}
#endif /* WOLFSSH_CERTS */
}
if (ret != WS_SUCCESS) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Failed to load in host "
"certificate %s.", hostCert);
}
#endif

freeBufferFromFile(data, heap);
FreeBufferFromFile(data, heap);
}
}
}
#endif /* WOLFSSH_OSSH_CERTS || WOLFSSH_CERTS */

#ifdef WOLFSSH_CERTS
#if defined(WOLFSSH_CERTS) || defined(WOLFSSH_OSSH_CERTS)
if (ret == WS_SUCCESS) {
char* caCert = wolfSSHD_ConfigGetUserCAKeysFile(conf);

if (caCert != NULL) {
byte* data;
word32 dataSz = 0;


wolfSSH_Log(WS_LOG_INFO, "[SSHD] Using CA keys file %s", caCert);
data = getBufferFromFile(caCert, &dataSz, heap);
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Using user CA keys file %s",
caCert);
data = GetBufferFromFile(caCert, &dataSz, heap);
if (data == NULL) {
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Error reading CA cert file.");
Expand All @@ -381,25 +385,32 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx)
}

if (ret == WS_SUCCESS) {
ret = wolfSSH_CTX_AddRootCert_buffer(*ctx, data, dataSz,
WOLFSSH_FORMAT_PEM);
if (ret != WS_SUCCESS) {
#ifdef WOLFSSH_OSSH_CERTS
ret = wolfSSH_CTX_AddOsshCAKey(*ctx, data, dataSz);
/*
* If wolfSSH_CTX_AddOsshCAKey failed, try
* wolfSSH_CTX_AddRootCert_buffer.
*/
if (ret != WS_SUCCESS)
#endif /* WOLFSSH_OSSH_CERTS */
{
#ifdef WOLFSSH_CERTS
/* Try PEM first. */
ret = wolfSSH_CTX_AddRootCert_buffer(*ctx, data, dataSz,
WOLFSSH_FORMAT_ASN1);
WOLFSSH_FORMAT_PEM);
if (ret != WS_SUCCESS) {
/* Try DER (ASN.1) if it wasn't PEM. */
ret = wolfSSH_CTX_AddRootCert_buffer(*ctx, data, dataSz,
WOLFSSH_FORMAT_ASN1);
}
#endif /* WOLFSSH_CERTS */
}
if (ret != WS_SUCCESS) {
#ifdef WOLFSSH_OPENSSH_CERTS
wolfSSH_Log(WS_LOG_INFO,
"[SSHD] Continuing on in case CA is openssh "
"style.");
ret = WS_SUCCESS;
#else
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Failed to load in CA certificate.");
#endif
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Failed to load in user CA"
" keys file %s.", caCert);
}

freeBufferFromFile(data, heap);
FreeBufferFromFile(data, heap);
}
}
}
Expand Down
Loading