*: demand RFC6979 signer where appropriate

It's needed for container operations, therefore default ones for client and
pool have to be of this type as well. And it's easier to check for it before
usage.

Fixes #209.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
This commit is contained in:
Roman Khimov 2023-05-22 17:05:44 +03:00
parent 2e18c3c16d
commit e99e9537a2
7 changed files with 78 additions and 27 deletions

View file

@ -4,6 +4,7 @@ import (
"context" "context"
"crypto/tls" "crypto/tls"
"errors" "errors"
"fmt"
"time" "time"
v2accounting "github.com/nspcc-dev/neofs-api-go/v2/accounting" v2accounting "github.com/nspcc-dev/neofs-api-go/v2/accounting"
@ -49,11 +50,19 @@ type Client struct {
server neoFSAPIServer server neoFSAPIServer
} }
var errNonNeoSigner = fmt.Errorf("%w: expected ECDSA_DETERMINISTIC_SHA256 scheme", neofscrypto.ErrIncorrectSigner)
// New creates an instance of Client initialized with the given parameters. // New creates an instance of Client initialized with the given parameters.
// //
// See docs of [PrmInit] methods for details. See also [Client.Dial]/[Client.Close]. // See docs of [PrmInit] methods for details. See also [Client.Dial]/[Client.Close].
//
// Returned errors:
// - [neofscrypto.ErrIncorrectSigner]
func New(prm PrmInit) (*Client, error) { func New(prm PrmInit) (*Client, error) {
var c = new(Client) var c = new(Client)
if prm.signer != nil && prm.signer.Scheme() != neofscrypto.ECDSA_DETERMINISTIC_SHA256 {
return nil, errNonNeoSigner
}
c.prm = prm c.prm = prm
return c, nil return c, nil
} }

View file

