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.
This commit is contained in:
Leonard Lyubich 2020-04-29 11:52:05 +03:00
parent 1e86e1112a
commit dfc2dd8a78
5 changed files with 90 additions and 28 deletions

37
session/private.go Normal file
View file

@ -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)
}

33
session/private_test.go Normal file
View file

@ -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,
),
)
}

View file

@ -17,10 +17,10 @@ type (
// TokenStore is a PToken storage manipulation interface. // TokenStore is a PToken storage manipulation interface.
TokenStore interface { TokenStore interface {
// New returns new token with specified parameters. // 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 tries to fetch a token with specified id.
Fetch(id TokenID) *PToken Fetch(id TokenID) PrivateToken
// Remove removes token with id from store. // Remove removes token with id from store.
Remove(id TokenID) Remove(id TokenID)

View file

@ -13,7 +13,7 @@ import (
type simpleStore struct { type simpleStore struct {
*sync.RWMutex *sync.RWMutex
tokens map[TokenID]*PToken tokens map[TokenID]PrivateToken
} }
// TODO get curve from neofs-crypto // TODO get curve from neofs-crypto
@ -25,12 +25,12 @@ func defaultCurve() elliptic.Curve {
func NewSimpleStore() TokenStore { func NewSimpleStore() TokenStore {
return &simpleStore{ return &simpleStore{
RWMutex: new(sync.RWMutex), RWMutex: new(sync.RWMutex),
tokens: make(map[TokenID]*PToken), tokens: make(map[TokenID]PrivateToken),
} }
} }
// New returns new token with specified parameters. // 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() tid, err := refs.NewUUID()
if err != nil { if err != nil {
return nil return nil
@ -54,10 +54,8 @@ func (s *simpleStore) New(p TokenParams) *PToken {
token.SetExpirationEpoch(p.LastEpoch) token.SetExpirationEpoch(p.LastEpoch)
token.SetSessionKey(crypto.MarshalPublicKey(&key.PublicKey)) token.SetSessionKey(crypto.MarshalPublicKey(&key.PublicKey))
t := &PToken{ t := &pToken{
mtx: new(sync.Mutex), sessionKey: key,
Token: *token,
PrivateKey: key,
} }
s.Lock() s.Lock()
@ -68,7 +66,7 @@ func (s *simpleStore) New(p TokenParams) *PToken {
} }
// Fetch tries to fetch a token with specified id. // 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() s.RLock()
defer s.RUnlock() defer s.RUnlock()

View file

@ -1,13 +1,9 @@
package session package session
import ( import (
"crypto/ecdsa"
"sync"
"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" "github.com/nspcc-dev/neofs-api-go/service"
crypto "github.com/nspcc-dev/neofs-crypto"
) )
type ( type (
@ -23,17 +19,20 @@ type (
Address = refs.Address Address = refs.Address
// Verb is Token_Info_Verb type alias // Verb is Token_Info_Verb type alias
Verb = service.Token_Info_Verb 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 ( const (
// ErrWrongFirstEpoch is raised when passed Token contains wrong first epoch. // ErrWrongFirstEpoch is raised when passed Token contains wrong first epoch.
// First epoch is an epoch since token is valid // 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 is raised when wrong signature is passed to VerificationHeader.VerifyData().
ErrInvalidSignature = internal.Error("invalid signature") 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)
}