add mutual X509 auth of host key and sshd_config parsing additions

pull/453/head
JacobBarthelmeh 2022-08-25 14:04:01 -07:00
parent 7c486e518a
commit 3e1a6ff342
9 changed files with 1234 additions and 551 deletions

View File

@ -76,7 +76,7 @@ struct WOLFSSHD_AUTH {
#endif #endif
#ifndef MAX_LINE_SZ #ifndef MAX_LINE_SZ
#define MAX_LINE_SZ 500 #define MAX_LINE_SZ 900
#endif #endif
#ifndef MAX_PATH_SZ #ifndef MAX_PATH_SZ
#define MAX_PATH_SZ 80 #define MAX_PATH_SZ 80
@ -144,14 +144,24 @@ static int CheckAuthKeysLine(char* line, word32 lineSz, const byte* key,
word32 keyCandSz; word32 keyCandSz;
char* last; char* last;
enum { enum {
#ifdef WOLFSSH_CERTS
NUM_ALLOWED_TYPES = 9
#else
NUM_ALLOWED_TYPES = 5 NUM_ALLOWED_TYPES = 5
#endif
}; };
static const char* allowedTypes[NUM_ALLOWED_TYPES] = { static const char* allowedTypes[NUM_ALLOWED_TYPES] = {
"ssh-rsa", "ssh-rsa",
"ssh-ed25519", "ssh-ed25519",
"ecdsa-sha2-nistp256", "ecdsa-sha2-nistp256",
"ecdsa-sha2-nistp384", "ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp521" "ecdsa-sha2-nistp521",
#ifdef WOLFSSH_CERTS
"x509v3-ssh-rsa",
"x509v3-ecdsa-sha2-nistp256",
"x509v3-ecdsa-sha2-nistp384",
"x509v3-ecdsa-sha2-nistp521",
#endif
}; };
int typeOk = 0; int typeOk = 0;
int i; int i;
@ -639,7 +649,7 @@ static int DoCheckUser(const char* usr, WOLFSSHD_AUTH* auth)
if (wolfSSHD_ConfigGetPermitRoot(auth->conf) == 0) { if (wolfSSHD_ConfigGetPermitRoot(auth->conf) == 0) {
if (XSTRCMP(usr, "root") == 0) { if (XSTRCMP(usr, "root") == 0) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Login as root not permited"); wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Login as root not permited");
ret = WOLFSSH_USERAUTH_FAILURE; ret = WOLFSSH_USERAUTH_REJECTED;
} }
} }
@ -692,7 +702,7 @@ static int RequestAuthentication(WS_UserAuthData* authData,
if (wolfSSHD_ConfigGetPwAuth(authCtx->conf) != 1) { if (wolfSSHD_ConfigGetPwAuth(authCtx->conf) != 1) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Password authentication not " wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Password authentication not "
"allowed by configuration!"); "allowed by configuration!");
ret = WOLFSSH_USERAUTH_FAILURE; ret = WOLFSSH_USERAUTH_REJECTED;
} }
/* Check if password is valid for this user. */ /* Check if password is valid for this user. */
/* first handle empty password cases */ /* first handle empty password cases */
@ -797,6 +807,35 @@ int DefaultUserAuth(byte authType, WS_UserAuthData* authData, void* ctx)
} }
int DefaultUserAuthTypes(WOLFSSH* ssh, void* ctx)
{
WOLFSSHD_CONFIG* usrConf;
WOLFSSHD_AUTH* authCtx;
char* usr;
int ret = 0;
if (ssh == NULL || ctx == NULL)
return WS_BAD_ARGUMENT;
authCtx = (WOLFSSHD_AUTH*)ctx;
/* get configuration for user */
usr = wolfSSH_GetUsername(ssh);
usrConf = wolfSSHD_AuthGetUserConf(authCtx, usr, NULL, NULL,
NULL, NULL, NULL);
if (usrConf == NULL) {
ret = WS_BAD_ARGUMENT;
}
else {
if (wolfSSHD_ConfigGetPwAuth(usrConf) == 1) {
ret |= WOLFSSH_USERAUTH_PASSWORD;
}
ret |= WOLFSSH_USERAUTH_PUBLICKEY;
}
return ret;
}
static int SetDefaultUserCheck(WOLFSSHD_AUTH* auth) static int SetDefaultUserCheck(WOLFSSHD_AUTH* auth)
{ {
int ret = WS_NOT_COMPILED; int ret = WS_NOT_COMPILED;
@ -1018,18 +1057,22 @@ WOLFSSHD_CONFIG* wolfSSHD_AuthGetUserConf(const WOLFSSHD_AUTH* auth,
if (auth != NULL) { if (auth != NULL) {
struct passwd *p_passwd; struct passwd *p_passwd;
char* gName = NULL;
p_passwd = getpwnam((const char *)usr); if (usr != NULL) {
if (p_passwd == NULL) { p_passwd = getpwnam((const char *)usr);
return NULL; if (p_passwd == NULL) {
return NULL;
}
g = getgrgid(p_passwd->pw_gid);
if (g == NULL) {
return NULL;
}
gName = g->gr_name;
} }
g = getgrgid(p_passwd->pw_gid); ret = wolfSSHD_GetUserConf(auth->conf, usr, gName, host, localAdr,
if (g == NULL) {
return NULL;
}
ret = wolfSSHD_GetUserConf(auth->conf, usr, g->gr_name, host, localAdr,
localPort, RDomain, adr); localPort, RDomain, adr);
} }
return ret; return ret;

View File

@ -30,6 +30,7 @@ USER_NODE* AddNewUser(USER_NODE* list, byte type, const byte* username,
void SetAuthKeysPattern(const char* pattern); void SetAuthKeysPattern(const char* pattern);
int DefaultUserAuth(byte authType, WS_UserAuthData* authData, void* ctx); int DefaultUserAuth(byte authType, WS_UserAuthData* authData, void* ctx);
int DefaultUserAuthTypes(WOLFSSH* ssh, void* ctx);
typedef struct WOLFSSHD_AUTH WOLFSSHD_AUTH; typedef struct WOLFSSHD_AUTH WOLFSSHD_AUTH;

View File

@ -478,6 +478,7 @@ static int HandlePwAuth(WOLFSSHD_CONFIG* conf, const char* value)
if (ret == WS_SUCCESS) { if (ret == WS_SUCCESS) {
if (WSTRCMP(value, "no") == 0) { if (WSTRCMP(value, "no") == 0) {
wolfSSH_Log(WS_LOG_INFO, "[SSHD] password authentication disabled");
conf->passwordAuth = 0; conf->passwordAuth = 0;
} }
else if (WSTRCMP(value, "yes") == 0) { else if (WSTRCMP(value, "yes") == 0) {

View File

@ -187,6 +187,47 @@ static void CleanupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx)
(void)conf; (void)conf;
} }
#ifndef NO_FILESYSTEM
static void freeBufferFromFile(byte* buf, void* heap)
{
if (buf != NULL)
WFREE(buf, heap, DYNTYPE_SSHD);
(void)heap;
}
/* set bufSz to size wanted if too small and buf is null */
static byte* getBufferFromFile(const char* fileName, word32* bufSz, void* heap)
{
FILE* file;
byte* buf = NULL;
word32 fileSz;
word32 readSz;
if (fileName == NULL) return NULL;
if (WFOPEN(&file, fileName, "rb") != 0)
return NULL;
fseek(file, 0, XSEEK_END);
fileSz = (word32)ftell(file);
rewind(file);
buf = (byte*)WMALLOC(fileSz + 1, heap, DYNTYPE_SSHD);
if (buf != NULL) {
readSz = (word32)fread(buf, 1, fileSz, file);
if (readSz < fileSz) {
fclose(file);
WFREE(buf, heap, DYNTYPE_SSHD);
return NULL;
}
*bufSz = readSz;
fclose(file);
}
(void)heap;
return buf;
}
#endif /* NO_FILESYSTEM */
/* Initializes and sets up the WOLFSSH_CTX struct based on the configure options /* Initializes and sets up the WOLFSSH_CTX struct based on the configure options
* return WS_SUCCESS on success * return WS_SUCCESS on success
@ -198,6 +239,7 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx)
DerBuffer* der = NULL; DerBuffer* der = NULL;
byte* privBuf; byte* privBuf;
word32 privBufSz; word32 privBufSz;
void* heap = NULL;
/* create a new WOLFSSH_CTX */ /* create a new WOLFSSH_CTX */
*ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL); *ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL);
@ -230,23 +272,18 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx)
ret = WS_BAD_ARGUMENT; ret = WS_BAD_ARGUMENT;
} }
else { else {
FILE* f; byte* data;
word32 dataSz = 0;
f = XFOPEN(hostKey, "rb"); data = getBufferFromFile(hostKey, &dataSz, heap);
if (f == NULL) { if (data == NULL) {
wolfSSH_Log(WS_LOG_ERROR, wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Unable to open host private key"); "[SSHD] Error reading host key file.");
ret = WS_BAD_ARGUMENT; ret = WS_MEMORY_E;
} }
else {
byte* data;
int dataSz = 4096;
data = (byte*)WMALLOC(dataSz, NULL, 0);
dataSz = (int)XFREAD(data, 1, dataSz, f);
XFCLOSE(f);
if (ret == WS_SUCCESS) {
if (wc_PemToDer(data, dataSz, PRIVATEKEY_TYPE, &der, NULL, if (wc_PemToDer(data, dataSz, PRIVATEKEY_TYPE, &der, NULL,
NULL, NULL) != 0) { NULL, NULL) != 0) {
wolfSSH_Log(WS_LOG_DEBUG, "[SSHD] Failed to convert host " wolfSSH_Log(WS_LOG_DEBUG, "[SSHD] Failed to convert host "
@ -267,49 +304,106 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx)
ret = WS_BAD_ARGUMENT; ret = WS_BAD_ARGUMENT;
} }
WFREE(data, NULL, 0); freeBufferFromFile(data, heap);
wc_FreeDer(&der); wc_FreeDer(&der);
} }
} }
} }
#ifdef WOLFSSH_OSSH_CERTS
#if defined(WOLFSSH_OSSH_CERTS) || defined(WOLFSSH_CERTS)
if (ret == WS_SUCCESS) { if (ret == WS_SUCCESS) {
/* TODO: Create a helper function that uses a file instead. */ /* TODO: Create a helper function that uses a file instead. */
char* hostCert = wolfSSHD_ConfigGetHostCertFile(conf); char* hostCert = wolfSSHD_ConfigGetHostCertFile(conf);
if (hostCert != NULL) { if (hostCert != NULL) {
FILE* f; byte* data;
word32 dataSz = 0;
f = XFOPEN(hostCert, "rb"); data = getBufferFromFile(hostCert, &dataSz, heap);
if (f == NULL) { if (data == NULL) {
wolfSSH_Log(WS_LOG_ERROR, wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Unable to open host certificate."); "[SSHD] Error reading host key file.");
ret = WS_BAD_ARGUMENT; ret = WS_MEMORY_E;
} }
else {
byte* data;
int dataSz = 4096;
data = (byte*)WMALLOC(dataSz, NULL, 0);
dataSz = (int)XFREAD(data, 1, dataSz, f);
XFCLOSE(f);
if (ret == WS_SUCCESS) {
#ifdef WOLFSSH_OPENSSH_CERTS
if (wolfSSH_CTX_UseOsshCert_buffer(*ctx, data, dataSz) < 0) { if (wolfSSH_CTX_UseOsshCert_buffer(*ctx, data, dataSz) < 0) {
wolfSSH_Log(WS_LOG_ERROR, wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Failed to use host certificate."); "[SSHD] Failed to use host certificate.");
ret = WS_BAD_ARGUMENT; ret = WS_BAD_ARGUMENT;
} }
#endif
#ifdef WOLFSSH_CERTS
if (ret == WS_SUCCESS || ret == WS_BAD_ARGUMENT) {
ret = wolfSSH_CTX_UseCert_buffer(*ctx, data, dataSz,
WOLFSSH_FORMAT_PEM);
if (ret != WS_SUCCESS) {
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
WFREE(data, NULL, 0); freeBufferFromFile(data, heap);
} }
} }
} }
#endif /* WOLFSSH_OSSH_CERTS */ #endif /* WOLFSSH_OSSH_CERTS || WOLFSSH_CERTS */
#ifdef WOLFSSH_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);
if (data == NULL) {
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Error reading CA cert file.");
ret = WS_MEMORY_E;
}
if (ret == WS_SUCCESS) {
ret = wolfSSH_CTX_AddRootCert_buffer(*ctx, data, dataSz,
WOLFSSH_FORMAT_PEM);
if (ret != WS_SUCCESS) {
ret = wolfSSH_CTX_AddRootCert_buffer(*ctx, data, dataSz,
WOLFSSH_FORMAT_ASN1);
}
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
}
freeBufferFromFile(data, heap);
}
}
}
#endif
wolfSSH_SetUserAuthTypes(*ctx, DefaultUserAuthTypes);
/* @TODO Load in host public key */ /* @TODO Load in host public key */
/* Set allowed connection type, i.e. public key / password */ /* Set allowed connection type, i.e. public key / password */
(void)heap;
return ret; return ret;
} }

