service: Add updated Sign/Verify mechanism

This commit is contained in:
Leonard Lyubich 2020-08-12 17:03:11 +03:00 committed by Stanislav Bogatyrev
parent ea7c6a22da
commit 297212886d
4 changed files with 206 additions and 0 deletions

85
service/signature/data.go Normal file
View file

@ -0,0 +1,85 @@
package signature
import (
"crypto/ecdsa"
crypto "github.com/nspcc-dev/neofs-crypto"
)
type DataSource interface {
ReadSignedData([]byte) ([]byte, error)
SignedDataLength() int
}
type DataWithSignature interface {
DataSource
GetSignatureWithKey() (key, sig []byte)
SetSignatureWithKey(key, sig []byte)
}
type SignOption func(*cfg)
type KeySignatureHandler func(key []byte, sig []byte)
type KeySignatureSource func() (key, sig []byte)
func DataSignature(key *ecdsa.PrivateKey, src DataSource, opts ...SignOption) ([]byte, error) {
if key == nil {
return nil, crypto.ErrEmptyPrivateKey
}
data, err := dataForSignature(src)
if err != nil {
return nil, err
}
defer bytesPool.Put(data)
cfg := defaultCfg()
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...)
if err != nil {
return err
}
handler(crypto.MarshalPublicKey(&key.PublicKey), sig)
return nil
}
func VerifyDataWithSource(dataSrc DataSource, sigSrc KeySignatureSource, opts ...SignOption) error {
data, err := dataForSignature(dataSrc)
if err != nil {
return err
}
defer bytesPool.Put(data)
cfg := defaultCfg()
for i := range opts {
opts[i](cfg)
}
key, sig := sigSrc()
return cfg.verifyFunc(
crypto.UnmarshalPublicKey(key),
data,
sig,
)
}
func SignData(key *ecdsa.PrivateKey, v DataWithSignature, opts ...SignOption) error {
return SignDataWithHandler(key, v, v.SetSignatureWithKey, opts...)
}
func VerifyData(src DataWithSignature, opts ...SignOption) error {
return VerifyDataWithSource(src, src.GetSignatureWithKey, opts...)
}

View file

@ -0,0 +1,26 @@
package signature
import (
"crypto/ecdsa"
crypto "github.com/nspcc-dev/neofs-crypto"
)
type cfg struct {
signFunc func(key *ecdsa.PrivateKey, msg []byte) ([]byte, error)
verifyFunc func(key *ecdsa.PublicKey, msg []byte, sig []byte) error
}
func defaultCfg() *cfg {
return &cfg{
signFunc: crypto.Sign,
verifyFunc: crypto.Verify,
}
}
func SignWithRFC6979() SignOption {
return func(c *cfg) {
c.signFunc = crypto.SignRFC6979
c.verifyFunc = crypto.VerifyRFC6979
}
}

View file

@ -0,0 +1,64 @@
package signature
import (
"crypto/ecdsa"
"github.com/pkg/errors"
)
type SignedRequest interface {
Body() DataSource
MetaHeader() DataSource
OriginVerificationHeader() DataSource
SetBodySignatureWithKey(key, sig []byte)
BodySignatureWithKey() (key, sig []byte)
SetMetaSignatureWithKey(key, sig []byte)
MetaSignatureWithKey() (key, sig []byte)
SetOriginSignatureWithKey(key, sig []byte)
OriginSignatureWithKey() (key, sig []byte)
}
func SignRequest(key *ecdsa.PrivateKey, src SignedRequest) error {
if src == nil {
return errors.New("nil source")
}
// sign body
if err := SignDataWithHandler(key, src.Body(), src.SetBodySignatureWithKey); err != nil {
return errors.Wrap(err, "could not sign body")
}
// sign meta
if err := SignDataWithHandler(key, src.Body(), src.SetMetaSignatureWithKey); err != nil {
return errors.Wrap(err, "could not sign meta header")
}
// sign verify origin
if err := SignDataWithHandler(key, src.OriginVerificationHeader(), src.SetOriginSignatureWithKey); err != nil {
return errors.Wrap(err, "could not sign verification header origin")
}
return nil
}
func VerifyRequest(src SignedRequest) error {
// verify body signature
if err := VerifyDataWithSource(src.Body(), src.BodySignatureWithKey); err != nil {
return errors.Wrap(err, "could not verify body")
}
// verify meta header
if err := VerifyDataWithSource(src.MetaHeader(), src.MetaSignatureWithKey); err != nil {
return errors.Wrap(err, "could not verify meta header")
}
// verify verification header origin
if err := VerifyDataWithSource(src.OriginVerificationHeader(), src.OriginSignatureWithKey); err != nil {
return errors.Wrap(err, "could not verify verification header origin")
}
return nil
}

31
service/signature/util.go Normal file
View file

@ -0,0 +1,31 @@
package signature
import (
"sync"
"github.com/pkg/errors"
)
var bytesPool = sync.Pool{
New: func() interface{} {
return make([]byte, 5<<20)
},
}
func dataForSignature(src DataSource) ([]byte, error) {
if src == nil {
return nil, errors.New("nil source")
}
buf := bytesPool.Get().([]byte)
if size := src.SignedDataLength(); size < 0 {
return nil, errors.New("negative length")
} else if size <= cap(buf) {
buf = buf[:size]
} else {
buf = make([]byte, size)
}
return src.ReadSignedData(buf)
}