diff --git a/.github/workflows/os-check.yml b/.github/workflows/os-check.yml index aa745135..afda6c2f 100644 --- a/.github/workflows/os-check.yml +++ b/.github/workflows/os-check.yml @@ -72,6 +72,7 @@ jobs: '--enable-all', '--enable-sftp', '--enable-scp', + '--enable-keyboard-interactive', '--enable-shell', ] name: Build wolfssh diff --git a/configure.ac b/configure.ac index 9fd557e0..6936b84d 100644 --- a/configure.ac +++ b/configure.ac @@ -126,6 +126,11 @@ AC_ARG_ENABLE([keygen], [AS_HELP_STRING([--enable-keygen],[Enable key generation (default: disabled)])], [ENABLED_KEYGEN=$enableval],[ENABLED_KEYGEN=no]) +# Keyboard Interactive +AC_ARG_ENABLE([keyboard-interactive], + [AS_HELP_STRING([--enable-keyboard-interactive],[Enable keyboard interactive authentication (default: disabled)])], + [ENABLED_KEYBOARD_INTERACTIVE=$enableval],[ENABLED_KEYBOARD_INTERACTIVE=no]) + # SCP AC_ARG_ENABLE([scp], [AS_HELP_STRING([--enable-scp],[Enable scp support (default: disabled)])], @@ -206,7 +211,7 @@ AC_ARG_ENABLE([distro], AS_IF([test "x$ENABLED_DISTRO" = "xyes"], [ENABLED_ALL=yes; enable_shared=yes; enable_static=yes]) AS_IF([test "x$ENABLED_ALL" = "xyes"], - [ENABLED_KEYGEN=yes; ENABLED_SCP=yes; ENABLED_SFTP=yes; ENABLED_FWD=yes; ENABLED_SHELL=yes; ENABLED_AGENT=yes; ENABLED_SSHD=yes; ENABLED_SSHCLIENT=yes; ENABLED_CERTS=yes]) + [ENABLED_KEYGEN=yes; ENABLED_SCP=yes; ENABLED_SFTP=yes; ENABLED_FWD=yes; ENABLED_SHELL=yes; ENABLED_AGENT=yes; ENABLED_SSHD=yes; ENABLED_SSHCLIENT=yes; ENABLED_CERTS=yes; ENABLED_KEYBOARD_INTERACTIVE=yes]) AS_IF([test "x$ENABLED_SSHD" = "xyes"], [ENABLED_SHELL=yes]) @@ -215,6 +220,8 @@ AS_IF([test "x$ENABLED_INLINE" = "xno"], [AM_CPPFLAGS="$AM_CPPFLAGS -DNO_INLINE"]) AS_IF([test "x$ENABLED_KEYGEN" = "xyes"], [AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_KEYGEN"]) +AS_IF([test "x$ENABLED_KEYBOARD_INTERACTIVE" = "xyes"], + [AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_KEYBOARD_INTERACTIVE"]) AS_IF([test "x$ENABLED_SCP" = "xyes"], [AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_SCP"]) AS_IF([test "x$ENABLED_SFTP" = "xyes"], @@ -292,6 +299,7 @@ AM_CONDITIONAL([BUILD_SSHD],[test "x$ENABLED_SSHD" = "xyes"]) AM_CONDITIONAL([BUILD_SSHCLIENT],[test "x$ENABLED_SSHCLIENT" = "xyes"]) AM_CONDITIONAL([BUILD_CERTS],[test "x$ENABLED_CERTS" = "xyes"]) AM_CONDITIONAL([BUILD_TPM],[test "x$ENABLED_TPM" = "xyes"]) +AM_CONDITIONAL([BUILD_KEYBOARD_INTERACTIVE],[test "x$ENABLED_KEYBOARD_INTERACTIVE" = "xyes"]) AX_HARDEN_CC_COMPILER_FLAGS @@ -328,6 +336,7 @@ AS_ECHO([" Features"]) AS_ECHO([" * Inline Code: $ENABLED_INLINE"]) AS_ECHO([" * Small stack: $ENABLED_SMALLSTACK"]) AS_ECHO([" * keygen: $ENABLED_KEYGEN"]) +AS_ECHO([" * keyboard interactive: $ENABLED_KEYBOARD_INTERACTIVE"]) AS_ECHO([" * psuedo-terminal: $ENABLED_TERM"]) AS_ECHO([" * echoserver shell support: $ENABLED_SHELL"]) AS_ECHO([" * scp: $ENABLED_SCP"]) diff --git a/examples/client/common.c b/examples/client/common.c index 3a0c5859..12f02e52 100644 --- a/examples/client/common.c +++ b/examples/client/common.c @@ -64,10 +64,11 @@ static word32 userPrivateKeySz = 0; static word32 userPrivateKeyTypeSz = 0; static byte isPrivate = 0; +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE static word32 keyboardResponseCount = 0; static byte** keyboardResponses; static word32* keyboardResponseLengths; - +#endif #ifdef WOLFSSH_CERTS #if 0 @@ -460,7 +461,7 @@ int ClientUserAuth(byte authType, { const char* defaultPassword = (const char*)ctx; word32 passwordSz = 0; -#ifdef WOLFSSH_TERM +#if defined(WOLFSSH_TERM) && defined(WOLFSSH_KEYBOARD_INTERACTIVE) word32 entry; #endif int ret = WOLFSSH_USERAUTH_SUCCESS; @@ -474,9 +475,11 @@ int ClientUserAuth(byte authType, if (authData->type & WOLFSSH_USERAUTH_PUBLICKEY) { printf(" - publickey\n"); } +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE if (authData->type & WOLFSSH_USERAUTH_KEYBOARD) { printf(" - keyboard\n"); } +#endif printf("wolfSSH requesting to use type %d\n", authType); #endif @@ -544,7 +547,7 @@ int ClientUserAuth(byte authType, authData->sf.password.passwordSz = passwordSz; } } -#ifdef WOLFSSH_TERM +#if defined(WOLFSSH_TERM) && defined(WOLFSSH_KEYBOARD_INTERACTIVE) else if (authType == WOLFSSH_USERAUTH_KEYBOARD) { if (authData->sf.keyboard.promptName && authData->sf.keyboard.promptName[0] != '\0') { @@ -1112,7 +1115,9 @@ int ClientLoadCA(WOLFSSH_CTX* ctx, const char* caCert) void ClientFreeBuffers(const char* pubKeyName, const char* privKeyName, void* heap) { +#if defined(WOLFSSH_TERM) && defined(WOLFSSH_KEYBOARD_INTERACTIVE) word32 entry; +#endif #ifdef WOLFSSH_TPM wolfSSH_TPM_Cleanup(&tpmDev, &tpmKey); #endif @@ -1126,9 +1131,11 @@ void ClientFreeBuffers(const char* pubKeyName, const char* privKeyName, WFREE(userPrivateKey, heap, DYNTYPE_PRIVKEY); } +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE for (entry = 0; entry < keyboardResponseCount; entry++) { WFREE(keyboardResponses[entry], NULL, 0); } WFREE(keyboardResponses, NULL, 0); WFREE(keyboardResponseLengths, NULL, 0); +#endif } diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index 214d60fc..22b14f3e 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -2006,7 +2006,7 @@ static int LoadPasswdList(StrList* strList, PwMapList* mapList) return count; } - +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE static int LoadKeyboardList(StrList* strList, PwMapList* mapList) { char names[256]; @@ -2034,6 +2034,7 @@ static int LoadKeyboardList(StrList* strList, PwMapList* mapList) return count; } +#endif #ifndef NO_FILESYSTEM static int LoadPubKeyList(StrList* strList, int format, PwMapList* mapList) @@ -2183,8 +2184,10 @@ static int wsUserAuth(byte authType, #ifdef WOLFSSH_ALLOW_USERAUTH_NONE authType != WOLFSSH_USERAUTH_NONE && #endif - authType != WOLFSSH_USERAUTH_PUBLICKEY && - authType != WOLFSSH_USERAUTH_KEYBOARD) { +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE + authType != WOLFSSH_USERAUTH_KEYBOARD && +#endif + authType != WOLFSSH_USERAUTH_PUBLICKEY) { return WOLFSSH_USERAUTH_FAILURE; } @@ -2194,6 +2197,7 @@ static int wsUserAuth(byte authType, authData->sf.password.passwordSz, authHash); } +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE else if (authType == WOLFSSH_USERAUTH_KEYBOARD) { if (authData->sf.keyboard.responseCount != 1) { return WOLFSSH_USERAUTH_FAILURE; @@ -2202,6 +2206,7 @@ static int wsUserAuth(byte authType, authData->sf.keyboard.responseLengths[0], authHash); } +#endif else if (authType == WOLFSSH_USERAUTH_PUBLICKEY) { wc_Sha256Hash(authData->sf.publicKey.publicKey, authData->sf.publicKey.publicKeySz, @@ -2302,6 +2307,7 @@ static int wsUserAuth(byte authType, WOLFSSH_USERAUTH_REJECTED; } } + #ifdef WOLFSSH_KEYBOARD_INTERACTIVE else if (authData->type == WOLFSSH_USERAUTH_KEYBOARD) { if (WMEMCMP(map->p, authHash, WC_SHA256_DIGEST_SIZE) == 0) { return WOLFSSH_USERAUTH_SUCCESS; @@ -2310,6 +2316,7 @@ static int wsUserAuth(byte authType, return WOLFSSH_USERAUTH_INVALID_PASSWORD; } } + #endif #ifdef WOLFSSH_ALLOW_USERAUTH_NONE else if (authData->type == WOLFSSH_USERAUTH_NONE) { return WOLFSSH_USERAUTH_SUCCESS; @@ -2325,6 +2332,7 @@ static int wsUserAuth(byte authType, return WOLFSSH_USERAUTH_INVALID_USER; } +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE static int keyboardCallback(WS_UserAuthData_Keyboard *kbAuth, void *ctx) { WS_UserAuthData_Keyboard *kbAuthData = (WS_UserAuthData_Keyboard*) ctx; @@ -2332,6 +2340,7 @@ static int keyboardCallback(WS_UserAuthData_Keyboard *kbAuth, void *ctx) return WS_SUCCESS; } +#endif #ifdef WOLFSSH_SFTP /* @@ -2417,9 +2426,11 @@ static void ShowUsage(void) " load in an X.509 DER cert to accept from peer\n"); printf(" -P :\n" " add password to accept from peer\n"); +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE printf(" -i :\n" " add passowrd to accept via keyboard-interactive " "from peer\n"); +#endif #ifdef WOLFSSH_CERTS printf(" -a load in a root CA certificate file\n"); #endif @@ -2463,8 +2474,10 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) StrList* derPubKeyList = NULL; #endif StrList* passwdList = NULL; + #ifdef WOLFSSH_KEYBOARD_INTERACTIVE StrList* keyboardList = NULL; WS_UserAuthData_Keyboard kbAuthData; + #endif WS_SOCKET_T listenFd = WOLFSSH_SOCKET_INVALID; word32 defaultHighwater = EXAMPLE_HIGHWATER_MARK; word32 threadCount = 0; @@ -2495,7 +2508,9 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) int argc = serverArgs->argc; char** argv = serverArgs->argv; serverArgs->return_code = EXIT_SUCCESS; +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE kbAuthData.promptCount = 0; +#endif if (argc > 0) { const char* optlist = "?1a:d:efEp:R:Ni:j:i:I:J:K:P:k:b:x:m:c:s:"; @@ -2582,9 +2597,11 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) passwdList = StrListAdd(passwdList, myoptarg); break; +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE case 'i': keyboardList = StrListAdd(keyboardList, myoptarg); break; +#endif case 'b': userAuthWouldBlock = atoi(myoptarg); @@ -2739,6 +2756,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) passwdList = NULL; } +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE if (keyboardList) { LoadKeyboardList(keyboardList, &pwMapList); StrListFree(keyboardList); @@ -2767,6 +2785,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) kbAuthData.promptEcho[0] = 0; wolfSSH_SetKeyboardAuthPrompts(ctx, keyboardCallback); } +#endif { const char* bufName = NULL; @@ -2973,7 +2992,9 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) #endif wolfSSH_SetUserAuthCtx(ssh, &pwMapList); wolfSSH_SetKeyingCompletionCbCtx(ssh, (void*)ssh); + #ifdef WOLFSSH_KEYBOARD_INTERACTIVE wolfSSH_SetKeyboardAuthCtx(ssh, &kbAuthData); + #endif /* Use the session object for its own highwater callback ctx */ if (defaultHighwater > 0) { wolfSSH_SetHighwaterCtx(ssh, (void*)ssh); @@ -3046,11 +3067,13 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) if (listenFd != WOLFSSH_SOCKET_INVALID) { WCLOSESOCKET(listenFd); } +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE if (kbAuthData.promptCount > 0) { WFREE(kbAuthData.promptLengths, NULL, 0); WFREE(kbAuthData.prompts, NULL, 0); WFREE(kbAuthData.promptEcho, NULL, 0); } +#endif wc_FreeMutex(&doneLock); PwMapListDelete(&pwMapList); wolfSSH_CTX_free(ctx); diff --git a/src/internal.c b/src/internal.c index 19257e5e..9f59f860 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1055,8 +1055,12 @@ WOLFSSH* SshInit(WOLFSSH* ssh, WOLFSSH_CTX* ctx) ssh->authId = ID_USERAUTH_PUBLICKEY; ssh->supportedAuth[0] = ID_USERAUTH_PUBLICKEY; ssh->supportedAuth[1] = ID_USERAUTH_PASSWORD; +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE ssh->supportedAuth[2] = ID_USERAUTH_KEYBOARD; ssh->supportedAuth[3] = ID_NONE; /* ID_NONE is treated as empty slot */ +#else + ssh->supportedAuth[2] = ID_NONE; /* ID_NONE is treated as empty slot */ +#endif ssh->nextChannel = DEFAULT_NEXT_CHANNEL; ssh->blockSz = MIN_BLOCK_SZ; ssh->encryptId = ID_NONE; @@ -2625,7 +2629,9 @@ static const NameIdPair NameIdMap[] = { /* UserAuth IDs */ { ID_USERAUTH_PASSWORD, TYPE_OTHER, "password" }, { ID_USERAUTH_PUBLICKEY, TYPE_OTHER, "publickey" }, +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE { ID_USERAUTH_KEYBOARD, TYPE_OTHER, "keyboard-interactive" }, +#endif /* Channel Type IDs */ { ID_CHANTYPE_SESSION, TYPE_OTHER, "session" }, @@ -6398,7 +6404,7 @@ static int DoUserAuthRequestNone(WOLFSSH* ssh, WS_UserAuthData* authData, #endif - +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE static int DoUserAuthInfoResponse(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) { @@ -6541,7 +6547,7 @@ static int DoUserAuthInfoResponse(WOLFSSH* ssh, return ret; } - +#endif /* Utility for DoUserAuthRequest() */ static int DoUserAuthRequestPassword(WOLFSSH* ssh, WS_UserAuthData* authData, @@ -7781,9 +7787,11 @@ static int DoUserAuthRequest(WOLFSSH* ssh, if (authNameId == ID_USERAUTH_PASSWORD) ret = DoUserAuthRequestPassword(ssh, &authData, buf, len, &begin); +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE else if (authNameId == ID_USERAUTH_KEYBOARD) { ret = SendUserAuthKeyboardRequest(ssh, &authData); } +#endif #if !defined(WOLFSSH_NO_RSA) || !defined(WOLFSSH_NO_ECDSA) else if (authNameId == ID_USERAUTH_PUBLICKEY) { authData.sf.publicKey.dataToSign = buf + *idx; @@ -7817,9 +7825,14 @@ static int DoUserAuthRequest(WOLFSSH* ssh, static int DoUserAuthFailure(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) { +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE byte authList[4]; /* Should only ever be password, publickey, hostname, keyboard */ word32 authListSz = 4; +#else + byte authList[3]; + word32 authListSz = 3; +#endif byte partialSuccess; byte authType = 0; int ret = WS_SUCCESS; @@ -7852,9 +7865,11 @@ static int DoUserAuthFailure(WOLFSSH* ssh, case ID_USERAUTH_PASSWORD: authType |= WOLFSSH_USERAUTH_PASSWORD; break; +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE case ID_USERAUTH_KEYBOARD: authType |= WOLFSSH_USERAUTH_KEYBOARD; break; +#endif #if !defined(WOLFSSH_NO_RSA) || !defined(WOLFSSH_NO_ECDSA) case ID_USERAUTH_PUBLICKEY: authType |= WOLFSSH_USERAUTH_PUBLICKEY; @@ -7898,9 +7913,11 @@ static int DoUserAuthSuccess(WOLFSSH* ssh, return ret; } +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE if (ssh->serverState == SERVER_USERAUTH_ACCEPT_KEYBOARD) ssh->serverState = SERVER_USERAUTH_ACCEPT_KEYBOARD_DONE; else +#endif ssh->serverState = SERVER_USERAUTH_ACCEPT_DONE; WLOG(WS_LOG_DEBUG, "Leaving DoUserAuthSuccess(), ret = %d", ret); @@ -7935,7 +7952,7 @@ static int DoUserAuthBanner(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) return ret; } - +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE static int DoUserAuthInfoRequest(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) { @@ -8036,7 +8053,7 @@ static int DoUserAuthInfoRequest(WOLFSSH* ssh, byte* buf, word32 len, return ret; } - +#endif #ifdef WOLFSSH_FWD static int DoGlobalRequestFwd(WOLFSSH* ssh, @@ -9388,6 +9405,7 @@ static int DoPacket(WOLFSSH* ssh, byte* bufferConsumed) ret = DoUserAuthRequest(ssh, buf + idx, payloadSz, &payloadIdx); break; +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE case MSGID_USERAUTH_INFO_RESPONSE: WLOG(WS_LOG_DEBUG, "Decoding MSG_USERAUTH_INFO_RESPONSE"); ret = DoUserAuthInfoResponse(ssh, buf + idx, payloadSz, &payloadIdx); @@ -9397,6 +9415,7 @@ static int DoPacket(WOLFSSH* ssh, byte* bufferConsumed) WLOG(WS_LOG_DEBUG, "Decoding MSGID_USERAUTH_INFO_REQUEST"); ret = DoUserAuthInfoRequest(ssh, buf + idx, payloadSz, &payloadIdx); break; +#endif case MSGID_USERAUTH_FAILURE: WLOG(WS_LOG_DEBUG, "Decoding MSGID_USERAUTH_FAILURE"); @@ -13225,6 +13244,7 @@ static int BuildUserAuthRequestPassword(WOLFSSH* ssh, return ret; } +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE static int PrepareUserAuthRequestKeyboard(WOLFSSH* ssh, word32* payloadSz, const WS_UserAuthData* authData) { @@ -13444,6 +13464,7 @@ static int BuildUserAuthResponseKeyboard(WOLFSSH* ssh, byte* output, word32* idx return ret; } +#endif #ifndef WOLFSSH_NO_RSA static int PrepareUserAuthRequestRsa(WOLFSSH* ssh, word32* payloadSz, @@ -14775,6 +14796,7 @@ static int BuildUserAuthRequestPublicKey(WOLFSSH* ssh, #endif /* !WOLFSSH_NO_RSA || !WOLFSSH_NO_ECDSA || !WOLFSSH_NO_ED25519 */ +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE int SendUserAuthKeyboardResponse(WOLFSSH* ssh) { byte* output; @@ -14864,6 +14886,7 @@ int SendUserAuthKeyboardResponse(WOLFSSH* ssh) return ret; } +#endif int SendUserAuthRequest(WOLFSSH* ssh, byte authType, int addSig) { @@ -14897,11 +14920,14 @@ int SendUserAuthRequest(WOLFSSH* ssh, byte authType, int addSig) WMEMSET(keySig_ptr, 0, sizeof(WS_KeySignature)); keySig_ptr->keySigId = ID_NONE; keySig_ptr->heap = ssh->ctx->heap; +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE /* Callback happens later for keyboard auth */ if (authType & WOLFSSH_USERAUTH_KEYBOARD) { authId = ID_USERAUTH_KEYBOARD; } - else if (ssh->ctx->userAuthCb != NULL) { + else +#endif + if (ssh->ctx->userAuthCb != NULL) { WLOG(WS_LOG_DEBUG, "SUAR: Calling the userauth callback"); WMEMSET(&authData, 0, sizeof(authData)); @@ -14927,8 +14953,13 @@ int SendUserAuthRequest(WOLFSSH* ssh, byte authType, int addSig) /* fall into public key case if keyboard or password case was not * successful */ if ((ret == WS_FATAL_ERROR || + +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE (!(authType & WOLFSSH_USERAUTH_PASSWORD) && !(authType & WOLFSSH_USERAUTH_KEYBOARD))) && +#else + !(authType & WOLFSSH_USERAUTH_PASSWORD)) && +#endif (authType & WOLFSSH_USERAUTH_PUBLICKEY)) { ret = ssh->ctx->userAuthCb(WOLFSSH_USERAUTH_PUBLICKEY, &authData, ssh->userAuthCtx); @@ -14966,7 +14997,10 @@ int SendUserAuthRequest(WOLFSSH* ssh, byte authType, int addSig) ret = PrepareUserAuthRequestPublicKey(ssh, &payloadSz, &authData, keySig_ptr); } - else if (authId != ID_NONE && authId != ID_USERAUTH_KEYBOARD && + else if (authId != ID_NONE && +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE + authId != ID_USERAUTH_KEYBOARD && +#endif !ssh->userAuthPkDone) ret = WS_INVALID_ALGO_ID; } @@ -15006,6 +15040,7 @@ int SendUserAuthRequest(WOLFSSH* ssh, byte authType, int addSig) ret = BuildUserAuthRequestPassword(ssh, output, &idx, &authData); } +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE else if (authId == ID_USERAUTH_KEYBOARD) { /* language tag, deprecated, should be empty */ c32toa(0, output + idx); @@ -15014,6 +15049,7 @@ int SendUserAuthRequest(WOLFSSH* ssh, byte authType, int addSig) c32toa(0, output + idx); idx += LENGTH_SZ; } +#endif else if (authId == ID_USERAUTH_PUBLICKEY) ret = BuildUserAuthRequestPublicKey(ssh, output, &idx, &authData, sigStart, sigStartIdx, keySig_ptr); @@ -15054,9 +15090,11 @@ static int GetAllowedAuth(WOLFSSH* ssh, char* authStr) return WS_BAD_ARGUMENT; typeAllowed |= WOLFSSH_USERAUTH_PASSWORD; +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE if (ssh->ctx->keyboardAuthCb != NULL) { typeAllowed |= WOLFSSH_USERAUTH_KEYBOARD; } +#endif #if !defined(WOLFSSH_NO_RSA) || !defined(WOLFSSH_NO_ECDSA) typeAllowed |= WOLFSSH_USERAUTH_PUBLICKEY; #endif @@ -15073,9 +15111,11 @@ static int GetAllowedAuth(WOLFSSH* ssh, char* authStr) WSTRNCAT(authStr, "password,", MAX_AUTH_STRING-1); } +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE if (typeAllowed & WOLFSSH_USERAUTH_KEYBOARD) { WSTRNCAT(authStr, "keyboard-interactive,", MAX_AUTH_STRING-1); } +#endif /* remove last comma from the list */ return (int)XSTRLEN(authStr) - 1; diff --git a/src/ssh.c b/src/ssh.c index 943a6db9..64207fca 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -891,6 +891,7 @@ int wolfSSH_connect(WOLFSSH* ssh) } } +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE while (ssh->serverState == SERVER_USERAUTH_ACCEPT_KEYBOARD) { if ( (ssh->error = SendUserAuthKeyboardResponse(ssh)) < WS_SUCCESS) { @@ -911,6 +912,7 @@ int wolfSSH_connect(WOLFSSH* ssh) } } } +#endif ssh->connectState = CONNECT_SERVER_USERAUTH_ACCEPT_DONE; WLOG(WS_LOG_DEBUG, connectState, "SERVER_USERAUTH_ACCEPT_DONE"); @@ -1360,6 +1362,7 @@ int wolfSSH_SendDisconnect(WOLFSSH *ssh, word32 reason) return SendDisconnect(ssh, reason); } +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE void wolfSSH_SetKeyboardAuthPrompts(WOLFSSH_CTX* ctx, WS_CallbackKeyboardAuthPrompts cb) { @@ -1374,6 +1377,7 @@ void wolfSSH_SetKeyboardAuthCtx(WOLFSSH* ssh, void* keyboardAuthCtx) ssh->keyboardAuthCtx = keyboardAuthCtx; } } +#endif void wolfSSH_SetUserAuth(WOLFSSH_CTX* ctx, WS_CallbackUserAuth cb) { diff --git a/tests/api.c b/tests/api.c index a5a753ce..cc78f801 100644 --- a/tests/api.c +++ b/tests/api.c @@ -1555,6 +1555,7 @@ static void test_wolfSSH_QueryAlgoList(void) AssertIntEQ(WS_INVALID_ALGO_ID, k); } +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE #if defined(WOLFSSH_SFTP) && !defined(NO_WOLFSSH_CLIENT) && \ !defined(SINGLE_THREADED) @@ -1699,6 +1700,7 @@ static void test_wolfSSH_KeyboardInteractive(void) #else /* WOLFSSH_SFTP && !NO_WOLFSSH_CLIENT && !SINGLE_THREADED */ static void test_wolfSSH_KeyboardInteractive(void) { ; } #endif /* WOLFSSH_SFTP && !NO_WOLFSSH_CLIENT && !SINGLE_THREADED */ +#endif /* WOLFSSH_KEYBOARD_INTERACTIVE */ #endif /* WOLFSSH_TEST_BLOCK */ @@ -1735,7 +1737,9 @@ int wolfSSH_ApiTest(int argc, char** argv) test_wolfSSH_ReadKey(); test_wolfSSH_QueryAlgoList(); test_wolfSSH_SetAlgoList(); +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE test_wolfSSH_KeyboardInteractive(); +#endif /* SCP tests */ test_wolfSSH_SCP_CB(); diff --git a/tests/auth.c b/tests/auth.c index a2ae5480..147db829 100644 --- a/tests/auth.c +++ b/tests/auth.c @@ -145,7 +145,7 @@ #if !defined(NO_WOLFSSH_SERVER) && !defined(NO_WOLFSSH_CLIENT) && \ !defined(SINGLE_THREADED) && !defined(WOLFSSH_TEST_BLOCK) && \ - !defined(NO_FILESYSTEM) + !defined(NO_FILESYSTEM) && defined(WOLFSSH_KEYBOARD_INTERACTIVE) const char *testText1 = "test"; const char *testText2 = "password"; @@ -387,7 +387,6 @@ static THREAD_RETURN WOLFSSH_THREAD server_thread(void* args) WOLFSSL_RETURN_FROM_THREAD(0); } - static int keyboardUserAuth(byte authType, WS_UserAuthData* authData, void* ctx) { (void) ctx; @@ -575,7 +574,6 @@ static void test_unbalanced_client_KeyboardInteractive(void) test_client(); unbalanced = 0; } - #endif /* WOLFSSH_TEST_BLOCK */ int wolfSSH_AuthTest(int argc, char** argv) @@ -585,7 +583,7 @@ int wolfSSH_AuthTest(int argc, char** argv) #if defined(NO_WOLFSSH_SERVER) || defined(NO_WOLFSSH_CLIENT) || \ defined(SINGLE_THREADED) || defined(WOLFSSH_TEST_BLOCK) || \ - defined(NO_FILESYSTEM) + defined(NO_FILESYSTEM) || !defined(WOLFSSH_KEYBOARD_INTERACTIVE) return 77; #else AssertIntEQ(wolfSSH_Init(), WS_SUCCESS); diff --git a/tests/include.am b/tests/include.am index fd11ab06..236f81b2 100644 --- a/tests/include.am +++ b/tests/include.am @@ -3,7 +3,7 @@ # All paths should be given relative to the root check_PROGRAMS += tests/unit.test tests/api.test \ - tests/testsuite.test tests/auth.test tests/kex.test + tests/testsuite.test tests/kex.test tests_unit_test_SOURCES = tests/unit.c tests/unit.h tests_unit_test_CPPFLAGS = -DNO_MAIN_DRIVER @@ -31,6 +31,9 @@ endif if BUILD_CERTS tests_unit_test_CPPFLAGS += -DWOLFSSH_CERTS endif +if BUILD_KEYBOARD_INTERACTIVE +tests_unit_test_CPPFLAGS += -DWOLFSSH_KEYBOARD_INTERACTIVE +endif tests_unit_test_LDADD = src/libwolfssh.la tests_unit_test_DEPENDENCIES = src/libwolfssh.la @@ -61,6 +64,9 @@ endif if BUILD_CERTS tests_api_test_CPPFLAGS += -DWOLFSSH_CERTS endif +if BUILD_KEYBOARD_INTERACTIVE +tests_api_test_CPPFLAGS += -DWOLFSSH_KEYBOARD_INTERACTIVE +endif tests_api_test_LDADD = src/libwolfssh.la tests_api_test_DEPENDENCIES = src/libwolfssh.la @@ -96,12 +102,16 @@ endif if BUILD_CERTS tests_testsuite_test_CPPFLAGS += -DWOLFSSH_CERTS endif +if BUILD_KEYBOARD_INTERACTIVE +tests_testsuite_test_CPPFLAGS += -DWOLFSSH_KEYBOARD_INTERACTIVE +endif tests_testsuite_test_LDADD = src/libwolfssh.la tests_testsuite_test_DEPENDENCIES = src/libwolfssh.la - +if BUILD_KEYBOARD_INTERACTIVE +check_PROGRAMS += tests/auth.test tests_auth_test_SOURCES = tests/auth.c tests/auth.h -tests_auth_test_CPPFLAGS = -DNO_MAIN_DRIVER +tests_auth_test_CPPFLAGS = -DNO_MAIN_DRIVER -DWOLFSSH_KEYBOARD_INTERACTIVE if BUILD_KEYGEN tests_auth_test_CPPFLAGS += -DWOLFSSH_KEYGEN endif @@ -128,7 +138,7 @@ tests_auth_test_CPPFLAGS += -DWOLFSSH_CERTS endif tests_auth_test_LDADD = src/libwolfssh.la tests_auth_test_DEPENDENCIES = src/libwolfssh.la - +endif tests_kex_test_SOURCES = tests/kex.c tests/kex.h \ examples/echoserver/echoserver.c \ @@ -160,5 +170,8 @@ endif if BUILD_CERTS tests_kex_test_CPPFLAGS += -DWOLFSSH_CERTS endif +if BUILD_KEYBOARD_INTERACTIVE +tests_kex_test_CPPFLAGS += -DWOLFSSH_KEYBOARD_INTERACTIVE +endif tests_kex_test_LDADD = src/libwolfssh.la tests_kex_test_DEPENDENCIES = src/libwolfssh.la diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 893d38f6..cf8516a5 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -370,7 +370,9 @@ enum { /* UserAuth IDs */ ID_USERAUTH_PASSWORD, ID_USERAUTH_PUBLICKEY, +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE ID_USERAUTH_KEYBOARD, +#endif /* Channel Type IDs */ ID_CHANTYPE_SESSION, @@ -527,7 +529,9 @@ struct WOLFSSH_CTX { WS_CallbackUserAuth userAuthCb; /* User Authentication Callback */ WS_CallbackUserAuthTypes userAuthTypesCb; /* Authentication Types Allowed */ WS_CallbackUserAuthResult userAuthResultCb; /* User Authentication Result */ +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE WS_CallbackKeyboardAuthPrompts keyboardAuthCb; /* Keyboard auth prompts */ +#endif WS_CallbackHighwater highwaterCb; /* Data Highwater Mark Callback */ WS_CallbackGlobalReq globalReqCb; /* Global Request Callback */ WS_CallbackReqSuccess reqSuccessCb; /* Global Request Success Callback */ @@ -825,7 +829,9 @@ struct WOLFSSH { void* userAuthCtx; void* userAuthResultCtx; +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE void* keyboardAuthCtx; +#endif char* userName; word32 userNameSz; char* password; @@ -914,7 +920,9 @@ struct WOLFSSH { word32 exitStatus; #endif void* keyingCompletionCtx; +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE WS_UserAuthData_Keyboard kbAuth; +#endif }; @@ -1052,8 +1060,10 @@ WOLFSSH_LOCAL int SendServiceRequest(WOLFSSH*, byte); WOLFSSH_LOCAL int SendServiceAccept(WOLFSSH*, byte); WOLFSSH_LOCAL int SendExtInfo(WOLFSSH* ssh); WOLFSSH_LOCAL int SendUserAuthRequest(WOLFSSH*, byte, int); +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE WOLFSSH_LOCAL int SendUserAuthKeyboardResponse(WOLFSSH*); WOLFSSH_LOCAL int SendUserAuthKeyboardRequest(WOLFSSH*, WS_UserAuthData*); +#endif WOLFSSH_LOCAL int SendUserAuthSuccess(WOLFSSH*); WOLFSSH_LOCAL int SendUserAuthFailure(WOLFSSH*, byte); WOLFSSH_LOCAL int SendUserAuthBanner(WOLFSSH*); @@ -1154,9 +1164,11 @@ enum ServerStates { SERVER_KEXINIT_DONE, SERVER_USERAUTH_REQUEST_DONE, SERVER_USERAUTH_ACCEPT_DONE, +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE SERVER_USERAUTH_ACCEPT_KEYBOARD, SERVER_USERAUTH_ACCEPT_KEYBOARD_NEXT, SERVER_USERAUTH_ACCEPT_KEYBOARD_DONE, +#endif SERVER_CHANNEL_OPEN_DONE, SERVER_DONE }; diff --git a/wolfssh/settings.h b/wolfssh/settings.h index 2be7d513..9fac26e5 100644 --- a/wolfssh/settings.h +++ b/wolfssh/settings.h @@ -101,7 +101,8 @@ extern "C" { /* Maximum number of prompts in one request / response transaction for * Keyboard-Interactive authentication. */ -#if !defined(WOLFSSH_MAX_PROMPTS) + +#if defined(WOLFSSH_KEYBOARD_INTERACTIVE) && !defined(WOLFSSH_MAX_PROMPTS) #define WOLFSSH_MAX_PROMPTS 64 #endif diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index c1aeadc3..9a49b440 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -311,6 +311,7 @@ typedef struct WS_UserAuthData_Password { word32 newPasswordSz; } WS_UserAuthData_Password; +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE typedef struct WS_UserAuthData_Keyboard { word32 promptCount; word32 responseCount; @@ -326,6 +327,7 @@ typedef struct WS_UserAuthData_Keyboard { byte** responses; byte** prompts; } WS_UserAuthData_Keyboard; +#endif typedef struct WS_UserAuthData_PublicKey { const byte* dataToSign; @@ -352,7 +354,9 @@ typedef struct WS_UserAuthData { union { WS_UserAuthData_Password password; WS_UserAuthData_PublicKey publicKey; +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE WS_UserAuthData_Keyboard keyboard; +#endif } sf; } WS_UserAuthData; @@ -364,10 +368,12 @@ WOLFSSH_API void wolfSSH_SetUserAuthTypes(WOLFSSH_CTX*, WOLFSSH_API void wolfSSH_SetUserAuthCtx(WOLFSSH*, void*); WOLFSSH_API void* wolfSSH_GetUserAuthCtx(WOLFSSH*); +#ifdef WOLFSSH_KEYBOARD_INTERACTIVE typedef int (*WS_CallbackKeyboardAuthPrompts)(WS_UserAuthData_Keyboard*, void*); WOLFSSH_API void wolfSSH_SetKeyboardAuthPrompts(WOLFSSH_CTX*, WS_CallbackKeyboardAuthPrompts); WOLFSSH_API void wolfSSH_SetKeyboardAuthCtx(WOLFSSH*, void*); +#endif typedef int (*WS_CallbackUserAuthResult)(byte result, WS_UserAuthData* authData, void* userAuthResultCtx); diff --git a/zephyr/samples/tests/prj_kbi.conf b/zephyr/samples/tests/prj_kbi.conf new file mode 100644 index 00000000..0ce421a7 --- /dev/null +++ b/zephyr/samples/tests/prj_kbi.conf @@ -0,0 +1,79 @@ +# Kernel options +CONFIG_MAIN_STACK_SIZE=32768 +CONFIG_ENTROPY_GENERATOR=y +CONFIG_INIT_STACKS=y +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=524288 + +# Enable wolfSSH +CONFIG_WOLFSSH=y +CONFIG_WOLFSSH_SETTINGS_FILE="samples/tests/wolfssh_user_settings_kbi.h" +CONFIG_WOLFSSH_SFTP_DEFAULT_DIR="/RAM:" + +# Pthreads +CONFIG_PTHREAD_IPC=y + +# Clock for time() +CONFIG_POSIX_CLOCK=y + +# Networking +CONFIG_NETWORKING=y +CONFIG_NET_TEST=y +CONFIG_NET_IPV4=y +CONFIG_NET_IPV6=n +CONFIG_NET_TCP=y +CONFIG_NET_SOCKETS=y +CONFIG_NET_SOCKETS_POSIX_NAMES=y + +CONFIG_NET_TEST=y +CONFIG_NET_LOOPBACK=y + +# Network driver config +CONFIG_TEST_RANDOM_GENERATOR=y + +# Network address config +CONFIG_NET_CONFIG_SETTINGS=y +CONFIG_NET_CONFIG_NEED_IPV4=y +CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1" +CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2" +CONFIG_NET_CONFIG_MY_IPV4_GW="192.0.2.2" + +CONFIG_NET_PKT_TX_COUNT=10 +CONFIG_NET_BUF_DATA_SIZE=256 + +# Logging +CONFIG_PRINTK=y +CONFIG_LOG=y +CONFIG_LOG_MODE_IMMEDIATE=y +#CONFIG_WOLFSSH_DEBUG=y +#CONFIG_WOLFSSL_DEBUG=y +#CONFIG_DEBUG=y + +# Enable logging using RTT and UART +#CONFIG_CBPRINTF_LIBC_SUBSTS=y +#CONFIG_CBPRINTF_FP_SUPPORT=y +#CONFIG_CONSOLE=y +#CONFIG_LOG_BACKEND_UART=y +#CONFIG_LOG_BUFFER_SIZE=15360 + +# TLS configuration +CONFIG_WOLFSSL=y +CONFIG_WOLFSSL_BUILTIN=y +CONFIG_WOLFSSL_SETTINGS_FILE="samples/tests/wolfssl_user_settings.h" + +CONFIG_WOLFSSL_TLS_VERSION_1_2=y +CONFIG_WOLFSSL_KEY_EXCHANGE_ALL_ENABLED=y +CONFIG_WOLFSSL_CIPHER_ALL_ENABLED=y +CONFIG_WOLFSSL_MAC_ALL_ENABLED=y +CONFIG_WOLFSSL_HMAC_DRBG_ENABLED=y + +# FS +CONFIG_DISK_ACCESS=y +CONFIG_DISK_DRIVERS=y +CONFIG_DISK_DRIVER_RAM=y +CONFIG_DISK_RAM_VOLUME_SIZE=64 +CONFIG_FILE_SYSTEM=y +CONFIG_FILE_SYSTEM_MKFS=y +CONFIG_FAT_FILESYSTEM_ELM=y +CONFIG_FS_FATFS_LFN=y +CONFIG_FS_FATFS_LFN_MODE_STACK=y + diff --git a/zephyr/samples/tests/sample.yaml b/zephyr/samples/tests/sample.yaml index 23abc38b..9467bfd8 100644 --- a/zephyr/samples/tests/sample.yaml +++ b/zephyr/samples/tests/sample.yaml @@ -19,3 +19,9 @@ tests: extra_args: CONF_FILE="prj_nofs.conf" integration_platforms: - qemu_x86 + sample.lib.wolfssh_kbi_tests: + timeout: 200 + platform_allow: qemu_x86 + extra_args: CONF_FILE="prj_kbi.conf" + integration_platforms: + - qemu_x86 diff --git a/zephyr/samples/tests/wolfssh_user_settings_kbi.h b/zephyr/samples/tests/wolfssh_user_settings_kbi.h new file mode 100644 index 00000000..dc804e59 --- /dev/null +++ b/zephyr/samples/tests/wolfssh_user_settings_kbi.h @@ -0,0 +1,74 @@ +/* user_settings.h + * + * Copyright (C) 2014-2024 wolfSSL Inc. + * + * This file is part of wolfSSH. + * + * wolfSSH is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfSSH. If not, see . + */ + +#ifndef WOLFSSH_USER_SETTINGS_H +#define WOLFSSH_USER_SETTINGS_H + + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#undef WOLFSSH_SFTP +#define WOLFSSH_SFTP + +#undef WOLFSSH_SCP +#define WOLFSSH_SCP + +#undef WOLFSSH_KEYBOARD_INTERACTIVE +#define WOLFSSH_KEYBOARD_INTERACTIVE + +#undef NO_AUTHTEST_MAIN_DRIVER +#define NO_AUTHTEST_MAIN_DRIVER + +#undef NO_APITEST_MAIN_DRIVER +#define NO_APITEST_MAIN_DRIVER + +#undef NO_TESTSUITE_MAIN_DRIVER +#define NO_TESTSUITE_MAIN_DRIVER + +#undef NO_UNITTEST_MAIN_DRIVER +#define NO_UNITTEST_MAIN_DRIVER + +#undef NO_MAIN_DRIVER +#define NO_MAIN_DRIVER + +#undef WS_NO_SIGNAL +#define WS_NO_SIGNAL + +#undef WS_USE_TEST_BUFFERS +#define WS_USE_TEST_BUFFERS + +#undef NO_WOLFSSL_DIR +#define NO_WOLFSSL_DIR + +#undef WOLFSSH_NO_NONBLOCKING +#define WOLFSSH_NO_NONBLOCKING + +#define DEFAULT_WINDOW_SZ (128 * 128) +#define WOLFSSH_MAX_SFTP_RW 8192 + +#ifdef __cplusplus +} +#endif + +#endif