@@ -898,6 +898,162 @@ TEST(encode_connect_flags_lwt_qos1_retain)
898898 ASSERT_EQ (0 , flags & MQTT_CONNECT_FLAG_CLEAN_SESSION );
899899}
900900
901+ /* ============================================================================
902+ * MqttDecode_Connect (broker-side)
903+ * ============================================================================ */
904+
905+ #ifdef WOLFMQTT_BROKER
906+ /* (a) Valid v3.1.1 CONNECT with username + password: decoder must surface both
907+ * credential strings and the session/keep-alive fields. */
908+ TEST (decode_connect_v311_username_password )
909+ {
910+ byte buf [256 ];
911+ MqttConnect enc , dec ;
912+ int enc_len , dec_len ;
913+
914+ XMEMSET (& enc , 0 , sizeof (enc ));
915+ enc .protocol_level = MQTT_CONNECT_PROTOCOL_LEVEL_4 ;
916+ enc .client_id = "test_client" ;
917+ enc .username = "user" ;
918+ enc .password = "pass" ;
919+ enc .clean_session = 1 ;
920+ enc .keep_alive_sec = 60 ;
921+
922+ enc_len = MqttEncode_Connect (buf , (int )sizeof (buf ), & enc );
923+ ASSERT_TRUE (enc_len > 0 );
924+
925+ XMEMSET (& dec , 0 , sizeof (dec ));
926+ dec_len = MqttDecode_Connect (buf , enc_len , & dec );
927+ ASSERT_EQ (enc_len , dec_len );
928+ ASSERT_EQ (MQTT_CONNECT_PROTOCOL_LEVEL_4 , dec .protocol_level );
929+ ASSERT_EQ (1 , dec .clean_session );
930+ ASSERT_EQ (0 , dec .enable_lwt );
931+ ASSERT_EQ (60 , dec .keep_alive_sec );
932+ ASSERT_NOT_NULL (dec .client_id );
933+ ASSERT_EQ (0 , XMEMCMP (dec .client_id , "test_client" ,
934+ XSTRLEN ("test_client" )));
935+ ASSERT_NOT_NULL (dec .username );
936+ ASSERT_EQ (0 , XMEMCMP (dec .username , "user" , 4 ));
937+ ASSERT_NOT_NULL (dec .password );
938+ ASSERT_EQ (0 , XMEMCMP (dec .password , "pass" , 4 ));
939+ }
940+
941+ /* (b) CONNECT with USERNAME/PASSWORD flags clear: decoder must NULL the
942+ * credential fields so the caller never observes uninitialized rx_buf
943+ * bytes as credentials. Pre-poison the struct to make the clearing visible. */
944+ TEST (decode_connect_v311_no_credentials )
945+ {
946+ byte buf [256 ];
947+ MqttConnect enc , dec ;
948+ int enc_len , dec_len ;
949+
950+ XMEMSET (& enc , 0 , sizeof (enc ));
951+ enc .protocol_level = MQTT_CONNECT_PROTOCOL_LEVEL_4 ;
952+ enc .client_id = "c1" ;
953+ enc .clean_session = 1 ;
954+
955+ enc_len = MqttEncode_Connect (buf , (int )sizeof (buf ), & enc );
956+ ASSERT_TRUE (enc_len > 0 );
957+
958+ XMEMSET (& dec , 0 , sizeof (dec ));
959+ dec .username = (const char * )0x1 ;
960+ dec .password = (const char * )0x1 ;
961+ dec_len = MqttDecode_Connect (buf , enc_len , & dec );
962+ ASSERT_EQ (enc_len , dec_len );
963+ ASSERT_NULL (dec .username );
964+ ASSERT_NULL (dec .password );
965+ }
966+
967+ /* (c) Wrong protocol name ("MQT_" with correct length=4) must be rejected
968+ * with MQTT_CODE_ERROR_MALFORMED_DATA. Catches an '||' -> '&&' mutation of
969+ * the protocol-name guard, where an acceptance would require both the
970+ * length and name to simultaneously be wrong. */
971+ TEST (decode_connect_wrong_protocol_name )
972+ {
973+ byte buf [] = {
974+ 0x10 , 0x10 , /* CONNECT, remain_len = 16 */
975+ 0x00 , 0x04 , /* protocol name length = 4 */
976+ 'M' , 'Q' , 'T' , '_' , /* WRONG protocol name */
977+ 0x04 , /* protocol level = v3.1.1 */
978+ 0x02 , /* flags: clean_session */
979+ 0x00 , 0x3C , /* keep alive = 60 */
980+ 0x00 , 0x04 , 'c' , 'i' , 'd' , '1' /* client_id "cid1" */
981+ };
982+ MqttConnect dec ;
983+ int rc ;
984+
985+ XMEMSET (& dec , 0 , sizeof (dec ));
986+ rc = MqttDecode_Connect (buf , (int )sizeof (buf ), & dec );
987+ ASSERT_EQ (MQTT_CODE_ERROR_MALFORMED_DATA , rc );
988+ }
989+
990+ /* (d) Wrong protocol length (3 instead of 4) must be rejected with
991+ * MQTT_CODE_ERROR_MALFORMED_DATA. Paired with (c) this covers both sides
992+ * of the length/name disjunction. */
993+ TEST (decode_connect_wrong_protocol_length )
994+ {
995+ byte buf [] = {
996+ 0x10 , 0x10 ,
997+ 0x00 , 0x03 , /* WRONG protocol name length = 3 */
998+ 'M' , 'Q' , 'T' , 'T' ,
999+ 0x04 ,
1000+ 0x02 ,
1001+ 0x00 , 0x3C ,
1002+ 0x00 , 0x04 , 'c' , 'i' , 'd' , '1'
1003+ };
1004+ MqttConnect dec ;
1005+ int rc ;
1006+
1007+ XMEMSET (& dec , 0 , sizeof (dec ));
1008+ rc = MqttDecode_Connect (buf , (int )sizeof (buf ), & dec );
1009+ ASSERT_EQ (MQTT_CODE_ERROR_MALFORMED_DATA , rc );
1010+ }
1011+
1012+ /* (e) CONNECT with WILL_FLAG set: decoder must set enable_lwt=1 and populate
1013+ * lwt_msg topic/payload/qos/retain from the flags and payload. Catches a
1014+ * mutation that flips the enable_lwt boolean, which would drop LWT decoding
1015+ * entirely. */
1016+ TEST (decode_connect_v311_with_lwt )
1017+ {
1018+ byte buf [256 ];
1019+ byte lwt_payload [] = { 'b' , 'y' , 'e' };
1020+ MqttConnect enc , dec ;
1021+ MqttMessage enc_lwt , dec_lwt ;
1022+ int enc_len , dec_len ;
1023+
1024+ XMEMSET (& enc , 0 , sizeof (enc ));
1025+ XMEMSET (& enc_lwt , 0 , sizeof (enc_lwt ));
1026+ enc .protocol_level = MQTT_CONNECT_PROTOCOL_LEVEL_4 ;
1027+ enc .client_id = "c1" ;
1028+ enc .enable_lwt = 1 ;
1029+ enc .lwt_msg = & enc_lwt ;
1030+ enc_lwt .topic_name = "will/topic" ;
1031+ enc_lwt .buffer = lwt_payload ;
1032+ enc_lwt .total_len = (word32 )sizeof (lwt_payload );
1033+ enc_lwt .qos = MQTT_QOS_1 ;
1034+ enc_lwt .retain = 1 ;
1035+
1036+ enc_len = MqttEncode_Connect (buf , (int )sizeof (buf ), & enc );
1037+ ASSERT_TRUE (enc_len > 0 );
1038+
1039+ XMEMSET (& dec , 0 , sizeof (dec ));
1040+ XMEMSET (& dec_lwt , 0 , sizeof (dec_lwt ));
1041+ dec .lwt_msg = & dec_lwt ;
1042+ dec_len = MqttDecode_Connect (buf , enc_len , & dec );
1043+ ASSERT_EQ (enc_len , dec_len );
1044+ ASSERT_EQ (1 , dec .enable_lwt );
1045+ ASSERT_EQ ((int )MQTT_QOS_1 , (int )dec_lwt .qos );
1046+ ASSERT_EQ (1 , dec_lwt .retain );
1047+ ASSERT_EQ ((int )XSTRLEN ("will/topic" ), (int )dec_lwt .topic_name_len );
1048+ ASSERT_EQ (0 , XMEMCMP (dec_lwt .topic_name , "will/topic" ,
1049+ XSTRLEN ("will/topic" )));
1050+ ASSERT_EQ ((word32 )sizeof (lwt_payload ), dec_lwt .total_len );
1051+ ASSERT_EQ ((word32 )sizeof (lwt_payload ), dec_lwt .buffer_len );
1052+ ASSERT_NOT_NULL (dec_lwt .buffer );
1053+ ASSERT_EQ (0 , XMEMCMP (dec_lwt .buffer , lwt_payload , sizeof (lwt_payload )));
1054+ }
1055+ #endif /* WOLFMQTT_BROKER */
1056+
9011057/* ============================================================================
9021058 * QoS 2 next-ack arithmetic (PUBLISH_REC -> REL -> COMP)
9031059 * ============================================================================ */
@@ -1232,6 +1388,15 @@ void run_mqtt_packet_tests(void)
12321388 RUN_TEST (encode_connect_flags_username_only );
12331389 RUN_TEST (encode_connect_flags_lwt_qos1_retain );
12341390
1391+ #ifdef WOLFMQTT_BROKER
1392+ /* MqttDecode_Connect */
1393+ RUN_TEST (decode_connect_v311_username_password );
1394+ RUN_TEST (decode_connect_v311_no_credentials );
1395+ RUN_TEST (decode_connect_wrong_protocol_name );
1396+ RUN_TEST (decode_connect_wrong_protocol_length );
1397+ RUN_TEST (decode_connect_v311_with_lwt );
1398+ #endif
1399+
12351400 /* QoS 2 ack arithmetic */
12361401 RUN_TEST (qos2_ack_arithmetic );
12371402
0 commit comments