forked from TrueCloudLab/frostfs-api-go
74e917810a
In previous implementation service package provided types and functions that wrapped signing/verification of data with session token. This allowed us to use these functions for signing / verification of service requests of other packages. To support the expansion of messages with additional parts that need to be signed, you must be able to easily expand the signed data with new parts. To achieve the described goal, this commit makes the following changes: * adds GroupSignedPayloads and GroupVerifyPayloads functions; * renames SignedDataWithToken to RequestData, DataWithTokenSignAccumulator to RequestSignedData, DataWithTokenSignSource to RequestVerifyData; * renames SignDataWithSessionToken/VerifyAccumulatedSignaturesWithToken function to SignRequestData/VerifyRequestData and makes it to use GroupSignedPayloads/GroupVerifyPayloads internally.
326 lines
6.5 KiB
Go
326 lines
6.5 KiB
Go
package service
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"crypto/rand"
|
|
"errors"
|
|
"io"
|
|
"testing"
|
|
|
|
crypto "github.com/nspcc-dev/neofs-crypto"
|
|
"github.com/nspcc-dev/neofs-crypto/test"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type testSignedDataSrc struct {
|
|
err error
|
|
data []byte
|
|
sig []byte
|
|
key *ecdsa.PublicKey
|
|
token SessionToken
|
|
}
|
|
|
|
type testSignedDataReader struct {
|
|
*testSignedDataSrc
|
|
}
|
|
|
|
func (s testSignedDataSrc) GetSignature() []byte {
|
|
return s.sig
|
|
}
|
|
|
|
func (s testSignedDataSrc) GetSignKeyPairs() []SignKeyPair {
|
|
return []SignKeyPair{
|
|
newSignatureKeyPair(s.key, s.sig),
|
|
}
|
|
}
|
|
|
|
func (s testSignedDataSrc) SignedData() ([]byte, error) {
|
|
return s.data, s.err
|
|
}
|
|
|
|
func (s *testSignedDataSrc) AddSignKey(sig []byte, key *ecdsa.PublicKey) {
|
|
s.key = key
|
|
s.sig = sig
|
|
}
|
|
|
|
func testData(t *testing.T, sz int) []byte {
|
|
d := make([]byte, sz)
|
|
_, err := rand.Read(d)
|
|
require.NoError(t, err)
|
|
return d
|
|
}
|
|
|
|
func (s testSignedDataSrc) GetSessionToken() SessionToken {
|
|
return s.token
|
|
}
|
|
|
|
func (s testSignedDataReader) SignedDataSize() int {
|
|
return len(s.data)
|
|
}
|
|
|
|
func (s testSignedDataReader) ReadSignedData(buf []byte) (int, error) {
|
|
if s.err != nil {
|
|
return 0, s.err
|
|
}
|
|
|
|
var err error
|
|
if len(buf) < len(s.data) {
|
|
err = io.ErrUnexpectedEOF
|
|
}
|
|
return copy(buf, s.data), err
|
|
}
|
|
|
|
func TestDataSignature(t *testing.T) {
|
|
var err error
|
|
|
|
// nil private key
|
|
_, err = DataSignature(nil, nil)
|
|
require.EqualError(t, err, crypto.ErrEmptyPrivateKey.Error())
|
|
|
|
// create test private key
|
|
sk := test.DecodeKey(0)
|
|
|
|
// nil private key
|
|
_, err = DataSignature(sk, nil)
|
|
require.EqualError(t, err, ErrNilSignedDataSource.Error())
|
|
|
|
t.Run("common signed data source", func(t *testing.T) {
|
|
// create test data source
|
|
src := &testSignedDataSrc{
|
|
data: testData(t, 10),
|
|
}
|
|
|
|
// create custom error for data source
|
|
src.err = errors.New("test error for data source")
|
|
|
|
_, err = DataSignature(sk, src)
|
|
require.EqualError(t, err, src.err.Error())
|
|
|
|
// reset error to nil
|
|
src.err = nil
|
|
|
|
// calculate data signature
|
|
sig, err := DataSignature(sk, src)
|
|
require.NoError(t, err)
|
|
|
|
// ascertain that the signature passes verification
|
|
require.NoError(t, crypto.Verify(&sk.PublicKey, src.data, sig))
|
|
})
|
|
|
|
t.Run("signed data reader", func(t *testing.T) {
|
|
// create test signed data reader
|
|
src := &testSignedDataSrc{
|
|
data: testData(t, 10),
|
|
}
|
|
|
|
// create custom error for signed data reader
|
|
src.err = errors.New("test error for signed data reader")
|
|
|
|
sig, err := DataSignature(sk, src)
|
|
require.EqualError(t, err, src.err.Error())
|
|
|
|
// reset error to nil
|
|
src.err = nil
|
|
|
|
// calculate data signature
|
|
sig, err = DataSignature(sk, src)
|
|
require.NoError(t, err)
|
|
|
|
// ascertain that the signature passes verification
|
|
require.NoError(t, crypto.Verify(&sk.PublicKey, src.data, sig))
|
|
})
|
|
}
|
|
|
|
func TestAddSignatureWithKey(t *testing.T) {
|
|
require.NoError(t,
|
|
AddSignatureWithKey(
|
|
test.DecodeKey(0),
|
|
&testSignedDataSrc{
|
|
data: testData(t, 10),
|
|
},
|
|
),
|
|
)
|
|
}
|
|
|
|
func TestVerifySignatures(t *testing.T) {
|
|
// empty signatures
|
|
require.NoError(t, VerifySignatures(nil))
|
|
|
|
// create test signature source
|
|
src := &testSignedDataSrc{
|
|
data: testData(t, 10),
|
|
}
|
|
|
|
// create private key for test
|
|
sk := test.DecodeKey(0)
|
|
|
|
// calculate a signature of the data
|
|
sig, err := crypto.Sign(sk, src.data)
|
|
require.NoError(t, err)
|
|
|
|
// ascertain that verification is passed
|
|
require.NoError(t,
|
|
VerifySignatures(
|
|
src,
|
|
newSignatureKeyPair(&sk.PublicKey, sig),
|
|
),
|
|
)
|
|
|
|
// break the signature
|
|
sig[0]++
|
|
|
|
require.Error(t,
|
|
VerifySignatures(
|
|
src,
|
|
newSignatureKeyPair(&sk.PublicKey, sig),
|
|
),
|
|
)
|
|
|
|
// restore the signature
|
|
sig[0]--
|
|
|
|
// empty data source
|
|
require.EqualError(t,
|
|
VerifySignatures(nil, nil),
|
|
ErrNilSignedDataSource.Error(),
|
|
)
|
|
|
|
}
|
|
|
|
func TestVerifyAccumulatedSignatures(t *testing.T) {
|
|
// nil signature source
|
|
require.EqualError(t,
|
|
VerifyAccumulatedSignatures(nil),
|
|
ErrNilSignatureKeySource.Error(),
|
|
)
|
|
|
|
// create test private key
|
|
sk := test.DecodeKey(0)
|
|
|
|
// create signature source
|
|
src := &testSignedDataSrc{
|
|
data: testData(t, 10),
|
|
key: &sk.PublicKey,
|
|
}
|
|
|
|
var err error
|
|
|
|
// calculate a signature
|
|
src.sig, err = crypto.Sign(sk, src.data)
|
|
require.NoError(t, err)
|
|
|
|
// ascertain that verification is passed
|
|
require.NoError(t, VerifyAccumulatedSignatures(src))
|
|
|
|
// break the signature
|
|
src.sig[0]++
|
|
|
|
// ascertain that verification is failed
|
|
require.Error(t, VerifyAccumulatedSignatures(src))
|
|
}
|
|
|
|
func TestVerifySignatureWithKey(t *testing.T) {
|
|
// nil signature source
|
|
require.EqualError(t,
|
|
VerifySignatureWithKey(nil, nil),
|
|
ErrEmptyDataWithSignature.Error(),
|
|
)
|
|
|
|
// create test signature source
|
|
src := &testSignedDataSrc{
|
|
data: testData(t, 10),
|
|
}
|
|
|
|
// nil public key
|
|
require.EqualError(t,
|
|
VerifySignatureWithKey(nil, src),
|
|
crypto.ErrEmptyPublicKey.Error(),
|
|
)
|
|
|
|
// create test private key
|
|
sk := test.DecodeKey(0)
|
|
|
|
var err error
|
|
|
|
// calculate a signature
|
|
src.sig, err = crypto.Sign(sk, src.data)
|
|
require.NoError(t, err)
|
|
|
|
// ascertain that verification is passed
|
|
require.NoError(t, VerifySignatureWithKey(&sk.PublicKey, src))
|
|
|
|
// break the signature
|
|
src.sig[0]++
|
|
|
|
// ascertain that verification is failed
|
|
require.Error(t, VerifySignatureWithKey(&sk.PublicKey, src))
|
|
}
|
|
|
|
func TestSignVerifyDataWithSessionToken(t *testing.T) {
|
|
// sign with empty RequestSignedData
|
|
require.EqualError(t,
|
|
SignRequestData(nil, nil),
|
|
ErrNilRequestSignedData.Error(),
|
|
)
|
|
|
|
// verify with empty RequestVerifyData
|
|
require.EqualError(t,
|
|
VerifyRequestData(nil),
|
|
ErrNilRequestVerifyData.Error(),
|
|
)
|
|
|
|
// create test session token
|
|
var (
|
|
token = new(Token)
|
|
initVerb = Token_Info_Verb(1)
|
|
)
|
|
|
|
token.SetVerb(initVerb)
|
|
|
|
// create test data with token
|
|
src := &testSignedDataSrc{
|
|
data: testData(t, 10),
|
|
token: token,
|
|
}
|
|
|
|
// create test private key
|
|
sk := test.DecodeKey(0)
|
|
|
|
// sign with private key
|
|
require.NoError(t, SignRequestData(sk, src))
|
|
|
|
// ascertain that verification is passed
|
|
require.NoError(t, VerifyRequestData(src))
|
|
|
|
// break the data
|
|
src.data[0]++
|
|
|
|
// ascertain that verification is failed
|
|
require.Error(t, VerifyRequestData(src))
|
|
|
|
// restore the data
|
|
src.data[0]--
|
|
|
|
// break the token
|
|
token.SetVerb(initVerb + 1)
|
|
|
|
// ascertain that verification is failed
|
|
require.Error(t, VerifyRequestData(src))
|
|
|
|
// restore the token
|
|
token.SetVerb(initVerb)
|
|
|
|
// ascertain that verification is passed
|
|
require.NoError(t, VerifyRequestData(src))
|
|
|
|
// wrap to data reader
|
|
rdr := &testSignedDataReader{
|
|
testSignedDataSrc: src,
|
|
}
|
|
|
|
// sign with private key
|
|
require.NoError(t, SignRequestData(sk, rdr))
|
|
|
|
// ascertain that verification is passed
|
|
require.NoError(t, VerifyRequestData(rdr))
|
|
}
|