[#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.SetSign(s.sign)
m.SetScheme(refs.SignatureScheme(s.scheme))
}
return m
@ -273,6 +274,7 @@ func (s *Signature) FromGRPCMessage(m grpc.Message) error {
s.key = v.GetKey()
s.sign = v.GetSign()
s.scheme = SignatureScheme(v.GetScheme())
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,
// 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
checksumValueField = 2
signatureKeyField = 1
signatureValueField = 2
signatureKeyField = 1
signatureValueField = 2
signatureSchemeField = 3
versionMajorField = 1
versionMinorField = 2
@ -250,7 +251,14 @@ func (s *Signature) StableMarshal(buf []byte) ([]byte, error) {
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 {
return nil, err
}
@ -265,6 +273,7 @@ func (s *Signature) StableSize() (size int) {
size += proto.BytesSize(signatureKeyField, s.key)
size += proto.BytesSize(signatureValueField, s.sign)
size += proto.EnumSize(signatureSchemeField, int32(s.scheme))
return size
}

View file

@ -24,3 +24,24 @@ func (t *ChecksumType) FromString(s string) bool {
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
import (
"math/rand"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
)
@ -88,6 +90,7 @@ func GenerateSignature(empty bool) *refs.Signature {
if !empty {
m.SetKey([]byte{1})
m.SetSign([]byte{2})
m.SetScheme(refs.SignatureScheme(rand.Int31() % 3))
}
return m

View file

@ -31,8 +31,17 @@ type Checksum struct {
type ChecksumType uint32
type SignatureScheme uint32
const (
UnspecifiedScheme SignatureScheme = iota
ECDSA_SHA512
ECDSA_RFC6979_SHA256
)
type Signature struct {
key, sign []byte
scheme SignatureScheme
}
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) {
if s != nil {
s.value = id

View file

@ -131,19 +131,6 @@ func (s StableMarshalerWrapper) SignedDataSize() int {
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 {
var (
body, meta, verifyOrigin stableMarshaler
@ -213,7 +200,9 @@ func signServiceMessagePart(key *ecdsa.PrivateKey, part stableMarshaler, sigWrit
if err := signature.SignDataWithHandler(
key,
&StableMarshalerWrapper{part},
keySignatureHandler(sig),
func(s *refs.Signature) {
*sig = *s
},
); err != nil {
return err
}
@ -285,7 +274,7 @@ func verifyMatryoshkaLevel(body stableMarshaler, meta metaHeader, verify verific
func verifyServiceMessagePart(part stableMarshaler, sigRdr func() *refs.Signature) error {
return signature.VerifyDataWithSource(
&StableMarshalerWrapper{part},
keySignatureSource(sigRdr()),
sigRdr,
)
}

View file

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

View file

@ -2,25 +2,58 @@ package signature
import (
"crypto/ecdsa"
"fmt"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
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
defaultScheme refs.SignatureScheme
restrictScheme refs.SignatureScheme
}
func defaultCfg() *cfg {
return &cfg{
signFunc: crypto.Sign,
verifyFunc: crypto.Verify,
defaultScheme: refs.ECDSA_SHA512,
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 {
return func(c *cfg) {
c.signFunc = crypto.SignRFC6979
c.verifyFunc = crypto.VerifyRFC6979
c.defaultScheme = refs.ECDSA_RFC6979_SHA256
c.restrictScheme = refs.ECDSA_RFC6979_SHA256
}
}