Skip to content

Commit 6d81c9d

Browse files
Fix SendUserAuthKeyboardResponse and add regress test
1 parent 4ed01d3 commit 6d81c9d

File tree

2 files changed

+198
-43
lines changed

2 files changed

+198
-43
lines changed

src/internal.c

Lines changed: 68 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -15419,55 +15419,80 @@ static int BuildUserAuthRequestPublicKey(WOLFSSH* ssh,
1541915419
int SendUserAuthKeyboardResponse(WOLFSSH* ssh)
1542015420
{
1542115421
byte* output;
15422+
int authRet = WOLFSSH_USERAUTH_FAILURE;
1542215423
int ret = WS_SUCCESS;
1542315424
word32 idx;
1542415425
word32 payloadSz = 0;
1542515426
word32 prompt;
1542615427
WS_UserAuthData authData;
1542715428

15428-
WLOG(WS_LOG_DEBUG, "Entering SendUserAuthKeyboardResponse()");
15429+
WMEMSET(&authData, 0, sizeof(authData));
1542915430

15430-
authData.type = WOLFSSH_USERAUTH_KEYBOARD;
15431-
authData.username = (const byte*)ssh->userName;
15432-
authData.usernameSz = ssh->userNameSz;
15433-
authData.sf.keyboard.promptCount = ssh->kbAuth.promptCount;
15434-
authData.sf.keyboard.promptName = ssh->kbAuth.promptName;
15435-
authData.sf.keyboard.promptNameSz = ssh->kbAuth.promptName ?
15436-
(word32)WSTRLEN((char*)ssh->kbAuth.promptName) : 0;
15437-
authData.sf.keyboard.promptInstruction = ssh->kbAuth.promptInstruction;
15438-
authData.sf.keyboard.promptInstructionSz = ssh->kbAuth.promptInstruction ?
15439-
(word32)WSTRLEN((char*)ssh->kbAuth.promptInstruction) : 0;
15440-
authData.sf.keyboard.promptLanguage = ssh->kbAuth.promptLanguage;
15441-
authData.sf.keyboard.promptLanguageSz = ssh->kbAuth.promptLanguage ?
15442-
(word32)WSTRLEN((char*)ssh->kbAuth.promptLanguage) : 0;
15443-
authData.sf.keyboard.prompts = ssh->kbAuth.prompts;
15444-
authData.sf.keyboard.promptEcho = ssh->kbAuth.promptEcho;
15445-
authData.sf.keyboard.responseCount = 0;
15446-
15447-
WLOG(WS_LOG_DEBUG, "SUAR: Calling the userauth callback");
15448-
ret = ssh->ctx->userAuthCb(WOLFSSH_USERAUTH_KEYBOARD, &authData,
15449-
ssh->userAuthCtx);
15431+
WLOG(WS_LOG_DEBUG, "Entering SendUserAuthKeyboardResponse()");
1545015432

15451-
WFREE(ssh->kbAuth.promptName, ssh->ctx->heap, 0);
15452-
WFREE(ssh->kbAuth.promptInstruction, ssh->ctx->heap, 0);
15453-
WFREE(ssh->kbAuth.promptLanguage, ssh->ctx->heap, 0);
15454-
WFREE(ssh->kbAuth.promptEcho, ssh->ctx->heap, 0);
15455-
for (prompt = 0; prompt < ssh->kbAuth.promptCount; prompt++) {
15456-
WFREE((void*)ssh->kbAuth.prompts[prompt], ssh->ctx->heap, 0);
15433+
if (ssh == NULL || ssh->ctx == NULL) {
15434+
ret = WS_BAD_ARGUMENT;
1545715435
}
15458-
WFREE(ssh->kbAuth.prompts, ssh->ctx->heap, 0);
15459-
15460-
if (ret != WOLFSSH_USERAUTH_SUCCESS) {
15461-
WLOG(WS_LOG_DEBUG, "SUAR: Couldn't get keyboard auth");
15462-
ret = WS_FATAL_ERROR;
15436+
if (ret == WS_SUCCESS && ssh->ctx->userAuthCb == NULL) {
15437+
ret = WS_INVALID_STATE_E;
1546315438
}
15464-
else if (ssh->kbAuth.promptCount != authData.sf.keyboard.responseCount) {
15465-
WLOG(WS_LOG_DEBUG,
15466-
"SUAR: Keyboard auth response count does not match request count");
15467-
ret = WS_USER_AUTH_E;
15439+
15440+
if (ret == WS_SUCCESS) {
15441+
authData.type = WOLFSSH_USERAUTH_KEYBOARD;
15442+
authData.username = (const byte*)ssh->userName;
15443+
authData.usernameSz = ssh->userNameSz;
15444+
authData.sf.keyboard.promptCount = ssh->kbAuth.promptCount;
15445+
authData.sf.keyboard.promptName = ssh->kbAuth.promptName;
15446+
authData.sf.keyboard.promptNameSz = ssh->kbAuth.promptName ?
15447+
(word32)WSTRLEN((char*)ssh->kbAuth.promptName) : 0;
15448+
authData.sf.keyboard.promptInstruction = ssh->kbAuth.promptInstruction;
15449+
authData.sf.keyboard.promptInstructionSz = ssh->kbAuth.promptInstruction ?
15450+
(word32)WSTRLEN((char*)ssh->kbAuth.promptInstruction) : 0;
15451+
authData.sf.keyboard.promptLanguage = ssh->kbAuth.promptLanguage;
15452+
authData.sf.keyboard.promptLanguageSz = ssh->kbAuth.promptLanguage ?
15453+
(word32)WSTRLEN((char*)ssh->kbAuth.promptLanguage) : 0;
15454+
authData.sf.keyboard.prompts = ssh->kbAuth.prompts;
15455+
authData.sf.keyboard.promptEcho = ssh->kbAuth.promptEcho;
15456+
authData.sf.keyboard.responseCount = 0;
15457+
15458+
WLOG(WS_LOG_DEBUG, "SUAR: Calling the userauth callback");
15459+
authRet = ssh->ctx->userAuthCb(WOLFSSH_USERAUTH_KEYBOARD, &authData,
15460+
ssh->userAuthCtx);
15461+
}
15462+
15463+
if (ret == WS_SUCCESS) {
15464+
if (authRet != WOLFSSH_USERAUTH_SUCCESS) {
15465+
WLOG(WS_LOG_DEBUG, "SUAR: Couldn't get keyboard auth");
15466+
ret = WS_FATAL_ERROR;
15467+
}
15468+
else if (ssh->kbAuth.promptCount != authData.sf.keyboard.responseCount) {
15469+
WLOG(WS_LOG_DEBUG,
15470+
"SUAR: Keyboard auth response count does not match request count");
15471+
ret = WS_USER_AUTH_E;
15472+
}
15473+
else {
15474+
WLOG(WS_LOG_DEBUG, "SUAR: Callback successful keyboard");
15475+
}
1546815476
}
15469-
else {
15470-
WLOG(WS_LOG_DEBUG, "SUAR: Callback successful keyboard");
15477+
15478+
if (ssh != NULL && ssh->ctx != NULL) {
15479+
WFREE(ssh->kbAuth.promptName, ssh->ctx->heap, 0);
15480+
WFREE(ssh->kbAuth.promptInstruction, ssh->ctx->heap, 0);
15481+
WFREE(ssh->kbAuth.promptLanguage, ssh->ctx->heap, 0);
15482+
WFREE(ssh->kbAuth.promptEcho, ssh->ctx->heap, 0);
15483+
if (ssh->kbAuth.prompts != NULL) {
15484+
for (prompt = 0; prompt < ssh->kbAuth.promptCount; prompt++) {
15485+
WFREE((void*)ssh->kbAuth.prompts[prompt], ssh->ctx->heap, 0);
15486+
}
15487+
}
15488+
WFREE(ssh->kbAuth.prompts, ssh->ctx->heap, 0);
15489+
15490+
ssh->kbAuth.promptName = NULL;
15491+
ssh->kbAuth.promptInstruction = NULL;
15492+
ssh->kbAuth.promptLanguage = NULL;
15493+
ssh->kbAuth.promptEcho = NULL;
15494+
ssh->kbAuth.prompts = NULL;
15495+
ssh->kbAuth.promptCount = 0;
1547115496
}
1547215497

1547315498
payloadSz = MSG_ID_SZ;
@@ -15479,13 +15504,13 @@ int SendUserAuthKeyboardResponse(WOLFSSH* ssh)
1547915504
ret = PreparePacket(ssh, payloadSz);
1548015505
}
1548115506

15482-
output = ssh->outputBuffer.buffer;
15483-
idx = ssh->outputBuffer.length;
15484-
15485-
output[idx++] = MSGID_USERAUTH_INFO_RESPONSE;
15507+
if (ret == WS_SUCCESS) {
15508+
output = ssh->outputBuffer.buffer;
15509+
idx = ssh->outputBuffer.length;
1548615510

15487-
if (ret == WS_SUCCESS)
15511+
output[idx++] = MSGID_USERAUTH_INFO_RESPONSE;
1548815512
ret = BuildUserAuthResponseKeyboard(ssh, output, &idx, &authData);
15513+
}
1548915514

1549015515
if (ret == WS_SUCCESS) {
1549115516
ssh->outputBuffer.length = idx;

tests/regress.c

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,129 @@ static void TestSftpBufferSendPendingOutput(void)
557557
#endif /* WOLFSSH_SFTP */
558558

559559

560+
#ifdef WOLFSSH_KEYBOARD_INTERACTIVE
561+
static int KbPreparePacketFailUserAuth(byte authType, WS_UserAuthData* authData,
562+
void* ctx)
563+
{
564+
static byte* responses[1];
565+
static word32 responseLens[1];
566+
static byte response[] = "regress";
567+
568+
(void)ctx;
569+
570+
if (authType != WOLFSSH_USERAUTH_KEYBOARD || authData == NULL) {
571+
return WOLFSSH_USERAUTH_INVALID_AUTHTYPE;
572+
}
573+
574+
if (authData->sf.keyboard.promptCount != 1 ||
575+
authData->sf.keyboard.prompts == NULL) {
576+
return WOLFSSH_USERAUTH_INVALID_PASSWORD;
577+
}
578+
579+
responses[0] = response;
580+
responseLens[0] = (word32)sizeof(response) - 1;
581+
authData->sf.keyboard.responseCount = 1;
582+
authData->sf.keyboard.responseLengths = responseLens;
583+
authData->sf.keyboard.responses = responses;
584+
585+
return WOLFSSH_USERAUTH_SUCCESS;
586+
}
587+
588+
static void TestKeyboardResponsePreparePacketFailure(WOLFSSH* ssh,
589+
WOLFSSH_CTX* ctx)
590+
{
591+
byte* prompt;
592+
byte** prompts;
593+
byte* promptEcho;
594+
int ret;
595+
596+
AssertNotNull(ssh);
597+
AssertNotNull(ctx);
598+
599+
ResetSession(ssh);
600+
wolfSSH_SetUserAuth(ctx, KbPreparePacketFailUserAuth);
601+
602+
prompt = (byte*)WMALLOC(9, ctx->heap, DYNTYPE_STRING); /* "Password" */
603+
prompts = (byte**)WMALLOC(sizeof(byte*), ctx->heap, DYNTYPE_STRING);
604+
promptEcho = (byte*)WMALLOC(1, ctx->heap, DYNTYPE_STRING);
605+
AssertNotNull(prompt);
606+
AssertNotNull(prompts);
607+
AssertNotNull(promptEcho);
608+
609+
WMEMCPY(prompt, "Password", 8);
610+
prompt[8] = '\0';
611+
prompts[0] = prompt;
612+
promptEcho[0] = 0;
613+
614+
ssh->kbAuth.promptCount = 1;
615+
ssh->kbAuth.prompts = prompts;
616+
ssh->kbAuth.promptEcho = promptEcho;
617+
ssh->kbAuth.promptName = NULL;
618+
ssh->kbAuth.promptInstruction = NULL;
619+
ssh->kbAuth.promptLanguage = NULL;
620+
621+
/* Force PreparePacket() to fail with WS_OVERFLOW_E. */
622+
ssh->outputBuffer.length = 0;
623+
ssh->outputBuffer.idx = 1;
624+
625+
ret = SendUserAuthKeyboardResponse(ssh);
626+
AssertIntEQ(ret, WS_OVERFLOW_E);
627+
628+
/* Ensure packet purge/reset happened cleanly. */
629+
AssertIntEQ(ssh->outputBuffer.idx, 0);
630+
AssertIntEQ(ssh->outputBuffer.length, 0);
631+
632+
/* Verify SendUserAuthKeyboardResponse() cleaned up kbAuth state. */
633+
AssertIntEQ(ssh->kbAuth.promptCount, 0);
634+
AssertTrue(ssh->kbAuth.prompts == NULL);
635+
AssertTrue(ssh->kbAuth.promptEcho == NULL);
636+
}
637+
638+
static void TestKeyboardResponseNoUserAuthCallback(WOLFSSH* ssh,
639+
WOLFSSH_CTX* ctx)
640+
{
641+
int ret;
642+
643+
AssertNotNull(ssh);
644+
AssertNotNull(ctx);
645+
646+
ResetSession(ssh);
647+
wolfSSH_SetUserAuth(ctx, NULL);
648+
649+
ret = SendUserAuthKeyboardResponse(ssh);
650+
AssertIntEQ(ret, WS_INVALID_STATE_E);
651+
652+
/* No packet should have been started. */
653+
AssertIntEQ(ssh->outputBuffer.length, 0);
654+
AssertIntEQ(ssh->outputBuffer.idx, 0);
655+
}
656+
657+
static void TestKeyboardResponseNullSsh(void)
658+
{
659+
int ret;
660+
661+
ret = SendUserAuthKeyboardResponse(NULL);
662+
AssertIntEQ(ret, WS_BAD_ARGUMENT);
663+
}
664+
665+
static void TestKeyboardResponseNullCtx(WOLFSSH* ssh)
666+
{
667+
WOLFSSH_CTX* savedCtx;
668+
int ret;
669+
670+
AssertNotNull(ssh);
671+
672+
savedCtx = ssh->ctx;
673+
ssh->ctx = NULL;
674+
675+
ret = SendUserAuthKeyboardResponse(ssh);
676+
AssertIntEQ(ret, WS_BAD_ARGUMENT);
677+
678+
ssh->ctx = savedCtx;
679+
}
680+
#endif /* WOLFSSH_KEYBOARD_INTERACTIVE */
681+
682+
560683
int main(int argc, char** argv)
561684
{
562685
WOLFSSH_CTX* ctx;
@@ -594,6 +717,13 @@ int main(int argc, char** argv)
594717
TestSftpBufferSendPendingOutput();
595718
#endif
596719

720+
#ifdef WOLFSSH_KEYBOARD_INTERACTIVE
721+
TestKeyboardResponsePreparePacketFailure(ssh, ctx);
722+
TestKeyboardResponseNoUserAuthCallback(ssh, ctx);
723+
TestKeyboardResponseNullSsh();
724+
TestKeyboardResponseNullCtx(ssh);
725+
#endif
726+
597727
/* TODO: add app-level regressions that simulate stdin EOF/password
598728
* prompts and mid-session socket closes once the test harness can
599729
* drive the wolfssh client without real sockets/tty. */

0 commit comments

Comments
 (0)