Skip to content

Commit eb49029

Browse files
authored
Merge pull request #910 from yosuke-wolfssl/f_2072
Fix SendUserAuthKeyboardResponse() and add regress tests
2 parents aaf3e55 + 6d81c9d commit eb49029

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
@@ -15445,55 +15445,80 @@ static int BuildUserAuthRequestPublicKey(WOLFSSH* ssh,
1544515445
int SendUserAuthKeyboardResponse(WOLFSSH* ssh)
1544615446
{
1544715447
byte* output;
15448+
int authRet = WOLFSSH_USERAUTH_FAILURE;
1544815449
int ret = WS_SUCCESS;
1544915450
word32 idx;
1545015451
word32 payloadSz = 0;
1545115452
word32 prompt;
1545215453
WS_UserAuthData authData;
1545315454

15454-
WLOG(WS_LOG_DEBUG, "Entering SendUserAuthKeyboardResponse()");
15455+
WMEMSET(&authData, 0, sizeof(authData));
1545515456

15456-
authData.type = WOLFSSH_USERAUTH_KEYBOARD;
15457-
authData.username = (const byte*)ssh->userName;
15458-
authData.usernameSz = ssh->userNameSz;
15459-
authData.sf.keyboard.promptCount = ssh->kbAuth.promptCount;
15460-
authData.sf.keyboard.promptName = ssh->kbAuth.promptName;
15461-
authData.sf.keyboard.promptNameSz = ssh->kbAuth.promptName ?
15462-
(word32)WSTRLEN((char*)ssh->kbAuth.promptName) : 0;
15463-
authData.sf.keyboard.promptInstruction = ssh->kbAuth.promptInstruction;
15464-
authData.sf.keyboard.promptInstructionSz = ssh->kbAuth.promptInstruction ?
15465-
(word32)WSTRLEN((char*)ssh->kbAuth.promptInstruction) : 0;
15466-
authData.sf.keyboard.promptLanguage = ssh->kbAuth.promptLanguage;
15467-
authData.sf.keyboard.promptLanguageSz = ssh->kbAuth.promptLanguage ?
15468-
(word32)WSTRLEN((char*)ssh->kbAuth.promptLanguage) : 0;
15469-
authData.sf.keyboard.prompts = ssh->kbAuth.prompts;
15470-
authData.sf.keyboard.promptEcho = ssh->kbAuth.promptEcho;
15471-
authData.sf.keyboard.responseCount = 0;
15472-
15473-
WLOG(WS_LOG_DEBUG, "SUAR: Calling the userauth callback");
15474-
ret = ssh->ctx->userAuthCb(WOLFSSH_USERAUTH_KEYBOARD, &authData,
15475-
ssh->userAuthCtx);
15457+
WLOG(WS_LOG_DEBUG, "Entering SendUserAuthKeyboardResponse()");
1547615458

15477-
WFREE(ssh->kbAuth.promptName, ssh->ctx->heap, 0);
15478-
WFREE(ssh->kbAuth.promptInstruction, ssh->ctx->heap, 0);
15479-
WFREE(ssh->kbAuth.promptLanguage, ssh->ctx->heap, 0);
15480-
WFREE(ssh->kbAuth.promptEcho, ssh->ctx->heap, 0);
15481-
for (prompt = 0; prompt < ssh->kbAuth.promptCount; prompt++) {
15482-
WFREE((void*)ssh->kbAuth.prompts[prompt], ssh->ctx->heap, 0);
15459+
if (ssh == NULL || ssh->ctx == NULL) {
15460+
ret = WS_BAD_ARGUMENT;
1548315461
}
15484-
WFREE(ssh->kbAuth.prompts, ssh->ctx->heap, 0);
15485-
15486-
if (ret != WOLFSSH_USERAUTH_SUCCESS) {
15487-
WLOG(WS_LOG_DEBUG, "SUAR: Couldn't get keyboard auth");
15488-
ret = WS_FATAL_ERROR;
15462+
if (ret == WS_SUCCESS && ssh->ctx->userAuthCb == NULL) {
15463+
ret = WS_INVALID_STATE_E;
1548915464
}
15490-
else if (ssh->kbAuth.promptCount != authData.sf.keyboard.responseCount) {
15491-
WLOG(WS_LOG_DEBUG,
15492-
"SUAR: Keyboard auth response count does not match request count");
15493-
ret = WS_USER_AUTH_E;
15465+
15466+
if (ret == WS_SUCCESS) {
15467+
authData.type = WOLFSSH_USERAUTH_KEYBOARD;
15468+
authData.username = (const byte*)ssh->userName;
15469+
authData.usernameSz = ssh->userNameSz;
15470+
authData.sf.keyboard.promptCount = ssh->kbAuth.promptCount;
15471+
authData.sf.keyboard.promptName = ssh->kbAuth.promptName;
15472+
authData.sf.keyboard.promptNameSz = ssh->kbAuth.promptName ?
15473+
(word32)WSTRLEN((char*)ssh->kbAuth.promptName) : 0;
15474+
authData.sf.keyboard.promptInstruction = ssh->kbAuth.promptInstruction;
15475+
authData.sf.keyboard.promptInstructionSz = ssh->kbAuth.promptInstruction ?
15476+
(word32)WSTRLEN((char*)ssh->kbAuth.promptInstruction) : 0;
15477+
authData.sf.keyboard.promptLanguage = ssh->kbAuth.promptLanguage;
15478+
authData.sf.keyboard.promptLanguageSz = ssh->kbAuth.promptLanguage ?
15479+
(word32)WSTRLEN((char*)ssh->kbAuth.promptLanguage) : 0;
15480+
authData.sf.keyboard.prompts = ssh->kbAuth.prompts;
15481+
authData.sf.keyboard.promptEcho = ssh->kbAuth.promptEcho;
15482+
authData.sf.keyboard.responseCount = 0;
15483+
15484+
WLOG(WS_LOG_DEBUG, "SUAR: Calling the userauth callback");
15485+
authRet = ssh->ctx->userAuthCb(WOLFSSH_USERAUTH_KEYBOARD, &authData,
15486+
ssh->userAuthCtx);
15487+
}
15488+
15489+
if (ret == WS_SUCCESS) {
15490+
if (authRet != WOLFSSH_USERAUTH_SUCCESS) {
15491+
WLOG(WS_LOG_DEBUG, "SUAR: Couldn't get keyboard auth");
15492+
ret = WS_FATAL_ERROR;
15493+
}
15494+
else if (ssh->kbAuth.promptCount != authData.sf.keyboard.responseCount) {
15495+
WLOG(WS_LOG_DEBUG,
15496+
"SUAR: Keyboard auth response count does not match request count");
15497+
ret = WS_USER_AUTH_E;
15498+
}
15499+
else {
15500+
WLOG(WS_LOG_DEBUG, "SUAR: Callback successful keyboard");
15501+
}
1549415502
}
15495-
else {
15496-
WLOG(WS_LOG_DEBUG, "SUAR: Callback successful keyboard");
15503+
15504+
if (ssh != NULL && ssh->ctx != NULL) {
15505+
WFREE(ssh->kbAuth.promptName, ssh->ctx->heap, 0);
15506+
WFREE(ssh->kbAuth.promptInstruction, ssh->ctx->heap, 0);
15507+
WFREE(ssh->kbAuth.promptLanguage, ssh->ctx->heap, 0);
15508+
WFREE(ssh->kbAuth.promptEcho, ssh->ctx->heap, 0);
15509+
if (ssh->kbAuth.prompts != NULL) {
15510+
for (prompt = 0; prompt < ssh->kbAuth.promptCount; prompt++) {
15511+
WFREE((void*)ssh->kbAuth.prompts[prompt], ssh->ctx->heap, 0);
15512+
}
15513+
}
15514+
WFREE(ssh->kbAuth.prompts, ssh->ctx->heap, 0);
15515+
15516+
ssh->kbAuth.promptName = NULL;
15517+
ssh->kbAuth.promptInstruction = NULL;
15518+
ssh->kbAuth.promptLanguage = NULL;
15519+
ssh->kbAuth.promptEcho = NULL;
15520+
ssh->kbAuth.prompts = NULL;
15521+
ssh->kbAuth.promptCount = 0;
1549715522
}
1549815523

1549915524
payloadSz = MSG_ID_SZ;
@@ -15505,13 +15530,13 @@ int SendUserAuthKeyboardResponse(WOLFSSH* ssh)
1550515530
ret = PreparePacket(ssh, payloadSz);
1550615531
}
1550715532

15508-
output = ssh->outputBuffer.buffer;
15509-
idx = ssh->outputBuffer.length;
15510-
15511-
output[idx++] = MSGID_USERAUTH_INFO_RESPONSE;
15533+
if (ret == WS_SUCCESS) {
15534+
output = ssh->outputBuffer.buffer;
15535+
idx = ssh->outputBuffer.length;
1551215536

15513-
if (ret == WS_SUCCESS)
15537+
output[idx++] = MSGID_USERAUTH_INFO_RESPONSE;
1551415538
ret = BuildUserAuthResponseKeyboard(ssh, output, &idx, &authData);
15539+
}
1551515540

1551615541
if (ret == WS_SUCCESS) {
1551715542
ssh->outputBuffer.length = idx;

tests/regress.c

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,129 @@ static void TestNucleusMonthConversion(void)
14961496
#endif /* WOLFSSH_SFTP */
14971497

14981498

1499+
#ifdef WOLFSSH_KEYBOARD_INTERACTIVE
1500+
static int KbPreparePacketFailUserAuth(byte authType, WS_UserAuthData* authData,
1501+
void* ctx)
1502+
{
1503+
static byte* responses[1];
1504+
static word32 responseLens[1];
1505+
static byte response[] = "regress";
1506+
1507+
(void)ctx;
1508+
1509+
if (authType != WOLFSSH_USERAUTH_KEYBOARD || authData == NULL) {
1510+
return WOLFSSH_USERAUTH_INVALID_AUTHTYPE;
1511+
}
1512+
1513+
if (authData->sf.keyboard.promptCount != 1 ||
1514+
authData->sf.keyboard.prompts == NULL) {
1515+
return WOLFSSH_USERAUTH_INVALID_PASSWORD;
1516+
}
1517+
1518+
responses[0] = response;
1519+
responseLens[0] = (word32)sizeof(response) - 1;
1520+
authData->sf.keyboard.responseCount = 1;
1521+
authData->sf.keyboard.responseLengths = responseLens;
1522+
authData->sf.keyboard.responses = responses;
1523+
1524+
return WOLFSSH_USERAUTH_SUCCESS;
1525+
}
1526+
1527+
static void TestKeyboardResponsePreparePacketFailure(WOLFSSH* ssh,
1528+
WOLFSSH_CTX* ctx)
1529+
{
1530+
byte* prompt;
1531+
byte** prompts;
1532+
byte* promptEcho;
1533+
int ret;
1534+
1535+
AssertNotNull(ssh);
1536+
AssertNotNull(ctx);
1537+
1538+
ResetSession(ssh);
1539+
wolfSSH_SetUserAuth(ctx, KbPreparePacketFailUserAuth);
1540+
1541+
prompt = (byte*)WMALLOC(9, ctx->heap, DYNTYPE_STRING); /* "Password" */
1542+
prompts = (byte**)WMALLOC(sizeof(byte*), ctx->heap, DYNTYPE_STRING);
1543+
promptEcho = (byte*)WMALLOC(1, ctx->heap, DYNTYPE_STRING);
1544+
AssertNotNull(prompt);
1545+
AssertNotNull(prompts);
1546+
AssertNotNull(promptEcho);
1547+
1548+
WMEMCPY(prompt, "Password", 8);
1549+
prompt[8] = '\0';
1550+
prompts[0] = prompt;
1551+
promptEcho[0] = 0;
1552+
1553+
ssh->kbAuth.promptCount = 1;
1554+
ssh->kbAuth.prompts = prompts;
1555+
ssh->kbAuth.promptEcho = promptEcho;
1556+
ssh->kbAuth.promptName = NULL;
1557+
ssh->kbAuth.promptInstruction = NULL;
1558+
ssh->kbAuth.promptLanguage = NULL;
1559+
1560+
/* Force PreparePacket() to fail with WS_OVERFLOW_E. */
1561+
ssh->outputBuffer.length = 0;
1562+
ssh->outputBuffer.idx = 1;
1563+
1564+
ret = SendUserAuthKeyboardResponse(ssh);
1565+
AssertIntEQ(ret, WS_OVERFLOW_E);
1566+
1567+
/* Ensure packet purge/reset happened cleanly. */
1568+
AssertIntEQ(ssh->outputBuffer.idx, 0);
1569+
AssertIntEQ(ssh->outputBuffer.length, 0);
1570+
1571+
/* Verify SendUserAuthKeyboardResponse() cleaned up kbAuth state. */
1572+
AssertIntEQ(ssh->kbAuth.promptCount, 0);
1573+
AssertTrue(ssh->kbAuth.prompts == NULL);
1574+
AssertTrue(ssh->kbAuth.promptEcho == NULL);
1575+
}
1576+
1577+
static void TestKeyboardResponseNoUserAuthCallback(WOLFSSH* ssh,
1578+
WOLFSSH_CTX* ctx)
1579+
{
1580+
int ret;
1581+
1582+
AssertNotNull(ssh);
1583+
AssertNotNull(ctx);
1584+
1585+
ResetSession(ssh);
1586+
wolfSSH_SetUserAuth(ctx, NULL);
1587+
1588+
ret = SendUserAuthKeyboardResponse(ssh);
1589+
AssertIntEQ(ret, WS_INVALID_STATE_E);
1590+
1591+
/* No packet should have been started. */
1592+
AssertIntEQ(ssh->outputBuffer.length, 0);
1593+
AssertIntEQ(ssh->outputBuffer.idx, 0);
1594+
}
1595+
1596+
static void TestKeyboardResponseNullSsh(void)
1597+
{
1598+
int ret;
1599+
1600+
ret = SendUserAuthKeyboardResponse(NULL);
1601+
AssertIntEQ(ret, WS_BAD_ARGUMENT);
1602+
}
1603+
1604+
static void TestKeyboardResponseNullCtx(WOLFSSH* ssh)
1605+
{
1606+
WOLFSSH_CTX* savedCtx;
1607+
int ret;
1608+
1609+
AssertNotNull(ssh);
1610+
1611+
savedCtx = ssh->ctx;
1612+
ssh->ctx = NULL;
1613+
1614+
ret = SendUserAuthKeyboardResponse(ssh);
1615+
AssertIntEQ(ret, WS_BAD_ARGUMENT);
1616+
1617+
ssh->ctx = savedCtx;
1618+
}
1619+
#endif /* WOLFSSH_KEYBOARD_INTERACTIVE */
1620+
1621+
14991622
int main(int argc, char** argv)
15001623
{
15011624
WOLFSSH_CTX* ctx;
@@ -1557,6 +1680,13 @@ int main(int argc, char** argv)
15571680
#endif
15581681
#endif
15591682

1683+
#ifdef WOLFSSH_KEYBOARD_INTERACTIVE
1684+
TestKeyboardResponsePreparePacketFailure(ssh, ctx);
1685+
TestKeyboardResponseNoUserAuthCallback(ssh, ctx);
1686+
TestKeyboardResponseNullSsh();
1687+
TestKeyboardResponseNullCtx(ssh);
1688+
#endif
1689+
15601690
/* TODO: add app-level regressions that simulate stdin EOF/password
15611691
* prompts and mid-session socket closes once the test harness can
15621692
* drive the wolfssh client without real sockets/tty. */

0 commit comments

Comments
 (0)