@@ -307,3 +307,90 @@ func GenKeyPair(t *testing.T, seed string) (cipher.PubKey, cipher.SecKey) {
307307 require .NoError (t , err )
308308 return pk , sk
309309}
310+
311+ // TestInvalidPublicKeyNoPanic tests that the server doesn't crash when receiving
312+ // a connection with an invalid public key during the noise handshake.
313+ // This is a regression test for a 2+ year old bug where invalid public keys
314+ // would cause the server to panic and crash.
315+ func TestInvalidPublicKeyNoPanic (t * testing.T ) {
316+ // Prepare mock discovery.
317+ dc := disc .NewMock (0 )
318+ const maxSessions = 10
319+
320+ // Prepare dmsg server.
321+ pkSrv , skSrv := GenKeyPair (t , "server" )
322+ srvConf := & ServerConfig {
323+ MaxSessions : maxSessions ,
324+ UpdateInterval : 0 ,
325+ }
326+ srv := NewServer (pkSrv , skSrv , dc , srvConf , nil )
327+ srv .SetLogger (logging .MustGetLogger ("server" ))
328+ lisSrv , err := net .Listen ("tcp" , "" )
329+ require .NoError (t , err )
330+
331+ // Serve dmsg server.
332+ chSrv := make (chan error , 1 )
333+ go func () { chSrv <- srv .Serve (lisSrv , "" ) }() //nolint:errcheck
334+
335+ // Give server time to start
336+ time .Sleep (500 * time .Millisecond )
337+
338+ // Attempt to send a handshake with invalid public key data
339+ // This simulates a malicious or buggy client
340+ t .Run ("invalid_pubkey_handshake" , func (t * testing.T ) {
341+ conn , err := net .Dial ("tcp" , lisSrv .Addr ().String ())
342+ require .NoError (t , err )
343+ defer func () { _ = conn .Close () }() //nolint:errcheck
344+
345+ // Send invalid noise handshake data (contains invalid public key)
346+ // In a real noise handshake, the public key would be embedded in the message
347+ // We send malformed data that will trigger invalid public key error
348+ invalidData := make ([]byte , 100 )
349+ // Write some invalid data that looks like a handshake but has invalid key
350+ copy (invalidData , []byte {0x00 , 0x32 }) // frame length prefix (50 bytes)
351+ // Rest is invalid/random data that will fail public key validation
352+ for i := 2 ; i < len (invalidData ); i ++ {
353+ invalidData [i ] = byte (i ) // deterministic but invalid
354+ }
355+
356+ _ , err = conn .Write (invalidData )
357+ // Write may succeed, but the server should handle the invalid data gracefully
358+ if err != nil {
359+ t .Logf ("Write failed (expected): %v" , err )
360+ }
361+
362+ // Give server time to process the invalid handshake
363+ time .Sleep (500 * time .Millisecond )
364+
365+ // Read to see if connection was closed (expected behavior)
366+ buf := make ([]byte , 10 )
367+ _ = conn .SetReadDeadline (time .Now ().Add (1 * time .Second )) //nolint:errcheck
368+ _ , _ = conn .Read (buf ) //nolint:errcheck
369+ // We expect the connection to be closed or timeout
370+ // The important thing is the server didn't crash
371+ })
372+
373+ // Verify server is still running and can accept valid connections
374+ t .Run ("valid_connection_after_invalid" , func (t * testing.T ) {
375+ // Prepare and serve a valid dmsg client
376+ pkA , skA := GenKeyPair (t , "client A" )
377+ clientA := NewClient (pkA , skA , dc , DefaultConfig ())
378+ clientA .SetLogger (logging .MustGetLogger ("client_A" ))
379+ go clientA .Serve (context .Background ())
380+
381+ // Wait for client to register
382+ time .Sleep (time .Second * 2 )
383+
384+ // Attempt to use the client - if server crashed, this will fail
385+ lis , err := clientA .Listen (8081 )
386+ require .NoError (t , err , "Server should still be running and accept valid connections" )
387+
388+ // Clean up
389+ require .NoError (t , lis .Close ())
390+ require .NoError (t , clientA .Close ())
391+ })
392+
393+ // Closing logic - server should still be healthy
394+ require .NoError (t , srv .Close ())
395+ require .NoError (t , <- chSrv )
396+ }
0 commit comments