diff --git a/client/container.go b/client/container.go index ef7c0e88..4e2aa7de 100644 --- a/client/container.go +++ b/client/container.go @@ -4,7 +4,6 @@ import ( "context" v2container "github.com/nspcc-dev/neofs-api-go/v2/container" - "github.com/nspcc-dev/neofs-api-go/v2/refs" rpcapi "github.com/nspcc-dev/neofs-api-go/v2/rpc" "github.com/nspcc-dev/neofs-api-go/v2/rpc/client" v2session "github.com/nspcc-dev/neofs-api-go/v2/session" @@ -87,11 +86,8 @@ func (c *Client) ContainerPut(ctx context.Context, prm PrmContainerPut) (*ResCon // sign container signWrapper := v2signature.StableMarshalerWrapper{SM: reqBody.GetContainer()} - err := sigutil.SignDataWithHandler(c.opts.key, signWrapper, func(key []byte, sig []byte) { - containerSignature := new(refs.Signature) - containerSignature.SetKey(key) - containerSignature.SetSign(sig) - reqBody.SetSignature(containerSignature) + err := sigutil.SignDataWithHandler(c.opts.key, signWrapper, func(sig *signature.Signature) { + reqBody.SetSignature(sig.ToV2()) }, sigutil.SignWithRFC6979()) if err != nil { return nil, err @@ -402,11 +398,8 @@ func (c *Client) ContainerDelete(ctx context.Context, prm PrmContainerDelete) (* delContainerSignWrapper{ body: reqBody, }, - func(key []byte, sig []byte) { - containerSignature := new(refs.Signature) - containerSignature.SetKey(key) - containerSignature.SetSign(sig) - reqBody.SetSignature(containerSignature) + func(sig *signature.Signature) { + reqBody.SetSignature(sig.ToV2()) }, sigutil.SignWithRFC6979()) if err != nil { @@ -599,11 +592,8 @@ func (c *Client) ContainerSetEACL(ctx context.Context, prm PrmContainerSetEACL) // sign the eACL table signWrapper := v2signature.StableMarshalerWrapper{SM: reqBody.GetEACL()} - err := sigutil.SignDataWithHandler(c.opts.key, signWrapper, func(key []byte, sig []byte) { - eaclSignature := new(refs.Signature) - eaclSignature.SetKey(key) - eaclSignature.SetSign(sig) - reqBody.SetSignature(eaclSignature) + err := sigutil.SignDataWithHandler(c.opts.key, signWrapper, func(sig *signature.Signature) { + reqBody.SetSignature(sig.ToV2()) }, sigutil.SignWithRFC6979()) if err != nil { return nil, err diff --git a/object/fmt.go b/object/fmt.go index 8229c198..2600d84a 100644 --- a/object/fmt.go +++ b/object/fmt.go @@ -94,9 +94,8 @@ func CalculateIDSignature(key *ecdsa.PrivateKey, id *oid.ID) (*signature.Signatu signatureV2.StableMarshalerWrapper{ SM: id.ToV2(), }, - func(key, sign []byte) { - sig.SetKey(key) - sig.SetSign(sign) + func(s *signature.Signature) { + *sig = *s }, ); err != nil { return nil, err @@ -121,11 +120,7 @@ func VerifyIDSignature(obj *Object) error { signatureV2.StableMarshalerWrapper{ SM: obj.ID().ToV2(), }, - func() ([]byte, []byte) { - sig := obj.Signature() - - return sig.Key(), sig.Sign() - }, + obj.Signature, ) } diff --git a/reputation/trust.go b/reputation/trust.go index bfa91721..034b937b 100644 --- a/reputation/trust.go +++ b/reputation/trust.go @@ -6,7 +6,8 @@ import ( "github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/nspcc-dev/neofs-api-go/v2/reputation" signatureV2 "github.com/nspcc-dev/neofs-api-go/v2/signature" - "github.com/nspcc-dev/neofs-sdk-go/util/signature" + "github.com/nspcc-dev/neofs-sdk-go/signature" + sigutil "github.com/nspcc-dev/neofs-sdk-go/util/signature" "github.com/nspcc-dev/neofs-sdk-go/version" ) @@ -259,18 +260,11 @@ func (x *GlobalTrust) Trust() *Trust { func (x *GlobalTrust) Sign(key *ecdsa.PrivateKey) error { v2 := (*reputation.GlobalTrust)(x) - sigV2 := v2.GetSignature() - if sigV2 == nil { - sigV2 = new(refs.Signature) - v2.SetSignature(sigV2) - } - - return signature.SignDataWithHandler( + return sigutil.SignDataWithHandler( key, signatureV2.StableMarshalerWrapper{SM: v2.GetBody()}, - func(key, sig []byte) { - sigV2.SetKey(key) - sigV2.SetSign(sig) + func(sig *signature.Signature) { + v2.SetSignature(sig.ToV2()) }, ) } @@ -284,10 +278,10 @@ func (x *GlobalTrust) VerifySignature() error { sigV2 = new(refs.Signature) } - return signature.VerifyDataWithSource( + return sigutil.VerifyDataWithSource( signatureV2.StableMarshalerWrapper{SM: v2.GetBody()}, - func() ([]byte, []byte) { - return sigV2.GetKey(), sigV2.GetSign() + func() *signature.Signature { + return signature.NewFromV2(sigV2) }, ) } diff --git a/session/session.go b/session/session.go index b926ba88..fe5a8ae7 100644 --- a/session/session.go +++ b/session/session.go @@ -3,7 +3,6 @@ package session import ( "crypto/ecdsa" - "github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/nspcc-dev/neofs-api-go/v2/session" v2signature "github.com/nspcc-dev/neofs-api-go/v2/signature" "github.com/nspcc-dev/neofs-sdk-go/owner" @@ -169,16 +168,8 @@ func (t *Token) Sign(key *ecdsa.PrivateKey) error { SM: tV2.GetBody(), } - return sigutil.SignDataWithHandler(key, signedData, func(key, sig []byte) { - tSig := tV2.GetSignature() - if tSig == nil { - tSig = new(refs.Signature) - } - - tSig.SetKey(key) - tSig.SetSign(sig) - - tV2.SetSignature(tSig) + return sigutil.SignDataWithHandler(key, signedData, func(sig *signature.Signature) { + tV2.SetSignature(sig.ToV2()) }) } @@ -191,10 +182,7 @@ func (t *Token) VerifySignature() bool { SM: tV2.GetBody(), } - return sigutil.VerifyDataWithSource(signedData, func() (key, sig []byte) { - tSig := tV2.GetSignature() - return tSig.GetKey(), tSig.GetSign() - }) == nil + return sigutil.VerifyDataWithSource(signedData, t.Signature) == nil } // Signature returns Token signature. diff --git a/signature/signature.go b/signature/signature.go index c0007ccf..a79b5bef 100644 --- a/signature/signature.go +++ b/signature/signature.go @@ -7,6 +7,16 @@ import ( // Signature represents v2-compatible signature. type Signature refs.Signature +// Scheme represents signature scheme. +type Scheme uint32 + +// Supported signature schemes. +const ( + Unspecified Scheme = iota + ECDSAWithSHA512 + RFC6979WithSHA256 +) + // NewFromV2 wraps v2 Signature message to Signature. // // Nil refs.Signature converts to nil. @@ -43,6 +53,16 @@ func (s *Signature) SetSign(v []byte) { (*refs.Signature)(s).SetSign(v) } +// Scheme returns signature scheme. +func (s *Signature) Scheme() Scheme { + return Scheme((*refs.Signature)(s).GetScheme()) +} + +// SetScheme sets signature scheme. +func (s *Signature) SetScheme(v Scheme) { + (*refs.Signature)(s).SetScheme(refs.SignatureScheme(v)) +} + // ToV2 converts Signature to v2 Signature message. // // Nil Signature converts to nil. diff --git a/token/bearer.go b/token/bearer.go index d2a82f7e..b40159b8 100644 --- a/token/bearer.go +++ b/token/bearer.go @@ -7,12 +7,11 @@ import ( "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neofs-api-go/v2/acl" - "github.com/nspcc-dev/neofs-api-go/v2/refs" v2signature "github.com/nspcc-dev/neofs-api-go/v2/signature" "github.com/nspcc-dev/neofs-sdk-go/eacl" "github.com/nspcc-dev/neofs-sdk-go/owner" "github.com/nspcc-dev/neofs-sdk-go/signature" - util "github.com/nspcc-dev/neofs-sdk-go/util/signature" + sigutil "github.com/nspcc-dev/neofs-sdk-go/util/signature" ) var ( @@ -103,11 +102,8 @@ func (b *BearerToken) SignToken(key *ecdsa.PrivateKey) error { signWrapper := v2signature.StableMarshalerWrapper{SM: b.token.GetBody()} - return util.SignDataWithHandler(key, signWrapper, func(key []byte, sig []byte) { - bearerSignature := new(refs.Signature) - bearerSignature.SetKey(key) - bearerSignature.SetSign(sig) - b.token.SetSignature(bearerSignature) + return sigutil.SignDataWithHandler(key, signWrapper, func(sig *signature.Signature) { + b.token.SetSignature(sig.ToV2()) }) } @@ -120,11 +116,11 @@ func (b BearerToken) VerifySignature() error { return nil } - return util.VerifyDataWithSource( + return sigutil.VerifyDataWithSource( v2signature.StableMarshalerWrapper{SM: b.token.GetBody()}, - func() (key, sig []byte) { + func() *signature.Signature { sigV2 := b.token.GetSignature() - return sigV2.GetKey(), sigV2.GetSign() + return signature.NewFromV2(sigV2) }) } diff --git a/util/signature/data.go b/util/signature/data.go index 783c66ee..3ded29be 100644 --- a/util/signature/data.go +++ b/util/signature/data.go @@ -7,6 +7,7 @@ import ( "fmt" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" + "github.com/nspcc-dev/neofs-sdk-go/signature" ) type DataSource interface { @@ -16,15 +17,15 @@ type DataSource interface { type DataWithSignature interface { DataSource - GetSignatureWithKey() (key, sig []byte) - SetSignatureWithKey(key, sig []byte) + GetSignature() *signature.Signature + SetSignature(*signature.Signature) } type SignOption func(*cfg) -type KeySignatureHandler func(key []byte, sig []byte) +type KeySignatureHandler func(*signature.Signature) -type KeySignatureSource func() (key, sig []byte) +type KeySignatureSource func() *signature.Signature const ( // PrivateKeyCompressedSize is constant with compressed size of private key (SK). @@ -49,34 +50,30 @@ var ( ErrInvalidSignature = errors.New("invalid signature") ) -func DataSignature(key *ecdsa.PrivateKey, src DataSource, opts ...SignOption) ([]byte, error) { +func SignDataWithHandler(key *ecdsa.PrivateKey, src DataSource, handler KeySignatureHandler, opts ...SignOption) error { if key == nil { - return nil, ErrEmptyPrivateKey + return ErrEmptyPrivateKey } data, err := dataForSignature(src) if err != nil { - return nil, err + return err } defer bytesPool.Put(&data) - cfg := defaultCfg() + cfg := getConfig(opts...) - for i := range opts { - opts[i](cfg) - } - - return cfg.signFunc(key, data) -} - -func SignDataWithHandler(key *ecdsa.PrivateKey, src DataSource, handler KeySignatureHandler, opts ...SignOption) error { - sig, err := DataSignature(key, src, opts...) + sigData, err := sign(cfg.defaultScheme, key, data) if err != nil { return err } - pub := (*keys.PublicKey)(&key.PublicKey) - handler(pub.Bytes(), sig) + sig := signature.New() + sig.SetKey((*keys.PublicKey)(&key.PublicKey).Bytes()) + sig.SetSign(sigData) + sig.SetScheme(cfg.defaultScheme) + + handler(sig) return nil } @@ -88,33 +85,38 @@ func VerifyDataWithSource(dataSrc DataSource, sigSrc KeySignatureSource, opts .. } defer bytesPool.Put(&data) - cfg := defaultCfg() + cfg := getConfig(opts...) - for i := range opts { - opts[i](cfg) - } - - key, sig := sigSrc() + sig := sigSrc() var pub *keys.PublicKey - if len(key) != 0 { - pub, err = keys.NewPublicKeyFromBytes(key, elliptic.P256()) + if len(sig.Key()) != 0 { + pub, err = keys.NewPublicKeyFromBytes(sig.Key(), elliptic.P256()) if err != nil { return fmt.Errorf("%w: %v", ErrInvalidPublicKey, err) } } - return cfg.verifyFunc( + scheme := sig.Scheme() + if scheme == signature.Unspecified { + scheme = cfg.defaultScheme + } + if cfg.restrictScheme != signature.Unspecified && scheme != cfg.restrictScheme { + return fmt.Errorf("%w: unexpected signature scheme", ErrInvalidSignature) + } + + return verify( + scheme, (*ecdsa.PublicKey)(pub), data, - sig, + sig.Sign(), ) } func SignData(key *ecdsa.PrivateKey, v DataWithSignature, opts ...SignOption) error { - return SignDataWithHandler(key, v, v.SetSignatureWithKey, opts...) + return SignDataWithHandler(key, v, v.SetSignature, opts...) } func VerifyData(src DataWithSignature, opts ...SignOption) error { - return VerifyDataWithSource(src, src.GetSignatureWithKey, opts...) + return VerifyDataWithSource(src, src.GetSignature, opts...) } diff --git a/util/signature/options.go b/util/signature/options.go index c1cefeed..9b6b0e73 100644 --- a/util/signature/options.go +++ b/util/signature/options.go @@ -9,38 +9,65 @@ import ( "math/big" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" + "github.com/nspcc-dev/neofs-sdk-go/signature" ) var curve = elliptic.P256() type cfg struct { - signFunc func(key *ecdsa.PrivateKey, msg []byte) ([]byte, error) - verifyFunc func(key *ecdsa.PublicKey, msg []byte, sig []byte) error + defaultScheme signature.Scheme + restrictScheme signature.Scheme } -func defaultCfg() *cfg { - return &cfg{ - signFunc: sign, - verifyFunc: verify, +func getConfig(opts ...SignOption) *cfg { + cfg := &cfg{ + defaultScheme: signature.ECDSAWithSHA512, + restrictScheme: signature.Unspecified, + } + + for i := range opts { + opts[i](cfg) + } + + return cfg +} + +func sign(scheme signature.Scheme, key *ecdsa.PrivateKey, msg []byte) ([]byte, error) { + switch scheme { + case signature.ECDSAWithSHA512: + h := sha512.Sum512(msg) + x, y, err := ecdsa.Sign(rand.Reader, key, h[:]) + if err != nil { + return nil, err + } + return elliptic.Marshal(elliptic.P256(), x, y), nil + case signature.RFC6979WithSHA256: + p := &keys.PrivateKey{PrivateKey: *key} + return p.Sign(msg), nil + default: + panic("unsupported scheme") } } -func sign(key *ecdsa.PrivateKey, msg []byte) ([]byte, error) { - h := sha512.Sum512(msg) - x, y, err := ecdsa.Sign(rand.Reader, key, h[:]) - if err != nil { - return nil, err +func verify(scheme signature.Scheme, key *ecdsa.PublicKey, msg []byte, sig []byte) error { + switch scheme { + case signature.ECDSAWithSHA512: + h := sha512.Sum512(msg) + r, s := unmarshalXY(sig) + if r != nil && s != nil && ecdsa.Verify(key, h[:], r, s) { + return nil + } + return ErrInvalidSignature + case signature.RFC6979WithSHA256: + p := (*keys.PublicKey)(key) + h := sha256.Sum256(msg) + if p.Verify(sig, h[:]) { + return nil + } + return ErrInvalidSignature + default: + return ErrInvalidSignature } - return elliptic.Marshal(elliptic.P256(), x, y), nil -} - -func verify(key *ecdsa.PublicKey, msg []byte, sig []byte) error { - h := sha512.Sum512(msg) - r, s := unmarshalXY(sig) - if r != nil && s != nil && ecdsa.Verify(key, h[:], r, s) { - return nil - } - return ErrInvalidSignature } // unmarshalXY converts a point, serialized by Marshal, into an x, y pair. @@ -71,21 +98,7 @@ func unmarshalXY(data []byte) (x *big.Int, y *big.Int) { func SignWithRFC6979() SignOption { return func(c *cfg) { - c.signFunc = signRFC6979 - c.verifyFunc = verifyRFC6979 + c.defaultScheme = signature.RFC6979WithSHA256 + c.restrictScheme = signature.RFC6979WithSHA256 } } - -func signRFC6979(key *ecdsa.PrivateKey, msg []byte) ([]byte, error) { - p := &keys.PrivateKey{PrivateKey: *key} - return p.Sign(msg), nil -} - -func verifyRFC6979(key *ecdsa.PublicKey, msg []byte, sig []byte) error { - p := (*keys.PublicKey)(key) - h := sha256.Sum256(msg) - if p.Verify(sig, h[:]) { - return nil - } - return ErrInvalidSignature -}