Skip to content

Commit

Permalink
Feature: Signature verification (#1)
Browse files Browse the repository at this point in the history
* Added working signatures

* Added some signature tests
  • Loading branch information
xBlaz3kx authored Dec 12, 2024
1 parent caaf5db commit f62dffc
Show file tree
Hide file tree
Showing 8 changed files with 366 additions and 178 deletions.
29 changes: 5 additions & 24 deletions builder.go
Original file line number Diff line number Diff line change
@@ -1,38 +1,20 @@
package ocmf_go

import (
"crypto"
"crypto/ecdsa"
"encoding/json"
"fmt"

"github.com/samber/lo"
)

type BuilderOption func(*Builder)

func WithSignatureAlgorithm(algorithm SignatureAlgorithm) BuilderOption {
return func(b *Builder) {
if isValidSignatureAlgorithm(algorithm) {
b.signature.Algorithm = algorithm
}
}
}

func WithSignatureEncoding(encoding SignatureEncoding) BuilderOption {
return func(b *Builder) {
if isValidSignatureEncoding(encoding) {
b.signature.Encoding = encoding
}
}
}

type Builder struct {
payload PayloadSection
signature Signature
privateKey crypto.PrivateKey
privateKey *ecdsa.PrivateKey
}

func NewBuilder(privateKey crypto.PrivateKey, opts ...BuilderOption) *Builder {
func NewBuilder(privateKey *ecdsa.PrivateKey, opts ...BuilderOption) *Builder {
builder := &Builder{
payload: PayloadSection{
FormatVersion: OcmfVersion,
Expand Down Expand Up @@ -130,11 +112,10 @@ func (b *Builder) AddLossCompensation(lossCompensation LossCompensation) *Builde
return b
}

func (b *Builder) ClearPayloadSection() *Builder {
func (b *Builder) ClearPayloadSection() {
b.payload = PayloadSection{
FormatVersion: OcmfVersion,
}
return b
}

func (b *Builder) Build() (*string, error) {
Expand All @@ -145,7 +126,7 @@ func (b *Builder) Build() (*string, error) {
}

// Sign payload with private key
err = b.signature.Sign(b.privateKey)
err = b.signature.Sign(b.payload, b.privateKey)
if err != nil {
return nil, err
}
Expand Down
30 changes: 30 additions & 0 deletions builder_opts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package ocmf_go

type BuilderOption func(*Builder)

func WithSignatureAlgorithm(algorithm SignatureAlgorithm) BuilderOption {
return func(b *Builder) {
if isValidSignatureAlgorithm(algorithm) {
b.signature.Algorithm = algorithm
}
}
}

func WithSignatureEncoding(encoding SignatureEncoding) BuilderOption {
return func(b *Builder) {
if isValidSignatureEncoding(encoding) {
b.signature.Encoding = encoding
}
}
}

func WithSignature(signature Signature) BuilderOption {
return func(b *Builder) {
err := signature.Validate()
if err != nil {
return
}

b.signature = signature
}
}
118 changes: 118 additions & 0 deletions builder_opts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package ocmf_go

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

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

type builderOptsTestSuite struct {
suite.Suite
}

func (s *builderOptsTestSuite) TestWithSignatureAlgorithm() {
tests := []struct {
name string
algorithm SignatureAlgorithm
want bool
}{
{
name: "ECDSA-secp192k1-SHA256",
algorithm: SignatureAlgorithmECDSAsecp192k1SHA256,
want: true,
},
{
name: "ECDSA-secp256k1-SHA256",
algorithm: SignatureAlgorithmECDSAsecp256k1SHA256,
want: true,
},
{
name: "ECDSA-secp384r1-SHA256",
algorithm: SignatureAlgorithmECDSAsecp384r1SHA256,
want: true,
},
{
name: "ECDSA-brainpool256r1-SHA256",
algorithm: SignatureAlgorithmECDSAbrainpool256r11SHA256,
want: true,
},
{
name: "ECDSA-secp256r1-SHA256",
algorithm: SignatureAlgorithmECDSAsecp256r1SHA256,
want: true,
},
{
name: "ECDSA-secp192r1-SHA256",
algorithm: SignatureAlgorithmECDSAsecp192r1SHA256,
want: true,
},
{
name: "Unknown algorithm",
algorithm: SignatureAlgorithm("ABCD"),
want: false,
},
{
name: "Empty algorithm",
algorithm: SignatureAlgorithm(""),
want: false,
},
}

for _, tt := range tests {
s.T().Run(tt.name, func(t *testing.T) {
curve := elliptic.P256()
privateKey, err := ecdsa.GenerateKey(curve, rand.Reader)
s.Require().NoError(err)

builder := NewBuilder(privateKey, WithSignatureAlgorithm(tt.algorithm))

if tt.name == "Unknown algorithm" || tt.name == "Empty algorithm" {
s.NotEqual(tt.algorithm, builder.signature.Algorithm)
} else {
s.Equal(tt.algorithm, builder.signature.Algorithm)
}
})
}
}

func (s *builderOptsTestSuite) TestWithWithSignatureEncoding() {
tests := []struct {
name string
encoding SignatureEncoding
}{
{
name: "Base64 encoding",
encoding: SignatureEncodingBase64,
},
{
name: "Hex encoding",
encoding: SignatureEncodingHex,
},
{
name: "Empty encoding",
encoding: SignatureEncoding(""),
},
{
name: "Unknown encoding",
encoding: SignatureEncoding("ABDD"),
},
}

for _, tt := range tests {
s.T().Run(tt.name, func(t *testing.T) {
builder := NewBuilder(nil, WithSignatureEncoding(tt.encoding))

if tt.encoding == SignatureEncodingBase64 || tt.encoding == SignatureEncodingHex {
s.Equal(tt.encoding, builder.signature.Encoding)
} else {
s.NotEqual(tt.encoding, builder.signature.Encoding)
}
})
}
}
func TestBuilderOpts(t *testing.T) {
suite.Run(t, new(builderOptsTestSuite))
}
111 changes: 9 additions & 102 deletions builder_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package ocmf_go

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

"github.com/stretchr/testify/suite"
Expand Down Expand Up @@ -32,7 +35,10 @@ func (s *builderTestSuite) TestNewBuilder() {
}

func (s *builderTestSuite) TestBuilder_Valid() {
privateKey := "" // todo
curve := elliptic.P256()
privateKey, err := ecdsa.GenerateKey(curve, rand.Reader)
s.Require().NoError(err)

builder := NewBuilder(privateKey).
WithPagination("1").
WithMeterSerial("exampleSerial123").
Expand Down Expand Up @@ -61,7 +67,7 @@ func (s *builderTestSuite) TestBuilder_Valid() {
}

func (s *builderTestSuite) TestBuilder_MissingAttributes() {
builder := NewBuilder("privateKey").
builder := NewBuilder(nil).
// WithPagination("1").
WithMeterSerial("exampleSerial123").
WithIdentificationStatus(true).
Expand All @@ -79,7 +85,7 @@ func (s *builderTestSuite) TestBuilder_MissingAttributes() {
}

func (s *builderTestSuite) TestBuilder_CantSign() {
builder := NewBuilder("privateKey").
builder := NewBuilder(nil).
WithPagination("1").
WithMeterSerial("exampleSerial123").
WithIdentificationStatus(true).
Expand All @@ -91,110 +97,11 @@ func (s *builderTestSuite) TestBuilder_CantSign() {
Status: string(MeterOk),
})

builder.privateKey = ""

payload, err := builder.Build()
s.Error(err)
s.Nil(payload)
}

func (s *builderTestSuite) TestWithSignatureAlgorithm() {
tests := []struct {
name string
algorithm SignatureAlgorithm
want bool
}{
{
name: "ECDSA-secp192k1-SHA256",
algorithm: SignatureAlgorithmECDSAsecp192k1SHA256,
want: true,
},
{
name: "ECDSA-secp256k1-SHA256",
algorithm: SignatureAlgorithmECDSAsecp256k1SHA256,
want: true,
},
{
name: "ECDSA-secp384r1-SHA256",
algorithm: SignatureAlgorithmECDSAsecp384r1SHA256,
want: true,
},
{
name: "ECDSA-brainpool256r1-SHA256",
algorithm: SignatureAlgorithmECDSAbrainpool256r11SHA256,
want: true,
},
{
name: "ECDSA-secp256r1-SHA256",
algorithm: SignatureAlgorithmECDSAsecp256r1SHA256,
want: true,
},
{
name: "ECDSA-secp192r1-SHA256",
algorithm: SignatureAlgorithmECDSAsecp192r1SHA256,
want: true,
},
{
name: "Unknown algorithm",
algorithm: SignatureAlgorithm("ABCD"),
want: false,
},
{
name: "Empty algorithm",
algorithm: SignatureAlgorithm(""),
want: false,
},
}

for _, tt := range tests {
s.T().Run(tt.name, func(t *testing.T) {
builder := NewBuilder("privateKey", WithSignatureAlgorithm(tt.algorithm))

if tt.name == "Unknown algorithm" || tt.name == "Empty algorithm" {
s.NotEqual(tt.algorithm, builder.signature.Algorithm)
} else {
s.Equal(tt.algorithm, builder.signature.Algorithm)
}
})
}
}

func (s *builderTestSuite) TestWithWithSignatureEncoding() {
tests := []struct {
name string
encoding SignatureEncoding
}{
{
name: "Base64 encoding",
encoding: SignatureEncodingBase64,
},
{
name: "Hex encoding",
encoding: SignatureEncodingHex,
},
{
name: "Empty encoding",
encoding: SignatureEncoding(""),
},
{
name: "Unknown encoding",
encoding: SignatureEncoding("ABDD"),
},
}

for _, tt := range tests {
s.T().Run(tt.name, func(t *testing.T) {
builder := NewBuilder("privateKey", WithSignatureEncoding(tt.encoding))

if tt.encoding == SignatureEncodingBase64 || tt.encoding == SignatureEncodingHex {
s.Equal(tt.encoding, builder.signature.Encoding)
} else {
s.NotEqual(tt.encoding, builder.signature.Encoding)
}
})
}
}

func TestBuilder(t *testing.T) {
suite.Run(t, new(builderTestSuite))
}
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.22

require (
github.com/go-playground/validator/v10 v10.22.1
github.com/pkg/errors v0.9.1
github.com/samber/lo v1.47.0
github.com/stretchr/testify v1.9.0
)
Expand All @@ -13,11 +14,13 @@ require (
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading

0 comments on commit f62dffc

Please sign in to comment.