Implement new request signing mechanism

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
Leonard Lyubich 2020-08-14 15:51:10 +03:00 committed by Stanislav Bogatyrev
parent 59858805a8
commit 6191903326
9 changed files with 904 additions and 64 deletions

0
pkg/.gitkeep Normal file
View file

View file

@ -1,64 +0,0 @@
package signature
import (
"crypto/ecdsa"
"github.com/pkg/errors"
)
type SignedRequest interface {
RequestBody() DataSource
RequestMetaHeader() DataSource
OriginVerificationHeader() DataSource
SetBodySignatureWithKey(key, sig []byte)
BodySignatureWithKey() (key, sig []byte)
SetMetaSignatureWithKey(key, sig []byte)
MetaSignatureWithKey() (key, sig []byte)
SetOriginSignatureWithKey(key, sig []byte)
OriginSignatureWithKey() (key, sig []byte)
}
func SignRequest(key *ecdsa.PrivateKey, src SignedRequest) error {
if src == nil {
return errors.New("nil source")
}
// sign body
if err := SignDataWithHandler(key, src.RequestBody(), src.SetBodySignatureWithKey); err != nil {
return errors.Wrap(err, "could not sign body")
}
// sign meta
if err := SignDataWithHandler(key, src.RequestMetaHeader(), src.SetMetaSignatureWithKey); err != nil {
return errors.Wrap(err, "could not sign meta header")
}
// sign verify origin
if err := SignDataWithHandler(key, src.OriginVerificationHeader(), src.SetOriginSignatureWithKey); err != nil {
return errors.Wrap(err, "could not sign verification header origin")
}
return nil
}
func VerifyRequest(src SignedRequest) error {
// verify body signature
if err := VerifyDataWithSource(src.RequestBody(), src.BodySignatureWithKey); err != nil {
return errors.Wrap(err, "could not verify body")
}
// verify meta header
if err := VerifyDataWithSource(src.RequestMetaHeader(), src.MetaSignatureWithKey); err != nil {
return errors.Wrap(err, "could not verify meta header")
}
// verify verification header origin
if err := VerifyDataWithSource(src.OriginVerificationHeader(), src.OriginSignatureWithKey); err != nil {
return errors.Wrap(err, "could not verify verification header origin")
}
return nil
}

85
v2/accounting.go Normal file
View file

@ -0,0 +1,85 @@
package v2
type BalanceRequestBody struct {
ownerID *OwnerID
}
type BalanceRequest struct {
body *BalanceRequestBody
metaHeader *RequestMetaHeader
verifyHeader *RequestVerificationHeader
}
func (b *BalanceRequestBody) GetOwnerID() *OwnerID {
if b != nil {
return b.ownerID
}
return nil
}
func (b *BalanceRequestBody) SetOwnerID(v *OwnerID) {
if b != nil {
b.ownerID = v
}
}
func (r *BalanceRequestBody) StableMarshal(buf []byte) ([]byte, error) {
if r == nil {
return nil, nil
}
// TODO: do not use hack
_, err := BalanceRequestBodyToGRPCMessage(r).MarshalTo(buf)
return buf, err
}
func (r *BalanceRequestBody) StableSize() int {
// TODO: do not use hack
return BalanceRequestBodyToGRPCMessage(r).Size()
}
func (b *BalanceRequest) GetBody() *BalanceRequestBody {
if b != nil {
return b.body
}
return nil
}
func (b *BalanceRequest) SetBody(v *BalanceRequestBody) {
if b != nil {
b.body = v
}
}
func (b *BalanceRequest) GetRequestMetaHeader() *RequestMetaHeader {
if b != nil {
return b.metaHeader
}
return nil
}
func (b *BalanceRequest) SetRequestMetaHeader(v *RequestMetaHeader) {
if b != nil {
b.metaHeader = v
}
}
func (b *BalanceRequest) GetRequestVerificationHeader() *RequestVerificationHeader {
if b != nil {
return b.verifyHeader
}
return nil
}
func (b *BalanceRequest) SetRequestVerificationHeader(v *RequestVerificationHeader) {
if b != nil {
b.verifyHeader = v
}
}

351
v2/convert.go Normal file
View file

@ -0,0 +1,351 @@
package v2
import (
"github.com/nspcc-dev/neofs-api-go/v2/accounting"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
"github.com/nspcc-dev/neofs-api-go/v2/service"
)
func SignatureToGRPCMessage(s *Signature) *service.Signature {
if s == nil {
return nil
}
m := new(service.Signature)
m.SetKey(s.GetKey())
m.SetSign(s.GetSign())
return m
}
func SignatureFromGRPCMessage(m *service.Signature) *Signature {
if m == nil {
return nil
}
s := new(Signature)
s.SetKey(m.GetKey())
s.SetSign(m.GetSign())
return s
}
func VersionToGRPCMessage(v *Version) *service.Version {
if v == nil {
return nil
}
msg := new(service.Version)
msg.SetMajor(v.GetMajor())
msg.SetMinor(v.GetMinor())
return msg
}
func VersionFromGRPCMessage(m *service.Version) *Version {
if m == nil {
return nil
}
v := new(Version)
v.SetMajor(m.GetMajor())
v.SetMinor(m.GetMinor())
return v
}
func XHeaderToGRPCMessage(x *XHeader) *service.XHeader {
if x == nil {
return nil
}
m := new(service.XHeader)
m.SetKey(x.GetKey())
m.SetValue(x.GetValue())
return m
}
func XHeaderFromGRPCMessage(m *service.XHeader) *XHeader {
if m == nil {
return nil
}
x := new(XHeader)
x.SetKey(m.GetKey())
x.SetValue(m.GetValue())
return x
}
func SessionTokenToGRPCMessage(t *SessionToken) *service.SessionToken {
// TODO: fill me
return nil
}
func SessionTokenFromGRPCMessage(m *service.SessionToken) *SessionToken {
// TODO: fill me
return nil
}
func BearerTokenToGRPCMessage(t *BearerToken) *service.BearerToken {
// TODO: fill me
return nil
}
func BearerTokenFromGRPCMessage(m *service.BearerToken) *BearerToken {
// TODO: fill me
return nil
}
func RequestVerificationHeaderToGRPCMessage(r *RequestVerificationHeader) *service.RequestVerificationHeader {
if r == nil {
return nil
}
m := new(service.RequestVerificationHeader)
m.SetBodySignature(
SignatureToGRPCMessage(r.GetBodySignature()),
)
m.SetMetaSignature(
SignatureToGRPCMessage(r.GetMetaSignature()),
)
m.SetOriginSignature(
SignatureToGRPCMessage(r.GetOriginSignature()),
)
m.SetOrigin(
RequestVerificationHeaderToGRPCMessage(r.GetOrigin()),
)
return m
}
func RequestVerificationHeaderFromGRPCMessage(m *service.RequestVerificationHeader) *RequestVerificationHeader {
if m == nil {
return nil
}
r := new(RequestVerificationHeader)
r.SetBodySignature(
SignatureFromGRPCMessage(m.GetBodySignature()),
)
r.SetMetaSignature(
SignatureFromGRPCMessage(m.GetMetaSignature()),
)
r.SetOriginSignature(
SignatureFromGRPCMessage(m.GetOriginSignature()),
)
r.SetOrigin(
RequestVerificationHeaderFromGRPCMessage(m.GetOrigin()),
)
return r
}
func RequestMetaHeaderToGRPCMessage(r *RequestMetaHeader) *service.RequestMetaHeader {
if r == nil {
return nil
}
m := new(service.RequestMetaHeader)
m.SetTtl(r.GetTTL())
m.SetEpoch(r.GetEpoch())
m.SetVersion(
VersionToGRPCMessage(r.GetVersion()),
)
m.SetSessionToken(
SessionTokenToGRPCMessage(r.GetSessionToken()),
)
m.SetBearerToken(
BearerTokenToGRPCMessage(r.GetBearerToken()),
)
m.SetOrigin(
RequestMetaHeaderToGRPCMessage(r.GetOrigin()),
)
xHeaders := r.GetXHeaders()
xHdrMsg := make([]*service.XHeader, 0, len(xHeaders))
for i := range xHeaders {
xHdrMsg = append(xHdrMsg, XHeaderToGRPCMessage(xHeaders[i]))
}
return m
}
func RequestMetaHeaderFromGRPCMessage(m *service.RequestMetaHeader) *RequestMetaHeader {
if m == nil {
return nil
}
r := new(RequestMetaHeader)
r.SetTTL(m.GetTtl())
r.SetEpoch(m.GetEpoch())
r.SetVersion(
VersionFromGRPCMessage(m.GetVersion()),
)
r.SetSessionToken(
SessionTokenFromGRPCMessage(m.GetSessionToken()),
)
r.SetBearerToken(
BearerTokenFromGRPCMessage(m.GetBearerToken()),
)
r.SetOrigin(
RequestMetaHeaderFromGRPCMessage(m.GetOrigin()),
)
xHdrMsg := m.GetXHeaders()
xHeaders := make([]*XHeader, 0, len(xHdrMsg))
for i := range xHdrMsg {
xHeaders = append(xHeaders, XHeaderFromGRPCMessage(xHdrMsg[i]))
}
return r
}
func OwnerIDToGRPCMessage(o *OwnerID) *refs.OwnerID {
if o == nil {
return nil
}
m := new(refs.OwnerID)
m.SetValue(o.GetValue())
return m
}
func OwnerIDFromGRPCMessage(m *refs.OwnerID) *OwnerID {
if m == nil {
return nil
}
o := new(OwnerID)
o.SetValue(m.GetValue())
return o
}
func BalanceRequestBodyToGRPCMessage(b *BalanceRequestBody) *accounting.BalanceRequest_Body {
if b == nil {
return nil
}
m := new(accounting.BalanceRequest_Body)
m.SetOwnerId(
OwnerIDToGRPCMessage(b.GetOwnerID()),
)
return m
}
func BalanceRequestBodyFromGRPCMessage(m *accounting.BalanceRequest_Body) *BalanceRequestBody {
if m == nil {
return nil
}
b := new(BalanceRequestBody)
b.SetOwnerID(
OwnerIDFromGRPCMessage(m.GetOwnerId()),
)
return b
}
func headersToGRPC(
src interface {
GetRequestMetaHeader() *RequestMetaHeader
GetRequestVerificationHeader() *RequestVerificationHeader
},
dst interface {
SetMetaHeader(*service.RequestMetaHeader)
SetVerifyHeader(*service.RequestVerificationHeader)
},
) {
dst.SetMetaHeader(
RequestMetaHeaderToGRPCMessage(src.GetRequestMetaHeader()),
)
dst.SetVerifyHeader(
RequestVerificationHeaderToGRPCMessage(src.GetRequestVerificationHeader()),
)
}
func headersFromGRPC(
src interface {
GetMetaHeader() *service.RequestMetaHeader
GetVerifyHeader() *service.RequestVerificationHeader
},
dst interface {
SetRequestMetaHeader(*RequestMetaHeader)
SetRequestVerificationHeader(*RequestVerificationHeader)
},
) {
dst.SetRequestMetaHeader(
RequestMetaHeaderFromGRPCMessage(src.GetMetaHeader()),
)
dst.SetRequestVerificationHeader(
RequestVerificationHeaderFromGRPCMessage(src.GetVerifyHeader()),
)
}
func BalanceRequestToGRPCMessage(b *BalanceRequest) *accounting.BalanceRequest {
if b == nil {
return nil
}
m := new(accounting.BalanceRequest)
m.SetBody(
BalanceRequestBodyToGRPCMessage(b.GetBody()),
)
headersToGRPC(b, m)
return m
}
func BalanceRequestFromGRPCMessage(m *accounting.BalanceRequest) *BalanceRequest {
if m == nil {
return nil
}
b := new(BalanceRequest)
b.SetBody(
BalanceRequestBodyFromGRPCMessage(m.GetBody()),
)
headersFromGRPC(m, b)
return b
}

