Merge pull request #85 from KirillovDenis/feature/75-using_256r1_instead_of_ed25519

[#75] Using secp256r1 instead of curve25519
This commit is contained in:
Roman Khimov 2021-06-17 16:39:17 +03:00 committed by GitHub
commit 9060b0a988
12 changed files with 179 additions and 406 deletions

View file

@ -34,29 +34,22 @@ Minimalistic S3 gateway setup needs:
NeoFS nodes with weighted load balancing). NeoFS nodes with weighted load balancing).
* a key used to communicate with NeoFS nodes * a key used to communicate with NeoFS nodes
Passed via `--neofs-key` parameter or `S3_GW_NEOFS-KEY` environment variable. Passed via `--neofs-key` parameter or `S3_GW_NEOFS-KEY` environment variable.
* a key used for client authentication
Passed via `--auth-key` parameter or `S3_GW_AUTH-KEY` environment variable.
To generate it use `neofs-authmate generate-keys` command.
These two commands are functionally equivalent, they run the gate with one These two commands are functionally equivalent, they run the gate with one
backend node, some keys and otherwise default settings: backend node, some keys and otherwise default settings:
``` ```
$ neofs-s3-gw -p 192.168.130.72:8080 --neofs-key KxDgvEKzgSBPPfuVfw67oPQBSjidEiqTHURKSDL1R7yGaGYAeYnr \ $ neofs-s3-gw -p 192.168.130.72:8080 --neofs-key KxDgvEKzgSBPPfuVfw67oPQBSjidEiqTHURKSDL1R7yGaGYAeYnr
--auth-key a04edd5b3c497eed83be25fb136bafd056928c17986440745775223615f2cbab
$ S3_GW_PEERS_0_ADDRESS=192.168.130.72:8080 \ $ S3_GW_PEERS_0_ADDRESS=192.168.130.72:8080 \
S3_GW_NEOFS-KEY=KxDgvEKzgSBPPfuVfw67oPQBSjidEiqTHURKSDL1R7yGaGYAeYnr \ S3_GW_NEOFS-KEY=KxDgvEKzgSBPPfuVfw67oPQBSjidEiqTHURKSDL1R7yGaGYAeYnr \
S3_GW_AUTH-KEY=a04edd5b3c497eed83be25fb136bafd056928c17986440745775223615f2cbab \
neofs-s3-gw neofs-s3-gw
``` ```
It's also possible to specify uri scheme (grpc or grpcs) when using `-p` or environment variables: It's also possible to specify uri scheme (grpc or grpcs) when using `-p` or environment variables:
``` ```
$ neofs-s3-gw -p grpc://192.168.130.72:8080 --neofs-key KxDgvEKzgSBPPfuVfw67oPQBSjidEiqTHURKSDL1R7yGaGYAeYnr \ $ neofs-s3-gw -p grpc://192.168.130.72:8080 --neofs-key KxDgvEKzgSBPPfuVfw67oPQBSjidEiqTHURKSDL1R7yGaGYAeYnr
--auth-key a04edd5b3c497eed83be25fb136bafd056928c17986440745775223615f2cbab
$ S3_GW_PEERS_0_ADDRESS=grpcs://192.168.130.72:8080 \ $ S3_GW_PEERS_0_ADDRESS=grpcs://192.168.130.72:8080 \
S3_GW_NEOFS-KEY=KxDgvEKzgSBPPfuVfw67oPQBSjidEiqTHURKSDL1R7yGaGYAeYnr \ S3_GW_NEOFS-KEY=KxDgvEKzgSBPPfuVfw67oPQBSjidEiqTHURKSDL1R7yGaGYAeYnr \
S3_GW_AUTH-KEY=a04edd5b3c497eed83be25fb136bafd056928c17986440745775223615f2cbab \
neofs-s3-gw neofs-s3-gw
``` ```
@ -84,12 +77,10 @@ $ HTTP_GW_PEERS_0_ADDRESS=192.168.130.72:8080 HTTP_GW_PEERS_0_WEIGHT=9 \
This command will make gateway use 192.168.130.72 for 90% of requests and This command will make gateway use 192.168.130.72 for 90% of requests and
192.168.130.71 for remaining 10%. 192.168.130.71 for remaining 10%.
### Keys ### Key
NeoFS (`--neofs-key`) and authentication (`--auth-key`) keys are mandatory NeoFS (`--neofs-key`) is mandatory parameter. NeoFS key can be a path to private key file (as raw bytes),
parameters. NeoFS key can be a path to private key file (as raw bytes), a hex a hex string or (unencrypted) WIF string.
string or (unencrypted) WIF string. Authentication key is either a path to
raw private key file or a hex string.
### Binding and TLS ### Binding and TLS
@ -208,7 +199,7 @@ potentially).
#### Generation of key pairs #### Generation of key pairs
To generate key pairs for gateways, run the following command (`--count` is 1 To generate neofs key pairs for gateways, run the following command (`--count` is 1
by default): by default):
``` ```

View file

