From a9067e9d6e6c50c686e50a8391145df2e08b428b Mon Sep 17 00:00:00 2001 From: Effi-S Date: Wed, 6 Aug 2025 12:34:44 +0300 Subject: [PATCH 1/6] Added Utils unit tests - envelope and crypto Signed-off-by: Effi-S --- utils/serialization/envelope_wrapper.go | 21 ++++- utils/serialization/envelope_wrapper_test.go | 86 +++++++++++++++++ utils/signature/sigtest/crypto.go | 6 ++ utils/signature/sigtest/crypto_test.go | 99 ++++++++++++++++++++ 4 files changed, 209 insertions(+), 3 deletions(-) create mode 100644 utils/serialization/envelope_wrapper_test.go create mode 100644 utils/signature/sigtest/crypto_test.go diff --git a/utils/serialization/envelope_wrapper.go b/utils/serialization/envelope_wrapper.go index 3c674e11..b1fd56e4 100644 --- a/utils/serialization/envelope_wrapper.go +++ b/utils/serialization/envelope_wrapper.go @@ -7,6 +7,7 @@ SPDX-License-Identifier: Apache-2.0 package serialization import ( + "errors" "fmt" "github.com/hyperledger/fabric-protos-go-apiv2/common" @@ -19,14 +20,23 @@ import ( // NoOpSigner supports unsigned envelopes. type NoOpSigner struct{} -// WrapEnvelope serialize envelope. -func WrapEnvelope(data []byte, header *common.Header) []byte { +// WrapEnvelopePayload serialize envelope. +func WrapEnvelopePayload(data []byte, header *common.Header) []byte { return protoutil.MarshalOrPanic(&common.Payload{ Header: header, Data: data, }) } +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) @@ -48,6 +58,11 @@ func ParseEnvelope(envelope *common.Envelope) (*common.Payload, *common.ChannelH if err != nil { return nil, nil, err } + + if payload.Header == nil { + return nil, nil, errors.New("payload header is nil") + } + channelHdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader) if err != nil { return nil, nil, err @@ -81,7 +96,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 { diff --git a/utils/serialization/envelope_wrapper_test.go b/utils/serialization/envelope_wrapper_test.go new file mode 100644 index 00000000..33cc438d --- /dev/null +++ b/utils/serialization/envelope_wrapper_test.go @@ -0,0 +1,86 @@ +package serialization_test + +import ( + "testing" + + "github.com/hyperledger/fabric-protos-go-apiv2/common" + "github.com/hyperledger/fabric-x-committer/utils/serialization" + "github.com/hyperledger/fabric-x-committer/utils/test" + "github.com/hyperledger/fabric/protoutil" + "github.com/stretchr/testify/require" +) + +// UnwrapEnvelope function with invalid inputs +func TestUnwrapEnvelopeBadInput(t *testing.T) { + t.Run("Not an envelope", func(t *testing.T) { + _, _, err := serialization.UnwrapEnvelope([]byte("invalid input")) + require.Error(t, err) + }) + + t.Run("OK Header with an invalid payload", func(t *testing.T) { + 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) { + 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) { + 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) + }) +} + +// Test properly wrapped envelope is unwrapped correctly +func TestUnwrapEnvelopeGoodInput(t *testing.T) { + + // -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) +} diff --git a/utils/signature/sigtest/crypto.go b/utils/signature/sigtest/crypto.go index 99d2e05d..44cbd4b9 100644 --- a/utils/signature/sigtest/crypto.go +++ b/utils/signature/sigtest/crypto.go @@ -32,10 +32,16 @@ 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, diff --git a/utils/signature/sigtest/crypto_test.go b/utils/signature/sigtest/crypto_test.go new file mode 100644 index 00000000..1e4dc70c --- /dev/null +++ b/utils/signature/sigtest/crypto_test.go @@ -0,0 +1,99 @@ +package sigtest + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSerializeVerificationKey(t *testing.T) { + 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) { + 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) { + emptyKey := &ecdsa.PrivateKey{} + _, err := SerializeSigningKey(emptyKey) + require.Error(t, err) + }) + t.Run("Key is nil", func(t *testing.T) { + _, err := SerializeSigningKey(nil) + require.Error(t, err) + }) + + t.Run("Key OK", func(t *testing.T) { + privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + key, err := SerializeSigningKey(privateKey) + fmt.Println(key) + require.NoError(t, err) + }) + +} + +func TestParseSigningKey(t *testing.T) { + t.Run("Key is nil", func(t *testing.T) { + _, err := ParseSigningKey(nil) + require.Error(t, err) + }) + t.Run("Key OK", func(t *testing.T) { + privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + key, err := SerializeSigningKey(privateKey) + require.NoError(t, err) + _, err = ParseSigningKey(key) + require.NoError(t, err) + }) +} From f93bf008719b61f3d76a0376d24f4cf6f67f9e35 Mon Sep 17 00:00:00 2001 From: Effi-S Date: Wed, 6 Aug 2025 12:40:17 +0300 Subject: [PATCH 2/6] Linter Fixes Signed-off-by: Effi-S --- utils/serialization/envelope_wrapper.go | 1 + utils/serialization/envelope_wrapper_test.go | 22 ++++++++++++++------ utils/signature/sigtest/crypto.go | 1 - utils/signature/sigtest/crypto_test.go | 19 +++++++++++++---- 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/utils/serialization/envelope_wrapper.go b/utils/serialization/envelope_wrapper.go index b1fd56e4..13f57386 100644 --- a/utils/serialization/envelope_wrapper.go +++ b/utils/serialization/envelope_wrapper.go @@ -28,6 +28,7 @@ func WrapEnvelopePayload(data []byte, header *common.Header) []byte { }) } +// WrapEnvelope wraps a payload with it's header and returns an envelope. func WrapEnvelope(data []byte, header *common.Header) []byte { payloadBytes := WrapEnvelopePayload(data, header) diff --git a/utils/serialization/envelope_wrapper_test.go b/utils/serialization/envelope_wrapper_test.go index 33cc438d..264d233f 100644 --- a/utils/serialization/envelope_wrapper_test.go +++ b/utils/serialization/envelope_wrapper_test.go @@ -1,23 +1,32 @@ +/* +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" - "github.com/hyperledger/fabric/protoutil" - "github.com/stretchr/testify/require" ) -// UnwrapEnvelope function with invalid inputs +// 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"), } @@ -29,6 +38,7 @@ func TestUnwrapEnvelopeBadInput(t *testing.T) { }) t.Run(" OK Payload with a nil Header", func(t *testing.T) { + t.Parallel() payload := &common.Payload{ Header: nil, Data: []byte("some data"), @@ -45,6 +55,7 @@ func TestUnwrapEnvelopeBadInput(t *testing.T) { }) t.Run("OK payload but invalid ChannelHeader", func(t *testing.T) { + t.Parallel() header := &common.Header{ ChannelHeader: []byte("not-a-channel-header"), } @@ -64,9 +75,9 @@ func TestUnwrapEnvelopeBadInput(t *testing.T) { }) } -// Test properly wrapped envelope is unwrapped correctly +// 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{ @@ -75,7 +86,6 @@ func TestUnwrapEnvelopeGoodInput(t *testing.T) { originalHeader := &common.Header{ ChannelHeader: protoutil.MarshalOrPanic(originalChannelHeader), } - wrappedEnvelope := serialization.WrapEnvelope(originalPayload, originalHeader) payload, channelHeader, err := serialization.UnwrapEnvelope(wrappedEnvelope) diff --git a/utils/signature/sigtest/crypto.go b/utils/signature/sigtest/crypto.go index 44cbd4b9..0aa7927d 100644 --- a/utils/signature/sigtest/crypto.go +++ b/utils/signature/sigtest/crypto.go @@ -32,7 +32,6 @@ 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") } diff --git a/utils/signature/sigtest/crypto_test.go b/utils/signature/sigtest/crypto_test.go index 1e4dc70c..257d05c8 100644 --- a/utils/signature/sigtest/crypto_test.go +++ b/utils/signature/sigtest/crypto_test.go @@ -1,16 +1,21 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ package sigtest import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" - "fmt" "testing" "github.com/stretchr/testify/require" ) func TestSerializeVerificationKey(t *testing.T) { + t.Parallel() tests := []struct { name string curve elliptic.Curve @@ -43,6 +48,7 @@ func TestSerializeVerificationKey(t *testing.T) { 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) @@ -57,7 +63,6 @@ func TestSerializeVerificationKey(t *testing.T) { } 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 { @@ -66,31 +71,37 @@ func TestSerializeSigningKey(t *testing.T) { }() 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) - fmt.Println(key) + 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) From 740050b281cf55ac99b99cba34aa219db1e7e0df Mon Sep 17 00:00:00 2001 From: Effi-S <57197982+Effi-S@users.noreply.github.com> Date: Thu, 7 Aug 2025 14:05:43 +0300 Subject: [PATCH 3/6] Update utils/serialization/envelope_wrapper.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Effi-S <57197982+Effi-S@users.noreply.github.com> --- utils/serialization/envelope_wrapper.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/serialization/envelope_wrapper.go b/utils/serialization/envelope_wrapper.go index 13f57386..6733ac54 100644 --- a/utils/serialization/envelope_wrapper.go +++ b/utils/serialization/envelope_wrapper.go @@ -28,7 +28,7 @@ func WrapEnvelopePayload(data []byte, header *common.Header) []byte { }) } -// WrapEnvelope wraps a payload with it's header and returns an envelope. +// WrapEnvelope wraps a payload with its header and returns an envelope. func WrapEnvelope(data []byte, header *common.Header) []byte { payloadBytes := WrapEnvelopePayload(data, header) From 71c4391c86cf9df5fe1fbc884ce4bcc6ca66c336 Mon Sep 17 00:00:00 2001 From: Effi-S <57197982+Effi-S@users.noreply.github.com> Date: Thu, 7 Aug 2025 14:05:50 +0300 Subject: [PATCH 4/6] Update utils/serialization/envelope_wrapper.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Effi-S <57197982+Effi-S@users.noreply.github.com> --- utils/serialization/envelope_wrapper.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/serialization/envelope_wrapper.go b/utils/serialization/envelope_wrapper.go index 6733ac54..b65f7cef 100644 --- a/utils/serialization/envelope_wrapper.go +++ b/utils/serialization/envelope_wrapper.go @@ -20,7 +20,7 @@ import ( // NoOpSigner supports unsigned envelopes. type NoOpSigner struct{} -// WrapEnvelopePayload serialize envelope. +// WrapEnvelopePayload serializes envelope payload. func WrapEnvelopePayload(data []byte, header *common.Header) []byte { return protoutil.MarshalOrPanic(&common.Payload{ Header: header, From 284be1fab3953bd79fe46c1605b8dc947439061a Mon Sep 17 00:00:00 2001 From: Effi-S <57197982+Effi-S@users.noreply.github.com> Date: Thu, 7 Aug 2025 14:06:30 +0300 Subject: [PATCH 5/6] Update utils/serialization/envelope_wrapper_test.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Effi-S <57197982+Effi-S@users.noreply.github.com> --- utils/serialization/envelope_wrapper_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/serialization/envelope_wrapper_test.go b/utils/serialization/envelope_wrapper_test.go index 264d233f..72c646d2 100644 --- a/utils/serialization/envelope_wrapper_test.go +++ b/utils/serialization/envelope_wrapper_test.go @@ -37,7 +37,7 @@ func TestUnwrapEnvelopeBadInput(t *testing.T) { require.Error(t, err) }) - t.Run(" OK Payload with a nil Header", func(t *testing.T) { + t.Run("OK Payload with a nil Header", func(t *testing.T) { t.Parallel() payload := &common.Payload{ Header: nil, From 1975c5e2a3c56ace940efe4670c89f12b5afda18 Mon Sep 17 00:00:00 2001 From: Effi-S <57197982+Effi-S@users.noreply.github.com> Date: Thu, 7 Aug 2025 14:07:05 +0300 Subject: [PATCH 6/6] Update utils/signature/sigtest/crypto_test.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Effi-S <57197982+Effi-S@users.noreply.github.com> --- utils/signature/sigtest/crypto_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/signature/sigtest/crypto_test.go b/utils/signature/sigtest/crypto_test.go index 257d05c8..2b95750a 100644 --- a/utils/signature/sigtest/crypto_test.go +++ b/utils/signature/sigtest/crypto_test.go @@ -39,7 +39,7 @@ func TestSerializeVerificationKey(t *testing.T) { }, // { - // // ? TODO find an invalid example? + // // TODO: find an invalid example? // name: "Invalid input", // curve: elliptic.(), // wantErr: true,