[#55] refs: Add Scheme field to Signature

Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
Evgenii Stratonikov 2022-02-22 14:25:43 +03:00 committed by LeL
parent 66e1fb8c53
commit a4349f6692
10 changed files with 140 additions and 46 deletions

View file

@ -260,6 +260,7 @@ func (s *Signature) ToGRPCMessage() grpc.Message {
m.SetKey(s.key) m.SetKey(s.key)
m.SetSign(s.sign) m.SetSign(s.sign)
m.SetScheme(refs.SignatureScheme(s.scheme))
} }
return m return m
@ -273,6 +274,7 @@ func (s *Signature) FromGRPCMessage(m grpc.Message) error {
s.key = v.GetKey() s.key = v.GetKey()
s.sign = v.GetSign() s.sign = v.GetSign()
s.scheme = SignatureScheme(v.GetScheme())
return nil return nil
} }

View file

@ -77,6 +77,26 @@ func (x *Signature) SetSign(v []byte) {
} }
} }
// SetScheme sets signature scheme.
func (x *Signature) SetScheme(s SignatureScheme) {
if x != nil {
x.Scheme = s
}
}
// FromString parses SignatureScheme from a string representation,
// It is a reverse action to String().
//
// Returns true if s was parsed successfully.
func (x *SignatureScheme) FromString(s string) bool {
i, ok := SignatureScheme_value[s]
if ok {
*x = SignatureScheme(i)
}
return ok
}
// FromString parses ChecksumType from a string representation, // FromString parses ChecksumType from a string representation,
// It is a reverse action to String(). // It is a reverse action to String().
// //

BIN
refs/grpc/types.pb.go generated

Binary file not shown.

View file

@ -19,8 +19,9 @@ const (
checksumTypeField = 1 checksumTypeField = 1
checksumValueField = 2 checksumValueField = 2
signatureKeyField = 1 signatureKeyField = 1
signatureValueField = 2 signatureValueField = 2
signatureSchemeField = 3
versionMajorField = 1 versionMajorField = 1
versionMinorField = 2 versionMinorField = 2
@ -250,7 +251,14 @@ func (s *Signature) StableMarshal(buf []byte) ([]byte, error) {
offset += n offset += n
_, err = proto.BytesMarshal(signatureValueField, buf[offset:], s.sign) n, err = proto.BytesMarshal(signatureValueField, buf[offset:], s.sign)
if err != nil {
return nil, err
}
offset += n
_, err = proto.EnumMarshal(signatureSchemeField, buf[offset:], int32(s.scheme))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -265,6 +273,7 @@ func (s *Signature) StableSize() (size int) {
size += proto.BytesSize(signatureKeyField, s.key) size += proto.BytesSize(signatureKeyField, s.key)
size += proto.BytesSize(signatureValueField, s.sign) size += proto.BytesSize(signatureValueField, s.sign)
size += proto.EnumSize(signatureSchemeField, int32(s.scheme))
return size return size
} }

View file

@ -24,3 +24,24 @@ func (t *ChecksumType) FromString(s string) bool {
return ok return ok
} }
// String returns string representation of SignatureScheme.
func (t SignatureScheme) String() string {
return refs.SignatureScheme(t).String()
}
// FromString parses SignatureScheme from a string representation.
// It is a reverse action to String().
//
// Returns true if s was parsed successfully.
func (t *SignatureScheme) FromString(s string) bool {
var g refs.SignatureScheme
ok := g.FromString(s)
if ok {
*t = SignatureScheme(g)
}
return ok
}

View file

@ -1,6 +1,8 @@
package refstest package refstest
import ( import (
"math/rand"
"github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/nspcc-dev/neofs-api-go/v2/refs"
) )
@ -88,6 +90,7 @@ func GenerateSignature(empty bool) *refs.Signature {
if !empty { if !empty {
m.SetKey([]byte{1}) m.SetKey([]byte{1})
m.SetSign([]byte{2}) m.SetSign([]byte{2})
m.SetScheme(refs.SignatureScheme(rand.Int31() % 3))
} }
return m return m

View file

@ -31,8 +31,17 @@ type Checksum struct {
type ChecksumType uint32 type ChecksumType uint32
type SignatureScheme uint32
const (
UnspecifiedScheme SignatureScheme = iota
ECDSA_SHA512
ECDSA_RFC6979_SHA256
)
type Signature struct { type Signature struct {
key, sign []byte key, sign []byte
scheme SignatureScheme
} }
type SubnetID struct { type SubnetID struct {
@ -175,6 +184,19 @@ func (s *Signature) SetSign(v []byte) {
} }
} }
func (s *Signature) GetScheme() SignatureScheme {
if s != nil {
return s.scheme
}
return UnspecifiedScheme
}
func (s *Signature) SetScheme(scheme SignatureScheme) {
if s != nil {
s.scheme = scheme
}
}
func (s *SubnetID) SetValue(id uint32) { func (s *SubnetID) SetValue(id uint32) {
if s != nil { if s != nil {
s.value = id s.value = id

View file

@ -131,19 +131,6 @@ func (s StableMarshalerWrapper) SignedDataSize() int {
return 0 return 0
} }
func keySignatureHandler(s *refs.Signature) signature.KeySignatureHandler {
return func(key []byte, sig []byte) {
s.SetKey(key)
s.SetSign(sig)
}
}
func keySignatureSource(s *refs.Signature) signature.KeySignatureSource {
return func() ([]byte, []byte) {
return s.GetKey(), s.GetSign()
}
}
func SignServiceMessage(key *ecdsa.PrivateKey, msg interface{}) error { func SignServiceMessage(key *ecdsa.PrivateKey, msg interface{}) error {
var ( var (
body, meta, verifyOrigin stableMarshaler body, meta, verifyOrigin stableMarshaler
@ -213,7 +200,9 @@ func signServiceMessagePart(key *ecdsa.PrivateKey, part stableMarshaler, sigWrit
if err := signature.SignDataWithHandler( if err := signature.SignDataWithHandler(
key, key,
&StableMarshalerWrapper{part}, &StableMarshalerWrapper{part},
keySignatureHandler(sig), func(s *refs.Signature) {
*sig = *s
},
); err != nil { ); err != nil {
return err return err
} }
@ -285,7 +274,7 @@ func verifyMatryoshkaLevel(body stableMarshaler, meta metaHeader, verify verific
func verifyServiceMessagePart(part stableMarshaler, sigRdr func() *refs.Signature) error { func verifyServiceMessagePart(part stableMarshaler, sigRdr func() *refs.Signature) error {
return signature.VerifyDataWithSource( return signature.VerifyDataWithSource(
&StableMarshalerWrapper{part}, &StableMarshalerWrapper{part},
keySignatureSource(sigRdr()), sigRdr,
) )
} }

View file

@ -3,6 +3,7 @@ package signature
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
crypto "github.com/nspcc-dev/neofs-crypto" crypto "github.com/nspcc-dev/neofs-crypto"
) )
@ -13,24 +14,24 @@ type DataSource interface {
type DataWithSignature interface { type DataWithSignature interface {
DataSource DataSource
GetSignatureWithKey() (key, sig []byte) GetSignature() *refs.Signature
SetSignatureWithKey(key, sig []byte) SetSignature(*refs.Signature)
} }
type SignOption func(*cfg) type SignOption func(*cfg)
type KeySignatureHandler func(key []byte, sig []byte) type KeySignatureHandler func(*refs.Signature)
type KeySignatureSource func() (key, sig []byte) type KeySignatureSource func() *refs.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 { if key == nil {
return nil, crypto.ErrEmptyPrivateKey return crypto.ErrEmptyPrivateKey
} }
data, err := dataForSignature(src) data, err := dataForSignature(src)
if err != nil { if err != nil {
return nil, err return err
} }
defer bytesPool.Put(data) defer bytesPool.Put(data)
@ -40,16 +41,16 @@ func DataSignature(key *ecdsa.PrivateKey, src DataSource, opts ...SignOption) ([
opts[i](cfg) opts[i](cfg)
} }
return cfg.signFunc(key, data) sigData, err := sign(cfg, cfg.defaultScheme, key, data)
}
func SignDataWithHandler(key *ecdsa.PrivateKey, src DataSource, handler KeySignatureHandler, opts ...SignOption) error {
sig, err := DataSignature(key, src, opts...)
if err != nil { if err != nil {
return err return err
} }
handler(crypto.MarshalPublicKey(&key.PublicKey), sig) sig := new(refs.Signature)
sig.SetScheme(cfg.defaultScheme)
sig.SetKey(crypto.MarshalPublicKey(&key.PublicKey))
sig.SetSign(sigData)
handler(sig)
return nil return nil
} }
@ -67,19 +68,13 @@ func VerifyDataWithSource(dataSrc DataSource, sigSrc KeySignatureSource, opts ..
opts[i](cfg) opts[i](cfg)
} }
key, sig := sigSrc() return verify(cfg, data, sigSrc())
return cfg.verifyFunc(
crypto.UnmarshalPublicKey(key),
data,
sig,
)
} }
func SignData(key *ecdsa.PrivateKey, v DataWithSignature, opts ...SignOption) error { 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 { func VerifyData(src DataWithSignature, opts ...SignOption) error {
return VerifyDataWithSource(src, src.GetSignatureWithKey, opts...) return VerifyDataWithSource(src, src.GetSignature, opts...)
} }

View file

@ -2,25 +2,58 @@ package signature
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"fmt"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
crypto "github.com/nspcc-dev/neofs-crypto" crypto "github.com/nspcc-dev/neofs-crypto"
) )
type cfg struct { type cfg struct {
signFunc func(key *ecdsa.PrivateKey, msg []byte) ([]byte, error) defaultScheme refs.SignatureScheme
verifyFunc func(key *ecdsa.PublicKey, msg []byte, sig []byte) error restrictScheme refs.SignatureScheme
} }
func defaultCfg() *cfg { func defaultCfg() *cfg {
return &cfg{ return &cfg{
signFunc: crypto.Sign, defaultScheme: refs.ECDSA_SHA512,
verifyFunc: crypto.Verify, restrictScheme: refs.UnspecifiedScheme,
}
}
func verify(cfg *cfg, data []byte, sig *refs.Signature) error {
scheme := sig.GetScheme()
if scheme == refs.UnspecifiedScheme {
scheme = cfg.defaultScheme
}
if cfg.restrictScheme != refs.UnspecifiedScheme && scheme != cfg.restrictScheme {
return fmt.Errorf("%w: unexpected signature scheme", crypto.ErrInvalidSignature)
}
pub := crypto.UnmarshalPublicKey(sig.GetKey())
switch scheme {
case refs.ECDSA_SHA512:
return crypto.Verify(pub, data, sig.GetSign())
case refs.ECDSA_RFC6979_SHA256:
return crypto.VerifyRFC6979(pub, data, sig.GetSign())
default:
return crypto.ErrInvalidSignature
}
}
func sign(cfg *cfg, scheme refs.SignatureScheme, key *ecdsa.PrivateKey, data []byte) ([]byte, error) {
switch scheme {
case refs.ECDSA_SHA512:
return crypto.Sign(key, data)
case refs.ECDSA_RFC6979_SHA256:
return crypto.SignRFC6979(key, data)
default:
panic("unsupported scheme")
} }
} }
func SignWithRFC6979() SignOption { func SignWithRFC6979() SignOption {
return func(c *cfg) { return func(c *cfg) {
c.signFunc = crypto.SignRFC6979 c.defaultScheme = refs.ECDSA_RFC6979_SHA256
c.verifyFunc = crypto.VerifyRFC6979 c.restrictScheme = refs.ECDSA_RFC6979_SHA256
} }
} }