Skip to content

Commit 73b1656

Browse files
committed
Client Out Of Order Messaging Checking
1. Add macro for logging an expected message. 2. Add an expected message ID to the HandshakeInfo. 3. Add a message ID for "none (0)". 4. Add a check in IsMessageAllowedClient() for the expected message ID. Clear it if successful. 5. The KEXDH messages sent to the server have expected responses. Set them if sending the message is successful. 6. Add the set of message ID ranges and macros for testing if a message ID is in a specific range. 7. Add flags for having sent the kexinit message and received it. Tweak the checks for isKeying and these flags. 8. IsMessageAllowedClient() to check for appropriate messages at the appropriate time during the connect.
1 parent a473a05 commit 73b1656

3 files changed

Lines changed: 178 additions & 46 deletions

File tree

src/internal.c

Lines changed: 124 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -612,8 +612,8 @@ INLINE static int IsMessageAllowedKeying(WOLFSSH *ssh, byte msg)
612612
return 0;
613613
}
614614

615-
/* case of resending SSH_MSG_KEXINIT */
616-
if (msg == MSGID_KEXINIT) {
615+
/* case of peer resending SSH_MSG_KEXINIT */
616+
if ((ssh->isKeying & WOLFSSH_PEER_IS_KEYING) && msg == MSGID_KEXINIT) {
617617
WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by during rekeying", msg);
618618
ssh->error = WS_REKEYING;
619619
return 0;
@@ -632,34 +632,50 @@ INLINE static int IsMessageAllowedKeying(WOLFSSH *ssh, byte msg)
632632
#ifndef NO_WOLFSSH_SERVER
633633
INLINE static int IsMessageAllowedServer(WOLFSSH *ssh, byte msg)
634634
{
635+
/* Only the server should send these messages, never receive. */
636+
if (msg == MSGID_SERVICE_ACCEPT) {
637+
WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by %s %s",
638+
msg, "client", "ever");
639+
return 0;
640+
}
641+
642+
/* Transport Layer Generic messages are always allowed. */
643+
if (MSGIDLIMIT_TRANS_GEN(msg)) {
644+
return 1;
645+
}
646+
635647
/* Has client userauth started? */
648+
/* Allows the server to receive up to KEXDH GEX Request during KEX. */
636649
if (ssh->acceptState < ACCEPT_KEYED) {
637-
if (msg > MSGID_KEXDH_LIMIT) {
650+
if (msg > MSGID_KEXDH_GEX_REQUEST) {
638651
return 0;
639652
}
640653
}
641654
/* Is server userauth complete? */
642655
if (ssh->acceptState < ACCEPT_SERVER_USERAUTH_SENT) {
656+
/* The server should only receive the user auth request message,
657+
* it should not accept the other user auth messages, it sends
658+
* them. (>50) */
643659
/* Explicitly check for messages not allowed before user
644660
* authentication has comleted. */
645-
if (msg >= MSGID_USERAUTH_LIMIT) {
646-
WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by server "
647-
"before user authentication is complete", msg);
661+
if (MSGIDLIMIT_POST_USERAUTH(msg)) {
662+
WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by %s %s",
663+
msg, "server", "before user authentication is complete");
648664
return 0;
649665
}
650666
/* Explicitly check for the user authentication messages that
651667
* only the server sends, it shouldn't receive them. */
652-
if ((msg > MSGID_USERAUTH_RESTRICT) &&
668+
if ((msg > MSGID_USERAUTH_REQUEST) &&
653669
(msg != MSGID_USERAUTH_INFO_RESPONSE)) {
654-
WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by server "
655-
"during user authentication", msg);
670+
WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by %s %s",
671+
msg, "server", "during user authentication");
656672
return 0;
657673
}
658674
}
659675
else {
660-
if (msg >= MSGID_USERAUTH_RESTRICT && msg < MSGID_USERAUTH_LIMIT) {
661-
WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by server "
662-
"after user authentication", msg);
676+
if (msg >= MSGID_USERAUTH_REQUEST && msg < MSGID_GLOBAL_REQUEST) {
677+
WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by %s %s",
678+
msg, "server", "after user authentication");
663679
return 0;
664680
}
665681
}
@@ -672,37 +688,95 @@ INLINE static int IsMessageAllowedServer(WOLFSSH *ssh, byte msg)
672688
#ifndef NO_WOLFSSH_CLIENT
673689
INLINE static int IsMessageAllowedClient(WOLFSSH *ssh, byte msg)
674690
{
675-
/* Has client userauth started? */
676-
if (ssh->connectState < CONNECT_CLIENT_KEXDH_INIT_SENT) {
677-
if (msg >= MSGID_KEXDH_LIMIT) {
691+
/* Only the client should send these messages, never receive. */
692+
if (msg == MSGID_SERVICE_REQUEST || msg == MSGID_USERAUTH_REQUEST) {
693+
WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by %s %s",
694+
msg, "client", "ever");
695+
return 0;
696+
}
697+
698+
if (msg == MSGID_SERVICE_ACCEPT) {
699+
if (ssh->connectState == CONNECT_CLIENT_USERAUTH_REQUEST_SENT) {
700+
return 1;
701+
}
702+
else {
703+
WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by %s %s",
704+
msg, "client", "after starting user auth");
678705
return 0;
679706
}
680707
}
681-
/* Is client userauth complete? */
682-
if (ssh->connectState < CONNECT_SERVER_USERAUTH_ACCEPT_DONE) {
683-
/* Explicitly check for messages not allowed before user
684-
* authentication has comleted. */
685-
if (msg >= MSGID_USERAUTH_LIMIT) {
686-
WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by client "
687-
"before user authentication is complete", msg);
708+
709+
/* Transport Layer Generic messages are always allowed. */
710+
if (MSGIDLIMIT_TRANS_GEN(msg)) {
711+
return 1;
712+
}
713+
714+
/* Is KEX complete? */
715+
if (MSGIDLIMIT_TRANS(msg)) {
716+
if (ssh->isKeying & WOLFSSH_PEER_IS_KEYING) {
717+
/* MSGID_KEXINIT not allowed when keying. */
718+
if (msg == MSGID_KEXINIT) {
719+
WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by %s %s",
720+
msg, "client", "when keying");
721+
return 0;
722+
}
723+
724+
/* Error if expecting a specific message and didn't receive. */
725+
if (ssh->handshake && ssh->handshake->expectMsgId != MSGID_NONE) {
726+
if (msg != ssh->handshake->expectMsgId) {
727+
WLOG(WS_LOG_DEBUG,
728+
"Message ID %u not the expected message %u",
729+
msg, ssh->handshake->expectMsgId);
730+
return 0;
731+
}
732+
else {
733+
/* Got the expected message, clear expectation. */
734+
ssh->handshake->expectMsgId = MSGID_NONE;
735+
return 1;
736+
}
737+
}
738+
}
739+
else {
740+
/* MSGID_KEXINIT only allowed when not keying. */
741+
if (msg == MSGID_KEXINIT) {
742+
return 1;
743+
}
744+
745+
/* All other transport KEX and ALGO messages are not allowed
746+
* when not keying. */
747+
WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by %s %s",
748+
msg, "client", "when not keying");
688749
return 0;
689750
}
690-
/* Explicitly check for the user authentication message that
691-
* only the client sends, it shouldn't receive it. */
692-
if (msg == MSGID_USERAUTH_RESTRICT) {
693-
WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by client "
694-
"during user authentication", msg);
751+
}
752+
753+
/* Is client userauth complete? */
754+
if (ssh->connectState >= CONNECT_KEYED
755+
&& ssh->connectState < CONNECT_SERVER_USERAUTH_ACCEPT_DONE) {
756+
/* The endpoints should not allow message IDs greater than or
757+
* equal to msgid 80 before user authentication is complete.
758+
* Per RFC 4252 section 6. */
759+
if (MSGIDLIMIT_POST_USERAUTH(msg)) {
760+
WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by %s %s",
761+
msg, "client", "before user authentication is complete");
695762
return 0;
696763
}
764+
else if (MSGIDLIMIT_AUTH(msg)) {
765+
return 1;
766+
}
697767
}
698768
else {
699-
if (msg >= MSGID_USERAUTH_RESTRICT && msg < MSGID_USERAUTH_LIMIT) {
700-
WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by client "
701-
"after user authentication", msg);
769+
if (MSGIDLIMIT_POST_USERAUTH(msg)) {
770+
return 1;
771+
}
772+
else if (MSGIDLIMIT_AUTH(msg)) {
773+
WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by %s %s",
774+
msg, "client", "after user authentication");
702775
return 0;
703776
}
704777
}
705-
return 1;
778+
779+
return 0;
706780
}
707781
#endif /* NO_WOLFSSH_CLIENT */
708782