331
v2/service.go Normal file
View file

@ -0,0 +1,331 @@
package v2
type Signature struct {
key, sign []byte
}
type Version struct {
major, minor uint32
}
type XHeader struct {
key, val string
}
type SessionToken struct {
// TODO: fill me
}
type BearerToken struct {
// TODO: fill me
}
type RequestVerificationHeader struct {
bodySig, metaSig, originSig *Signature
origin *RequestVerificationHeader
}
type RequestMetaHeader struct {
version *Version
ttl uint32
epoch uint64
xHeaders []*XHeader
sessionToken *SessionToken
bearerToken *BearerToken
origin *RequestMetaHeader
}
type OwnerID struct {
val []byte
}
func (s *Signature) GetKey() []byte {
if s != nil {
return s.key
}
return nil
}
func (s *Signature) SetKey(v []byte) {
if s != nil {
s.key = v
}
}
func (s *Signature) GetSign() []byte {
if s != nil {
return s.sign
}
return nil
}
func (s *Signature) SetSign(v []byte) {
if s != nil {
s.sign = v
}
}
func (v *Version) GetMajor() uint32 {
if v != nil {
return v.major
}
return 0
}
func (v *Version) SetMajor(val uint32) {
if v != nil {
v.major = val
}
}
func (v *Version) GetMinor() uint32 {
if v != nil {
return v.minor
}
return 0
}
func (v *Version) SetMinor(val uint32) {
if v != nil {
v.minor = val
}
}
func (x *XHeader) GetKey() string {
if x != nil {
return x.key
}
return ""
}
func (x *XHeader) SetKey(v string) {
if x != nil {
x.key = v
}
}
func (x *XHeader) GetValue() string {
if x != nil {
return x.val
}
return ""
}
func (x *XHeader) SetValue(v string) {
if x != nil {
x.val = v
}
}
func (r *RequestVerificationHeader) GetBodySignature() *Signature {
if r != nil {
return r.bodySig
}
return nil
}
func (r *RequestVerificationHeader) SetBodySignature(v *Signature) {
if r != nil {
r.bodySig = v
}
}
func (r *RequestVerificationHeader) GetMetaSignature() *Signature {
if r != nil {
return r.metaSig
}
return nil
}
func (r *RequestVerificationHeader) SetMetaSignature(v *Signature) {
if r != nil {
r.metaSig = v
}
}
func (r *RequestVerificationHeader) GetOriginSignature() *Signature {
if r != nil {
return r.originSig
}
return nil
}
func (r *RequestVerificationHeader) SetOriginSignature(v *Signature) {
if r != nil {
r.originSig = v
}
}
func (r *RequestVerificationHeader) GetOrigin() *RequestVerificationHeader {
if r != nil {
return r.origin
}
return nil
}
func (r *RequestVerificationHeader) SetOrigin(v *RequestVerificationHeader) {
if r != nil {
r.origin = v
}
}
func (r *RequestVerificationHeader) StableMarshal(buf []byte) ([]byte, error) {
if r == nil {
return nil, nil
}
// TODO: do not use hack
_, err := RequestVerificationHeaderToGRPCMessage(r).MarshalTo(buf)
return buf, err
}
func (r *RequestVerificationHeader) StableSize() int {
// TODO: do not use hack
return RequestVerificationHeaderToGRPCMessage(r).Size()
}
func (r *RequestMetaHeader) GetVersion() *Version {
if r != nil {
return r.version
}
return nil
}
func (r *RequestMetaHeader) SetVersion(v *Version) {
if r != nil {
r.version = v
}
}
func (r *RequestMetaHeader) GetTTL() uint32 {
if r != nil {
return r.ttl
}
return 0
}
func (r *RequestMetaHeader) SetTTL(v uint32) {
if r != nil {
r.ttl = v
}
}
func (r *RequestMetaHeader) GetEpoch() uint64 {
if r != nil {
return r.epoch
}
return 0
}
func (r *RequestMetaHeader) SetEpoch(v uint64) {
if r != nil {
r.epoch = v
}
}
func (r *RequestMetaHeader) GetXHeaders() []*XHeader {
if r != nil {
return r.xHeaders
}
return nil
}
func (r *RequestMetaHeader) SetXHeaders(v []*XHeader) {
if r != nil {
r.xHeaders = v
}
}
func (r *RequestMetaHeader) GetSessionToken() *SessionToken {
if r != nil {
return r.sessionToken
}
return nil
}
func (r *RequestMetaHeader) SetSessionToken(v *SessionToken) {
if r != nil {
r.sessionToken = v
}
}
func (r *RequestMetaHeader) GetBearerToken() *BearerToken {
if r != nil {
return r.bearerToken
}
return nil
}
func (r *RequestMetaHeader) SetBearerToken(v *BearerToken) {
if r != nil {
r.bearerToken = v
}
}
func (r *RequestMetaHeader) GetOrigin() *RequestMetaHeader {
if r != nil {
return r.origin
}
return nil
}
func (r *RequestMetaHeader) SetOrigin(v *RequestMetaHeader) {
if r != nil {
r.origin = v
}
}
func (r *RequestMetaHeader) StableMarshal(buf []byte) ([]byte, error) {
if r == nil {
return nil, nil
}
// TODO: do not use hack
_, err := RequestMetaHeaderToGRPCMessage(r).MarshalTo(buf)
return buf, err
}
func (r *RequestMetaHeader) StableSize() int {
// TODO: do not use hack
return RequestMetaHeaderToGRPCMessage(r).Size()
}
func (o *OwnerID) GetValue() []byte {
if o != nil {
return o.val
}
return nil
}
func (o *OwnerID) SetValue(v []byte) {
if o != nil {
o.val = v
}
}

