@@ -5011,6 +5011,26 @@ static void TestServerUserauthBlockedBeforeKeyed(WOLFSSH* ssh)
50115011}
50125012
50135013
5014+ /* Keyed is not enough: userauth waits for the service request. */
5015+ static void TestServerUserauthBlockedBeforeServiceRequest(WOLFSSH* ssh)
5016+ {
5017+ ResetSession(ssh);
5018+ ssh->acceptState = ACCEPT_KEYED;
5019+
5020+ AssertFalse(wolfSSH_TestIsMessageAllowed(ssh, MSGID_USERAUTH_REQUEST,
5021+ WS_MSG_RECV));
5022+ AssertFalse(wolfSSH_TestIsMessageAllowed(ssh,
5023+ MSGID_USERAUTH_INFO_RESPONSE, WS_MSG_RECV));
5024+
5025+ ssh->acceptState = ACCEPT_CLIENT_USERAUTH_REQUEST_DONE;
5026+
5027+ AssertTrue(wolfSSH_TestIsMessageAllowed(ssh, MSGID_USERAUTH_REQUEST,
5028+ WS_MSG_RECV));
5029+ AssertTrue(wolfSSH_TestIsMessageAllowed(ssh,
5030+ MSGID_USERAUTH_INFO_RESPONSE, WS_MSG_RECV));
5031+ }
5032+
5033+
50145034/* One packet fed to a keyed but unauthenticated server. The cases below
50155035 * differ only in the packet and the answer it draws. */
50165036static void RunServerMsgIdAtKeyed(const byte* pkt, word32 pktSz,
@@ -7910,6 +7930,82 @@ static void TestSameUserRetryAllowed(void)
79107930 FreeChannelOpenHarness(&harness);
79117931}
79127932
7933+ static int AcceptPasswordUserAuthCb(byte authType, WS_UserAuthData* authData,
7934+ void* ctx)
7935+ {
7936+ (void)authData;
7937+ (void)ctx;
7938+
7939+ authCbInvoked = 1;
7940+ return (authType == WOLFSSH_USERAUTH_PASSWORD) ?
7941+ WOLFSSH_USERAUTH_SUCCESS : WOLFSSH_USERAUTH_FAILURE;
7942+ }
7943+
7944+ /* A userauth request without a service request draws a disconnect, not a
7945+ * SERVICE_ACCEPT, even with a password the callback accepts. */
7946+ static void TestUserAuthBeforeServiceRequestDisconnects(void)
7947+ {
7948+ ChannelOpenHarness harness;
7949+ byte in[128];
7950+ word32 inSz;
7951+
7952+ inSz = BuildUserAuthPasswordRequest("alice", "pw", in, sizeof(in));
7953+
7954+ ResetAuthCbRecord();
7955+ InitChannelOpenHarness(&harness, in, inSz);
7956+ wolfSSH_SetUserAuth(harness.ctx, AcceptPasswordUserAuthCb);
7957+ harness.ssh->acceptState = ACCEPT_KEYED;
7958+
7959+ AssertIntEQ(wolfSSH_accept(harness.ssh), WS_FATAL_ERROR);
7960+ AssertIntEQ(harness.ssh->error, WS_MSGID_NOT_ALLOWED_E);
7961+ AssertIntEQ(authCbInvoked, 0);
7962+ AssertIntEQ(harness.ssh->acceptState, ACCEPT_KEYED);
7963+ AssertTrue(harness.io.outSz > 0);
7964+ AssertIntEQ(ParseMsgId(harness.io.out, harness.io.outSz),
7965+ MSGID_DISCONNECT);
7966+ AssertTrue(harness.ssh->disconnected);
7967+
7968+ FreeChannelOpenHarness(&harness);
7969+ }
7970+
7971+ /* A userauth request queued right behind the service request draws
7972+ * SERVICE_ACCEPT, then its answer. */
7973+ static void TestUserAuthPipelinedAfterServiceRequest(void)
7974+ {
7975+ ChannelOpenHarness harness;
7976+ byte payload[32];
7977+ byte in[256];
7978+ word32 inSz;
7979+ word32 idx = 0;
7980+ word32 off;
7981+
7982+ idx = AppendString(payload, sizeof(payload), idx, "ssh-userauth");
7983+ inSz = WrapPacket(MSGID_SERVICE_REQUEST, payload, idx, in, sizeof(in));
7984+ inSz += BuildUserAuthPasswordRequest("alice", "pw",
7985+ in + inSz, sizeof(in) - inSz);
7986+
7987+ ResetAuthCbRecord();
7988+ InitChannelOpenHarness(&harness, in, inSz);
7989+ wolfSSH_SetUserAuth(harness.ctx, AcceptPasswordUserAuthCb);
7990+ harness.ssh->acceptState = ACCEPT_KEYED;
7991+
7992+ /* Stops for want of the channel open that would follow. */
7993+ AssertIntEQ(wolfSSH_accept(harness.ssh), WS_FATAL_ERROR);
7994+ AssertIntEQ(harness.ssh->error, WS_WANT_READ);
7995+ AssertIntEQ(authCbInvoked, 1);
7996+ AssertIntEQ(harness.ssh->acceptState, ACCEPT_SERVER_USERAUTH_SENT);
7997+ AssertIntEQ(harness.io.inOff, harness.io.inSz);
7998+ AssertIntEQ(ParseMsgId(harness.io.out, harness.io.outSz),
7999+ MSGID_SERVICE_ACCEPT);
8000+ off = NextPacketOffset(harness.io.out, harness.io.outSz);
8001+ AssertIntEQ(ParseMsgId(harness.io.out + off, harness.io.outSz - off),
8002+ MSGID_USERAUTH_SUCCESS);
8003+ off += NextPacketOffset(harness.io.out + off, harness.io.outSz - off);
8004+ AssertIntEQ(off, harness.io.outSz);
8005+
8006+ FreeChannelOpenHarness(&harness);
8007+ }
8008+
79138009#ifdef WOLFSSH_KEYBOARD_INTERACTIVE
79148010static word32 BuildUserAuthKeyboardRequest(const char* user,
79158011 byte* out, word32 outSz)
@@ -19042,6 +19138,7 @@ int main(int argc, char** argv)
1904219138 TestServerChannelBlockedBeforeAuth(serverSsh);
1904319139 TestServerChannelAllowedAfterAuth(serverSsh);
1904419140 TestServerUserauthBlockedBeforeKeyed(serverSsh);
19141+ TestServerUserauthBlockedBeforeServiceRequest(serverSsh);
1904519142 TestServerHighMsgIdBeforeAuthDisconnects();
1904619143 TestServerUnknownMsgIdBeforeAuthUnimplemented();
1904719144 TestServerKnownAuthMsgIdBeforeAuthDisconnects();
@@ -19111,6 +19208,8 @@ int main(int argc, char** argv)
1911119208 TestSecondSessionChannelRejected();
1911219209 TestUsernameChangeDisconnects();
1911319210 TestSameUserRetryAllowed();
19211+ TestUserAuthBeforeServiceRequestDisconnects();
19212+ TestUserAuthPipelinedAfterServiceRequest();
1911419213#ifdef WOLFSSH_KEYBOARD_INTERACTIVE
1911519214 TestKbInfoResponseCountMismatchSendsFailure();
1911619215 TestKbInfoResponseMismatchKeepsFraming();
0 commit comments