check on user name in UPN if exists

add check on host IP address in certificate alt names
pull/465/head
Jacob Barthelmeh 2022-10-01 00:00:28 -06:00 committed by JacobBarthelmeh
parent c11c7e3bbd
commit 9e3c2f3b78
3 changed files with 182 additions and 32 deletions

View File

@ -39,6 +39,10 @@
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/coding.h>
#ifdef WOLFSSL_FPKI
#include <wolfssl/wolfcrypt/asn.h>
#endif
#ifdef NO_INLINE
#include <wolfssh/misc.h>
#else
@ -740,29 +744,73 @@ static int RequestAuthentication(WS_UserAuthData* authData,
if (ret == WOLFSSH_USERAUTH_SUCCESS &&
authData->type == WOLFSSH_USERAUTH_PUBLICKEY) {
/* if this is a certificate and no specific authorized keys file has
* been set then rely on CA to have verified the cert */
if (authData->sf.publicKey.isCert &&
!wolfSSHD_ConfigGetAuthKeysFileSet(authCtx->conf)) {
wolfSSH_Log(WS_LOG_INFO,
"[SSHD] Relying on CA for public key check");
ret = WOLFSSH_USERAUTH_SUCCESS;
}
else {
/* if not a certificate then parse through authorized key file */
rc = authCtx->checkPublicKeyCb(usr, &authData->sf.publicKey,
wolfSSHD_ConfigGetUserCAKeysFile(authCtx->conf));
if (rc == WSSHD_AUTH_SUCCESS) {
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Public key ok.");
ret = WOLFSSH_USERAUTH_SUCCESS;
}
else if (rc == WSSHD_AUTH_FAILURE) {
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Public key not authorized.");
#ifdef WOLFSSL_FPKI
/* compare user name to UPN in certificate */
if (authData->sf.publicKey.isCert) {
DecodedCert dCert;
wc_InitDecodedCert(&dCert, authData->sf.publicKey.publicKey,
authData->sf.publicKey.publicKeySz, NULL);
if (wc_ParseCert(&dCert, CERT_TYPE, NO_VERIFY, NULL) != 0) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Unable to parse peer cert.");
ret = WOLFSSH_USERAUTH_INVALID_PUBLICKEY;
}
else {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error checking public key.");
ret = WOLFSSH_USERAUTH_FAILURE;
int usrMatch = 0;
DNS_entry* current = dCert.altNames;
while (current != NULL) {
if (current->type == ASN_OTHER_TYPE &&
current->oidSum == UPN_OID) {
/* found UPN oid, check name against user */
int idx;
for (idx = 0; idx < current->len; idx++) {
if (current->name[idx] == '@') break;
}
if ((int)XSTRLEN(usr) == idx &&
XSTRNCMP(usr, current->name, idx) == 0) {
usrMatch = 1;
}
}
current = current->next;
}
if (usrMatch == 0) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] incorrect user cert sent");
ret = WOLFSSH_USERAUTH_INVALID_PUBLICKEY;
}
}
FreeDecodedCert(&dCert);
}
#endif
if (ret == WOLFSSH_USERAUTH_SUCCESS) {
/* if this is a certificate and no specific authorized keys file has
* been set then rely on CA to have verified the cert */
if (authData->sf.publicKey.isCert &&
!wolfSSHD_ConfigGetAuthKeysFileSet(authCtx->conf)) {
wolfSSH_Log(WS_LOG_INFO,
"[SSHD] Relying on CA for public key check");
ret = WOLFSSH_USERAUTH_SUCCESS;
}
else {
/* if not a certificate then parse through authorized key file */
rc = authCtx->checkPublicKeyCb(usr, &authData->sf.publicKey,
wolfSSHD_ConfigGetUserCAKeysFile(authCtx->conf));
if (rc == WSSHD_AUTH_SUCCESS) {
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Public key ok.");
ret = WOLFSSH_USERAUTH_SUCCESS;
}
else if (rc == WSSHD_AUTH_FAILURE) {
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Public key not authorized.");
ret = WOLFSSH_USERAUTH_INVALID_PUBLICKEY;
}
else {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error checking public key.");
ret = WOLFSSH_USERAUTH_FAILURE;
}
}
}
}

View File

@ -60,6 +60,10 @@
#include <sys/select.h>
#endif
#ifdef WOLFSSH_CERTS
#include <wolfssl/wolfcrypt/asn.h>
#endif
#ifndef NO_WOLFSSH_CLIENT
@ -471,8 +475,71 @@ static int wsUserAuth(byte authType,
}
#if defined(WOLFSSH_AGENT) || defined(WOLFSSH_CERTS)
static inline void ato32(const byte* c, word32* u32)
{
*u32 = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
}
#endif
#ifdef WOLFSSH_CERTS
static int ParseRFC6187(const byte* in, word32 inSz, byte** leafOut,
word32* leafOutSz)
{
int ret = WS_SUCCESS;
word32 l = 0, m = 0;
if (inSz < sizeof(word32)) {
printf("inSz %d too small for holding cert name\n", inSz);
return WS_BUFFER_E;
}
/* Skip the name */
ato32(in, &l);
m += l + sizeof(word32);
/* Get the cert count */
if (ret == WS_SUCCESS) {
word32 count;
if (inSz - m < sizeof(word32))
return WS_BUFFER_E;
ato32(in + m, &count);
m += sizeof(word32);
if (ret == WS_SUCCESS && count == 0)
ret = WS_FATAL_ERROR; /* need at least one cert */
}
if (ret == WS_SUCCESS) {
word32 certSz = 0;
if (inSz - m < sizeof(word32))
return WS_BUFFER_E;
ato32(in + m, &certSz);
m += sizeof(word32);
if (ret == WS_SUCCESS) {
/* store leaf cert size to present to user callback */
*leafOutSz = certSz;
*leafOut = (byte*)in + m;
}
if (inSz - m < certSz)
return WS_BUFFER_E;
}
return ret;
}
#endif /* WOLFSSH_CERTS */
static int wsPublicKeyCheck(const byte* pubKey, word32 pubKeySz, void* ctx)
{
int ret = 0;
#ifdef DEBUG_WOLFSSH
printf("Sample public key check callback\n"
" public key = %p\n"
@ -483,7 +550,49 @@ static int wsPublicKeyCheck(const byte* pubKey, word32 pubKeySz, void* ctx)
(void)pubKeySz;
(void)ctx;
#endif
return 0;
#ifdef WOLFSSH_CERTS
#if defined(OPENSSL_ALL) || defined(WOLFSSL_IP_ALT_NAME)
/* try to parse the certificate and check it's IP address */
if (pubKeySz > 0) {
DecodedCert dCert;
byte* der = NULL;
word32 derSz = 0;
if (ParseRFC6187(pubKey, pubKeySz, &der, &derSz) == WS_SUCCESS) {
wc_InitDecodedCert(&dCert, der, derSz, NULL);
if (wc_ParseCert(&dCert, CERT_TYPE, NO_VERIFY, NULL) != 0) {
printf("public key not a cert\n");
}
else {
int ipMatch = 0;
DNS_entry* current = dCert.altNames;
while (current != NULL) {
if (current->type == ASN_IP_TYPE) {
printf("host cert alt. name IP : %s\n",
current->ipString);
printf("\texpecting host IP : %s\n", (char*)ctx);
if (XSTRCMP(ctx, current->ipString) == 0) {
printf("\tmatched!\n");
ipMatch = 1;
}
}
current = current->next;
}
if (ipMatch == 0) {
printf("IP did not match expected IP\n");
ret = -1;
}
}
FreeDecodedCert(&dCert);
}
}
#endif
#endif
return ret;
}
@ -581,14 +690,6 @@ static THREAD_RET readInput(void* in)
}
#ifdef WOLFSSH_AGENT
static inline void ato32(const byte* c, word32* u32)
{
*u32 = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
}
#endif
static THREAD_RET readPeer(void* in)
{
byte buf[80];
@ -1161,7 +1262,7 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
#endif /* WOLFSSH_CERTS */
wolfSSH_CTX_SetPublicKeyCheck(ctx, wsPublicKeyCheck);
wolfSSH_SetPublicKeyCheckCtx(ssh, (void*)"You've been sampled!");
wolfSSH_SetPublicKeyCheckCtx(ssh, (void*)host);
ret = wolfSSH_SetUsername(ssh, username);
if (ret != WS_SUCCESS)

View File

@ -20,6 +20,7 @@ EXTRA_DIST+= \
keys/pubkeys-rsa.txt keys/passwd.txt keys/ca-cert-ecc.der \
keys/ca-cert-ecc.pem keys/ca-key-ecc.der keys/ca-key-ecc.pem \
keys/server-cert.der keys/server-cert.pem \
keys/john-cert.der keys/john-cert.pem \
keys/server-key.pem keys/john-key.der keys/john-key.pem
keys/fred-cert.der keys/fred-cert.pem \
keys/server-key.pem keys/fred-key.der keys/fred-key.pem \
keys/renewcerts.sh keys/renewcerts.cnf