forked from TrueCloudLab/frostfs-api-go
[#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.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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
BIN
refs/grpc/types.pb.go
generated
Binary file not shown.
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue