[#55] refs: Add Scheme field to Signature
Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
66e1fb8c53
commit
a4349f6692
10 changed files with 140 additions and 46 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
BIN
refs/grpc/types.pb.go
generated
Binary file not shown.
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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...)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue