From b57dd6b245c5c352299f68ebd2a7bdae4092683a Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 17 Apr 2023 20:14:45 +0200 Subject: [PATCH] [P2P, Testing] Ensure node refuses unencrypted connections (#598) ## Description Libp2p supports transport security via its [noise](https://noiseprotocol.org/) and [TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security) and defaults to requiring peers to support at least one transport security protocol. This PR adds a test which asserts this behavior by starting up a P2P module and attempting to connect to it via a separate, insecure libp2p host. ## Issue Fixes #544 ## Type of change Please mark the relevant option(s): - [ ] New feature, functionality or library - [ ] Bug fix - [ ] Code health or cleanup - [ ] Major breaking change - [ ] Documentation - [x] Other: Regression test ## List of changes - Added a test which asserts that transport encryption is required (i.e. unencrypted connections are refused) ## Testing - [x] `make develop_test` - [ ] ~~[LocalNet](https://github.com/pokt-network/pocket/blob/main/docs/development/README.md) w/ all of the steps outlined in the `README`~~ ## Required Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have added, or updated, [`godoc` format comments](https://go.dev/blog/godoc) on touched members (see: [tip.golang.org/doc/comment](https://tip.golang.org/doc/comment)) - [ ] I have tested my changes using the available tooling - [ ] I have updated the corresponding CHANGELOG ### If Applicable Checklist - [ ] I have updated the corresponding README(s); local and/or global - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] I have added, or updated, [mermaid.js](https://mermaid-js.github.io) diagrams in the corresponding README(s) - [ ] I have added, or updated, documentation and [mermaid.js](https://mermaid-js.github.io) diagrams in `shared/docs/*` if I updated `shared/*`README(s) --------- Co-authored-by: Daniel Olshansky Co-authored-by: Dmitry K Co-authored-by: github-actions --- p2p/CHANGELOG.md | 4 ++ p2p/transport_encryption_test.go | 110 +++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 p2p/transport_encryption_test.go diff --git a/p2p/CHANGELOG.md b/p2p/CHANGELOG.md index a7232ef1e..31167fc0b 100644 --- a/p2p/CHANGELOG.md +++ b/p2p/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.0.0.42] - 2023-04-17 + +- Added a test which asserts that transport encryption is required (i.e. unencrypted connections are refused) + ## [0.0.0.41] - 2023-04-17 - Moved peer & url conversion utils to `p2p/utils` package diff --git a/p2p/transport_encryption_test.go b/p2p/transport_encryption_test.go new file mode 100644 index 000000000..c897224ac --- /dev/null +++ b/p2p/transport_encryption_test.go @@ -0,0 +1,110 @@ +package p2p + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/golang/mock/gomock" + "github.com/libp2p/go-libp2p" + "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/require" + + "github.com/pokt-network/pocket/p2p/protocol" + typesP2P "github.com/pokt-network/pocket/p2p/types" + "github.com/pokt-network/pocket/p2p/utils" + "github.com/pokt-network/pocket/runtime/configs" + "github.com/pokt-network/pocket/runtime/configs/types" + "github.com/pokt-network/pocket/runtime/defaults" + cryptoPocket "github.com/pokt-network/pocket/shared/crypto" + "github.com/pokt-network/pocket/shared/modules" + mockModules "github.com/pokt-network/pocket/shared/modules/mocks" +) + +func TestP2pModule_Insecure_Error(t *testing.T) { + // TECHDEBT(#609): refactor mock setup with similar test utilities. + ctrl := gomock.NewController(t) + hostname := "127.0.0.1" + + privKey := cryptoPocket.GetPrivKeySeed(1) + + mockConsensusModule := mockModules.NewMockConsensusModule(ctrl) + mockConsensusModule.EXPECT().CurrentHeight().Return(uint64(1)).AnyTimes() + + runtimeMgrMock := mockModules.NewMockRuntimeMgr(ctrl) + runtimeMgrMock.EXPECT().GetConfig().Return(&configs.Config{ + PrivateKey: privKey.String(), + P2P: &configs.P2PConfig{ + PrivateKey: privKey.String(), + Hostname: hostname, + Port: defaults.DefaultP2PPort, + ConnectionType: types.ConnectionType_TCPConnection, + }, + }).AnyTimes() + + timeSeriesAgentMock := prepareNoopTimeSeriesAgentMock(t) + eventMetricsAgentMock := mockModules.NewMockEventMetricsAgent(ctrl) + eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + + telemetryMock := mockModules.NewMockTelemetryModule(ctrl) + telemetryMock.EXPECT().GetTimeSeriesAgent().Return(timeSeriesAgentMock).AnyTimes() + telemetryMock.EXPECT().GetEventMetricsAgent().Return(eventMetricsAgentMock).AnyTimes() + telemetryMock.EXPECT().GetModuleName().Return(modules.TelemetryModuleName).AnyTimes() + + busMock := createMockBus(t, runtimeMgrMock) + busMock.EXPECT().GetConsensusModule().Return(mockConsensusModule).AnyTimes() + busMock.EXPECT().GetRuntimeMgr().Return(runtimeMgrMock).AnyTimes() + busMock.EXPECT().GetTelemetryModule().Return(telemetryMock).AnyTimes() + + genesisStateMock := createMockGenesisState(keys[:1]) + persistenceMock := preparePersistenceMock(t, busMock, genesisStateMock) + busMock.EXPECT().GetPersistenceModule().Return(persistenceMock).AnyTimes() + + telemetryMock.EXPECT().GetBus().Return(busMock).AnyTimes() + telemetryMock.EXPECT().SetBus(busMock).AnyTimes() + + p2pMod, err := Create(busMock) + require.NoError(t, err) + + err = p2pMod.Start() + require.NoError(t, err) + + t.Cleanup(func() { + err = p2pMod.Stop() + require.NoError(t, err) + }) + + // Setup cleartext transport node + clearNodeMultiAddrStr := fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", defaults.DefaultP2PPort+1) + clearNodeAddr, err := multiaddr.NewMultiaddr(clearNodeMultiAddrStr) + require.NoError(t, err) + + clearNode, err := libp2p.New(libp2p.NoSecurity, libp2p.ListenAddrs(clearNodeAddr)) + require.NoError(t, err) + + t.Cleanup(func() { + err := clearNode.Close() + require.NoError(t, err) + }) + + p2pModPeer := &typesP2P.NetworkPeer{ + PublicKey: privKey.PublicKey(), + Address: privKey.Address(), + ServiceURL: fmt.Sprintf("%s:%d", hostname, defaults.DefaultP2PPort), + } + + libp2pPeerInfo, err := utils.Libp2pAddrInfoFromPeer(p2pModPeer) + require.NoError(t, err) + + libp2pPubKey, err := utils.Libp2pPublicKeyFromPeer(p2pModPeer) + require.NoError(t, err) + + clearNode.Peerstore().AddAddrs(libp2pPeerInfo.ID, libp2pPeerInfo.Addrs, time.Hour) + err = clearNode.Peerstore().AddPubKey(libp2pPeerInfo.ID, libp2pPubKey) + require.NoError(t, err) + + ctx := context.Background() + _, err = clearNode.NewStream(ctx, libp2pPeerInfo.ID, protocol.PoktProtocolID) + require.ErrorContains(t, err, "failed to negotiate security protocol: protocols not supported:") +}