View File

@ -184,6 +184,7 @@ static void ShowUsage(void)
printf(" -J <filename> filename for DER certificate to use\n"); printf(" -J <filename> filename for DER certificate to use\n");
printf(" Certificate example : client -u orange \\\n"); printf(" Certificate example : client -u orange \\\n");
printf(" -J orange-cert.der -i orange-key.der\n"); printf(" -J orange-cert.der -i orange-key.der\n");
printf(" -A <filename> filename for DER CA certificate to verify host\n");
#endif #endif
} }
@ -194,6 +195,7 @@ static byte* userPublicKey = userPublicKeyBuf;
static const byte* userPublicKeyType = NULL; static const byte* userPublicKeyType = NULL;
static const char* pubKeyName = NULL; static const char* pubKeyName = NULL;
static const char* certName = NULL; static const char* certName = NULL;
static const char* caCert = NULL;
static byte userPrivateKeyBuf[1191]; /* Size equal to hanselPrivateRsaSz. */ static byte userPrivateKeyBuf[1191]; /* Size equal to hanselPrivateRsaSz. */
static byte* userPrivateKey = userPrivateKeyBuf; static byte* userPrivateKey = userPrivateKeyBuf;
static const byte* userPrivateKeyType = NULL; static const byte* userPrivateKeyType = NULL;
@ -912,7 +914,7 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
char** argv = ((func_args*)args)->argv; char** argv = ((func_args*)args)->argv;
((func_args*)args)->return_code = 0; ((func_args*)args)->return_code = 0;
while ((ch = mygetopt(argc, argv, "?ac:eh:i:j:p:tu:xzNP:RJ:")) != -1) { while ((ch = mygetopt(argc, argv, "?ac:eh:i:j:p:tu:xzNP:RJ:A:")) != -1) {
switch (ch) { switch (ch) {
case 'h': case 'h':
host = myoptarg; host = myoptarg;
@ -957,6 +959,11 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
case 'J': case 'J':
certName = myoptarg; certName = myoptarg;
break; break;
case 'A':
caCert = myoptarg;
break;
#endif #endif
case 'x': case 'x':
@ -1134,6 +1141,24 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
wolfSSH_set_agent_cb_ctx(ssh, &agentCbCtx); wolfSSH_set_agent_cb_ctx(ssh, &agentCbCtx);
} }
#endif #endif
#ifdef WOLFSSH_CERTS
/* CA certificate to verify host cert with */
if (caCert) {
byte* der = NULL;
word32 derSz;
ret = load_der_file(caCert, &der, &derSz);
if (ret != 0) err_sys("Couldn't load CA certificate file.");
if (wolfSSH_CTX_AddRootCert_buffer(ctx, der, derSz,
WOLFSSH_FORMAT_ASN1) != WS_SUCCESS) {
err_sys("Couldn't parse in CA certificate.");
}
WFREE(der, NULL, 0);
}
#else
(void)caCert;
#endif /* WOLFSSH_CERTS */
wolfSSH_CTX_SetPublicKeyCheck(ctx, wsPublicKeyCheck); wolfSSH_CTX_SetPublicKeyCheck(ctx, wsPublicKeyCheck);
wolfSSH_SetPublicKeyCheckCtx(ssh, (void*)"You've been sampled!"); wolfSSH_SetPublicKeyCheckCtx(ssh, (void*)"You've been sampled!");

File diff suppressed because it is too large Load Diff

View File

@ -1259,6 +1259,14 @@ void wolfSSH_SetUserAuth(WOLFSSH_CTX* ctx, WS_CallbackUserAuth cb)
} }
void wolfSSH_SetUserAuthTypes(WOLFSSH_CTX* ctx, WS_CallbackUserAuthTypes cb)
{
if (ctx != NULL) {
ctx->userAuthTypesCb = cb;
}
}
void wolfSSH_SetUserAuthCtx(WOLFSSH* ssh, void* userAuthCtx) void wolfSSH_SetUserAuthCtx(WOLFSSH* ssh, void* userAuthCtx)
{ {
if (ssh != NULL) { if (ssh != NULL) {

View File

@ -408,6 +408,7 @@ struct WOLFSSH_CTX {
WS_CallbackIORecv ioRecvCb; /* I/O Receive Callback */ WS_CallbackIORecv ioRecvCb; /* I/O Receive Callback */
WS_CallbackIOSend ioSendCb; /* I/O Send Callback */ WS_CallbackIOSend ioSendCb; /* I/O Send Callback */
WS_CallbackUserAuth userAuthCb; /* User Authentication Callback */ WS_CallbackUserAuth userAuthCb; /* User Authentication Callback */
WS_CallbackUserAuthTypes userAuthTypesCb; /* Authentication Types Allowed */
WS_CallbackUserAuthResult userAuthResultCb; /* User Authentication Result */ WS_CallbackUserAuthResult userAuthResultCb; /* User Authentication Result */
WS_CallbackHighwater highwaterCb; /* Data Highwater Mark Callback */ WS_CallbackHighwater highwaterCb; /* Data Highwater Mark Callback */
WS_CallbackGlobalReq globalReqCb; /* Global Request Callback */ WS_CallbackGlobalReq globalReqCb; /* Global Request Callback */

View File

@ -210,6 +210,9 @@ typedef struct WS_UserAuthData {
typedef int (*WS_CallbackUserAuth)(byte, WS_UserAuthData*, void*); typedef int (*WS_CallbackUserAuth)(byte, WS_UserAuthData*, void*);
WOLFSSH_API void wolfSSH_SetUserAuth(WOLFSSH_CTX*, WS_CallbackUserAuth); WOLFSSH_API void wolfSSH_SetUserAuth(WOLFSSH_CTX*, WS_CallbackUserAuth);
typedef int (*WS_CallbackUserAuthTypes)(WOLFSSH* ssh, void* ctx);
WOLFSSH_API void wolfSSH_SetUserAuthTypes(WOLFSSH_CTX*,
WS_CallbackUserAuthTypes);
WOLFSSH_API void wolfSSH_SetUserAuthCtx(WOLFSSH*, void*); WOLFSSH_API void wolfSSH_SetUserAuthCtx(WOLFSSH*, void*);
WOLFSSH_API void* wolfSSH_GetUserAuthCtx(WOLFSSH*); WOLFSSH_API void* wolfSSH_GetUserAuthCtx(WOLFSSH*);