From 71be7ba804c299ba18929397cb7afa9154242d48 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Thu, 7 Nov 2019 12:01:00 -0500 Subject: [PATCH] tests for SignedEnvelopes --- crypto/envelope.go | 13 ++-- crypto/envelope_test.go | 150 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+), 6 deletions(-) create mode 100644 crypto/envelope_test.go diff --git a/crypto/envelope.go b/crypto/envelope.go index 1f9cf41..daf891f 100644 --- a/crypto/envelope.go +++ b/crypto/envelope.go @@ -6,7 +6,6 @@ import ( "errors" "github.com/golang/protobuf/proto" pb "github.com/libp2p/go-libp2p-core/crypto/pb" - "github.com/libp2p/go-libp2p-core/peer" ) // SignedEnvelope contains an arbitrary []byte payload, signed by a libp2p peer. @@ -76,11 +75,6 @@ func UnmarshalEnvelope(serializedEnvelope []byte) (*SignedEnvelope, error) { }, nil } -// SignerID returns the peer.ID of the peer who produced the SignedEnvelope. -func (e *SignedEnvelope) SignerID() (peer.ID, error) { - return peer.IDFromPublicKey(e.PublicKey) -} - // Validate returns true if the envelope signature is valid for the given 'domain', // or false if it is invalid. May return an error if signature validation fails. func (e *SignedEnvelope) Validate(domain string) (bool, error) { @@ -118,6 +112,13 @@ func (e *SignedEnvelope) Open(domain string) ([]byte, error) { return e.contents, nil } +func (e *SignedEnvelope) Equals(other *SignedEnvelope) bool { + return e.PublicKey.Equals(other.PublicKey) && + bytes.Compare(e.TypeHint, other.TypeHint) == 0 && + bytes.Compare(e.contents, other.contents) == 0 && + bytes.Compare(e.signature, other.signature) == 0 +} + // makeSigBuffer is a helper function that prepares a buffer to sign or verify. func makeSigBuffer(domain string, typeHint []byte, content []byte) []byte { b := bytes.Buffer{} diff --git a/crypto/envelope_test.go b/crypto/envelope_test.go new file mode 100644 index 0000000..860ade3 --- /dev/null +++ b/crypto/envelope_test.go @@ -0,0 +1,150 @@ +package crypto_test + +import ( + "bytes" + "github.com/gogo/protobuf/proto" + . "github.com/libp2p/go-libp2p-core/crypto" + pb "github.com/libp2p/go-libp2p-core/crypto/pb" + "github.com/libp2p/go-libp2p-core/test" + "testing" +) + +// Make an envelope, verify & open it, marshal & unmarshal it +func TestEnvelopeHappyPath(t *testing.T) { + priv, pub, err := test.RandTestKeyPair(Ed25519, 256) + if err != nil { + t.Error(err) + } + contents := []byte("happy hacking") + domain := "libp2p-testing" + typeHint := []byte("/libp2p/testdata") + envelope, err := MakeEnvelope(priv, domain, typeHint, contents) + if err != nil { + t.Errorf("error constructing envelope: %v", err) + } + + if !envelope.PublicKey.Equals(pub) { + t.Error("envelope has unexpected public key") + } + + if bytes.Compare(typeHint, envelope.TypeHint) != 0 { + t.Error("TypeHint does not match typeHint used to construct envelope") + } + + valid, err := envelope.Validate(domain) + if err != nil { + t.Errorf("error validating envelope: %v", err) + } + if !valid { + t.Error("envelope should be valid, but Valid returns false") + } + + c, err := envelope.Open(domain) + if err != nil { + t.Errorf("error opening envelope: %v", err) + } + if bytes.Compare(c, contents) != 0 { + t.Error("contents of envelope do not match input") + } + + serialized, err := envelope.Marshal() + if err != nil { + t.Errorf("error serializing envelope: %v", err) + } + deserialized, err := UnmarshalEnvelope(serialized) + if err != nil { + t.Errorf("error deserializing envelope: %v", err) + } + + if !envelope.Equals(deserialized) { + t.Error("round-trip serde results in unequal envelope structures") + } +} + +func TestEnvelopeValidateFailsForDifferentDomain(t *testing.T) { + priv, _, err := test.RandTestKeyPair(Ed25519, 256) + if err != nil { + t.Error(err) + } + contents := []byte("happy hacking") + domain := "libp2p-testing" + typeHint := []byte("/libp2p/testdata") + envelope, err := MakeEnvelope(priv, domain, typeHint, contents) + if err != nil { + t.Errorf("error constructing envelope: %v", err) + } + + valid, err := envelope.Validate("other-domain") + if err != nil { + t.Errorf("error validating envelope: %v", err) + } + if valid { + t.Error("envelope should be invalid, but Valid returns true") + } +} + +func TestEnvelopeValidateFailsIfTypeHintIsAltered(t *testing.T) { + priv, _, err := test.RandTestKeyPair(Ed25519, 256) + if err != nil { + t.Error(err) + } + contents := []byte("happy hacking") + domain := "libp2p-testing" + typeHint := []byte("/libp2p/testdata") + envelope, err := MakeEnvelope(priv, domain, typeHint, contents) + if err != nil { + t.Errorf("error constructing envelope: %v", err) + } + envelope.TypeHint = []byte("foo") + valid, err := envelope.Validate("other-domain") + if err != nil { + t.Errorf("error validating envelope: %v", err) + } + if valid { + t.Error("envelope should be invalid, but Valid returns true") + } +} + +func TestEnvelopeValidateFailsIfContentsAreAltered(t *testing.T) { + priv, _, err := test.RandTestKeyPair(Ed25519, 256) + if err != nil { + t.Error(err) + } + contents := []byte("happy hacking") + domain := "libp2p-testing" + typeHint := []byte("/libp2p/testdata") + envelope, err := MakeEnvelope(priv, domain, typeHint, contents) + if err != nil { + t.Errorf("error constructing envelope: %v", err) + } + + // since the contents field is private, we'll serialize and alter the + // serialized protobuf + serialized, err := envelope.Marshal() + if err != nil { + t.Errorf("error serializing envelope: %v", err) + } + + msg := pb.SignedEnvelope{} + err = proto.Unmarshal(serialized, &msg) + if err != nil { + t.Errorf("error deserializing envelope: %v", err) + } + msg.Contents = []byte("totally legit, trust me") + serialized, err = proto.Marshal(&msg) + + // unmarshal our altered envelope + deserialized, err := UnmarshalEnvelope(serialized) + if err != nil { + t.Errorf("error deserializing envelope: %v", err) + } + + // verify that it's now invalid + valid, err := deserialized.Validate(domain) + if err != nil { + t.Errorf("error validating envelope: %v", err) + } + if valid { + t.Error("envelope should be invalid, but Valid returns true") + } +} \ No newline at end of file