2021-05-25 19:59:21 +00:00
|
|
|
package accessbox
|
|
|
|
|
2021-06-14 13:39:25 +00:00
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"crypto/rand"
|
|
|
|
"fmt"
|
2021-05-25 19:59:21 +00:00
|
|
|
|
2021-06-14 13:39:25 +00:00
|
|
|
"github.com/nspcc-dev/neofs-api-go/pkg/session"
|
|
|
|
"github.com/nspcc-dev/neofs-api-go/pkg/token"
|
|
|
|
"github.com/nspcc-dev/neofs-s3-gw/creds/hcs"
|
|
|
|
"golang.org/x/crypto/chacha20poly1305"
|
|
|
|
"golang.org/x/crypto/curve25519"
|
|
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
)
|
|
|
|
|
|
|
|
type tokenInterface interface {
|
|
|
|
Marshal(bs ...[]byte) ([]byte, error)
|
|
|
|
Unmarshal([]byte) error
|
|
|
|
}
|
|
|
|
|
|
|
|
// Marshal returns the wire-format of AccessBox.
|
|
|
|
func (x *AccessBox) Marshal() ([]byte, error) {
|
|
|
|
return proto.Marshal(x)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unmarshal parses the wire-format message and put data to x.
|
|
|
|
func (x *AccessBox) Unmarshal(data []byte) error {
|
|
|
|
return proto.Unmarshal(data, x)
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddBearerToken adds a bearer token to BearerTokens list.
|
|
|
|
func (x *AccessBox) AddBearerToken(tkn *token.BearerToken, owner hcs.PrivateKey, keys ...hcs.PublicKey) error {
|
|
|
|
if x.OwnerPublicKey == nil {
|
|
|
|
return fmt.Errorf("owner's public key is nil")
|
2021-05-25 19:59:21 +00:00
|
|
|
}
|
2021-06-14 13:39:25 +00:00
|
|
|
// restriction to rewrite token for the second time
|
|
|
|
if len(x.BearerTokens) > 0 {
|
|
|
|
return fmt.Errorf("bearer token is already set")
|
|
|
|
}
|
|
|
|
return x.addToken(tkn, &x.BearerTokens, owner, keys...)
|
|
|
|
}
|
2021-05-25 19:59:21 +00:00
|
|
|
|
2021-06-14 13:39:25 +00:00
|
|
|
// AddSessionToken adds a session token to SessionTokens list.
|
|
|
|
func (x *AccessBox) AddSessionToken(tkn *session.Token, owner hcs.PrivateKey, keys ...hcs.PublicKey) error {
|
|
|
|
if x.OwnerPublicKey == nil {
|
|
|
|
return fmt.Errorf("owner's public key is nil")
|
|
|
|
}
|
|
|
|
//restriction to rewrite token for the second time
|
|
|
|
if len(x.SessionTokens) > 0 {
|
|
|
|
return fmt.Errorf("bearer token is already set")
|
2021-05-25 19:59:21 +00:00
|
|
|
}
|
2021-06-14 13:39:25 +00:00
|
|
|
return x.addToken(tkn, &x.SessionTokens, owner, keys...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetOwnerPublicKey sets a public key of an issuer.
|
|
|
|
func (x *AccessBox) SetOwnerPublicKey(key hcs.PublicKey) {
|
|
|
|
x.OwnerPublicKey = key.Bytes()
|
|
|
|
}
|
2021-05-25 19:59:21 +00:00
|
|
|
|
2021-06-14 13:39:25 +00:00
|
|
|
// GetBearerToken returns bearer token from AccessBox.
|
|
|
|
func (x *AccessBox) GetBearerToken(owner hcs.PrivateKey) (*token.BearerToken, error) {
|
|
|
|
sender, err := hcs.PublicKeyFromBytes(x.OwnerPublicKey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to load owner public key from AccessBox: %w", err)
|
|
|
|
}
|
|
|
|
for _, data := range x.BearerTokens {
|
|
|
|
if !bytes.Equal(data.GatePublicKey, owner.PublicKey().Bytes()) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
tkn := token.NewBearerToken()
|
|
|
|
if err := decodeToken(data.Token, tkn, owner, sender); err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to decode bearer token: %w", err)
|
|
|
|
}
|
|
|
|
return tkn, nil
|
2021-05-25 19:59:21 +00:00
|
|
|
}
|
|
|
|
|
2021-06-14 13:39:25 +00:00
|
|
|
return nil, fmt.Errorf("no bearer token for key %s was found", owner.String())
|
|
|
|
}
|
2021-05-25 19:59:21 +00:00
|
|
|
|
2021-06-14 13:39:25 +00:00
|
|
|
// GetSessionToken returns session token from AccessBox.
|
|
|
|
func (x *AccessBox) GetSessionToken(owner hcs.PrivateKey) (*session.Token, error) {
|
|
|
|
sender, err := hcs.PublicKeyFromBytes(x.OwnerPublicKey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to load owner public key from AccessBox: %w", err)
|
2021-05-25 19:59:21 +00:00
|
|
|
}
|
2021-06-14 13:39:25 +00:00
|
|
|
for _, data := range x.SessionTokens {
|
|
|
|
if !bytes.Equal(data.GatePublicKey, owner.PublicKey().Bytes()) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
tkn := session.NewToken()
|
|
|
|
|
|
|
|
if err := decodeToken(data.Token, tkn, owner, sender); err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to decode session token: %w", err)
|
|
|
|
}
|
|
|
|
return tkn, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, fmt.Errorf("no session token for key %s was found", owner.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (x *AccessBox) addToken(tkn tokenInterface, list *[]*AccessBox_Token, owner hcs.PrivateKey, keys ...hcs.PublicKey) error {
|
|
|
|
for i, sender := range keys {
|
|
|
|
data, err := encodeToken(tkn, owner, sender)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("%w, sender = %d", err, i)
|
|
|
|
}
|
|
|
|
*list = append(*list, newToken(data, sender.Bytes()))
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func newToken(data []byte, key []byte) *AccessBox_Token {
|
|
|
|
res := new(AccessBox_Token)
|
|
|
|
res.Token = data
|
|
|
|
res.GatePublicKey = key
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
|
|
|
func encodeToken(tkn tokenInterface, owner hcs.PrivateKey, sender hcs.PublicKey) ([]byte, error) {
|
|
|
|
data, err := tkn.Marshal()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
encrypted, err := encrypt(owner, sender, data)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return encrypted, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func decodeToken(data []byte, tkn tokenInterface, owner hcs.PrivateKey, sender hcs.PublicKey) error {
|
|
|
|
decoded, err := decrypt(owner, sender, data)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = tkn.Unmarshal(decoded)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func encrypt(owner hcs.PrivateKey, sender hcs.PublicKey, data []byte) ([]byte, error) {
|
|
|
|
key, err := curve25519.X25519(owner.Bytes(), sender.Bytes())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
enc, err := chacha20poly1305.NewX(key)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
nonce := make([]byte, enc.NonceSize(), enc.NonceSize()+len(data)+enc.Overhead())
|
|
|
|
if _, err := rand.Read(nonce); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return enc.Seal(nonce, nonce, data, nil), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func decrypt(owner hcs.PrivateKey, sender hcs.PublicKey, data []byte) ([]byte, error) {
|
|
|
|
sb := sender.Bytes()
|
|
|
|
|
|
|
|
key, err := curve25519.X25519(owner.Bytes(), sb)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
dec, err := chacha20poly1305.NewX(key)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if ld, ns := len(data), dec.NonceSize(); ld < ns {
|
|
|
|
return nil, fmt.Errorf("wrong data size (%d), should be greater than %d", ld, ns)
|
|
|
|
}
|
|
|
|
|
|
|
|
nonce, cypher := data[:dec.NonceSize()], data[dec.NonceSize():]
|
|
|
|
return dec.Open(nil, nonce, cypher, nil)
|
|
|
|
}
|