forked from TrueCloudLab/frostfs-api-go
Resolve update conflicts
This commit is contained in:
parent
24108f42c3
commit
4ac17201b7
13 changed files with 61 additions and 320 deletions
|
@ -19,21 +19,6 @@ func (m Object) IsLinking() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerificationHeader returns verification header if it is presented in extended headers.
|
|
||||||
func (m Object) VerificationHeader() (*VerificationHeader, error) {
|
|
||||||
_, vh := m.LastHeader(HeaderType(VerifyHdr))
|
|
||||||
if vh == nil {
|
|
||||||
return nil, ErrHeaderNotFound
|
|
||||||
}
|
|
||||||
return vh.Value.(*Header_Verify).Verify, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetVerificationHeader sets verification header in the object.
|
|
||||||
// It will replace existing verification header or add a new one.
|
|
||||||
func (m *Object) SetVerificationHeader(header *VerificationHeader) {
|
|
||||||
m.SetHeader(&Header{Value: &Header_Verify{Verify: header}})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Links returns slice of ids of specified link type
|
// Links returns slice of ids of specified link type
|
||||||
func (m *Object) Links(t Link_Type) []ID {
|
func (m *Object) Links(t Link_Type) []ID {
|
||||||
var res []ID
|
var res []ID
|
||||||
|
|
|
@ -16,8 +16,8 @@ func TestRequest(t *testing.T) {
|
||||||
&DeleteRequest{},
|
&DeleteRequest{},
|
||||||
&GetRangeRequest{},
|
&GetRangeRequest{},
|
||||||
&GetRangeHashRequest{},
|
&GetRangeHashRequest{},
|
||||||
MakePutRequestHeader(nil, nil),
|
MakePutRequestHeader(nil),
|
||||||
MakePutRequestHeader(&Object{}, nil),
|
MakePutRequestHeader(&Object{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
types := []RequestType{
|
types := []RequestType{
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"github.com/gogo/protobuf/proto"
|
"github.com/gogo/protobuf/proto"
|
||||||
"github.com/nspcc-dev/neofs-api-go/internal"
|
"github.com/nspcc-dev/neofs-api-go/internal"
|
||||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
"github.com/nspcc-dev/neofs-api-go/refs"
|
||||||
"github.com/nspcc-dev/neofs-api-go/session"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
@ -19,9 +18,6 @@ type (
|
||||||
// Address is a type alias of object Address.
|
// Address is a type alias of object Address.
|
||||||
Address = refs.Address
|
Address = refs.Address
|
||||||
|
|
||||||
// VerificationHeader is a type alias of session's verification header.
|
|
||||||
VerificationHeader = session.VerificationHeader
|
|
||||||
|
|
||||||
// PositionReader defines object reader that returns slice of bytes
|
// PositionReader defines object reader that returns slice of bytes
|
||||||
// for specified object and data range.
|
// for specified object and data range.
|
||||||
PositionReader interface {
|
PositionReader interface {
|
||||||
|
@ -60,8 +56,8 @@ const (
|
||||||
TransformHdr
|
TransformHdr
|
||||||
// TombstoneHdr is a tombstone header type.
|
// TombstoneHdr is a tombstone header type.
|
||||||
TombstoneHdr
|
TombstoneHdr
|
||||||
// VerifyHdr is a verification header type.
|
// TokenHdr is a token header type.
|
||||||
VerifyHdr
|
TokenHdr
|
||||||
// HomoHashHdr is a homomorphic hash header type.
|
// HomoHashHdr is a homomorphic hash header type.
|
||||||
HomoHashHdr
|
HomoHashHdr
|
||||||
// PayloadChecksumHdr is a payload checksum header type.
|
// PayloadChecksumHdr is a payload checksum header type.
|
||||||
|
@ -175,8 +171,8 @@ func (m Header) typeOf(t isHeader_Value) (ok bool) {
|
||||||
_, ok = m.Value.(*Header_Transform)
|
_, ok = m.Value.(*Header_Transform)
|
||||||
case *Header_Tombstone:
|
case *Header_Tombstone:
|
||||||
_, ok = m.Value.(*Header_Tombstone)
|
_, ok = m.Value.(*Header_Tombstone)
|
||||||
case *Header_Verify:
|
case *Header_Token:
|
||||||
_, ok = m.Value.(*Header_Verify)
|
_, ok = m.Value.(*Header_Token)
|
||||||
case *Header_HomoHash:
|
case *Header_HomoHash:
|
||||||
_, ok = m.Value.(*Header_HomoHash)
|
_, ok = m.Value.(*Header_HomoHash)
|
||||||
case *Header_PayloadChecksum:
|
case *Header_PayloadChecksum:
|
||||||
|
@ -205,8 +201,8 @@ func HeaderType(t headerType) Pred {
|
||||||
return func(h *Header) bool { _, ok := h.Value.(*Header_Transform); return ok }
|
return func(h *Header) bool { _, ok := h.Value.(*Header_Transform); return ok }
|
||||||
case TombstoneHdr:
|
case TombstoneHdr:
|
||||||
return func(h *Header) bool { _, ok := h.Value.(*Header_Tombstone); return ok }
|
return func(h *Header) bool { _, ok := h.Value.(*Header_Tombstone); return ok }
|
||||||
case VerifyHdr:
|
case TokenHdr:
|
||||||
return func(h *Header) bool { _, ok := h.Value.(*Header_Verify); return ok }
|
return func(h *Header) bool { _, ok := h.Value.(*Header_Token); return ok }
|
||||||
case HomoHashHdr:
|
case HomoHashHdr:
|
||||||
return func(h *Header) bool { _, ok := h.Value.(*Header_HomoHash); return ok }
|
return func(h *Header) bool { _, ok := h.Value.(*Header_HomoHash); return ok }
|
||||||
case PayloadChecksumHdr:
|
case PayloadChecksumHdr:
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/session"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -46,11 +45,10 @@ func (b ByteSize) String() string {
|
||||||
|
|
||||||
// MakePutRequestHeader combines object and session token value
|
// MakePutRequestHeader combines object and session token value
|
||||||
// into header of object put request.
|
// into header of object put request.
|
||||||
func MakePutRequestHeader(obj *Object, token *session.Token) *PutRequest {
|
func MakePutRequestHeader(obj *Object) *PutRequest {
|
||||||
return &PutRequest{
|
return &PutRequest{
|
||||||
R: &PutRequest_Header{Header: &PutRequest_PutHeader{
|
R: &PutRequest_Header{Header: &PutRequest_PutHeader{
|
||||||
Object: obj,
|
Object: obj,
|
||||||
Token: token,
|
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ func (m Object) Verify() error {
|
||||||
integrity := ih.Value.(*Header_Integrity).Integrity
|
integrity := ih.Value.(*Header_Integrity).Integrity
|
||||||
|
|
||||||
// Prepare structures
|
// Prepare structures
|
||||||
_, vh := m.LastHeader(HeaderType(VerifyHdr))
|
_, vh := m.LastHeader(HeaderType(TokenHdr))
|
||||||
if vh == nil {
|
if vh == nil {
|
||||||
_, pkh := m.LastHeader(HeaderType(PublicKeyHdr))
|
_, pkh := m.LastHeader(HeaderType(PublicKeyHdr))
|
||||||
if pkh == nil {
|
if pkh == nil {
|
||||||
|
@ -85,7 +85,7 @@ func (m Object) Verify() error {
|
||||||
}
|
}
|
||||||
pubkey = pkh.Value.(*Header_PublicKey).PublicKey.Value
|
pubkey = pkh.Value.(*Header_PublicKey).PublicKey.Value
|
||||||
} else {
|
} else {
|
||||||
pubkey = vh.Value.(*Header_Verify).Verify.PublicKey
|
pubkey = vh.Value.(*Header_Token).Token.SessionKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify signature
|
// Verify signature
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/nspcc-dev/neofs-api-go/container"
|
"github.com/nspcc-dev/neofs-api-go/container"
|
||||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
"github.com/nspcc-dev/neofs-api-go/refs"
|
||||||
"github.com/nspcc-dev/neofs-api-go/session"
|
"github.com/nspcc-dev/neofs-api-go/service"
|
||||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
crypto "github.com/nspcc-dev/neofs-crypto"
|
||||||
"github.com/nspcc-dev/neofs-crypto/test"
|
"github.com/nspcc-dev/neofs-crypto/test"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -77,11 +77,13 @@ func TestObject_Verify(t *testing.T) {
|
||||||
|
|
||||||
dataPK := crypto.MarshalPublicKey(&sessionkey.PublicKey)
|
dataPK := crypto.MarshalPublicKey(&sessionkey.PublicKey)
|
||||||
signature, err = crypto.Sign(key, dataPK)
|
signature, err = crypto.Sign(key, dataPK)
|
||||||
vh := &session.VerificationHeader{
|
tok := &service.Token{
|
||||||
PublicKey: dataPK,
|
Token_Info: service.Token_Info{
|
||||||
KeySignature: signature,
|
SessionKey: dataPK,
|
||||||
|
},
|
||||||
|
Signature: signature,
|
||||||
}
|
}
|
||||||
obj.SetVerificationHeader(vh)
|
obj.AddHeader(&Header{Value: &Header_Token{Token: tok}})
|
||||||
|
|
||||||
// validation header is not last
|
// validation header is not last
|
||||||
t.Run("error validation header is not last", func(t *testing.T) {
|
t.Run("error validation header is not last", func(t *testing.T) {
|
||||||
|
@ -90,7 +92,7 @@ func TestObject_Verify(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
obj.Headers = obj.Headers[:len(obj.Headers)-2]
|
obj.Headers = obj.Headers[:len(obj.Headers)-2]
|
||||||
obj.SetVerificationHeader(vh)
|
obj.AddHeader(&Header{Value: &Header_Token{Token: tok}})
|
||||||
obj.SetHeader(&Header{Value: &Header_Integrity{ih}})
|
obj.SetHeader(&Header{Value: &Header_Integrity{ih}})
|
||||||
|
|
||||||
t.Run("error invalid header checksum", func(t *testing.T) {
|
t.Run("error invalid header checksum", func(t *testing.T) {
|
||||||
|
@ -115,7 +117,7 @@ func TestObject_Verify(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
obj.SetHeader(genIH)
|
obj.SetHeader(genIH)
|
||||||
|
|
||||||
t.Run("correct with vh", func(t *testing.T) {
|
t.Run("correct with tok", func(t *testing.T) {
|
||||||
err = obj.Verify()
|
err = obj.Verify()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
|
@ -123,7 +125,7 @@ func TestObject_Verify(t *testing.T) {
|
||||||
pkh := Header{Value: &Header_PublicKey{&PublicKey{
|
pkh := Header{Value: &Header_PublicKey{&PublicKey{
|
||||||
Value: crypto.MarshalPublicKey(&key.PublicKey),
|
Value: crypto.MarshalPublicKey(&key.PublicKey),
|
||||||
}}}
|
}}}
|
||||||
// replace vh with pkh
|
// replace tok with pkh
|
||||||
obj.Headers[len(obj.Headers)-2] = pkh
|
obj.Headers[len(obj.Headers)-2] = pkh
|
||||||
// re-sign object
|
// re-sign object
|
||||||
obj.Sign(sessionkey)
|
obj.Sign(sessionkey)
|
||||||
|
|
14
service/alias.go
Normal file
14
service/alias.go
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/refs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TokenID is type alias of UUID ref.
|
||||||
|
type TokenID = refs.UUID
|
||||||
|
|
||||||
|
// OwnerID is type alias of OwnerID ref.
|
||||||
|
type OwnerID = refs.OwnerID
|
||||||
|
|
||||||
|
// Address is type alias of Address ref.
|
||||||
|
type Address = refs.Address
|
|
@ -53,18 +53,6 @@ func (m *RequestVerificationHeader) AddSignature(sig *RequestVerificationHeader_
|
||||||
m.Signatures = append(m.Signatures, sig)
|
m.Signatures = append(m.Signatures, sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetOwner adds origin (sign and public key) of owner (client) into first signature.
|
|
||||||
func (m *RequestVerificationHeader) SetOwner(pub *ecdsa.PublicKey, sign []byte) {
|
|
||||||
if len(m.Signatures) == 0 || pub == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
m.Signatures[0].Origin = &RequestVerificationHeader_Sign{
|
|
||||||
Sign: sign,
|
|
||||||
Peer: crypto.MarshalPublicKey(pub),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckOwner validates, that passed OwnerID is equal to present PublicKey of owner.
|
// CheckOwner validates, that passed OwnerID is equal to present PublicKey of owner.
|
||||||
func (m *RequestVerificationHeader) CheckOwner(owner refs.OwnerID) error {
|
func (m *RequestVerificationHeader) CheckOwner(owner refs.OwnerID) error {
|
||||||
if key, err := m.GetOwner(); err != nil {
|
if key, err := m.GetOwner(); err != nil {
|
||||||
|
@ -83,18 +71,6 @@ func (m *RequestVerificationHeader) CheckOwner(owner refs.OwnerID) error {
|
||||||
func (m *RequestVerificationHeader) GetOwner() (*ecdsa.PublicKey, error) {
|
func (m *RequestVerificationHeader) GetOwner() (*ecdsa.PublicKey, error) {
|
||||||
if len(m.Signatures) == 0 {
|
if len(m.Signatures) == 0 {
|
||||||
return nil, ErrCannotFindOwner
|
return nil, ErrCannotFindOwner
|
||||||
}
|
|
||||||
|
|
||||||
// if first signature contains origin, we should try to validate session key
|
|
||||||
if m.Signatures[0].Origin != nil {
|
|
||||||
owner := crypto.UnmarshalPublicKey(m.Signatures[0].Origin.Peer)
|
|
||||||
if owner == nil {
|
|
||||||
return nil, ErrCannotLoadPublicKey
|
|
||||||
} else if err := crypto.Verify(owner, m.Signatures[0].Peer, m.Signatures[0].Origin.Sign); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "could not verify session token")
|
|
||||||
}
|
|
||||||
|
|
||||||
return owner, nil
|
|
||||||
} else if key := crypto.UnmarshalPublicKey(m.Signatures[0].Peer); key != nil {
|
} else if key := crypto.UnmarshalPublicKey(m.Signatures[0].Peer); key != nil {
|
||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
@ -128,10 +104,8 @@ func newSignature(key *ecdsa.PrivateKey, data []byte) (*RequestVerificationHeade
|
||||||
}
|
}
|
||||||
|
|
||||||
return &RequestVerificationHeader_Signature{
|
return &RequestVerificationHeader_Signature{
|
||||||
RequestVerificationHeader_Sign: RequestVerificationHeader_Sign{
|
Sign: sign,
|
||||||
Sign: sign,
|
Peer: crypto.MarshalPublicKey(&key.PublicKey),
|
||||||
Peer: crypto.MarshalPublicKey(&key.PublicKey),
|
|
||||||
},
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,15 +119,13 @@ func TestMaintainableRequest(t *testing.T) {
|
||||||
req.TTL--
|
req.TTL--
|
||||||
|
|
||||||
key := test.DecodeKey(i)
|
key := test.DecodeKey(i)
|
||||||
require.NoError(t, SignRequestHeader(key, req))
|
|
||||||
|
|
||||||
// sign first key (session key) by owner key
|
// sign first key (session key) by owner key
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
sign, err := crypto.Sign(owner, crypto.MarshalPublicKey(&key.PublicKey))
|
key = owner
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
req.SetOwner(&owner.PublicKey, sign)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
require.NoError(t, SignRequestHeader(key, req))
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Validate owner
|
{ // Validate owner
|
||||||
|
@ -150,17 +148,8 @@ func TestMaintainableRequest(t *testing.T) {
|
||||||
require.Equal(t, &owner.PublicKey, pub)
|
require.Equal(t, &owner.PublicKey, pub)
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // wrong owner:
|
|
||||||
req.Signatures[0].Origin = nil
|
|
||||||
|
|
||||||
pub, err := req.GetOwner()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
require.NotEqual(t, &owner.PublicKey, pub)
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // Wrong signatures:
|
{ // Wrong signatures:
|
||||||
copy(req.Signatures[count-1].Sign, req.Signatures[count-1].Peer)
|
copy(req.Signatures[count-1].Sign, req.Signatures[count-2].Sign)
|
||||||
err := VerifyRequestHeader(req)
|
err := VerifyRequestHeader(req)
|
||||||
require.EqualError(t, errors.Cause(err), crypto.ErrInvalidSignature.Error())
|
require.EqualError(t, errors.Cause(err), crypto.ErrInvalidSignature.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
"github.com/nspcc-dev/neofs-api-go/refs"
|
||||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
@ -31,9 +30,9 @@ type (
|
||||||
TokenParams struct {
|
TokenParams struct {
|
||||||
FirstEpoch uint64
|
FirstEpoch uint64
|
||||||
LastEpoch uint64
|
LastEpoch uint64
|
||||||
ObjectID []ObjectID
|
Address Address
|
||||||
OwnerID OwnerID
|
OwnerID OwnerID
|
||||||
PublicKeys [][]byte
|
Verb Verb
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -46,13 +45,3 @@ func NewInitRequest(t *Token) *CreateRequest {
|
||||||
func NewSignedRequest(t *Token) *CreateRequest {
|
func NewSignedRequest(t *Token) *CreateRequest {
|
||||||
return &CreateRequest{Message: &CreateRequest_Signed{Signed: t}}
|
return &CreateRequest{Message: &CreateRequest_Signed{Signed: t}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign signs contents of the header with the private key.
|
|
||||||
func (m *VerificationHeader) Sign(key *ecdsa.PrivateKey) error {
|
|
||||||
s, err := crypto.Sign(key, m.PublicKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
m.KeySignature = s
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
"github.com/nspcc-dev/neofs-api-go/refs"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/service"
|
||||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
crypto "github.com/nspcc-dev/neofs-crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -48,13 +49,15 @@ func (s *simpleStore) New(p TokenParams) *PToken {
|
||||||
t := &PToken{
|
t := &PToken{
|
||||||
mtx: new(sync.Mutex),
|
mtx: new(sync.Mutex),
|
||||||
Token: Token{
|
Token: Token{
|
||||||
ID: tid,
|
Token_Info: service.Token_Info{
|
||||||
Header: VerificationHeader{PublicKey: crypto.MarshalPublicKey(&key.PublicKey)},
|
ID: tid,
|
||||||
FirstEpoch: p.FirstEpoch,
|
OwnerID: p.OwnerID,
|
||||||
LastEpoch: p.LastEpoch,
|
Verb: p.Verb,
|
||||||
ObjectID: p.ObjectID,
|
Address: p.Address,
|
||||||
OwnerID: p.OwnerID,
|
Created: p.FirstEpoch,
|
||||||
PublicKeys: p.PublicKeys,
|
ValidUntil: p.LastEpoch,
|
||||||
|
SessionKey: crypto.MarshalPublicKey(&key.PublicKey),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
PrivateKey: key,
|
PrivateKey: key,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,96 +1,3 @@
|
||||||
package session
|
package session
|
||||||
|
|
||||||
import (
|
// TODO: write unit tests
|
||||||
"crypto/ecdsa"
|
|
||||||
"crypto/rand"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
|
||||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
type testClient struct {
|
|
||||||
*ecdsa.PrivateKey
|
|
||||||
OwnerID OwnerID
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *testClient) Sign(data []byte) ([]byte, error) {
|
|
||||||
return crypto.Sign(c.PrivateKey, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newTestClient(t *testing.T) *testClient {
|
|
||||||
key, err := ecdsa.GenerateKey(defaultCurve(), rand.Reader)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
owner, err := refs.NewOwnerID(&key.PublicKey)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
return &testClient{PrivateKey: key, OwnerID: owner}
|
|
||||||
}
|
|
||||||
|
|
||||||
func signToken(t *testing.T, token *PToken, c *testClient) {
|
|
||||||
require.NotNil(t, token)
|
|
||||||
token.SetPublicKeys(&c.PublicKey)
|
|
||||||
|
|
||||||
signH, err := c.Sign(token.Header.PublicKey)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NotNil(t, signH)
|
|
||||||
|
|
||||||
// data is not yet signed
|
|
||||||
keys := UnmarshalPublicKeys(&token.Token)
|
|
||||||
require.False(t, token.Verify(keys...))
|
|
||||||
|
|
||||||
signT, err := c.Sign(token.verificationData())
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NotNil(t, signT)
|
|
||||||
|
|
||||||
token.AddSignatures(signH, signT)
|
|
||||||
require.True(t, token.Verify(keys...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTokenStore(t *testing.T) {
|
|
||||||
s := NewSimpleStore()
|
|
||||||
|
|
||||||
oid, err := refs.NewObjectID()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
c := newTestClient(t)
|
|
||||||
require.NotNil(t, c)
|
|
||||||
pk := [][]byte{crypto.MarshalPublicKey(&c.PublicKey)}
|
|
||||||
|
|
||||||
// create new token
|
|
||||||
token := s.New(TokenParams{
|
|
||||||
ObjectID: []ObjectID{oid},
|
|
||||||
OwnerID: c.OwnerID,
|
|
||||||
PublicKeys: pk,
|
|
||||||
})
|
|
||||||
signToken(t, token, c)
|
|
||||||
|
|
||||||
// check that it can be fetched
|
|
||||||
t1 := s.Fetch(token.ID)
|
|
||||||
require.NotNil(t, t1)
|
|
||||||
require.Equal(t, token, t1)
|
|
||||||
|
|
||||||
// create and sign another token by the same client
|
|
||||||
t1 = s.New(TokenParams{
|
|
||||||
ObjectID: []ObjectID{oid},
|
|
||||||
OwnerID: c.OwnerID,
|
|
||||||
PublicKeys: pk,
|
|
||||||
})
|
|
||||||
|
|
||||||
signToken(t, t1, c)
|
|
||||||
|
|
||||||
data := []byte{1, 2, 3}
|
|
||||||
sign, err := t1.SignData(data)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Error(t, token.Header.VerifyData(data, sign))
|
|
||||||
|
|
||||||
sign, err = token.SignData(data)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NoError(t, token.Header.VerifyData(data, sign))
|
|
||||||
|
|
||||||
s.Remove(token.ID)
|
|
||||||
require.Nil(t, s.Fetch(token.ID))
|
|
||||||
require.NotNil(t, s.Fetch(t1.ID))
|
|
||||||
}
|
|
||||||
|
|
130
session/types.go
130
session/types.go
|
@ -2,14 +2,12 @@ package session
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"encoding/binary"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/chain"
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/internal"
|
"github.com/nspcc-dev/neofs-api-go/internal"
|
||||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
"github.com/nspcc-dev/neofs-api-go/refs"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/service"
|
||||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
crypto "github.com/nspcc-dev/neofs-crypto"
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
@ -19,6 +17,12 @@ type (
|
||||||
OwnerID = refs.OwnerID
|
OwnerID = refs.OwnerID
|
||||||
// TokenID type alias.
|
// TokenID type alias.
|
||||||
TokenID = refs.UUID
|
TokenID = refs.UUID
|
||||||
|
// Token type alias
|
||||||
|
Token = service.Token
|
||||||
|
// Address type alias
|
||||||
|
Address = refs.Address
|
||||||
|
// Verb is Token_Info_Verb type alias
|
||||||
|
Verb = service.Token_Info_Verb
|
||||||
|
|
||||||
// PToken is a wrapper around Token that allows to sign data
|
// PToken is a wrapper around Token that allows to sign data
|
||||||
// and to do thread-safe manipulations.
|
// and to do thread-safe manipulations.
|
||||||
|
@ -55,127 +59,7 @@ const (
|
||||||
ErrInvalidSignature = internal.Error("invalid signature")
|
ErrInvalidSignature = internal.Error("invalid signature")
|
||||||
)
|
)
|
||||||
|
|
||||||
// verificationData returns byte array to sign.
|
|
||||||
// Note: protobuf serialization is inconsistent as
|
|
||||||
// wire order is unspecified.
|
|
||||||
func (m *Token) verificationData() (data []byte) {
|
|
||||||
var size int
|
|
||||||
if l := len(m.ObjectID); l > 0 {
|
|
||||||
size = m.ObjectID[0].Size()
|
|
||||||
data = make([]byte, 16+l*size)
|
|
||||||
} else {
|
|
||||||
data = make([]byte, 16)
|
|
||||||
}
|
|
||||||
binary.BigEndian.PutUint64(data, m.FirstEpoch)
|
|
||||||
binary.BigEndian.PutUint64(data[8:], m.LastEpoch)
|
|
||||||
for i := range m.ObjectID {
|
|
||||||
copy(data[16+i*size:], m.ObjectID[i].Bytes())
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsSame checks if the passed token is valid and equal to current token
|
|
||||||
func (m *Token) IsSame(t *Token) error {
|
|
||||||
switch {
|
|
||||||
case m.FirstEpoch != t.FirstEpoch:
|
|
||||||
return ErrWrongFirstEpoch
|
|
||||||
case m.LastEpoch != t.LastEpoch:
|
|
||||||
return ErrWrongLastEpoch
|
|
||||||
case !m.OwnerID.Equal(t.OwnerID):
|
|
||||||
return ErrWrongOwner
|
|
||||||
case m.Header.PublicKey == nil:
|
|
||||||
return ErrEmptyPublicKey
|
|
||||||
case len(m.ObjectID) != len(t.ObjectID):
|
|
||||||
return ErrWrongObjectsCount
|
|
||||||
default:
|
|
||||||
for i := range m.ObjectID {
|
|
||||||
if !m.ObjectID[i].Equal(t.ObjectID[i]) {
|
|
||||||
return errors.Wrapf(ErrWrongObjects, "expect %s, actual: %s", m.ObjectID[i], t.ObjectID[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sign tries to sign current Token data and stores signature inside it.
|
|
||||||
func (m *Token) Sign(key *ecdsa.PrivateKey) error {
|
|
||||||
if err := m.Header.Sign(key); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
s, err := crypto.Sign(key, m.verificationData())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
m.Signature = s
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPublicKeys sets owner's public keys to the token
|
|
||||||
func (m *Token) SetPublicKeys(keys ...*ecdsa.PublicKey) {
|
|
||||||
m.PublicKeys = m.PublicKeys[:0]
|
|
||||||
for i := range keys {
|
|
||||||
m.PublicKeys = append(m.PublicKeys, crypto.MarshalPublicKey(keys[i]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify checks if token is correct and signed.
|
|
||||||
func (m *Token) Verify(keys ...*ecdsa.PublicKey) bool {
|
|
||||||
if m.FirstEpoch > m.LastEpoch {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
ownerFromKeys := chain.KeysToAddress(keys...)
|
|
||||||
if m.OwnerID.String() != ownerFromKeys {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range keys {
|
|
||||||
if m.Header.Verify(keys[i]) && crypto.Verify(keys[i], m.verificationData(), m.Signature) == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddSignatures adds token signatures.
|
|
||||||
func (t *PToken) AddSignatures(signH, signT []byte) {
|
|
||||||
t.mtx.Lock()
|
|
||||||
|
|
||||||
t.Header.KeySignature = signH
|
|
||||||
t.Signature = signT
|
|
||||||
|
|
||||||
t.mtx.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SignData signs data with session private key.
|
// SignData signs data with session private key.
|
||||||
func (t *PToken) SignData(data []byte) ([]byte, error) {
|
func (t *PToken) SignData(data []byte) ([]byte, error) {
|
||||||
return crypto.Sign(t.PrivateKey, data)
|
return crypto.Sign(t.PrivateKey, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyData checks if signature of data by token is equal to sign.
|
|
||||||
func (m *VerificationHeader) VerifyData(data, sign []byte) error {
|
|
||||||
if crypto.Verify(crypto.UnmarshalPublicKey(m.PublicKey), data, sign) != nil {
|
|
||||||
return ErrInvalidSignature
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify checks if verification header was issued by id.
|
|
||||||
func (m *VerificationHeader) Verify(keys ...*ecdsa.PublicKey) bool {
|
|
||||||
for i := range keys {
|
|
||||||
if crypto.Verify(keys[i], m.PublicKey, m.KeySignature) == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalPublicKeys returns unmarshal public keys from the token
|
|
||||||
func UnmarshalPublicKeys(t *Token) []*ecdsa.PublicKey {
|
|
||||||
r := make([]*ecdsa.PublicKey, 0, len(t.PublicKeys))
|
|
||||||
for i := range t.PublicKeys {
|
|
||||||
r = append(r, crypto.UnmarshalPublicKey(t.PublicKeys[i]))
|
|
||||||
}
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue