package negotiation import ( "context" "crypto/rand" "testing" "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/p2p/security/noise" tls "github.com/libp2p/go-libp2p/p2p/security/tls" "github.com/libp2p/go-libp2p/p2p/transport/tcp" "github.com/stretchr/testify/require" ) var ( noiseOpt = libp2p.Security("/noise", noise.New) tlsOpt = libp2p.Security("/tls", tls.New) ) func TestSecurityNegotiation(t *testing.T) { testcases := []testcase{ { Name: "server and client have the same preference", ServerPreference: []libp2p.Option{tlsOpt, noiseOpt}, ClientPreference: []libp2p.Option{tlsOpt, noiseOpt}, Expected: "/tls", }, { Name: "client only supports one security", ServerPreference: []libp2p.Option{tlsOpt, noiseOpt}, ClientPreference: []libp2p.Option{noiseOpt}, Expected: "/noise", }, { Name: "server only supports one security", ServerPreference: []libp2p.Option{noiseOpt}, ClientPreference: []libp2p.Option{tlsOpt, noiseOpt}, Expected: "/noise", }, { Name: "no overlap", ServerPreference: []libp2p.Option{noiseOpt}, ClientPreference: []libp2p.Option{tlsOpt}, Error: "failed to negotiate security protocol: protocols not supported", }, } clientID, _, err := crypto.GenerateEd25519Key(rand.Reader) require.NoError(t, err) serverID, _, err := crypto.GenerateEd25519Key(rand.Reader) require.NoError(t, err) for _, tc := range testcases { tc := tc t.Run(tc.Name, func(t *testing.T) { server, err := libp2p.New( libp2p.Identity(serverID), libp2p.ChainOptions(tc.ServerPreference...), libp2p.Transport(tcp.NewTCPTransport), libp2p.ListenAddrStrings("/ip4/127.0.0.1/tcp/0"), ) require.NoError(t, err) client, err := libp2p.New( libp2p.Identity(clientID), libp2p.ChainOptions(tc.ClientPreference...), libp2p.Transport(tcp.NewTCPTransport), libp2p.NoListenAddrs, ) require.NoError(t, err) err = client.Connect(context.Background(), peer.AddrInfo{ID: server.ID(), Addrs: server.Addrs()}) if tc.Error != "" { require.Error(t, err) require.ErrorContains(t, err, tc.Error) return } require.NoError(t, err) conns := client.Network().ConnsToPeer(server.ID()) require.Len(t, conns, 1, "expected exactly one connection") require.Equal(t, tc.Expected, conns[0].ConnState().Security) }) } }