@ -406,6 +406,7 @@ func (x *PrmContainerDelete) WithinSession(tok session.Container) {
// //
// Return errors: // Return errors:
// - [ErrMissingContainer] // - [ErrMissingContainer]
// - [neofscrypto.ErrIncorrectSigner]
// //
// Reflects all internal errors in second return value (transport problems, response processing, etc.). // Reflects all internal errors in second return value (transport problems, response processing, etc.).
func (c *Client) ContainerDelete(ctx context.Context, prm PrmContainerDelete) error { func (c *Client) ContainerDelete(ctx context.Context, prm PrmContainerDelete) error {
@ -429,6 +430,9 @@ func (c *Client) ContainerDelete(ctx context.Context, prm PrmContainerDelete) er
signer = c.defaultSigner() signer = c.defaultSigner()
} }
if signer.Scheme() != neofscrypto.ECDSA_DETERMINISTIC_SHA256 {
return errNonNeoSigner
}
err := sig.Calculate(signer, data) err := sig.Calculate(signer, data)
if err != nil { if err != nil {
return fmt.Errorf("calculate signature: %w", err) return fmt.Errorf("calculate signature: %w", err)
@ -622,6 +626,7 @@ func (x *PrmContainerSetEACL) WithinSession(s session.Container) {
// Return errors: // Return errors:
// - [ErrMissingEACL] // - [ErrMissingEACL]
// - [ErrMissingEACLContainer] // - [ErrMissingEACLContainer]
// - [neofscrypto.ErrIncorrectSigner]
// //
// Context is required and must not be nil. It is used for network communication. // Context is required and must not be nil. It is used for network communication.
func (c *Client) ContainerSetEACL(ctx context.Context, prm PrmContainerSetEACL) error { func (c *Client) ContainerSetEACL(ctx context.Context, prm PrmContainerSetEACL) error {
@ -645,6 +650,10 @@ func (c *Client) ContainerSetEACL(ctx context.Context, prm PrmContainerSetEACL)
signer = c.defaultSigner() signer = c.defaultSigner()
} }
if signer.Scheme() != neofscrypto.ECDSA_DETERMINISTIC_SHA256 {
return errNonNeoSigner
}
err := sig.Calculate(signer, eaclV2.StableMarshal(nil)) err := sig.Calculate(signer, eaclV2.StableMarshal(nil))
if err != nil { if err != nil {
return fmt.Errorf("calculate signature: %w", err) return fmt.Errorf("calculate signature: %w", err)

View file

@ -481,7 +481,13 @@ func ReadDomain(cnr Container) (res Domain) {
// can be used. // can be used.
// //
// See also VerifySignature. // See also VerifySignature.
//
// Returned errors:
// - [neofscrypto.ErrIncorrectSigner]
func CalculateSignature(dst *neofscrypto.Signature, cnr Container, signer neofscrypto.Signer) error { func CalculateSignature(dst *neofscrypto.Signature, cnr Container, signer neofscrypto.Signer) error {
if signer.Scheme() != neofscrypto.ECDSA_DETERMINISTIC_SHA256 {
return fmt.Errorf("%w: expected ECDSA_DETERMINISTIC_SHA256 scheme", neofscrypto.ErrIncorrectSigner)
}
return dst.Calculate(signer, cnr.Marshal()) return dst.Calculate(signer, cnr.Marshal())
} }

View file

@ -336,6 +336,7 @@ func TestCalculateSignature(t *testing.T) {
var sig neofscrypto.Signature var sig neofscrypto.Signature
require.Error(t, container.CalculateSignature(&sig, val, test.RandomSigner(t)))
require.NoError(t, container.CalculateSignature(&sig, val, test.RandomSignerRFC6979(t))) require.NoError(t, container.CalculateSignature(&sig, val, test.RandomSignerRFC6979(t)))
var msg refs.Signature var msg refs.Signature

View file

@ -1,11 +1,18 @@
package neofscrypto package neofscrypto
import ( import (
"errors"
"fmt" "fmt"
"github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/nspcc-dev/neofs-api-go/v2/refs"
) )
// ErrIncorrectSigner is returned from function when the signer passed to it
// is incompatible with the function requirements. This variable is intended
// to be used as documentation and for [errors.Is] purposes and MUST NOT be
// changed.
var ErrIncorrectSigner = errors.New("incorrect signer")
// Scheme represents digital signature algorithm with fixed cryptographic hash function. // Scheme represents digital signature algorithm with fixed cryptographic hash function.
// //
// Negative values are reserved and depend on context (e.g. unsupported scheme). // Negative values are reserved and depend on context (e.g. unsupported scheme).

View file

@ -1535,10 +1535,16 @@ const (
) )
// NewPool creates connection pool using parameters. // NewPool creates connection pool using parameters.
//
// Returned errors:
// - [neofscrypto.ErrIncorrectSigner]
func NewPool(options InitParameters) (*Pool, error) { func NewPool(options InitParameters) (*Pool, error) {
if options.signer == nil { if options.signer == nil {
return nil, fmt.Errorf("missed required parameter 'Signer'") return nil, fmt.Errorf("missed required parameter 'Signer'")
} }
if options.signer.Scheme() != neofscrypto.ECDSA_DETERMINISTIC_SHA256 {
return nil, fmt.Errorf("%w: expected ECDSA_DETERMINISTIC_SHA256 scheme", neofscrypto.ErrIncorrectSigner)
}
nodesParams, err := adjustNodeParams(options.nodeParams) nodesParams, err := adjustNodeParams(options.nodeParams)
if err != nil { if err != nil {

View file

@ -25,7 +25,7 @@ func TestBuildPoolClientFailed(t *testing.T) {
return nil, errors.New("oops") return nil, errors.New("oops")
} }
mockClientBuilder2 := func(addr string) (client, error) { mockClientBuilder2 := func(addr string) (client, error) {
mockCli := newMockClient(addr, test.RandomSigner(t)) mockCli := newMockClient(addr, test.RandomSignerRFC6979(t))
mockCli.errOnDial() mockCli.errOnDial()
return mockCli, nil return mockCli, nil
} }
@ -36,7 +36,7 @@ func TestBuildPoolClientFailed(t *testing.T) {
} { } {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
opts := InitParameters{ opts := InitParameters{
signer: test.RandomSigner(t), signer: test.RandomSignerRFC6979(t),
nodeParams: []NodeParam{{1, "peer0", 1}}, nodeParams: []NodeParam{{1, "peer0", 1}},
} }
opts.setClientBuilder(b) opts.setClientBuilder(b)
@ -51,13 +51,13 @@ func TestBuildPoolClientFailed(t *testing.T) {
func TestBuildPoolCreateSessionFailed(t *testing.T) { func TestBuildPoolCreateSessionFailed(t *testing.T) {
clientMockBuilder := func(addr string) (client, error) { clientMockBuilder := func(addr string) (client, error) {
mockCli := newMockClient(addr, test.RandomSigner(t)) mockCli := newMockClient(addr, test.RandomSignerRFC6979(t))
mockCli.errOnCreateSession() mockCli.errOnCreateSession()
return mockCli, nil return mockCli, nil
} }
opts := InitParameters{ opts := InitParameters{
signer: test.RandomSigner(t), signer: test.RandomSignerRFC6979(t),
nodeParams: []NodeParam{{1, "peer0", 1}}, nodeParams: []NodeParam{{1, "peer0", 1}},
} }
opts.setClientBuilder(clientMockBuilder) opts.setClientBuilder(clientMockBuilder)
@ -76,7 +76,7 @@ func TestBuildPoolOneNodeFailed(t *testing.T) {
var clientKeys []neofscrypto.Signer var clientKeys []neofscrypto.Signer
mockClientBuilder := func(addr string) (client, error) { mockClientBuilder := func(addr string) (client, error) {
key := test.RandomSigner(t) key := test.RandomSignerRFC6979(t)
clientKeys = append(clientKeys, key) clientKeys = append(clientKeys, key)
if addr == nodes[0].address { if addr == nodes[0].address {
@ -91,7 +91,7 @@ func TestBuildPoolOneNodeFailed(t *testing.T) {
log, err := zap.NewProduction() log, err := zap.NewProduction()
require.NoError(t, err) require.NoError(t, err)
opts := InitParameters{ opts := InitParameters{
signer: test.RandomSigner(t), signer: test.RandomSignerRFC6979(t),
clientRebalanceInterval: 1000 * time.Millisecond, clientRebalanceInterval: 1000 * time.Millisecond,
logger: log, logger: log,
nodeParams: nodes, nodeParams: nodes,
@ -118,6 +118,19 @@ func TestBuildPoolOneNodeFailed(t *testing.T) {
} }
func TestBuildPoolZeroNodes(t *testing.T) { func TestBuildPoolZeroNodes(t *testing.T) {
opts := InitParameters{
signer: test.RandomSignerRFC6979(t),
}
_, err := NewPool(opts)
require.Error(t, err)
}
func TestBuildPoolNoSigner(t *testing.T) {
_, err := NewPool(InitParameters{})
require.Error(t, err)
}
func TestBuildPoolWrongSigner(t *testing.T) {
opts := InitParameters{ opts := InitParameters{
signer: test.RandomSigner(t), signer: test.RandomSigner(t),
} }
@ -126,13 +139,13 @@ func TestBuildPoolZeroNodes(t *testing.T) {
} }
func TestOneNode(t *testing.T) { func TestOneNode(t *testing.T) {
key1 := test.RandomSigner(t) key1 := test.RandomSignerRFC6979(t)
mockClientBuilder := func(addr string) (client, error) { mockClientBuilder := func(addr string) (client, error) {
return newMockClient(addr, key1), nil return newMockClient(addr, key1), nil
} }
opts := InitParameters{ opts := InitParameters{
signer: test.RandomSigner(t), signer: test.RandomSignerRFC6979(t),
nodeParams: []NodeParam{{1, "peer0", 1}}, nodeParams: []NodeParam{{1, "peer0", 1}},
} }
opts.setClientBuilder(mockClientBuilder) opts.setClientBuilder(mockClientBuilder)
@ -152,13 +165,13 @@ func TestOneNode(t *testing.T) {
func TestTwoNodes(t *testing.T) { func TestTwoNodes(t *testing.T) {
var clientKeys []neofscrypto.Signer var clientKeys []neofscrypto.Signer
mockClientBuilder := func(addr string) (client, error) { mockClientBuilder := func(addr string) (client, error) {
key := test.RandomSigner(t) key := test.RandomSignerRFC6979(t)
clientKeys = append(clientKeys, key) clientKeys = append(clientKeys, key)
return newMockClient(addr, key), nil return newMockClient(addr, key), nil
} }
opts := InitParameters{ opts := InitParameters{
signer: test.RandomSigner(t), signer: test.RandomSignerRFC6979(t),
nodeParams: []NodeParam{ nodeParams: []NodeParam{
{1, "peer0", 1}, {1, "peer0", 1},
{1, "peer1", 1}, {1, "peer1", 1},
@ -196,7 +209,7 @@ func TestOneOfTwoFailed(t *testing.T) {
var clientKeys []neofscrypto.Signer var clientKeys []neofscrypto.Signer
mockClientBuilder := func(addr string) (client, error) { mockClientBuilder := func(addr string) (client, error) {
key := test.RandomSigner(t) key := test.RandomSignerRFC6979(t)
clientKeys = append(clientKeys, key) clientKeys = append(clientKeys, key)
if addr == nodes[0].address { if addr == nodes[0].address {
@ -210,7 +223,7 @@ func TestOneOfTwoFailed(t *testing.T) {
} }
opts := InitParameters{ opts := InitParameters{
signer: test.RandomSigner(t), signer: test.RandomSignerRFC6979(t),
nodeParams: nodes, nodeParams: nodes,
clientRebalanceInterval: 200 * time.Millisecond, clientRebalanceInterval: 200 * time.Millisecond,
} }
@ -237,7 +250,7 @@ func TestOneOfTwoFailed(t *testing.T) {
func TestTwoFailed(t *testing.T) { func TestTwoFailed(t *testing.T) {
var clientKeys []neofscrypto.Signer var clientKeys []neofscrypto.Signer
mockClientBuilder := func(addr string) (client, error) { mockClientBuilder := func(addr string) (client, error) {
key := test.RandomSigner(t) key := test.RandomSignerRFC6979(t)
clientKeys = append(clientKeys, key) clientKeys = append(clientKeys, key)
mockCli := newMockClient(addr, key) mockCli := newMockClient(addr, key)
mockCli.errOnEndpointInfo() mockCli.errOnEndpointInfo()
@ -245,7 +258,7 @@ func TestTwoFailed(t *testing.T) {
} }
opts := InitParameters{ opts := InitParameters{
signer: test.RandomSigner(t), signer: test.RandomSignerRFC6979(t),
nodeParams: []NodeParam{ nodeParams: []NodeParam{
{1, "peer0", 1}, {1, "peer0", 1},
{1, "peer1", 1}, {1, "peer1", 1},
@ -269,7 +282,7 @@ func TestTwoFailed(t *testing.T) {
} }
func TestSessionCache(t *testing.T) { func TestSessionCache(t *testing.T) {
key := test.RandomSigner(t) key := test.RandomSignerRFC6979(t)
mockClientBuilder := func(addr string) (client, error) { mockClientBuilder := func(addr string) (client, error) {
mockCli := newMockClient(addr, key) mockCli := newMockClient(addr, key)
@ -278,7 +291,7 @@ func TestSessionCache(t *testing.T) {
} }
opts := InitParameters{ opts := InitParameters{
signer: test.RandomSigner(t), signer: test.RandomSignerRFC6979(t),
nodeParams: []NodeParam{ nodeParams: []NodeParam{
{1, "peer0", 1}, {1, "peer0", 1},
}, },
@ -335,7 +348,7 @@ func TestPriority(t *testing.T) {
var clientKeys []neofscrypto.Signer var clientKeys []neofscrypto.Signer
mockClientBuilder := func(addr string) (client, error) { mockClientBuilder := func(addr string) (client, error) {
key := test.RandomSigner(t) key := test.RandomSignerRFC6979(t)
clientKeys = append(clientKeys, key) clientKeys = append(clientKeys, key)
if addr == nodes[0].address { if addr == nodes[0].address {
@ -348,7 +361,7 @@ func TestPriority(t *testing.T) {
} }
opts := InitParameters{ opts := InitParameters{
signer: test.RandomSigner(t), signer: test.RandomSignerRFC6979(t),
nodeParams: nodes, nodeParams: nodes,
clientRebalanceInterval: 1500 * time.Millisecond, clientRebalanceInterval: 1500 * time.Millisecond,
} }
@ -385,14 +398,14 @@ func TestPriority(t *testing.T) {
} }
func TestSessionCacheWithKey(t *testing.T) { func TestSessionCacheWithKey(t *testing.T) {
key := test.RandomSigner(t) key := test.RandomSignerRFC6979(t)
mockClientBuilder := func(addr string) (client, error) { mockClientBuilder := func(addr string) (client, error) {
return newMockClient(addr, key), nil return newMockClient(addr, key), nil
} }
opts := InitParameters{ opts := InitParameters{
signer: test.RandomSigner(t), signer: test.RandomSignerRFC6979(t),
nodeParams: []NodeParam{ nodeParams: []NodeParam{
{1, "peer0", 1}, {1, "peer0", 1},
}, },
@ -416,7 +429,7 @@ func TestSessionCacheWithKey(t *testing.T) {
var prm PrmObjectDelete var prm PrmObjectDelete
prm.SetAddress(oid.Address{}) prm.SetAddress(oid.Address{})
anonKey := test.RandomSigner(t) anonKey := test.RandomSignerRFC6979(t)
prm.UseSigner(anonKey) prm.UseSigner(anonKey)
err = pool.DeleteObject(ctx, prm) err = pool.DeleteObject(ctx, prm)
@ -427,12 +440,12 @@ func TestSessionCacheWithKey(t *testing.T) {
func TestSessionTokenOwner(t *testing.T) { func TestSessionTokenOwner(t *testing.T) {
mockClientBuilder := func(addr string) (client, error) { mockClientBuilder := func(addr string) (client, error) {
key := test.RandomSigner(t) key := test.RandomSignerRFC6979(t)
return newMockClient(addr, key), nil return newMockClient(addr, key), nil
} }
opts := InitParameters{ opts := InitParameters{
signer: test.RandomSigner(t), signer: test.RandomSignerRFC6979(t),
nodeParams: []NodeParam{ nodeParams: []NodeParam{
{1, "peer0", 1}, {1, "peer0", 1},
}, },
@ -448,7 +461,7 @@ func TestSessionTokenOwner(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
t.Cleanup(p.Close) t.Cleanup(p.Close)
anonKey := test.RandomSigner(t) anonKey := test.RandomSignerRFC6979(t)
var anonOwner user.ID var anonOwner user.ID
require.NoError(t, user.IDFromSigner(&anonOwner, anonKey)) require.NoError(t, user.IDFromSigner(&anonOwner, anonKey))
@ -473,7 +486,7 @@ func TestSessionTokenOwner(t *testing.T) {
} }
func TestWaitPresence(t *testing.T) { func TestWaitPresence(t *testing.T) {
mockCli := newMockClient("", test.RandomSigner(t)) mockCli := newMockClient("", test.RandomSignerRFC6979(t))
t.Run("context canceled", func(t *testing.T) { t.Run("context canceled", func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
@ -612,7 +625,7 @@ func TestSwitchAfterErrorThreshold(t *testing.T) {
var clientKeys []neofscrypto.Signer var clientKeys []neofscrypto.Signer
mockClientBuilder := func(addr string) (client, error) { mockClientBuilder := func(addr string) (client, error) {
key := test.RandomSigner(t) key := test.RandomSignerRFC6979(t)
clientKeys = append(clientKeys, key) clientKeys = append(clientKeys, key)
if addr == nodes[0].address { if addr == nodes[0].address {
@ -626,7 +639,7 @@ func TestSwitchAfterErrorThreshold(t *testing.T) {
} }
opts := InitParameters{ opts := InitParameters{
signer: test.RandomSigner(t), signer: test.RandomSignerRFC6979(t),
nodeParams: nodes, nodeParams: nodes,
clientRebalanceInterval: 30 * time.Second, clientRebalanceInterval: 30 * time.Second,
} }