2023-02-28 10:01:18 +00:00
|
|
|
package signature
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/util/signature"
|
2023-02-28 15:52:50 +00:00
|
|
|
"golang.org/x/sync/errgroup"
|
2023-02-28 10:01:18 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type signatureProvider interface {
|
|
|
|
GetBodySignature() *refs.Signature
|
|
|
|
GetMetaSignature() *refs.Signature
|
|
|
|
GetOriginSignature() *refs.Signature
|
|
|
|
}
|
|
|
|
|
2023-02-28 15:52:50 +00:00
|
|
|
type buffers struct {
|
|
|
|
Body []byte
|
|
|
|
Meta []byte
|
|
|
|
Header []byte
|
|
|
|
}
|
|
|
|
|
2023-02-28 10:01:18 +00:00
|
|
|
// VerifyServiceMessage verifies service message.
|
|
|
|
func VerifyServiceMessage(msg interface{}) error {
|
|
|
|
switch v := msg.(type) {
|
|
|
|
case nil:
|
|
|
|
return nil
|
|
|
|
case serviceRequest:
|
|
|
|
return verifyServiceRequest(v)
|
|
|
|
case serviceResponse:
|
|
|
|
return verifyServiceResponse(v)
|
|
|
|
default:
|
|
|
|
panic(fmt.Sprintf("unsupported session message %T", v))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func verifyServiceRequest(v serviceRequest) error {
|
|
|
|
meta := v.GetMetaHeader()
|
|
|
|
verificationHeader := v.GetVerificationHeader()
|
|
|
|
body := serviceMessageBody(v)
|
2023-02-28 15:52:50 +00:00
|
|
|
buffers := createBuffers(body.StableSize(), meta.StableSize(), verificationHeader.StableSize())
|
|
|
|
return verifyServiceRequestRecursive(body, meta, verificationHeader, buffers)
|
|
|
|
}
|
|
|
|
|
|
|
|
func createBuffers(bodySize, metaSize, headerSize int) *buffers {
|
|
|
|
return &buffers{
|
|
|
|
Body: make([]byte, 0, bodySize),
|
|
|
|
Meta: make([]byte, 0, metaSize),
|
|
|
|
Header: make([]byte, 0, headerSize),
|
|
|
|
}
|
2023-02-28 10:01:18 +00:00
|
|
|
}
|
|
|
|
|
2023-02-28 15:52:50 +00:00
|
|
|
func verifyServiceRequestRecursive(body stableMarshaler, meta *session.RequestMetaHeader, verify *session.RequestVerificationHeader, buffers *buffers) error {
|
2023-02-28 10:01:18 +00:00
|
|
|
verificationHeaderOrigin := verify.GetOrigin()
|
|
|
|
metaOrigin := meta.GetOrigin()
|
|
|
|
|
2023-02-28 15:52:50 +00:00
|
|
|
stop, err := verifyMessageParts(body, meta, verificationHeaderOrigin, verificationHeaderOrigin != nil, verify, buffers)
|
2023-02-28 10:01:18 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if stop {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-02-28 15:52:50 +00:00
|
|
|
return verifyServiceRequestRecursive(body, metaOrigin, verificationHeaderOrigin, buffers)
|
2023-02-28 10:01:18 +00:00
|
|
|
}
|
|
|
|
|
2023-02-28 15:52:50 +00:00
|
|
|
func verifyMessageParts(body, meta, originHeader stableMarshaler, hasOriginHeader bool, sigProvider signatureProvider, buffers *buffers) (stop bool, err error) {
|
|
|
|
eg := &errgroup.Group{}
|
|
|
|
|
|
|
|
eg.Go(func() error {
|
|
|
|
if err := verifyServiceMessagePart(meta, sigProvider.GetMetaSignature, buffers.Meta); err != nil {
|
|
|
|
return fmt.Errorf("could not verify meta header: %w", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
eg.Go(func() error {
|
|
|
|
if err := verifyServiceMessagePart(originHeader, sigProvider.GetOriginSignature, buffers.Header); err != nil {
|
|
|
|
return fmt.Errorf("could not verify origin of verification header: %w", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
if !hasOriginHeader {
|
|
|
|
eg.Go(func() error {
|
|
|
|
if err := verifyServiceMessagePart(body, sigProvider.GetBodySignature, buffers.Body); err != nil {
|
|
|
|
return fmt.Errorf("could not verify body: %w", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
2023-02-28 10:01:18 +00:00
|
|
|
}
|
|
|
|
|
2023-02-28 15:52:50 +00:00
|
|
|
if err := eg.Wait(); err != nil {
|
|
|
|
return false, err
|
2023-02-28 10:01:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if !hasOriginHeader {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if sigProvider.GetBodySignature() != nil {
|
|
|
|
return false, errors.New("body signature misses at the matryoshka upper level")
|
|
|
|
}
|
|
|
|
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func verifyServiceResponse(v serviceResponse) error {
|
|
|
|
meta := v.GetMetaHeader()
|
|
|
|
verificationHeader := v.GetVerificationHeader()
|
|
|
|
body := serviceMessageBody(v)
|
2023-02-28 15:52:50 +00:00
|
|
|
buffers := createBuffers(body.StableSize(), meta.StableSize(), verificationHeader.StableSize())
|
|
|
|
return verifyServiceResponseRecursive(body, meta, verificationHeader, buffers)
|
2023-02-28 10:01:18 +00:00
|
|
|
}
|
|
|
|
|
2023-02-28 15:52:50 +00:00
|
|
|
func verifyServiceResponseRecursive(body stableMarshaler, meta *session.ResponseMetaHeader, verify *session.ResponseVerificationHeader, buffers *buffers) error {
|
2023-02-28 10:01:18 +00:00
|
|
|
verificationHeaderOrigin := verify.GetOrigin()
|
|
|
|
metaOrigin := meta.GetOrigin()
|
|
|
|
|
2023-02-28 15:52:50 +00:00
|
|
|
stop, err := verifyMessageParts(body, meta, verificationHeaderOrigin, verificationHeaderOrigin != nil, verify, buffers)
|
2023-02-28 10:01:18 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if stop {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-02-28 15:52:50 +00:00
|
|
|
return verifyServiceResponseRecursive(body, metaOrigin, verificationHeaderOrigin, buffers)
|
2023-02-28 10:01:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func verifyServiceMessagePart(part stableMarshaler, sigRdr func() *refs.Signature, buf []byte) error {
|
|
|
|
return signature.VerifyDataWithSource(
|
|
|
|
&StableMarshalerWrapper{part},
|
|
|
|
sigRdr,
|
|
|
|
signature.WithBuffer(buf),
|
|
|
|
)
|
|
|
|
}
|