@@ -206,6 +206,18 @@ static word32 BuildChannelOpenPacket(const char* type, word32 peerChannelId,
206206 return WrapPacket (MSGID_CHANNEL_OPEN , payload , idx , out , outSz );
207207}
208208
209+ static word32 BuildDisconnectPacket (word32 reason , byte * out , word32 outSz )
210+ {
211+ byte payload [64 ];
212+ word32 idx = 0 ;
213+
214+ idx = AppendUint32 (payload , sizeof (payload ), idx , reason );
215+ idx = AppendUint32 (payload , sizeof (payload ), idx , 0 );
216+ idx = AppendUint32 (payload , sizeof (payload ), idx , 0 );
217+
218+ return WrapPacket (MSGID_DISCONNECT , payload , idx , out , outSz );
219+ }
220+
209221#ifdef WOLFSSH_FWD
210222static word32 BuildDirectTcpipExtra (const char * host , word32 hostPort ,
211223 const char * origin , word32 originPort , byte * out , word32 outSz )
@@ -906,6 +918,8 @@ static void AssertChannelOpenFailResponse(const ChannelOpenHarness* harness,
906918 msgId = ParseMsgId (harness -> io .out , harness -> io .outSz );
907919 AssertIntEQ (msgId , MSGID_CHANNEL_OPEN_FAIL );
908920 AssertFalse (msgId == MSGID_REQUEST_FAILURE );
921+ AssertIntEQ (harness -> ssh -> channelListSz , 0 );
922+ AssertTrue (harness -> ssh -> channelList == NULL );
909923}
910924
911925static int RejectChannelOpenCb (WOLFSSH_CHANNEL * channel , void * ctx )
@@ -1207,6 +1221,100 @@ static void TestKexInitRejectedWhenKeying(WOLFSSH* ssh)
12071221 AssertFalse (allowed );
12081222}
12091223
1224+ static void TestDisconnectSetsDisconnectError (void )
1225+ {
1226+ WOLFSSH_CTX * ctx ;
1227+ WOLFSSH * ssh ;
1228+ MemIo io ;
1229+ byte in [128 ];
1230+ byte out [32 ];
1231+ word32 inSz ;
1232+ int ret ;
1233+
1234+ ctx = wolfSSH_CTX_new (WOLFSSH_ENDPOINT_CLIENT , NULL );
1235+ AssertNotNull (ctx );
1236+
1237+ wolfSSH_SetIORecv (ctx , MemRecv );
1238+ wolfSSH_SetIOSend (ctx , MemSend );
1239+
1240+ ssh = wolfSSH_new (ctx );
1241+ AssertNotNull (ssh );
1242+
1243+ inSz = BuildDisconnectPacket (WOLFSSH_DISCONNECT_BY_APPLICATION ,
1244+ in , sizeof (in ));
1245+ MemIoInit (& io , in , inSz , out , sizeof (out ));
1246+ wolfSSH_SetIOReadCtx (ssh , & io );
1247+ wolfSSH_SetIOWriteCtx (ssh , & io );
1248+
1249+ ret = DoReceive (ssh );
1250+ AssertIntEQ (ret , WS_FATAL_ERROR );
1251+ AssertIntEQ (wolfSSH_get_error (ssh ), WS_DISCONNECT );
1252+ AssertIntEQ (io .inOff , io .inSz );
1253+
1254+ wolfSSH_free (ssh );
1255+ wolfSSH_CTX_free (ctx );
1256+ }
1257+
1258+ #ifdef WOLFSSH_SFTP
1259+ static void TestOct2DecRejectsInvalidNonLeadingDigit (void )
1260+ {
1261+ WOLFSSH_CTX * ctx ;
1262+ WOLFSSH * ssh ;
1263+ byte invalidOct [] = "0718" ;
1264+ int ret ;
1265+
1266+ ctx = wolfSSH_CTX_new (WOLFSSH_ENDPOINT_CLIENT , NULL );
1267+ AssertNotNull (ctx );
1268+
1269+ ssh = wolfSSH_new (ctx );
1270+ AssertNotNull (ssh );
1271+
1272+ ret = wolfSSH_oct2dec (ssh , invalidOct , (word32 )WSTRLEN ((char * )invalidOct ));
1273+ AssertIntEQ (ret , WS_BAD_ARGUMENT );
1274+
1275+ wolfSSH_free (ssh );
1276+ wolfSSH_CTX_free (ctx );
1277+ }
1278+
1279+ #ifdef WOLFSSH_STOREHANDLE
1280+ static void TestSftpRemoveHandleHeadUpdate (void )
1281+ {
1282+ WOLFSSH_CTX * ctx ;
1283+ WOLFSSH * ssh ;
1284+ byte firstHandle [] = { 0x01 , 0x02 , 0x03 , 0x04 };
1285+ byte secondHandle [] = { 0x10 , 0x20 , 0x30 , 0x40 };
1286+ int ret ;
1287+
1288+ ctx = wolfSSH_CTX_new (WOLFSSH_ENDPOINT_CLIENT , NULL );
1289+ AssertNotNull (ctx );
1290+
1291+ ssh = wolfSSH_new (ctx );
1292+ AssertNotNull (ssh );
1293+
1294+ ret = SFTP_AddHandleNode (ssh , firstHandle , sizeof (firstHandle ), "first" );
1295+ AssertIntEQ (ret , WS_SUCCESS );
1296+
1297+ ret = SFTP_AddHandleNode (ssh , secondHandle , sizeof (secondHandle ), "second" );
1298+ AssertIntEQ (ret , WS_SUCCESS );
1299+
1300+ ret = SFTP_RemoveHandleNode (ssh , secondHandle , sizeof (secondHandle ));
1301+ AssertIntEQ (ret , WS_SUCCESS );
1302+
1303+ AssertNotNull (ssh -> handleList );
1304+ AssertTrue (ssh -> handleList -> prev == NULL );
1305+ AssertIntEQ (ssh -> handleList -> handleSz , (int )sizeof (firstHandle ));
1306+ AssertIntEQ (WMEMCMP (ssh -> handleList -> handle , firstHandle ,
1307+ sizeof (firstHandle )), 0 );
1308+
1309+ ret = SFTP_RemoveHandleNode (ssh , firstHandle , sizeof (firstHandle ));
1310+ AssertIntEQ (ret , WS_SUCCESS );
1311+
1312+ wolfSSH_free (ssh );
1313+ wolfSSH_CTX_free (ctx );
1314+ }
1315+ #endif
1316+ #endif
1317+
12101318/* Ensure client buffer cleanup tolerates multiple invocations after allocs. */
12111319static void TestClientBuffersIdempotent (void )
12121320{
@@ -1378,6 +1486,13 @@ static void TestSftpBufferSendPendingOutput(void)
13781486 wolfSSH_free (ssh );
13791487 wolfSSH_CTX_free (ctx );
13801488}
1489+ #if defined(WOLFSSL_NUCLEUS ) && !defined(NO_WOLFSSH_MKTIME )
1490+ static void TestNucleusMonthConversion (void )
1491+ {
1492+ AssertIntEQ (wolfSSH_TestNucleusMonthFromDate ((word16 )(1U << 5 )), 0 );
1493+ AssertIntEQ (wolfSSH_TestNucleusMonthFromDate ((word16 )(12U << 5 )), 11 );
1494+ }
1495+ #endif
13811496#endif /* WOLFSSH_SFTP */
13821497
13831498
@@ -1415,6 +1530,7 @@ int main(int argc, char** argv)
14151530 TestAgentChannelNullAgentSendsOpenFail ();
14161531#endif
14171532 TestKexInitRejectedWhenKeying (ssh );
1533+ TestDisconnectSetsDisconnectError ();
14181534 TestClientBuffersIdempotent ();
14191535 TestPasswordEofNoCrash ();
14201536#ifndef WOLFSSH_TEST_BLOCK
@@ -1431,7 +1547,14 @@ int main(int argc, char** argv)
14311547#endif
14321548
14331549#ifdef WOLFSSH_SFTP
1550+ TestOct2DecRejectsInvalidNonLeadingDigit ();
1551+ #ifdef WOLFSSH_STOREHANDLE
1552+ TestSftpRemoveHandleHeadUpdate ();
1553+ #endif
14341554 TestSftpBufferSendPendingOutput ();
1555+ #if defined(WOLFSSL_NUCLEUS ) && !defined(NO_WOLFSSH_MKTIME )
1556+ TestNucleusMonthConversion ();
1557+ #endif
14351558#endif
14361559
14371560 /* TODO: add app-level regressions that simulate stdin EOF/password
0 commit comments