@ -2,6 +2,7 @@ package auth
import ( import (
"context" "context"
"crypto/ecdsa"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -15,7 +16,6 @@ import (
"github.com/nspcc-dev/neofs-api-go/pkg/object" "github.com/nspcc-dev/neofs-api-go/pkg/object"
"github.com/nspcc-dev/neofs-api-go/pkg/token" "github.com/nspcc-dev/neofs-api-go/pkg/token"
"github.com/nspcc-dev/neofs-s3-gw/authmate" "github.com/nspcc-dev/neofs-s3-gw/authmate"
"github.com/nspcc-dev/neofs-s3-gw/creds/hcs"
"github.com/nspcc-dev/neofs-s3-gw/creds/tokens" "github.com/nspcc-dev/neofs-s3-gw/creds/tokens"
"github.com/nspcc-dev/neofs-sdk-go/pkg/pool" "github.com/nspcc-dev/neofs-sdk-go/pkg/pool"
"go.uber.org/zap" "go.uber.org/zap"
@ -36,9 +36,8 @@ type (
// Params stores node connection parameters. // Params stores node connection parameters.
Params struct { Params struct {
Pool pool.Pool Pool pool.Pool
Logger *zap.Logger Logger *zap.Logger
Credential hcs.Credentials
} }
prs int prs int
@ -58,7 +57,7 @@ func (p prs) Seek(_ int64, _ int) (int64, error) {
var _ io.ReadSeeker = prs(0) var _ io.ReadSeeker = prs(0)
// New creates an instance of AuthCenter. // New creates an instance of AuthCenter.
func New(conns pool.Pool, key hcs.PrivateKey) Center { func New(conns pool.Pool, key *ecdsa.PrivateKey) Center {
return &center{ return &center{
cli: tokens.New(conns, key), cli: tokens.New(conns, key),
reg: &regexpSubmatcher{re: authorizationFieldRegexp}, reg: &regexpSubmatcher{re: authorizationFieldRegexp},

View file

@ -21,16 +21,16 @@ import (
"github.com/nspcc-dev/neofs-api-go/pkg/owner" "github.com/nspcc-dev/neofs-api-go/pkg/owner"
"github.com/nspcc-dev/neofs-api-go/pkg/session" "github.com/nspcc-dev/neofs-api-go/pkg/session"
"github.com/nspcc-dev/neofs-api-go/pkg/token" "github.com/nspcc-dev/neofs-api-go/pkg/token"
crypto "github.com/nspcc-dev/neofs-crypto"
"github.com/nspcc-dev/neofs-node/pkg/policy" "github.com/nspcc-dev/neofs-node/pkg/policy"
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox" "github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
"github.com/nspcc-dev/neofs-s3-gw/creds/hcs"
"github.com/nspcc-dev/neofs-s3-gw/creds/tokens" "github.com/nspcc-dev/neofs-s3-gw/creds/tokens"
"github.com/nspcc-dev/neofs-sdk-go/pkg/pool" "github.com/nspcc-dev/neofs-sdk-go/pkg/pool"
"go.uber.org/zap" "go.uber.org/zap"
) )
const ( const (
defaultAuthContainerBasicACL uint32 = 0b00111100100011001000110011001100 defaultAuthContainerBasicACL uint32 = 0b00111100100011001000110011001110
containerCreationTimeout = 120 * time.Second containerCreationTimeout = 120 * time.Second
containerPollInterval = 5 * time.Second containerPollInterval = 5 * time.Second
) )
@ -52,8 +52,7 @@ type (
ContainerID *cid.ID ContainerID *cid.ID
ContainerFriendlyName string ContainerFriendlyName string
NeoFSKey *ecdsa.PrivateKey NeoFSKey *ecdsa.PrivateKey
OwnerPrivateKey hcs.PrivateKey GatesPublicKeys []*ecdsa.PublicKey
GatesPublicKeys []hcs.PublicKey
EACLRules []byte EACLRules []byte
ContextRules []byte ContextRules []byte
SessionTkn bool SessionTkn bool
@ -62,7 +61,7 @@ type (
// ObtainSecretOptions contains options for passing to Agent.ObtainSecret method. // ObtainSecretOptions contains options for passing to Agent.ObtainSecret method.
ObtainSecretOptions struct { ObtainSecretOptions struct {
SecretAddress string SecretAddress string
GatePrivateKey hcs.PrivateKey GatePrivateKey *ecdsa.PrivateKey
} }
) )
@ -134,7 +133,7 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
var ( var (
err error err error
cid *cid.ID cid *cid.ID
box accessbox.AccessBox box *accessbox.AccessBox
) )
a.log.Info("check container", zap.Stringer("cid", options.ContainerID)) a.log.Info("check container", zap.Stringer("cid", options.ContainerID))
@ -142,8 +141,6 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
return err return err
} }
box.SetOwnerPublicKey(options.OwnerPrivateKey.PublicKey())
oid, err := ownerIDFromNeoFSKey(&options.NeoFSKey.PublicKey) oid, err := ownerIDFromNeoFSKey(&options.NeoFSKey.PublicKey)
if err != nil { if err != nil {
return err return err
@ -155,35 +152,24 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
return fmt.Errorf("failed to build eacl table: %w", err) return fmt.Errorf("failed to build eacl table: %w", err)
} }
bearerTkn, err := buildBearerToken(options.NeoFSKey, oid, bearerRules) bearerTkn, err := buildBearerToken(options.NeoFSKey, bearerRules, options.GatesPublicKeys[0])
if err != nil { if err != nil {
return fmt.Errorf("failed to build bearer token: %w", err) return fmt.Errorf("failed to build bearer token: %w", err)
} }
err = box.AddBearerToken(bearerTkn, options.OwnerPrivateKey, options.GatesPublicKeys...) sessionTkn, err := createSessionToken(options, oid)
if err != nil { if err != nil {
return fmt.Errorf("failed to add bearer token to accessbox: %w", err) return fmt.Errorf("failed to create session token: %w", err)
} }
box, ownerKey, err := accessbox.PackTokens(bearerTkn, sessionTkn, options.GatesPublicKeys...)
if err != nil {
return err
}
a.log.Info("store bearer token into NeoFS", a.log.Info("store bearer token into NeoFS",
zap.Stringer("owner_tkn", bearerTkn.Issuer())) zap.Stringer("owner_tkn", bearerTkn.Issuer()))
if options.SessionTkn {
sessionRules, err := buildContext(options.ContextRules)
if err != nil {
return fmt.Errorf("failed to build context for session token: %w", err)
}
sessionTkn, err := buildSessionToken(options.NeoFSKey, oid, sessionRules)
if err != nil {
return fmt.Errorf("failed to create session token: %w", err)
}
err = box.AddSessionToken(sessionTkn, options.OwnerPrivateKey, options.GatesPublicKeys...)
if err != nil {
return fmt.Errorf("failed to add session token to accessbox: %w", err)
}
}
if !options.SessionTkn && len(options.ContextRules) > 0 { if !options.SessionTkn && len(options.ContextRules) > 0 {
_, err := w.Write([]byte("Warning: rules for session token were set but --create-session flag wasn't, " + _, err := w.Write([]byte("Warning: rules for session token were set but --create-session flag wasn't, " +
"so session token was not created\n")) "so session token was not created\n"))
@ -193,8 +179,8 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
} }
address, err := tokens. address, err := tokens.
New(a.pool, options.OwnerPrivateKey). New(a.pool, ownerKey).
Put(ctx, cid, oid, &box, options.GatesPublicKeys...) Put(ctx, cid, oid, box, options.GatesPublicKeys...)
if err != nil { if err != nil {
return fmt.Errorf("failed to put bearer token: %w", err) return fmt.Errorf("failed to put bearer token: %w", err)
} }
@ -209,7 +195,7 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
ir := &issuingResult{ ir := &issuingResult{
AccessKeyID: accessKeyID, AccessKeyID: accessKeyID,
SecretAccessKey: secret, SecretAccessKey: secret,
OwnerPrivateKey: options.OwnerPrivateKey.String(), OwnerPrivateKey: hex.EncodeToString(crypto.MarshalPrivateKey(ownerKey)),
} }
enc := json.NewEncoder(w) enc := json.NewEncoder(w)
@ -316,7 +302,12 @@ func buildContext(rules []byte) (*session.ContainerContext, error) {
return sessionCtx, nil return sessionCtx, nil
} }
func buildBearerToken(key *ecdsa.PrivateKey, oid *owner.ID, table *eacl.Table) (*token.BearerToken, error) { func buildBearerToken(key *ecdsa.PrivateKey, table *eacl.Table, ownerKey *ecdsa.PublicKey) (*token.BearerToken, error) {
oid, err := ownerIDFromNeoFSKey(ownerKey)
if err != nil {
return nil, err
}
bearerToken := token.NewBearerToken() bearerToken := token.NewBearerToken()
bearerToken.SetEACLTable(table) bearerToken.SetEACLTable(table)
bearerToken.SetOwner(oid) bearerToken.SetOwner(oid)
@ -338,6 +329,17 @@ func buildSessionToken(key *ecdsa.PrivateKey, oid *owner.ID, ctx *session.Contai
return tok, tok.Sign(key) return tok, tok.Sign(key)
} }
func createSessionToken(options *IssueSecretOptions, oid *owner.ID) (*session.Token, error) {
if options.SessionTkn {
sessionRules, err := buildContext(options.ContextRules)
if err != nil {
return nil, fmt.Errorf("failed to build context for session token: %w", err)
}
return buildSessionToken(options.NeoFSKey, oid, sessionRules)
}
return nil, nil
}
// BearerToAccessKey returns secret access key generated from given BearerToken. // BearerToAccessKey returns secret access key generated from given BearerToken.
func BearerToAccessKey(tkn *token.BearerToken) (string, error) { func BearerToAccessKey(tkn *token.BearerToken) (string, error) {
data, err := tkn.Marshal() data, err := tkn.Marshal()
@ -356,3 +358,16 @@ func ownerIDFromNeoFSKey(key *ecdsa.PublicKey) (*owner.ID, error) {
} }
return owner.NewIDFromNeo3Wallet(wallet), nil return owner.NewIDFromNeo3Wallet(wallet), nil
} }
// LoadPublicKey returns ecdsa.PublicKey from hex string.
func LoadPublicKey(val string) (*ecdsa.PublicKey, error) {
data, err := hex.DecodeString(val)
if err != nil {
return nil, fmt.Errorf("unknown key format (%q), expect: hex-string", val)
}
if key := crypto.UnmarshalPublicKey(data); key != nil {
return key, nil
}
return nil, fmt.Errorf("couldn't unmarshal public key (%q)", val)
}

View file

@ -3,7 +3,9 @@ package main
import ( import (
"context" "context"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/elliptic"
"crypto/rand" "crypto/rand"
"encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
@ -15,7 +17,6 @@ import (
cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id" cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id"
crypto "github.com/nspcc-dev/neofs-crypto" crypto "github.com/nspcc-dev/neofs-crypto"
"github.com/nspcc-dev/neofs-s3-gw/authmate" "github.com/nspcc-dev/neofs-s3-gw/authmate"
"github.com/nspcc-dev/neofs-s3-gw/creds/hcs"
"github.com/nspcc-dev/neofs-s3-gw/internal/version" "github.com/nspcc-dev/neofs-s3-gw/internal/version"
"github.com/nspcc-dev/neofs-sdk-go/pkg/pool" "github.com/nspcc-dev/neofs-sdk-go/pkg/pool"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
@ -40,7 +41,6 @@ var (
contextRulesFlag string contextRulesFlag string
gatePrivateKeyFlag string gatePrivateKeyFlag string
accessKeyIDFlag string accessKeyIDFlag string
ownerPrivateKeyFlag string
containerIDFlag string containerIDFlag string
containerFriendlyName string containerFriendlyName string
gatesPublicKeysFlag cli.StringSlice gatesPublicKeysFlag cli.StringSlice
@ -124,14 +124,14 @@ func appCommands() []*cli.Command {
} }
} }
func generateGatesKeys(count int) ([]hcs.Credentials, error) { func generateGatesKeys(count int) ([]*ecdsa.PrivateKey, error) {
var ( var (
err error err error
res = make([]hcs.Credentials, count) res = make([]*ecdsa.PrivateKey, count)
) )
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
if res[i], err = hcs.Generate(rand.Reader); err != nil { if res[i], err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader); err != nil {
return nil, err return nil, err
} }
} }
@ -146,7 +146,7 @@ func generateKeys() *cli.Command {
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.IntFlag{ &cli.IntFlag{
Name: "count", Name: "count",
Usage: "number of x25519 key pairs to generate", Usage: "number of 256r1 key pairs to generate",
Value: 1, Value: 1,
Destination: &gatesKeysCountFlag, Destination: &gatesKeysCountFlag,
}, },
@ -154,18 +154,18 @@ func generateKeys() *cli.Command {
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
_, log := prepare() _, log := prepare()
log.Info("start generating x25519 keys") log.Info("start generating P-256 keys")
csl, err := generateGatesKeys(gatesKeysCountFlag) csl, err := generateGatesKeys(gatesKeysCountFlag)
if err != nil { if err != nil {
return cli.Exit(fmt.Sprintf("failed to create key pairs of gates: %s", err), 1) return cli.Exit(fmt.Sprintf("failed to create key pairs of gates: %s", err), 1)
} }
log.Info("generated x25519 keys") log.Info("generated P-256 keys")
gatesKeys := make([]gateKey, len(csl)) gatesKeys := make([]gateKey, len(csl))
for i, cs := range csl { for i, cs := range csl {
privateKey, publicKey := cs.PrivateKey().String(), cs.PublicKey().String() privateKey, publicKey := hex.EncodeToString(cs.D.Bytes()), hex.EncodeToString(crypto.MarshalPublicKey(&cs.PublicKey))
gatesKeys[i] = gateKey{PrivateKey: privateKey, PublicKey: publicKey} gatesKeys[i] = gateKey{PrivateKey: privateKey, PublicKey: publicKey}
} }
@ -213,16 +213,10 @@ func issueSecret() *cli.Command {
}, },
&cli.StringSliceFlag{ &cli.StringSliceFlag{
Name: "gate-public-key", Name: "gate-public-key",
Usage: "public x25519 key of a gate (use flags repeatedly for multiple gates)", Usage: "public 256r1 key of a gate (use flags repeatedly for multiple gates)",
Required: true, Required: true,
Destination: &gatesPublicKeysFlag, Destination: &gatesPublicKeysFlag,
}, },
&cli.StringFlag{
Name: "owner-private-key",
Usage: "owner's private x25519 key",
Required: false,
Destination: &ownerPrivateKeyFlag,
},
&cli.StringFlag{ &cli.StringFlag{
Name: "container-id", Name: "container-id",
Usage: "auth container id to put the secret into", Usage: "auth container id to put the secret into",
@ -269,14 +263,9 @@ func issueSecret() *cli.Command {
} }
} }
var owner hcs.Credentials var gatesPublicKeys []*ecdsa.PublicKey
if owner, err = fetchHCSCredentials(ownerPrivateKeyFlag); err != nil {
return cli.Exit(fmt.Sprintf("failed to create owner's private key: %s", err), 4)
}
var gatesPublicKeys []hcs.PublicKey
for _, key := range gatesPublicKeysFlag.Value() { for _, key := range gatesPublicKeysFlag.Value() {
gpk, err := hcs.LoadPublicKey(key) gpk, err := authmate.LoadPublicKey(key)
if err != nil { if err != nil {
return cli.Exit(fmt.Sprintf("failed to load gate's public key: %s", err), 5) return cli.Exit(fmt.Sprintf("failed to load gate's public key: %s", err), 5)
} }
@ -287,7 +276,6 @@ func issueSecret() *cli.Command {
ContainerID: containerID, ContainerID: containerID,
ContainerFriendlyName: containerFriendlyName, ContainerFriendlyName: containerFriendlyName,
NeoFSKey: key, NeoFSKey: key,
OwnerPrivateKey: owner.PrivateKey(),
GatesPublicKeys: gatesPublicKeys, GatesPublicKeys: gatesPublicKeys,
EACLRules: []byte(eaclRulesFlag), EACLRules: []byte(eaclRulesFlag),
ContextRules: []byte(contextRulesFlag), ContextRules: []byte(contextRulesFlag),
@ -355,7 +343,7 @@ func obtainSecret() *cli.Command {
var _ = agent var _ = agent
gateCreds, err := hcs.NewCredentials(gatePrivateKeyFlag) gateCreds, err := crypto.LoadPrivateKey(gatePrivateKeyFlag)
if err != nil { if err != nil {
return cli.Exit(fmt.Sprintf("failed to create owner's private key: %s", err), 4) return cli.Exit(fmt.Sprintf("failed to create owner's private key: %s", err), 4)
} }
@ -364,7 +352,7 @@ func obtainSecret() *cli.Command {
obtainSecretOptions := &authmate.ObtainSecretOptions{ obtainSecretOptions := &authmate.ObtainSecretOptions{
SecretAddress: secretAddress, SecretAddress: secretAddress,
GatePrivateKey: gateCreds.PrivateKey(), GatePrivateKey: gateCreds,
} }
if err = agent.ObtainSecret(ctx, os.Stdout, obtainSecretOptions); err != nil { if err = agent.ObtainSecret(ctx, os.Stdout, obtainSecretOptions); err != nil {
@ -377,14 +365,6 @@ func obtainSecret() *cli.Command {
return command return command
} }
func fetchHCSCredentials(val string) (hcs.Credentials, error) {
if val == "" {
return hcs.Generate(rand.Reader)
}
return hcs.NewCredentials(val)
}
func createSDKClient(ctx context.Context, log *zap.Logger, key *ecdsa.PrivateKey, peerAddress string) (pool.Pool, error) { func createSDKClient(ctx context.Context, log *zap.Logger, key *ecdsa.PrivateKey, peerAddress string) (pool.Pool, error) {
log.Debug("prepare connection pool") log.Debug("prepare connection pool")

View file

@ -43,8 +43,7 @@ const ( // Settings.
cfgLoggerSamplingThereafter = "logger.sampling.thereafter" cfgLoggerSamplingThereafter = "logger.sampling.thereafter"
// Keys. // Keys.
cfgNeoFSPrivateKey = "neofs-key" cfgNeoFSPrivateKey = "neofs-key"
cfgGateAuthPrivateKey = "auth-key"
// HTTPS/TLS. // HTTPS/TLS.
cfgTLSKeyFile = "tls.key_file" cfgTLSKeyFile = "tls.key_file"
@ -163,7 +162,6 @@ func newSettings() *viper.Viper {
versionFlag := flags.BoolP(cmdVersion, "v", false, "show version") versionFlag := flags.BoolP(cmdVersion, "v", false, "show version")
flags.String(cfgNeoFSPrivateKey, "", "set value to hex string, WIF string, or path to NeoFS private key file") flags.String(cfgNeoFSPrivateKey, "", "set value to hex string, WIF string, or path to NeoFS private key file")
flags.String(cfgGateAuthPrivateKey, "", "set path to file with auth (curve25519) private key to use in auth scheme")
flags.Bool(cfgGRPCVerbose, false, "set debug mode of gRPC connections") flags.Bool(cfgGRPCVerbose, false, "set debug mode of gRPC connections")
flags.Duration(cfgRequestTimeout, defaultRequestTimeout, "set gRPC request timeout") flags.Duration(cfgRequestTimeout, defaultRequestTimeout, "set gRPC request timeout")

View file

@ -12,7 +12,6 @@ import (
"github.com/nspcc-dev/neofs-s3-gw/api/auth" "github.com/nspcc-dev/neofs-s3-gw/api/auth"
"github.com/nspcc-dev/neofs-s3-gw/api/handler" "github.com/nspcc-dev/neofs-s3-gw/api/handler"
"github.com/nspcc-dev/neofs-s3-gw/api/layer" "github.com/nspcc-dev/neofs-s3-gw/api/layer"
"github.com/nspcc-dev/neofs-s3-gw/creds/hcs"
"github.com/nspcc-dev/neofs-sdk-go/pkg/pool" "github.com/nspcc-dev/neofs-sdk-go/pkg/pool"
"github.com/spf13/viper" "github.com/spf13/viper"
"go.uber.org/zap" "go.uber.org/zap"
@ -51,8 +50,6 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App {
ctr auth.Center ctr auth.Center
obj layer.Client obj layer.Client
hcsCred hcs.Credentials
poolPeers = fetchPeers(l, v) poolPeers = fetchPeers(l, v)
reBalance = defaultRebalanceTimer reBalance = defaultRebalanceTimer
@ -62,7 +59,6 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App {
maxClientsCount = defaultMaxClientsCount maxClientsCount = defaultMaxClientsCount
maxClientsDeadline = defaultMaxClientsDeadline maxClientsDeadline = defaultMaxClientsDeadline
hcsCredential = v.GetString(cfgGateAuthPrivateKey)
nfsCredential = v.GetString(cfgNeoFSPrivateKey) nfsCredential = v.GetString(cfgNeoFSPrivateKey)
) )
@ -90,10 +86,6 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App {
l.Fatal("could not load NeoFS private key") l.Fatal("could not load NeoFS private key")
} }
if hcsCred, err = hcs.NewCredentials(hcsCredential); err != nil {
l.Fatal("could not load gate auth key")
}
if v.IsSet(cfgTLSKeyFile) && v.IsSet(cfgTLSCertFile) { if v.IsSet(cfgTLSKeyFile) && v.IsSet(cfgTLSCertFile) {
tls = &tlsConfig{ tls = &tlsConfig{
KeyFile: v.GetString(cfgTLSKeyFile), KeyFile: v.GetString(cfgTLSKeyFile),
@ -102,7 +94,6 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App {
} }
l.Info("using credentials", l.Info("using credentials",
zap.String("HCS", hcsCredential),
zap.String("NeoFS", nfsCredential)) zap.String("NeoFS", nfsCredential))
opts := &pool.BuilderOptions{ opts := &pool.BuilderOptions{
@ -121,7 +112,7 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App {
obj = layer.NewLayer(l, conns) obj = layer.NewLayer(l, conns)
// prepare auth center // prepare auth center
ctr = auth.New(conns, hcsCred.PrivateKey()) ctr = auth.New(conns, key)
if caller, err = handler.New(l, obj); err != nil { if caller, err = handler.New(l, obj); err != nil {
l.Fatal("could not initialize API handler", zap.Error(err)) l.Fatal("could not initialize API handler", zap.Error(err))

View file

@ -2,14 +2,19 @@ package accessbox
import ( import (
"bytes" "bytes"
"crypto/cipher"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand" "crypto/rand"
"crypto/sha256"
"fmt" "fmt"
"io"
"github.com/nspcc-dev/neofs-api-go/pkg/session" "github.com/nspcc-dev/neofs-api-go/pkg/session"
"github.com/nspcc-dev/neofs-api-go/pkg/token" "github.com/nspcc-dev/neofs-api-go/pkg/token"
"github.com/nspcc-dev/neofs-s3-gw/creds/hcs" crypto "github.com/nspcc-dev/neofs-crypto"
"golang.org/x/crypto/chacha20poly1305" "golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/curve25519" "golang.org/x/crypto/hkdf"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
) )
@ -28,43 +33,34 @@ func (x *AccessBox) Unmarshal(data []byte) error {
return proto.Unmarshal(data, x) return proto.Unmarshal(data, x)
} }
// AddBearerToken adds a bearer token to BearerTokens list. // PackTokens adds a bearer and session tokens to BearerTokens and SessionToken lists respectively.
func (x *AccessBox) AddBearerToken(tkn *token.BearerToken, owner hcs.PrivateKey, keys ...hcs.PublicKey) error { // Session token can be nil.
if x.OwnerPublicKey == nil { func PackTokens(bearer *token.BearerToken, sess *session.Token, keys ...*ecdsa.PublicKey) (*AccessBox, *ecdsa.PrivateKey, error) {
return fmt.Errorf("owner's public key is nil") box := &AccessBox{}
ephemeralKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return nil, nil, err
} }
// restriction to rewrite token for the second time box.OwnerPublicKey = crypto.MarshalPublicKey(&ephemeralKey.PublicKey)
if len(x.BearerTokens) > 0 {
return fmt.Errorf("bearer token is already set")
}
return x.addToken(tkn, &x.BearerTokens, owner, keys...)
}
// AddSessionToken adds a session token to SessionTokens list. if err := box.addToken(bearer, &box.BearerTokens, ephemeralKey, keys...); err != nil {
func (x *AccessBox) AddSessionToken(tkn *session.Token, owner hcs.PrivateKey, keys ...hcs.PublicKey) error { return nil, nil, fmt.Errorf("failed to add bearer token to accessbox: %w", err)
if x.OwnerPublicKey == nil {
return fmt.Errorf("owner's public key is nil")
} }
//restriction to rewrite token for the second time if sess != nil {
if len(x.SessionTokens) > 0 { if err := box.addToken(sess, &box.SessionTokens, ephemeralKey, keys...); err != nil {
return fmt.Errorf("bearer token is already set") return nil, nil, fmt.Errorf("failed to add session token to accessbox: %w", err)
}
} }
return x.addToken(tkn, &x.SessionTokens, owner, keys...)
}
// SetOwnerPublicKey sets a public key of an issuer. return box, ephemeralKey, err
func (x *AccessBox) SetOwnerPublicKey(key hcs.PublicKey) {
x.OwnerPublicKey = key.Bytes()
} }
// GetBearerToken returns bearer token from AccessBox. // GetBearerToken returns bearer token from AccessBox.
func (x *AccessBox) GetBearerToken(owner hcs.PrivateKey) (*token.BearerToken, error) { func (x *AccessBox) GetBearerToken(owner *ecdsa.PrivateKey) (*token.BearerToken, error) {
sender, err := hcs.PublicKeyFromBytes(x.OwnerPublicKey) sender := crypto.UnmarshalPublicKey(x.OwnerPublicKey)
if err != nil { ownerKey := crypto.MarshalPublicKey(&owner.PublicKey)
return nil, fmt.Errorf("failed to load owner public key from AccessBox: %w", err)
}
for _, data := range x.BearerTokens { for _, data := range x.BearerTokens {
if !bytes.Equal(data.GatePublicKey, owner.PublicKey().Bytes()) { if !bytes.Equal(data.GatePublicKey, ownerKey) {
continue continue
} }
tkn := token.NewBearerToken() tkn := token.NewBearerToken()
@ -74,17 +70,15 @@ func (x *AccessBox) GetBearerToken(owner hcs.PrivateKey) (*token.BearerToken, er
return tkn, nil return tkn, nil
} }
return nil, fmt.Errorf("no bearer token for key %s was found", owner.String()) return nil, fmt.Errorf("no bearer token for key %x was found", ownerKey)
} }
// GetSessionToken returns session token from AccessBox. // GetSessionToken returns session token from AccessBox.
func (x *AccessBox) GetSessionToken(owner hcs.PrivateKey) (*session.Token, error) { func (x *AccessBox) GetSessionToken(owner *ecdsa.PrivateKey) (*session.Token, error) {
sender, err := hcs.PublicKeyFromBytes(x.OwnerPublicKey) sender := crypto.UnmarshalPublicKey(x.OwnerPublicKey)
if err != nil { ownerKey := crypto.MarshalPublicKey(&owner.PublicKey)
return nil, fmt.Errorf("failed to load owner public key from AccessBox: %w", err)
}
for _, data := range x.SessionTokens { for _, data := range x.SessionTokens {
if !bytes.Equal(data.GatePublicKey, owner.PublicKey().Bytes()) { if !bytes.Equal(data.GatePublicKey, ownerKey) {
continue continue
} }
tkn := session.NewToken() tkn := session.NewToken()
@ -95,16 +89,16 @@ func (x *AccessBox) GetSessionToken(owner hcs.PrivateKey) (*session.Token, error
return tkn, nil return tkn, nil
} }
return nil, fmt.Errorf("no session token for key %s was found", owner.String()) return nil, fmt.Errorf("no session token for key %x was found", ownerKey)
} }
func (x *AccessBox) addToken(tkn tokenInterface, list *[]*AccessBox_Token, owner hcs.PrivateKey, keys ...hcs.PublicKey) error { func (x *AccessBox) addToken(tkn tokenInterface, list *[]*AccessBox_Token, owner *ecdsa.PrivateKey, keys ...*ecdsa.PublicKey) error {
for i, sender := range keys { for i, sender := range keys {
data, err := encodeToken(tkn, owner, sender) data, err := encodeToken(tkn, owner, sender)
if err != nil { if err != nil {
return fmt.Errorf("%w, sender = %d", err, i) return fmt.Errorf("%w, sender = %d", err, i)
} }
*list = append(*list, newToken(data, sender.Bytes())) *list = append(*list, newToken(data, crypto.MarshalPublicKey(sender)))
} }
return nil return nil
} }
@ -116,7 +110,7 @@ func newToken(data []byte, key []byte) *AccessBox_Token {
return res return res
} }
func encodeToken(tkn tokenInterface, owner hcs.PrivateKey, sender hcs.PublicKey) ([]byte, error) { func encodeToken(tkn tokenInterface, owner *ecdsa.PrivateKey, sender *ecdsa.PublicKey) ([]byte, error) {
data, err := tkn.Marshal() data, err := tkn.Marshal()
if err != nil { if err != nil {
return nil, err return nil, err
@ -129,7 +123,7 @@ func encodeToken(tkn tokenInterface, owner hcs.PrivateKey, sender hcs.PublicKey)
return encrypted, nil return encrypted, nil
} }
func decodeToken(data []byte, tkn tokenInterface, owner hcs.PrivateKey, sender hcs.PublicKey) error { func decodeToken(data []byte, tkn tokenInterface, owner *ecdsa.PrivateKey, sender *ecdsa.PublicKey) error {
decoded, err := decrypt(owner, sender, data) decoded, err := decrypt(owner, sender, data)
if err != nil { if err != nil {
return err return err
@ -143,13 +137,32 @@ func decodeToken(data []byte, tkn tokenInterface, owner hcs.PrivateKey, sender h
return nil return nil
} }
func encrypt(owner hcs.PrivateKey, sender hcs.PublicKey, data []byte) ([]byte, error) { func generateShared256(prv *ecdsa.PrivateKey, pub *ecdsa.PublicKey) (sk []byte, err error) {
key, err := curve25519.X25519(owner.Bytes(), sender.Bytes()) if prv.PublicKey.Curve != pub.Curve {
if err != nil { return nil, fmt.Errorf("not equal curves")
return nil, err
} }
enc, err := chacha20poly1305.NewX(key) x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, prv.D.Bytes())
if x == nil {
return nil, fmt.Errorf("shared key is point at infinity")
}
sk = make([]byte, 32)
skBytes := x.Bytes()
copy(sk[len(sk)-len(skBytes):], skBytes)
return sk, nil
}
func deriveKey(secret []byte) ([]byte, error) {
hash := sha256.New
kdf := hkdf.New(hash, secret, nil, nil)
key := make([]byte, 32)
_, err := io.ReadFull(kdf, key)
return key, err
}
func encrypt(owner *ecdsa.PrivateKey, sender *ecdsa.PublicKey, data []byte) ([]byte, error) {
enc, err := getCipher(owner, sender)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -162,15 +175,8 @@ func encrypt(owner hcs.PrivateKey, sender hcs.PublicKey, data []byte) ([]byte, e
return enc.Seal(nonce, nonce, data, nil), nil return enc.Seal(nonce, nonce, data, nil), nil
} }
func decrypt(owner hcs.PrivateKey, sender hcs.PublicKey, data []byte) ([]byte, error) { func decrypt(owner *ecdsa.PrivateKey, sender *ecdsa.PublicKey, data []byte) ([]byte, error) {
sb := sender.Bytes() dec, err := getCipher(owner, sender)
key, err := curve25519.X25519(owner.Bytes(), sb)
if err != nil {
return nil, err
}
dec, err := chacha20poly1305.NewX(key)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -182,3 +188,21 @@ func decrypt(owner hcs.PrivateKey, sender hcs.PublicKey, data []byte) ([]byte, e
nonce, cypher := data[:dec.NonceSize()], data[dec.NonceSize():] nonce, cypher := data[:dec.NonceSize()], data[dec.NonceSize():]
return dec.Open(nil, nonce, cypher, nil) return dec.Open(nil, nonce, cypher, nil)
} }
func getCipher(owner *ecdsa.PrivateKey, sender *ecdsa.PublicKey) (cipher.AEAD, error) {
secret, err := generateShared256(owner, sender)
if err != nil {
return nil, err
}
key, err := deriveKey(secret)
if err != nil {
return nil, err
}
aead, err := chacha20poly1305.NewX(key)
if err != nil {
return nil, err
}
return aead, nil
}

View file

@ -8,7 +8,6 @@ import (
"github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl" "github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl"
"github.com/nspcc-dev/neofs-api-go/pkg/token" "github.com/nspcc-dev/neofs-api-go/pkg/token"
"github.com/nspcc-dev/neofs-s3-gw/creds/hcs"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -20,16 +19,16 @@ func Test_tokens_encode_decode(t *testing.T) {
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err) require.NoError(t, err)
cred, err := hcs.Generate(rand.Reader) cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err) require.NoError(t, err)
tkn.SetEACLTable(eacl.NewTable()) tkn.SetEACLTable(eacl.NewTable())
require.NoError(t, tkn.SignToken(sec)) require.NoError(t, tkn.SignToken(sec))
data, err := encodeToken(tkn, cred.PrivateKey(), cred.PublicKey()) data, err := encodeToken(tkn, cred, &cred.PublicKey)
require.NoError(t, err) require.NoError(t, err)
err = decodeToken(data, tkn2, cred.PrivateKey(), cred.PublicKey()) err = decodeToken(data, tkn2, cred, &cred.PublicKey)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, tkn, tkn2) require.Equal(t, tkn, tkn2)
@ -37,22 +36,21 @@ func Test_tokens_encode_decode(t *testing.T) {
func Test_bearer_token_in_access_box(t *testing.T) { func Test_bearer_token_in_access_box(t *testing.T) {
var ( var (
box, box2 AccessBox box *AccessBox
tkn = token.NewBearerToken() box2 AccessBox
tkn = token.NewBearerToken()
) )
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err) require.NoError(t, err)
cred, err := hcs.Generate(rand.Reader) cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err) require.NoError(t, err)
tkn.SetEACLTable(eacl.NewTable()) tkn.SetEACLTable(eacl.NewTable())
require.NoError(t, tkn.SignToken(sec)) require.NoError(t, tkn.SignToken(sec))
box.SetOwnerPublicKey(cred.PublicKey()) box, _, err = PackTokens(tkn, nil, &cred.PublicKey)
err = box.AddBearerToken(tkn, cred.PrivateKey(), cred.PublicKey())
require.NoError(t, err) require.NoError(t, err)
data, err := box.Marshal() data, err := box.Marshal()
@ -61,7 +59,7 @@ func Test_bearer_token_in_access_box(t *testing.T) {
err = box2.Unmarshal(data) err = box2.Unmarshal(data)
require.NoError(t, err) require.NoError(t, err)
tkn2, err := box2.GetBearerToken(cred.PrivateKey()) tkn2, err := box2.GetBearerToken(cred)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, tkn, tkn2) require.Equal(t, tkn, tkn2)
@ -69,35 +67,30 @@ func Test_bearer_token_in_access_box(t *testing.T) {
func Test_accessbox_multiple_keys(t *testing.T) { func Test_accessbox_multiple_keys(t *testing.T) {
var ( var (
box AccessBox box *AccessBox
tkn = token.NewBearerToken() tkn = token.NewBearerToken()
) )
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err) require.NoError(t, err)
cred, err := hcs.Generate(rand.Reader)
require.NoError(t, err)
tkn.SetEACLTable(eacl.NewTable()) tkn.SetEACLTable(eacl.NewTable())
require.NoError(t, tkn.SignToken(sec)) require.NoError(t, tkn.SignToken(sec))
count := 10 count := 10
pubs := make([]hcs.PublicKey, 0, count) pubs := make([]*ecdsa.PublicKey, 0, count)
keys := make([]hcs.PrivateKey, 0, count) keys := make([]*ecdsa.PrivateKey, 0, count)
{ // generate keys { // generate keys
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
cred, err := hcs.Generate(rand.Reader) cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err) require.NoError(t, err)
pubs = append(pubs, cred.PublicKey()) pubs = append(pubs, &cred.PublicKey)
keys = append(keys, cred.PrivateKey()) keys = append(keys, cred)
} }
} }
box.SetOwnerPublicKey(cred.PublicKey()) box, _, err = PackTokens(tkn, nil, pubs...)
err = box.AddBearerToken(tkn, cred.PrivateKey(), pubs...)
require.NoError(t, err) require.NoError(t, err)
for i, k := range keys { for i, k := range keys {
@ -109,27 +102,25 @@ func Test_accessbox_multiple_keys(t *testing.T) {
func Test_unknown_key(t *testing.T) { func Test_unknown_key(t *testing.T) {
var ( var (
box AccessBox box *AccessBox
tkn = token.NewBearerToken() tkn = token.NewBearerToken()
) )
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err) require.NoError(t, err)
cred, err := hcs.Generate(rand.Reader) cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err) require.NoError(t, err)
wrongCred, err := hcs.Generate(rand.Reader) wrongCred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err) require.NoError(t, err)
tkn.SetEACLTable(eacl.NewTable()) tkn.SetEACLTable(eacl.NewTable())
require.NoError(t, tkn.SignToken(sec)) require.NoError(t, tkn.SignToken(sec))
box.SetOwnerPublicKey(cred.PublicKey()) box, _, err = PackTokens(tkn, nil, &cred.PublicKey)
err = box.AddBearerToken(tkn, cred.PrivateKey(), cred.PublicKey())
require.NoError(t, err) require.NoError(t, err)
_, err = box.GetBearerToken(wrongCred.PrivateKey()) _, err = box.GetBearerToken(wrongCred)
require.Error(t, err) require.Error(t, err)
} }

View file

@ -1,90 +0,0 @@
package hcs
import (
"errors"
"io"
"golang.org/x/crypto/curve25519"
)
type (
// Credentials is an HCS interface (private/public key).
Credentials interface {
PublicKey() PublicKey
PrivateKey() PrivateKey
}
keyer interface {
io.WriterTo
Bytes() []byte
String() string
}
// PublicKey is a public key wrapper providing useful methods.
PublicKey interface {
keyer
}
// PrivateKey is private key wrapper providing useful methods.
PrivateKey interface {
keyer
PublicKey() PublicKey
}
credentials struct {
public PublicKey
secret PrivateKey
}
public []byte
secret []byte
)
// ErrEmptyCredentials is returned when no credentials are provided.
var ErrEmptyCredentials = errors.New("empty credentials")
var _ = NewCredentials
// Generate generates new key pair using given source of randomness.
func Generate(r io.Reader) (Credentials, error) {
buf := make([]byte, curve25519.ScalarSize)
if _, err := r.Read(buf); err != nil {
return nil, err
}
sk := secret(buf)
return &credentials{
secret: &sk,
public: sk.PublicKey(),
}, nil
}
// NewCredentials loads private key from the string given and returns Credentials wrapper.
func NewCredentials(val string) (Credentials, error) {
if val == "" {
return nil, ErrEmptyCredentials
}
sk, err := loadPrivateKey(val)
if err != nil {
return nil, err
}
return &credentials{
secret: sk,
public: sk.PublicKey(),
}, nil
}
// PublicKey returns public key.
func (c *credentials) PublicKey() PublicKey {
return c.public
}
// PrivateKey returns private key.
func (c *credentials) PrivateKey() PrivateKey {
return c.secret
}

View file

@ -1,66 +0,0 @@
package hcs
import (
"encoding/hex"
"io"
"io/ioutil"
"os"
"golang.org/x/crypto/curve25519"
)
func (p *public) Bytes() []byte {
buf := make([]byte, curve25519.PointSize)
copy(buf, *p)
return buf
}
func (p *public) String() string {
buf := p.Bytes()
return hex.EncodeToString(buf)
}
func (p *public) WriteTo(w io.Writer) (int64, error) {
pb := p.Bytes()
pl, err := w.Write(pb)
return int64(pl), err
}
// PublicKeyFromBytes reads a public key from given bytes.
func PublicKeyFromBytes(v []byte) (PublicKey, error) {
pub := public(v)
return &pub, nil
}
func publicKeyFromString(val string) (PublicKey, error) {
v, err := hex.DecodeString(val)
if err != nil {
return nil, err
}
return PublicKeyFromBytes(v)
}
// NewPublicKeyFromReader reads new public key from given reader.
func NewPublicKeyFromReader(r io.Reader) (PublicKey, error) {
data := make([]byte, curve25519.PointSize)
if _, err := r.Read(data); err != nil {
return nil, err
}
return PublicKeyFromBytes(data)
}
// LoadPublicKey loads public key from given file or (serialized) string.
func LoadPublicKey(val string) (PublicKey, error) {
data, err := ioutil.ReadFile(val)
if err != nil {
if os.IsNotExist(err) {
return publicKeyFromString(val)
}
return nil, err
}
return PublicKeyFromBytes(data)
}

View file

@ -1,60 +0,0 @@
package hcs
import (
"encoding/hex"
"io"
"io/ioutil"
"os"
"golang.org/x/crypto/curve25519"
)
func (s *secret) Bytes() []byte {
buf := make([]byte, curve25519.ScalarSize)
copy(buf, *s)
return buf
}
func (s *secret) String() string {
buf := s.Bytes()
return hex.EncodeToString(buf)
}
func (s *secret) PublicKey() PublicKey {
sk := s.Bytes()
pb, _ := curve25519.X25519(sk, curve25519.Basepoint)
pk := public(pb)
return &pk
}
func (s *secret) WriteTo(w io.Writer) (int64, error) {
sb := s.Bytes()
sl, err := w.Write(sb)
return int64(sl), err
}
func privateKeyFromBytes(val []byte) (PrivateKey, error) {
sk := secret(val)
return &sk, nil
}
func privateKeyFromString(val string) (PrivateKey, error) {
data, err := hex.DecodeString(val)
if err != nil {
return nil, err
}
return privateKeyFromBytes(data)
}
func loadPrivateKey(val string) (PrivateKey, error) {
data, err := ioutil.ReadFile(val)
if os.IsNotExist(err) {
return privateKeyFromString(val)
} else if err != nil {
return nil, err
}
return privateKeyFromBytes(data)
}

View file

@ -3,6 +3,7 @@ package tokens
import ( import (
"bytes" "bytes"
"context" "context"
"crypto/ecdsa"
"errors" "errors"
"strconv" "strconv"
"sync" "sync"
@ -15,7 +16,6 @@ import (
"github.com/nspcc-dev/neofs-api-go/pkg/session" "github.com/nspcc-dev/neofs-api-go/pkg/session"
"github.com/nspcc-dev/neofs-api-go/pkg/token" "github.com/nspcc-dev/neofs-api-go/pkg/token"
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox" "github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
"github.com/nspcc-dev/neofs-s3-gw/creds/hcs"
"github.com/nspcc-dev/neofs-sdk-go/pkg/pool" "github.com/nspcc-dev/neofs-sdk-go/pkg/pool"
) )
@ -24,11 +24,11 @@ type (
Credentials interface { Credentials interface {
GetBearerToken(context.Context, *object.Address) (*token.BearerToken, error) GetBearerToken(context.Context, *object.Address) (*token.BearerToken, error)
GetSessionToken(context.Context, *object.Address) (*session.Token, error) GetSessionToken(context.Context, *object.Address) (*session.Token, error)
Put(context.Context, *cid.ID, *owner.ID, *accessbox.AccessBox, ...hcs.PublicKey) (*object.Address, error) Put(context.Context, *cid.ID, *owner.ID, *accessbox.AccessBox, ...*ecdsa.PublicKey) (*object.Address, error)
} }
cred struct { cred struct {
key hcs.PrivateKey key *ecdsa.PrivateKey
pool pool.Pool pool pool.Pool
} }
) )
@ -49,7 +49,7 @@ var bufferPool = sync.Pool{
var _ = New var _ = New
// New creates new Credentials instance using given cli and key. // New creates new Credentials instance using given cli and key.
func New(conns pool.Pool, key hcs.PrivateKey) Credentials { func New(conns pool.Pool, key *ecdsa.PrivateKey) Credentials {
return &cred{pool: conns, key: key} return &cred{pool: conns, key: key}
} }
@ -112,7 +112,7 @@ func (c *cred) getAccessBox(ctx context.Context, address *object.Address) (*acce
return &box, nil return &box, nil
} }
func (c *cred) Put(ctx context.Context, cid *cid.ID, issuer *owner.ID, box *accessbox.AccessBox, keys ...hcs.PublicKey) (*object.Address, error) { func (c *cred) Put(ctx context.Context, cid *cid.ID, issuer *owner.ID, box *accessbox.AccessBox, keys ...*ecdsa.PublicKey) (*object.Address, error) {
var ( var (
err error err error
created = strconv.FormatInt(time.Now().Unix(), 10) created = strconv.FormatInt(time.Now().Unix(), 10)