@@ -711,7 +785,7 @@ INLINE static int IsMessageAllowedClient(WOLFSSH *ssh, byte msg)
711785
* Returns 1 if allowed 0 if not allowed. */
712786
INLINE static int IsMessageAllowed(WOLFSSH *ssh, byte msg, byte state)
713787
{
714-
if (state == WS_MSG_SEND && !IsMessageAllowedKeying(ssh, msg)) {
788+
if (!IsMessageAllowedKeying(ssh, msg)) {
715789
return 0;
716790
}
717791

@@ -725,6 +799,7 @@ INLINE static int IsMessageAllowed(WOLFSSH *ssh, byte msg, byte state)
725799
return IsMessageAllowedClient(ssh, msg);
726800
}
727801
#endif /* NO_WOLFSSH_CLIENT */
802+
(void)state;
728803
return 0;
729804
}
730805

@@ -5872,8 +5947,10 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
58725947
ret = GenerateKeys(ssh, hashId, !ssh->handshake->useEccMlKem);
58735948
}
58745949

5875-
if (ret == WS_SUCCESS)
5950+
if (ret == WS_SUCCESS) {
58765951
ret = SendNewKeys(ssh);
5952+
ssh->handshake->expectMsgId = MSGID_NEWKEYS;
5953+
}
58775954

58785955
if (sigKeyBlock_ptr)
58795956
WFREE(sigKeyBlock_ptr, ssh->ctx->heap, DYNTYPE_PRIVKEY);
@@ -10648,8 +10725,9 @@ int SendKexInit(WOLFSSH* ssh)
1064810725
ret = BundlePacket(ssh);
1064910726
}
1065010727

10651-
if (ret == WS_SUCCESS)
10728+
if (ret == WS_SUCCESS) {
1065210729
ret = wolfSSH_SendPacket(ssh);
10730+
}
1065310731

1065410732
if (ret != WS_WANT_WRITE && ret != WS_SUCCESS)
1065510733
PurgePacket(ssh);
@@ -12613,6 +12691,11 @@ int SendKexDhGexRequest(WOLFSSH* ssh)
1261312691
if (ret == WS_SUCCESS)
1261412692
ret = wolfSSH_SendPacket(ssh);
1261512693

12694+
if (ret == WS_SUCCESS) {
12695+
WLOG_EXPECT_MSGID(MSGID_KEXDH_GEX_GROUP);
12696+
ssh->handshake->expectMsgId = MSGID_KEXDH_GEX_GROUP;
12697+
}
12698+
1261612699
WLOG(WS_LOG_DEBUG, "Leaving SendKexDhGexRequest(), ret = %d", ret);
1261712700
return ret;
1261812701
}
@@ -12701,6 +12784,7 @@ int SendKexDhInit(WOLFSSH* ssh)
1270112784
#endif
1270212785
int ret = WS_SUCCESS;
1270312786
byte msgId = MSGID_KEXDH_INIT;
12787+
byte expectMsgId = MSGID_KEXDH_REPLY;
1270412788
byte e[MAX_KEX_KEY_SZ+1]; /* plus 1 in case of padding. */
1270512789
word32 eSz = (word32)sizeof(e);
1270612790
byte ePad = 0;
@@ -12752,6 +12836,7 @@ int SendKexDhInit(WOLFSSH* ssh)
1275212836
generator = ssh->handshake->generator;
1275312837
generatorSz = ssh->handshake->generatorSz;
1275412838
msgId = MSGID_KEXDH_GEX_INIT;
12839+
expectMsgId = MSGID_KEXDH_GEX_REPLY;
1275512840
break;
1275612841
#endif
1275712842
#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256
@@ -12963,6 +13048,11 @@ int SendKexDhInit(WOLFSSH* ssh)
1296313048
if (ret == WS_SUCCESS)
1296413049
ret = wolfSSH_SendPacket(ssh);
1296513050

13051+
if (ret == WS_SUCCESS) {
13052+
WLOG_EXPECT_MSGID(expectMsgId);
13053+
ssh->handshake->expectMsgId = expectMsgId;
13054+
}
13055+
1296613056
WLOG(WS_LOG_DEBUG, "Leaving SendKexDhInit(), ret = %d", ret);
1296713057
return ret;
1296813058
}

wolfssh/internal.h

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,7 @@ typedef struct Keys {
607607

608608

609609
typedef struct HandshakeInfo {
610+
byte expectMsgId;
610611
byte kexId;
611612
byte kexIdGuess;
612613
byte kexHashId;
@@ -1183,6 +1184,8 @@ enum ProcessReplyStates {
11831184

11841185

11851186
enum WS_MessageIds {
1187+
MSGID_NONE = 0,
1188+
11861189
MSGID_DISCONNECT = 1,
11871190
MSGID_IGNORE = 2,
11881191
MSGID_UNIMPLEMENTED = 3,
@@ -1238,19 +1241,56 @@ enum WS_MessageIds {
12381241
};
12391242

12401243

1241-
/* Allows the server to receive up to KEXDH GEX Request during KEX. */
1242-
#define MSGID_KEXDH_LIMIT MSGID_KEXDH_GEX_REQUEST
1243-
1244-
/* The endpoints should not allow message IDs greater than or
1245-
* equal to msgid 80 before user authentication is complete.
1246-
* Per RFC 4252 section 6. */
1247-
#define MSGID_USERAUTH_LIMIT 80
1244+
/* The following message ID ranges are described in RFC 5251, section 7. */
1245+
enum WS_MessageIdLimits {
1246+
/* Transport Layer Protocol: */
1247+
MSGIDLIMIT_TRANS_MIN = 1,
1248+
MSGIDLIMIT_TRANS_GEN_MIN = 1,
1249+
MSGIDLIMIT_TRANS_GEN_MAX = 19,
1250+
MSGIDLIMIT_TRANS_ALGO_MIN = 20,
1251+
MSGIDLIMIT_TRANS_ALGO_MAX = 29,
1252+
MSGIDLIMIT_TRANS_KEX_MIN = 30,
1253+
MSGIDLIMIT_TRANS_KEX_MAX = 49,
1254+
MSGIDLIMIT_TRANS_MAX = 49,
1255+
/* User Authentication Protocol: */
1256+
MSGIDLIMIT_AUTH_MIN = 50,
1257+
MSGIDLIMIT_AUTH_GEN_MIN = 50,
1258+
MSGIDLIMIT_AUTH_GEN_MAX = 59,
1259+
MSGIDLIMIT_AUTH_METH_MIN = 60,
1260+
MSGIDLIMIT_AUTH_METH_MAX = 79,
1261+
MSGIDLIMIT_AUTH_MAX = 79,
1262+
/* Connection Protocol: */
1263+
MSGIDLIMIT_CONN_MIN = 80,
1264+
MSGIDLIMIT_CONN_GEN_MIN = 80,
1265+
MSGIDLIMIT_CONN_GEN_MAX = 89,
1266+
MSGIDLIMIT_CONN_CHAN_MIN = 90,
1267+
MSGIDLIMIT_CONN_CHAN_MAX = 127,
1268+
MSGIDLIMIT_CONN_MAX = 127,
1269+
/* Reserved For Client Protocols: */
1270+
MSGIDLIMIT_RESERVED_MIN = 128,
1271+
MSGIDLIMIT_RESERVED_MAX = 191,
1272+
/* Local Extensions: */
1273+
MSGIDLIMIT_EXTENDED_MIN = 192,
1274+
MSGIDLIMIT_EXTENDED_MAX = 255,
1275+
};
12481276

1249-
/* The client should only send the user auth request message
1250-
* (50), it should not accept it. The server should only receive
1251-
* the user auth request message, it should not accept the other
1252-
* user auth messages, it sends them. (>50) */
1253-
#define MSGID_USERAUTH_RESTRICT 50
1277+
/* Message ID bounds checking. */
1278+
#define MSGIDLIMIT_BOUND(x,y,z) ((x) >= (y) && (x) <= (z))
1279+
#define MSGIDLIMIT_COMP(x,name) \
1280+
MSGIDLIMIT_BOUND((x),MSGIDLIMIT_##name##_MIN,MSGIDLIMIT_##name##_MAX)
1281+
#define MSGIDLIMIT_TRANS(x) MSGIDLIMIT_COMP((x),TRANS)
1282+
#define MSGIDLIMIT_TRANS_GEN(x) MSGIDLIMIT_COMP((x),TRANS_GEN)
1283+
#define MSGIDLIMIT_TRANS_ALGO(x) MSGIDLIMIT_COMP((x),TRANS_ALGO)
1284+
#define MSGIDLIMIT_TRANS_KEX(x) MSGIDLIMIT_COMP((x),TRANS_KEX)
1285+
#define MSGIDLIMIT_AUTH(x) MSGIDLIMIT_COMP((x),AUTH)
1286+
#define MSGIDLIMIT_AUTH_GEN(x) MSGIDLIMIT_COMP((x),AUTH_GEN)
1287+
#define MSGIDLIMIT_AUTH_METH(x) MSGIDLIMIT_COMP((x),AUTH_METH)
1288+
#define MSGIDLIMIT_CONN(x) MSGIDLIMIT_COMP((x),CONN)
1289+
#define MSGIDLIMIT_CONN_GEN(x) MSGIDLIMIT_COMP((x),CONN_GEN)
1290+
#define MSGIDLIMIT_CONN_CHAN(x) MSGIDLIMIT_COMP((x),CONN_CHAN)
1291+
#define MSGIDLIMIT_RESERVED(x) MSGIDLIMIT_COMP((x),RESERVED)
1292+
#define MSGIDLIMIT_EXTENDED(x) MSGIDLIMIT_COMP((x),EXTENDED)
1293+
#define MSGIDLIMIT_POST_USERAUTH(x) ((x) >= MSGIDLIMIT_CONN_MIN)
12541294

12551295

12561296
#define CHANNEL_EXTENDED_DATA_STDERR WOLFSSH_EXT_DATA_STDERR

wolfssh/log.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ WOLFSSH_API void wolfSSH_Log(enum wolfSSH_LogLevel,
8181
#define WLOG(...) WC_DO_NOTHING
8282
#endif
8383

84+
#define WLOG_EXPECT_MSGID(x) WLOG(WS_LOG_DEBUG, "Expecting message %d", (x))
85+
8486
#ifdef __cplusplus
8587
}
8688
#endif

0 commit comments

Comments
 (0)