Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions utils/serialization/envelope_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ SPDX-License-Identifier: Apache-2.0
package serialization

import (
"errors"
"fmt"

"github.com/hyperledger/fabric-protos-go-apiv2/common"
Expand All @@ -19,14 +20,24 @@ import (
// NoOpSigner supports unsigned envelopes.
type NoOpSigner struct{}

// WrapEnvelope serialize envelope.
func WrapEnvelope(data []byte, header *common.Header) []byte {
// WrapEnvelopePayload serializes envelope payload.
func WrapEnvelopePayload(data []byte, header *common.Header) []byte {
return protoutil.MarshalOrPanic(&common.Payload{
Header: header,
Data: data,
})
}

// WrapEnvelope wraps a payload with its header and returns an envelope.
func WrapEnvelope(data []byte, header *common.Header) []byte {
payloadBytes := WrapEnvelopePayload(data, header)

envelope := &common.Envelope{
Payload: payloadBytes,
}
return protoutil.MarshalOrPanic(envelope)
}

// UnwrapEnvelope deserialize an envelope.
func UnwrapEnvelope(message []byte) ([]byte, *common.ChannelHeader, error) {
envelope, err := protoutil.GetEnvelopeFromBlock(message)
Expand All @@ -48,6 +59,11 @@ func ParseEnvelope(envelope *common.Envelope) (*common.Payload, *common.ChannelH
if err != nil {
return nil, nil, err
}

if payload.Header == nil {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graceful failure

return nil, nil, errors.New("payload header is nil")
}

channelHdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
if err != nil {
return nil, nil, err
Expand Down Expand Up @@ -81,7 +97,7 @@ func CreateEnvelope(
channelHeader.TxId = protoutil.ComputeTxID(signatureHeader.Nonce, signatureHeader.Creator)
}
payloadHeader := protoutil.MakePayloadHeader(channelHeader, signatureHeader)
payload := WrapEnvelope(data, payloadHeader)
payload := WrapEnvelopePayload(data, payloadHeader)

signature, err := signer.Sign(payload)
if err != nil {
Expand Down
96 changes: 96 additions & 0 deletions utils/serialization/envelope_wrapper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/
package serialization_test

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/hyperledger/fabric-protos-go-apiv2/common"
"github.com/hyperledger/fabric/protoutil"

"github.com/hyperledger/fabric-x-committer/utils/serialization"
"github.com/hyperledger/fabric-x-committer/utils/test"
)

// TestUnwrapEnvelopeBadInput tests UnwrapEnvelope function with invalid inputs.
func TestUnwrapEnvelopeBadInput(t *testing.T) {
t.Run("Not an envelope", func(t *testing.T) {
t.Parallel()
_, _, err := serialization.UnwrapEnvelope([]byte("invalid input"))
require.Error(t, err)
})

t.Run("OK Header with an invalid payload", func(t *testing.T) {
t.Parallel()
envelope := &common.Envelope{
Payload: []byte("not-a-payload"),
}

envelopeBytes := protoutil.MarshalOrPanic(envelope)

_, _, err := serialization.UnwrapEnvelope(envelopeBytes)
require.Error(t, err)
})

t.Run("OK Payload with a nil Header", func(t *testing.T) {
t.Parallel()
payload := &common.Payload{
Header: nil,
Data: []byte("some data"),
}
payloadBytes := protoutil.MarshalOrPanic(payload)

envelope := &common.Envelope{
Payload: payloadBytes,
}
envelopeBytes := protoutil.MarshalOrPanic(envelope)

_, _, err := serialization.UnwrapEnvelope(envelopeBytes)
require.Error(t, err)
})

t.Run("OK payload but invalid ChannelHeader", func(t *testing.T) {
t.Parallel()
header := &common.Header{
ChannelHeader: []byte("not-a-channel-header"),
}
payload := &common.Payload{
Header: header,
Data: []byte("some data"),
}
payloadBytes := protoutil.MarshalOrPanic(payload)

envelope := &common.Envelope{
Payload: payloadBytes,
}
envelopeBytes := protoutil.MarshalOrPanic(envelope)

_, _, err := serialization.UnwrapEnvelope(envelopeBytes)
require.Error(t, err)
})
}

// TestUnwrapEnvelopeGoodInput Tests properly wrapped envelope is unwrapped correctly.
func TestUnwrapEnvelopeGoodInput(t *testing.T) {
t.Parallel()
// -1- Check unwrap envelope has no error
originalPayload := []byte("test payload")
originalChannelHeader := &common.ChannelHeader{
ChannelId: "test-channel",
}
originalHeader := &common.Header{
ChannelHeader: protoutil.MarshalOrPanic(originalChannelHeader),
}
wrappedEnvelope := serialization.WrapEnvelope(originalPayload, originalHeader)
payload, channelHeader, err := serialization.UnwrapEnvelope(wrappedEnvelope)

// -2- Check we get the correct Payload & Header
require.NoError(t, err)
require.Equal(t, originalPayload, payload)
test.RequireProtoEqual(t, originalChannelHeader, channelHeader)
}
5 changes: 5 additions & 0 deletions utils/signature/sigtest/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,15 @@ func SerializeVerificationKey(key *ecdsa.PublicKey) ([]byte, error) {

// SerializeSigningKey encodes a ECDSA private key into a PEM file.
func SerializeSigningKey(key *ecdsa.PrivateKey) ([]byte, error) {
if key == nil {
return nil, errors.New("key is nil")
}

x509encodedPri, err := x509.MarshalECPrivateKey(key)
if err != nil {
return nil, errors.Wrap(err, "cannot serialize private key")
}

return pem.EncodeToMemory(&pem.Block{
Type: "EC PRIVATE KEY",
Bytes: x509encodedPri,
Expand Down
110 changes: 110 additions & 0 deletions utils/signature/sigtest/crypto_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/
package sigtest

import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"testing"

"github.com/stretchr/testify/require"
)

func TestSerializeVerificationKey(t *testing.T) {
t.Parallel()
tests := []struct {
name string
curve elliptic.Curve
wantErr bool
}{
{
name: "P256",
curve: elliptic.P256(),
},
{
name: "P384",
curve: elliptic.P384(),
},
{
name: "P224",
curve: elliptic.P224(),
},
{
name: "P521",
curve: elliptic.P521(),
},

// {
// // TODO: find an invalid example?
// name: "Invalid input",
// curve: elliptic.(),
// wantErr: true,
// },
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
privKey, err := ecdsa.GenerateKey(tt.curve, rand.Reader)
require.NoError(t, err)

_, err = SerializeVerificationKey(&privKey.PublicKey)
if tt.wantErr {
require.Error(t, err)
} else {
require.NoError(t, err)
}
})
}
}

func TestSerializeSigningKey(t *testing.T) {
// Panic can happen from unwanted side effects when nil and empty Keys are passed
defer func() {
if r := recover(); r != nil {
t.Errorf("SerializeSigningKey() panics: %v", r)
}
}()

t.Run("Key Empty", func(t *testing.T) {
t.Parallel()
emptyKey := &ecdsa.PrivateKey{}
_, err := SerializeSigningKey(emptyKey)
require.Error(t, err)
})
t.Run("Key is nil", func(t *testing.T) {
t.Parallel()
_, err := SerializeSigningKey(nil)
require.Error(t, err)
})

t.Run("Key OK", func(t *testing.T) {
t.Parallel()
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err)
key, err := SerializeSigningKey(privateKey)
require.NotNil(t, key)
require.NoError(t, err)
})
}

func TestParseSigningKey(t *testing.T) {
t.Run("Key is nil", func(t *testing.T) {
t.Parallel()
_, err := ParseSigningKey(nil)
require.Error(t, err)
})
t.Run("Key OK", func(t *testing.T) {
t.Parallel()
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err)
key, err := SerializeSigningKey(privateKey)
require.NoError(t, err)
_, err = ParseSigningKey(key)
require.NoError(t, err)
})
}