137
v2/signature/sign.go Normal file
View file

@ -0,0 +1,137 @@
package signature
import (
"crypto/ecdsa"
"fmt"
"github.com/nspcc-dev/neofs-api-go/util/signature"
v2 "github.com/nspcc-dev/neofs-api-go/v2"
"github.com/pkg/errors"
)
type SignedRequest interface {
GetRequestMetaHeader() *v2.RequestMetaHeader
GetRequestVerificationHeader() *v2.RequestVerificationHeader
SetRequestVerificationHeader(*v2.RequestVerificationHeader)
}
type stableMarshaler interface {
StableMarshal([]byte) ([]byte, error)
StableSize() int
}
type stableMarshalerWrapper struct {
sm stableMarshaler
}
func (s stableMarshalerWrapper) ReadSignedData(buf []byte) ([]byte, error) {
return s.sm.StableMarshal(buf)
}
func (s stableMarshalerWrapper) SignedDataSize() int {
return s.sm.StableSize()
}
func keySignatureHandler(s *v2.Signature) signature.KeySignatureHandler {
return func(key []byte, sig []byte) {
s.SetKey(key)
s.SetSign(sig)
}
}
func keySignatureSource(s *v2.Signature) signature.KeySignatureSource {
return func() ([]byte, []byte) {
return s.GetKey(), s.GetSign()
}
}
func requestBody(req SignedRequest) stableMarshaler {
switch v := req.(type) {
case *v2.BalanceRequest:
return v.GetBody()
default:
panic(fmt.Sprintf("unknown request %T", req))
}
}
func SignRequest(key *ecdsa.PrivateKey, req SignedRequest) error {
if req == nil {
return nil
}
// create new level of matryoshka
verifyHdr := new(v2.RequestVerificationHeader)
// attach the previous matryoshka
verifyHdr.SetOrigin(req.GetRequestVerificationHeader())
// sign request body
if err := signRequestPart(key, requestBody(req), verifyHdr.SetBodySignature); err != nil {
return errors.Wrap(err, "could not sign request body")
}
// sign meta header
if err := signRequestPart(key, req.GetRequestMetaHeader(), verifyHdr.SetMetaSignature); err != nil {
return errors.Wrap(err, "could not sign request meta header")
}
// sign verification header origin
if err := signRequestPart(key, verifyHdr.GetOrigin(), verifyHdr.SetOriginSignature); err != nil {
return errors.Wrap(err, "could not sign origin of request verification header")
}
// make a new top of the matryoshka
req.SetRequestVerificationHeader(verifyHdr)
return nil
}
func signRequestPart(key *ecdsa.PrivateKey, part stableMarshaler, sigWrite func(*v2.Signature)) error {
sig := new(v2.Signature)
// sign part
if err := signature.SignDataWithHandler(
key,
&stableMarshalerWrapper{part},
keySignatureHandler(sig),
); err != nil {
return err
}
// write part signature
sigWrite(sig)
return nil
}
func VerifyRequest(req SignedRequest) error {
verifyHdr := req.GetRequestVerificationHeader()
// verify body signature
if err := verifyRequestPart(requestBody(req), verifyHdr.GetBodySignature); err != nil {
return errors.Wrap(err, "could not verify request body")
}
// verify meta header
if err := verifyRequestPart(req.GetRequestMetaHeader(), verifyHdr.GetMetaSignature); err != nil {
return errors.Wrap(err, "could not verify request meta header")
}
// verify verification header origin
if err := verifyRequestPart(verifyHdr.GetOrigin(), verifyHdr.GetOriginSignature); err != nil {
return errors.Wrap(err, "could not verify origin of request verification header")
}
return nil
}
func verifyRequestPart(part stableMarshaler, sigRdr func() *v2.Signature) error {
if err := signature.VerifyDataWithSource(
&stableMarshalerWrapper{part},
keySignatureSource(sigRdr()),
); err != nil {
return err
}
return nil
}