forked from TrueCloudLab/frostfs-api-go
[#393] util/signature: Remove bytes pool and provide buffer explicitly
Chained verification is done in a single thread there is no need to use pool to do this. Also because newly allocated items are 5 MiB in size we can run out of memory given that typical header it much less in size. Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
e8e09f0d00
commit
77a3ba9197
4 changed files with 46 additions and 49 deletions
|
@ -242,22 +242,32 @@ func VerifyServiceMessage(msg interface{}) error {
|
||||||
panic(fmt.Sprintf("unsupported session message %T", v))
|
panic(fmt.Sprintf("unsupported session message %T", v))
|
||||||
}
|
}
|
||||||
|
|
||||||
return verifyMatryoshkaLevel(serviceMessageBody(msg), meta, verify)
|
body := serviceMessageBody(msg)
|
||||||
|
size := body.StableSize()
|
||||||
|
if sz := meta.StableSize(); sz > size {
|
||||||
|
size = sz
|
||||||
|
}
|
||||||
|
if sz := verify.StableSize(); sz > size {
|
||||||
|
size = sz
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyMatryoshkaLevel(body stableMarshaler, meta metaHeader, verify verificationHeader) error {
|
buf := make([]byte, 0, size)
|
||||||
if err := verifyServiceMessagePart(meta, verify.GetMetaSignature); err != nil {
|
return verifyMatryoshkaLevel(body, meta, verify, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyMatryoshkaLevel(body stableMarshaler, meta metaHeader, verify verificationHeader, buf []byte) error {
|
||||||
|
if err := verifyServiceMessagePart(meta, verify.GetMetaSignature, buf); err != nil {
|
||||||
return fmt.Errorf("could not verify meta header: %w", err)
|
return fmt.Errorf("could not verify meta header: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
origin := verify.getOrigin()
|
origin := verify.getOrigin()
|
||||||
|
|
||||||
if err := verifyServiceMessagePart(origin, verify.GetOriginSignature); err != nil {
|
if err := verifyServiceMessagePart(origin, verify.GetOriginSignature, buf); err != nil {
|
||||||
return fmt.Errorf("could not verify origin of verification header: %w", err)
|
return fmt.Errorf("could not verify origin of verification header: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if origin == nil {
|
if origin == nil {
|
||||||
if err := verifyServiceMessagePart(body, verify.GetBodySignature); err != nil {
|
if err := verifyServiceMessagePart(body, verify.GetBodySignature, buf); err != nil {
|
||||||
return fmt.Errorf("could not verify body: %w", err)
|
return fmt.Errorf("could not verify body: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,13 +278,14 @@ func verifyMatryoshkaLevel(body stableMarshaler, meta metaHeader, verify verific
|
||||||
return errors.New("body signature at the matryoshka upper level")
|
return errors.New("body signature at the matryoshka upper level")
|
||||||
}
|
}
|
||||||
|
|
||||||
return verifyMatryoshkaLevel(body, meta.getOrigin(), origin)
|
return verifyMatryoshkaLevel(body, meta.getOrigin(), origin, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyServiceMessagePart(part stableMarshaler, sigRdr func() *refs.Signature) error {
|
func verifyServiceMessagePart(part stableMarshaler, sigRdr func() *refs.Signature, buf []byte) error {
|
||||||
return signature.VerifyDataWithSource(
|
return signature.VerifyDataWithSource(
|
||||||
&StableMarshalerWrapper{part},
|
&StableMarshalerWrapper{part},
|
||||||
sigRdr,
|
sigRdr,
|
||||||
|
signature.WithBuffer(buf),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,18 +29,17 @@ func SignDataWithHandler(key *ecdsa.PrivateKey, src DataSource, handler KeySigna
|
||||||
return crypto.ErrEmptyPrivateKey
|
return crypto.ErrEmptyPrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := dataForSignature(src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer bytesPool.Put(data)
|
|
||||||
|
|
||||||
cfg := defaultCfg()
|
cfg := defaultCfg()
|
||||||
|
|
||||||
for i := range opts {
|
for i := range opts {
|
||||||
opts[i](cfg)
|
opts[i](cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data, err := readSignedData(cfg, src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
sigData, err := sign(cfg, key, data)
|
sigData, err := sign(cfg, key, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -56,18 +55,17 @@ func SignDataWithHandler(key *ecdsa.PrivateKey, src DataSource, handler KeySigna
|
||||||
}
|
}
|
||||||
|
|
||||||
func VerifyDataWithSource(dataSrc DataSource, sigSrc KeySignatureSource, opts ...SignOption) error {
|
func VerifyDataWithSource(dataSrc DataSource, sigSrc KeySignatureSource, opts ...SignOption) error {
|
||||||
data, err := dataForSignature(dataSrc)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer bytesPool.Put(data)
|
|
||||||
|
|
||||||
cfg := defaultCfg()
|
cfg := defaultCfg()
|
||||||
|
|
||||||
for i := range opts {
|
for i := range opts {
|
||||||
opts[i](cfg)
|
opts[i](cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data, err := readSignedData(cfg, dataSrc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return verify(cfg, data, sigSrc())
|
return verify(cfg, data, sigSrc())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,3 +76,13 @@ func SignData(key *ecdsa.PrivateKey, v DataWithSignature, opts ...SignOption) er
|
||||||
func VerifyData(src DataWithSignature, opts ...SignOption) error {
|
func VerifyData(src DataWithSignature, opts ...SignOption) error {
|
||||||
return VerifyDataWithSource(src, src.GetSignature, opts...)
|
return VerifyDataWithSource(src, src.GetSignature, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readSignedData(cfg *cfg, src DataSource) ([]byte, error) {
|
||||||
|
size := src.SignedDataSize()
|
||||||
|
if cfg.buffer == nil || cap(cfg.buffer) < size {
|
||||||
|
cfg.buffer = make([]byte, size)
|
||||||
|
} else {
|
||||||
|
cfg.buffer = cfg.buffer[:size]
|
||||||
|
}
|
||||||
|
return src.ReadSignedData(cfg.buffer)
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
type cfg struct {
|
type cfg struct {
|
||||||
schemeFixed bool
|
schemeFixed bool
|
||||||
scheme refs.SignatureScheme
|
scheme refs.SignatureScheme
|
||||||
|
buffer []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultCfg() *cfg {
|
func defaultCfg() *cfg {
|
||||||
|
@ -51,3 +52,10 @@ func SignWithRFC6979() SignOption {
|
||||||
c.scheme = refs.ECDSA_RFC6979_SHA256
|
c.scheme = refs.ECDSA_RFC6979_SHA256
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithBuffer allows providing pre-allocated buffer for signature verification.
|
||||||
|
func WithBuffer(buf []byte) SignOption {
|
||||||
|
return func(c *cfg) {
|
||||||
|
c.buffer = buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
package signature
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
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.SignedDataSize(); 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)
|
|
||||||
}
|
|
Loading…
Reference in a new issue