From 8a267e2bd23df5996b0073e6b82d5a3115b7f556 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Tue, 26 Mar 2019 13:51:10 -0700 Subject: [PATCH] Public Key Check Callback The public key check callback hook is given a pointer to the public key, the size of the key, and the application-specific context data. 1. Added a callback function hook for checking the public key sent to the client by the server. It defaults to accepting the key. 2. Added accessors for the public key check callback function and context data. 3. Added a dummy callback to all the example tools. --- examples/client/client.c | 13 +++++++++++++ examples/portfwd/portfwd.c | 13 +++++++++++++ examples/sftpclient/sftpclient.c | 13 +++++++++++++ src/internal.c | 22 ++++++++++++++++++++++ src/ssh.c | 26 ++++++++++++++++++++++++++ wolfssh/error.h | 3 ++- wolfssh/internal.h | 3 +++ wolfssh/ssh.h | 7 +++++++ 8 files changed, 99 insertions(+), 1 deletion(-) diff --git a/examples/client/client.c b/examples/client/client.c index 9bc6d31..9a265c4 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -152,6 +152,16 @@ static int wsUserAuth(byte authType, } +static int wsPublicKeyCheck(const byte* pubKey, word32 pubKeySz, void* ctx) +{ + printf("Sample public key check callback\n" + " public key = %p\n" + " public key size = %u\n" + " ctx = %s\n", pubKey, pubKeySz, (const char*)ctx); + return 0; +} + + static int NonBlockSSH_connect(WOLFSSH* ssh) { int ret; @@ -269,6 +279,9 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) if (password != NULL) wolfSSH_SetUserAuthCtx(ssh, (void*)password); + wolfSSH_CTX_SetPublicKeyCheck(ctx, wsPublicKeyCheck); + wolfSSH_SetPublicKeyCheckCtx(ssh, (void*)"You've been sampled!"); + ret = wolfSSH_SetUsername(ssh, username); if (ret != WS_SUCCESS) err_sys("Couldn't set the username."); diff --git a/examples/portfwd/portfwd.c b/examples/portfwd/portfwd.c index 7ef5264..4d42b9e 100644 --- a/examples/portfwd/portfwd.c +++ b/examples/portfwd/portfwd.c @@ -180,6 +180,16 @@ static int wsUserAuth(byte authType, } +static int wsPublicKeyCheck(const byte* pubKey, word32 pubKeySz, void* ctx) +{ + printf("Sample public key check callback\n" + " public key = %p\n" + " public key size = %u\n" + " ctx = %s\n", pubKey, pubKeySz, (const char*)ctx); + return 0; +} + + /* * fwdFromHost - address to bind the local listener socket to (default: any) * fwdFromHostPort - port number to bind the local listener socket to @@ -312,6 +322,9 @@ THREAD_RETURN WOLFSSH_THREAD portfwd_worker(void* args) if (password != NULL) wolfSSH_SetUserAuthCtx(ssh, (void*)password); + wolfSSH_CTX_SetPublicKeyCheck(ctx, wsPublicKeyCheck); + wolfSSH_SetPublicKeyCheckCtx(ssh, (void*)"You've been sampled."); + ret = wolfSSH_SetUsername(ssh, username); if (ret != WS_SUCCESS) err_sys("Couldn't set the username."); diff --git a/examples/sftpclient/sftpclient.c b/examples/sftpclient/sftpclient.c index 98b5b32..67c6a14 100644 --- a/examples/sftpclient/sftpclient.c +++ b/examples/sftpclient/sftpclient.c @@ -326,6 +326,16 @@ static int wsUserAuth(byte authType, } +static int wsPublicKeyCheck(const byte* pubKey, word32 pubKeySz, void* ctx) +{ + printf("Sample public key check callback\n" + " public key = %p\n" + " public key size = %u\n" + " ctx = %s\n", pubKey, pubKeySz, (const char*)ctx); + return 0; +} + + /* returns 0 on success */ static INLINE int SFTP_FPUTS(func_args* args, const char* msg) { @@ -1065,6 +1075,9 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) if (password != NULL) wolfSSH_SetUserAuthCtx(ssh, (void*)password); + wolfSSH_CTX_SetPublicKeyCheck(ctx, wsPublicKeyCheck); + wolfSSH_SetPublicKeyCheckCtx(ssh, (void*)"You've been sampled!"); + ret = wolfSSH_SetUsername(ssh, username); if (ret != WS_SUCCESS) err_sys("Couldn't set the username."); diff --git a/src/internal.c b/src/internal.c index fdcaa73..f782846 100644 --- a/src/internal.c +++ b/src/internal.c @@ -266,6 +266,9 @@ const char* GetErrorString(int err) case WS_CLOSE_FILE_E: return "Unable to close local file"; + case WS_PUBKEY_REJECTED_E: + return "server's public key is rejected"; + default: return "Unknown error code"; } @@ -2342,7 +2345,26 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) if (ret == WS_SUCCESS && (pubKeySz > len - LENGTH_SZ - begin )) { ret = WS_BUFFER_E; } + } + if (ret == WS_SUCCESS) { + if (ssh->ctx->publicKeyCheckCb != NULL) { + WLOG(WS_LOG_DEBUG, "DKDR: Calling the public key check callback"); + ret = ssh->ctx->publicKeyCheckCb(pubKey, pubKeySz, + ssh->publicKeyCheckCtx); + if (ret == 0) { + WLOG(WS_LOG_DEBUG, "DKDR: public key accepted"); + ret = WS_SUCCESS; + } + else { + WLOG(WS_LOG_DEBUG, "DKDR: public key rejected"); + ret = WS_PUBKEY_REJECTED_E; + } + } + else { + WLOG(WS_LOG_DEBUG, "DKDR: no public key check callback, accepted"); + ret = WS_SUCCESS; + } } if (ret == WS_SUCCESS) diff --git a/src/ssh.c b/src/ssh.c index acdd1c6..6246bad 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -924,6 +924,32 @@ void* wolfSSH_GetUserAuthCtx(WOLFSSH* ssh) } +void wolfSSH_CTX_SetPublicKeyCheck(WOLFSSH_CTX* ctx, + WS_CallbackPublicKeyCheck cb) +{ + if (ctx != NULL) { + ctx->publicKeyCheckCb = cb; + } +} + + +void wolfSSH_SetPublicKeyCheckCtx(WOLFSSH* ssh, void* publicKeyCheckCtx) +{ + if (ssh != NULL) { + ssh->publicKeyCheckCtx = publicKeyCheckCtx; + } +} + + +void* wolfSSH_GetPublicKeyCheckCtx(WOLFSSH* ssh) +{ + if (ssh != NULL) { + return ssh->publicKeyCheckCtx; + } + return NULL; +} + + /* Used to set the channel request type sent in wolfSSH connect. The default * type set is shell if this function is not called. * diff --git a/wolfssh/error.h b/wolfssh/error.h index bd0fb3d..ffe4a35 100644 --- a/wolfssh/error.h +++ b/wolfssh/error.h @@ -103,8 +103,9 @@ enum WS_ErrorCodes { WS_SFTP_FILE_DNE = -63, /* SFTP File Does Not Exist */ WS_SIZE_ONLY = -64, /* Only getting the size of buffer needed */ WS_CLOSE_FILE_E = -65, /* Unable to close local file */ + WS_PUBKEY_REJECTED_E = -66, /* Server public key rejected */ - WS_LAST_E = -65 /* Update this to indicate last error */ + WS_LAST_E = -66 /* Update this to indicate last error */ }; diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 7f740b6..a67cff2 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -181,6 +181,8 @@ struct WOLFSSH_CTX { WS_CallbackScpRecv scpRecvCb; /* SCP receive callback */ WS_CallbackScpSend scpSendCb; /* SCP send callback */ #endif + WS_CallbackPublicKeyCheck publicKeyCheckCb; + /* Check server's public key callback */ byte* privateKey; /* Owned by CTX */ word32 privateKeySz; @@ -388,6 +390,7 @@ struct WOLFSSH { word32 pkBlobSz; byte* peerProtoId; /* Save for rekey */ word32 peerProtoIdSz; + void* publicKeyCheckCtx; #ifdef WOLFSSH_SFTP word32 reqId; diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index f3d1b96..cbdddd4 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -148,6 +148,13 @@ WOLFSSH_API void wolfSSH_SetUserAuth(WOLFSSH_CTX*, WS_CallbackUserAuth); WOLFSSH_API void wolfSSH_SetUserAuthCtx(WOLFSSH*, void*); WOLFSSH_API void* wolfSSH_GetUserAuthCtx(WOLFSSH*); +/* Public Key Check Callback */ +typedef int (*WS_CallbackPublicKeyCheck)(const byte*, word32, void*); +WOLFSSH_API void wolfSSH_CTX_SetPublicKeyCheck(WOLFSSH_CTX*, + WS_CallbackPublicKeyCheck); +WOLFSSH_API void wolfSSH_SetPublicKeyCheckCtx(WOLFSSH*, void*); +WOLFSSH_API void* wolfSSH_GetPublicKeyCheckCtx(WOLFSSH*); + WOLFSSH_API int wolfSSH_SetUsername(WOLFSSH*, const char*); WOLFSSH_API int wolfSSH_CTX_SetBanner(WOLFSSH_CTX*, const char*);