From dfc2dd8a78ee2b63b43fb5fab221c7acf5bf71fd Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Wed, 29 Apr 2020 11:52:05 +0300 Subject: [PATCH] session: replace PToken structure with PrivateToken interface In previous implementation PToken contained the full Token structure. Since private token is used for data signature only, storing unused fields of a user token is impractical. To emphasize the purpose of the private part of the session, it makes sense to provide the user of the session package with its interface. The interface will only provide the functionality of data signing with private session key. This commit: * removes PToken structure from session package; * defines PrivateToken interface of private session part; * adds the implementation of PrivateToken on unexported struct; * provides the constructor that generates session key internally. --- session/private.go | 37 +++++++++++++++++++++++++++++++++++++ session/private_test.go | 33 +++++++++++++++++++++++++++++++++ session/service.go | 4 ++-- session/store.go | 14 ++++++-------- session/types.go | 30 ++++++++++++------------------ 5 files changed, 90 insertions(+), 28 deletions(-) create mode 100644 session/private.go create mode 100644 session/private_test.go diff --git a/session/private.go b/session/private.go new file mode 100644 index 00000000..4d4f3c20 --- /dev/null +++ b/session/private.go @@ -0,0 +1,37 @@ +package session + +import ( + "crypto/ecdsa" + "crypto/rand" + + crypto "github.com/nspcc-dev/neofs-crypto" +) + +type pToken struct { + // private session token + sessionKey *ecdsa.PrivateKey +} + +// NewSessionPrivateToken creates PrivateToken instance. +// +// Returns non-nil error on key generation error. +func NewPrivateToken() (PrivateToken, error) { + sk, err := ecdsa.GenerateKey(defaultCurve(), rand.Reader) + if err != nil { + return nil, err + } + + return &pToken{ + sessionKey: sk, + }, nil +} + +// Sign signs data with session private key. +func (t *pToken) Sign(data []byte) ([]byte, error) { + return crypto.Sign(t.sessionKey, data) +} + +// PublicKey returns a binary representation of the session public key. +func (t *pToken) PublicKey() []byte { + return crypto.MarshalPublicKey(&t.sessionKey.PublicKey) +} diff --git a/session/private_test.go b/session/private_test.go new file mode 100644 index 00000000..f0fb9f4e --- /dev/null +++ b/session/private_test.go @@ -0,0 +1,33 @@ +package session + +import ( + "crypto/rand" + "testing" + + crypto "github.com/nspcc-dev/neofs-crypto" + "github.com/stretchr/testify/require" +) + +func TestPrivateToken(t *testing.T) { + // create new private token + pToken, err := NewPrivateToken() + require.NoError(t, err) + + // generate data to sign + data := make([]byte, 10) + _, err = rand.Read(data) + require.NoError(t, err) + + // sign data via private token + sig, err := pToken.Sign(data) + require.NoError(t, err) + + // check signature + require.NoError(t, + crypto.Verify( + crypto.UnmarshalPublicKey(pToken.PublicKey()), + data, + sig, + ), + ) +} diff --git a/session/service.go b/session/service.go index 367aeb13..915abb4b 100644 --- a/session/service.go +++ b/session/service.go @@ -17,10 +17,10 @@ type ( // TokenStore is a PToken storage manipulation interface. TokenStore interface { // New returns new token with specified parameters. - New(p TokenParams) *PToken + New(p TokenParams) PrivateToken // Fetch tries to fetch a token with specified id. - Fetch(id TokenID) *PToken + Fetch(id TokenID) PrivateToken // Remove removes token with id from store. Remove(id TokenID) diff --git a/session/store.go b/session/store.go index 7c56c39a..440fbb56 100644 --- a/session/store.go +++ b/session/store.go @@ -13,7 +13,7 @@ import ( type simpleStore struct { *sync.RWMutex - tokens map[TokenID]*PToken + tokens map[TokenID]PrivateToken } // TODO get curve from neofs-crypto @@ -25,12 +25,12 @@ func defaultCurve() elliptic.Curve { func NewSimpleStore() TokenStore { return &simpleStore{ RWMutex: new(sync.RWMutex), - tokens: make(map[TokenID]*PToken), + tokens: make(map[TokenID]PrivateToken), } } // New returns new token with specified parameters. -func (s *simpleStore) New(p TokenParams) *PToken { +func (s *simpleStore) New(p TokenParams) PrivateToken { tid, err := refs.NewUUID() if err != nil { return nil @@ -54,10 +54,8 @@ func (s *simpleStore) New(p TokenParams) *PToken { token.SetExpirationEpoch(p.LastEpoch) token.SetSessionKey(crypto.MarshalPublicKey(&key.PublicKey)) - t := &PToken{ - mtx: new(sync.Mutex), - Token: *token, - PrivateKey: key, + t := &pToken{ + sessionKey: key, } s.Lock() @@ -68,7 +66,7 @@ func (s *simpleStore) New(p TokenParams) *PToken { } // Fetch tries to fetch a token with specified id. -func (s *simpleStore) Fetch(id TokenID) *PToken { +func (s *simpleStore) Fetch(id TokenID) PrivateToken { s.RLock() defer s.RUnlock() diff --git a/session/types.go b/session/types.go index e56373cf..e7e4b2a3 100644 --- a/session/types.go +++ b/session/types.go @@ -1,13 +1,9 @@ package session import ( - "crypto/ecdsa" - "sync" - "github.com/nspcc-dev/neofs-api-go/internal" "github.com/nspcc-dev/neofs-api-go/refs" "github.com/nspcc-dev/neofs-api-go/service" - crypto "github.com/nspcc-dev/neofs-crypto" ) type ( @@ -23,17 +19,20 @@ type ( 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 - // and to do thread-safe manipulations. - PToken struct { - Token - - mtx *sync.Mutex - PrivateKey *ecdsa.PrivateKey - } ) +// PrivateToken is an interface of session private part. +type PrivateToken interface { + // PublicKey must return a binary representation of session public key. + PublicKey() []byte + + // Sign must return the signature of passed data. + // + // Resulting signature must be verified by crypto.Verify function + // with the session public key. + Sign([]byte) ([]byte, error) +} + const ( // ErrWrongFirstEpoch is raised when passed Token contains wrong first epoch. // First epoch is an epoch since token is valid @@ -58,8 +57,3 @@ const ( // ErrInvalidSignature is raised when wrong signature is passed to VerificationHeader.VerifyData(). ErrInvalidSignature = internal.Error("invalid signature") ) - -// SignData signs data with session private key. -func (t *PToken) SignData(data []byte) ([]byte, error) { - return crypto.Sign(t.PrivateKey, data) -}