From c33d8a83531062b479f5a59345901c0dd5376001 Mon Sep 17 00:00:00 2001 From: Raghav Gulati Date: Tue, 7 May 2019 09:56:09 -0700 Subject: [PATCH] Add test for improperly signed message Test the case where an adversarial peer signs a message with a key they didn't originally register with. First, we test that an adversarial peer will allow the message to pass through validation as they turn off strict verification (putting themselves at risk), but an honest peer with strict verification on will never see the message! --- floodsub_test.go | 127 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 121 insertions(+), 6 deletions(-) diff --git a/floodsub_test.go b/floodsub_test.go index d9fb732..40fe28b 100644 --- a/floodsub_test.go +++ b/floodsub_test.go @@ -12,10 +12,11 @@ import ( host "github.com/libp2p/go-libp2p-host" peer "github.com/libp2p/go-libp2p-peer" + protocol "github.com/libp2p/go-libp2p-protocol" swarmt "github.com/libp2p/go-libp2p-swarm/testing" + //bhost "github.com/libp2p/go-libp2p/p2p/host/basic" bhost "github.com/libp2p/go-libp2p-blankhost" - "github.com/libp2p/go-libp2p-protocol" ) func checkMessageRouting(t *testing.T, topic string, pubs []*PubSub, subs []*Subscription) { @@ -90,14 +91,18 @@ func connectAll(t *testing.T, hosts []host.Host) { } } +func getPubsub(ctx context.Context, h host.Host, opts ...Option) *PubSub { + ps, err := NewFloodSub(ctx, h, opts...) + if err != nil { + panic(err) + } + return ps +} + func getPubsubs(ctx context.Context, hs []host.Host, opts ...Option) []*PubSub { var psubs []*PubSub for _, h := range hs { - ps, err := NewFloodSub(ctx, h, opts...) - if err != nil { - panic(err) - } - psubs = append(psubs, ps) + psubs = append(psubs, getPubsub(ctx, h, opts...)) } return psubs } @@ -943,3 +948,113 @@ func TestWithSigning(t *testing.T) { t.Fatalf("unexpected data: %s", string(msg.Data)) } } + +func TestImproperlySignedMessageNotRelayed(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + hosts := getNetHosts(t, ctx, 2) + adversarialPeer := hosts[0] + honestPeer := hosts[1] + + // The adversary enables signing, but disables verification to let through + // an incorrectly signed message. + adversaryPubSub := getPubsub( + ctx, + adversarialPeer, + WithMessageSigning(true), + WithStrictSignatureVerification(false), + ) + honestPubSub := getPubsub( + ctx, + honestPeer, + WithStrictSignatureVerification(true), + ) + + connect(t, hosts[0], hosts[1]) + + var ( + topic = "foobar" + correctMessage = []byte("this is a correct message") + incorrectMessage = []byte("this is the incorrect message") + ) + + _, err := adversaryPubSub.Subscribe(topic) + if err != nil { + t.Fatal(err) + } + + adversarialPeerSubscription, err := adversaryPubSub.Subscribe(topic) + if err != nil { + t.Fatal(err) + } + honestPeerSubscription, err := honestPubSub.Subscribe(topic) + if err != nil { + t.Fatal(err) + } + time.Sleep(time.Millisecond * 10) + + // First the adversary sends the correct message. + err = adversaryPubSub.Publish(topic, correctMessage) + if err != nil { + t.Fatal(err) + } + + // Change the sign key for the adversarial peer, and send the second message. + adversaryPubSub.signID = honestPubSub.signID + adversaryPubSub.signKey = honestPubSub.host.Peerstore().PrivKey(honestPubSub.signID) + err = adversaryPubSub.Publish(topic, incorrectMessage) + if err != nil { + t.Fatal(err) + } + + var adversaryMessages []*Message + adversaryContext, adversaryCancel := context.WithCancel(ctx) + go func(ctx context.Context) { + for { + select { + case <-ctx.Done(): + return + default: + msg, err := adversarialPeerSubscription.Next(ctx) + if err != nil { + return + } + adversaryMessages = append(adversaryMessages, msg) + } + } + }(adversaryContext) + + <-time.After(2 * time.Second) + adversaryCancel() + + if len(adversaryMessages) != 2 { + t.Fatalf("got %d messages, expected 2", len(adversaryMessages)) + } + + // the honest peer's validation process will drop the message; + // next will never furnish the incorrect message. + var honestPeerMessages []*Message + honestPeerContext, honestPeerCancel := context.WithCancel(ctx) + go func(ctx context.Context) { + for { + select { + case <-ctx.Done(): + return + default: + msg, err := honestPeerSubscription.Next(ctx) + if err != nil { + return + } + honestPeerMessages = append(honestPeerMessages, msg) + } + } + }(honestPeerContext) + + <-time.After(2 * time.Second) + honestPeerCancel() + + if len(honestPeerMessages) != 1 { + t.Fatalf("got %d messages, expected 1", len(honestPeerMessages)) + } +}