github.com/trustbloc/kms-go@v1.1.2/crypto/tinkcrypto/primitive/secp256k1/secp256k1_signer_key_manager_test.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package secp256k1_test
     8  
     9  import (
    10  	"crypto/ecdsa"
    11  	"crypto/rand"
    12  	"fmt"
    13  	"math/big"
    14  	"testing"
    15  
    16  	"github.com/google/tink/go/core/registry"
    17  	commonpb "github.com/google/tink/go/proto/common_go_proto"
    18  	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
    19  	"github.com/google/tink/go/subtle/random"
    20  	"github.com/stretchr/testify/require"
    21  	"google.golang.org/protobuf/proto"
    22  
    23  	secp256k1pb "github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/proto/secp256k1_go_proto"
    24  	"github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/secp256k1/subtle"
    25  )
    26  
    27  const (
    28  	secp256k1SignerKeyVersion = uint32(0)
    29  	secp256k1SignerTypeURL    = "type.googleapis.com/google.crypto.tink.secp256k1PrivateKey"
    30  )
    31  
    32  type secp256k1Params struct {
    33  	hashType commonpb.HashType
    34  	curve    secp256k1pb.BitcoinCurveType
    35  }
    36  
    37  func TestSecp256k1SignerGetPrimitiveBasic(t *testing.T) {
    38  	testParams := genValidSecp256k1Params()
    39  	km, err := registry.GetKeyManager(secp256k1SignerTypeURL)
    40  	require.NoError(t, err)
    41  
    42  	for i := 0; i < len(testParams); i++ {
    43  		serializedKey, e := proto.Marshal(NewRandomSecp256K1PrivateKey(testParams[i].hashType, testParams[i].curve))
    44  		require.NoError(t, e)
    45  
    46  		_, err = km.Primitive(serializedKey)
    47  		require.NoErrorf(t, err, "unexpect error in test case %d ", i)
    48  	}
    49  }
    50  
    51  func TestECDSASecp256K1SignGetPrimitiveWithInvalidInput(t *testing.T) {
    52  	// invalid params
    53  	testParams := genInvalidSecp256k1Params()
    54  	km, err := registry.GetKeyManager(secp256k1SignerTypeURL)
    55  	require.NoError(t, err)
    56  
    57  	for i := 0; i < len(testParams); i++ {
    58  		serializedKey, e := proto.Marshal(NewRandomSecp256K1PrivateKey(testParams[i].hashType, testParams[i].curve))
    59  		if testParams[i].curve != secp256k1pb.BitcoinCurveType_INVALID_BITCOIN_CURVE {
    60  			require.NoError(t, e)
    61  		}
    62  
    63  		_, err = km.Primitive(serializedKey)
    64  		require.Errorf(t, err, "expect an error in test case %d", i)
    65  	}
    66  
    67  	// invalid version
    68  	key := NewRandomSecp256K1PrivateKey(commonpb.HashType_SHA256,
    69  		secp256k1pb.BitcoinCurveType_SECP256K1)
    70  	key.Version = secp256k1SignerKeyVersion + 1
    71  	serializedKey, e := proto.Marshal(key)
    72  	require.NoError(t, e)
    73  
    74  	_, err = km.Primitive(serializedKey)
    75  	require.Error(t, err, "expect an error when version is invalid")
    76  
    77  	// nil input
    78  	_, err = km.Primitive(nil)
    79  	require.Error(t, err, "expect an error when input is nil")
    80  
    81  	_, err = km.Primitive([]byte{})
    82  	require.Error(t, err, "expect an error when input is empty slice")
    83  }
    84  
    85  func TestECDSASecp256K1SignNewKeyBasic(t *testing.T) {
    86  	testParams := genValidSecp256k1Params()
    87  
    88  	km, err := registry.GetKeyManager(secp256k1SignerTypeURL)
    89  	require.NoError(t, err)
    90  
    91  	for i := 0; i < len(testParams); i++ {
    92  		params := NewSecp256K1Params(testParams[i].hashType, testParams[i].curve,
    93  			secp256k1pb.Secp256K1SignatureEncoding_Bitcoin_DER)
    94  
    95  		serializedFormat, e := proto.Marshal(newSecp256K1KeyFormat(params))
    96  		require.NoError(t, e)
    97  
    98  		tmp, e := km.NewKey(serializedFormat)
    99  		require.NoError(t, e)
   100  
   101  		key, ok := tmp.(*secp256k1pb.Secp256K1PrivateKey)
   102  		require.True(t, ok)
   103  
   104  		err = validateECDSASecp256K1PrivateKey(t, key, params)
   105  		require.NoErrorf(t, err, "invalid private key in test case %d", i)
   106  	}
   107  }
   108  
   109  func TestECDSASecp256K1SignNewKeyWithInvalidInput(t *testing.T) {
   110  	km, err := registry.GetKeyManager(secp256k1SignerTypeURL)
   111  	require.NoError(t, err)
   112  
   113  	// invalid hash and curve type
   114  	testParams := genInvalidSecp256k1Params()
   115  	for i := 0; i < len(testParams); i++ {
   116  		params := NewSecp256K1Params(testParams[i].hashType, testParams[i].curve,
   117  			secp256k1pb.Secp256K1SignatureEncoding_Bitcoin_DER)
   118  
   119  		serializedFormat, e := proto.Marshal(newSecp256K1KeyFormat(params))
   120  		require.NoError(t, e)
   121  
   122  		_, err = km.NewKey(serializedFormat)
   123  		require.Errorf(t, err, "expect an error in test case %d", i)
   124  	}
   125  
   126  	// invalid encoding
   127  	testParams = genValidSecp256k1Params()
   128  	for i := 0; i < len(testParams); i++ {
   129  		params := NewSecp256K1Params(testParams[i].hashType, testParams[i].curve,
   130  			secp256k1pb.Secp256K1SignatureEncoding_UNKNOWN_BITCOIN_ENCODING)
   131  
   132  		serializedFormat, e := proto.Marshal(newSecp256K1KeyFormat(params))
   133  		require.NoError(t, e)
   134  
   135  		_, err = km.NewKey(serializedFormat)
   136  		require.Errorf(t, err, "expect an error in test case %d", i)
   137  	}
   138  
   139  	// nil input
   140  	_, err = km.NewKey(nil)
   141  	require.Error(t, err, "expect an error when input is nil")
   142  
   143  	_, err = km.NewKey([]byte{})
   144  	require.Error(t, err, "expect an error when input is empty slice")
   145  }
   146  
   147  func TestECDSASecp256K1SignNewKeyMultipleTimes(t *testing.T) {
   148  	km, err := registry.GetKeyManager(secp256k1SignerTypeURL)
   149  	require.NoError(t, err)
   150  
   151  	testParams := genValidSecp256k1Params()
   152  
   153  	nTest := 27
   154  
   155  	for i := 0; i < len(testParams); i++ {
   156  		keys := make(map[string]bool)
   157  		params := NewSecp256K1Params(testParams[i].hashType, testParams[i].curve,
   158  			secp256k1pb.Secp256K1SignatureEncoding_Bitcoin_DER)
   159  		format := newSecp256K1KeyFormat(params)
   160  
   161  		serializedFormat, e := proto.Marshal(format)
   162  		require.NoError(t, e)
   163  
   164  		for j := 0; j < nTest; j++ {
   165  			key, e := km.NewKey(serializedFormat)
   166  			require.NoError(t, e)
   167  
   168  			serializedKey, e := proto.Marshal(key)
   169  			require.NoError(t, e)
   170  
   171  			keys[string(serializedKey)] = true
   172  
   173  			keyData, e := km.NewKeyData(serializedFormat)
   174  			require.NoError(t, e)
   175  
   176  			serializedKey = keyData.Value
   177  			keys[string(serializedKey)] = true
   178  		}
   179  
   180  		require.Equalf(t, len(keys), nTest*2, "key is repeated with params: %s", params)
   181  	}
   182  }
   183  
   184  func TestECDSASecp256K1SignNewKeyDataBasic(t *testing.T) {
   185  	km, err := registry.GetKeyManager(secp256k1SignerTypeURL)
   186  	require.NoError(t, err)
   187  
   188  	testParams := genValidSecp256k1Params()
   189  	for i := 0; i < len(testParams); i++ {
   190  		params := NewSecp256K1Params(testParams[i].hashType, testParams[i].curve,
   191  			secp256k1pb.Secp256K1SignatureEncoding_Bitcoin_DER)
   192  		serializedFormat, e := proto.Marshal(newSecp256K1KeyFormat(params))
   193  		require.NoError(t, e)
   194  
   195  		keyData, e := km.NewKeyData(serializedFormat)
   196  		require.NoErrorf(t, e, "unexpected error in test case  %d", i)
   197  
   198  		require.Equalf(t, keyData.TypeUrl, secp256k1SignerTypeURL,
   199  			"incorrect type url in test case  %d: expect %s, got %s",
   200  			i, secp256k1SignerTypeURL, keyData.TypeUrl)
   201  
   202  		require.Equalf(t, keyData.KeyMaterialType, tinkpb.KeyData_ASYMMETRIC_PRIVATE,
   203  			"incorrect key material type in test case  %d: expect %s, got %s",
   204  			i, tinkpb.KeyData_ASYMMETRIC_PRIVATE, keyData.KeyMaterialType)
   205  
   206  		key := new(secp256k1pb.Secp256K1PrivateKey)
   207  		err = proto.Unmarshal(keyData.Value, key)
   208  		require.NoErrorf(t, err, "unexpect error in test case %d", i)
   209  
   210  		err = validateECDSASecp256K1PrivateKey(t, key, params)
   211  		require.NoErrorf(t, err, "invalid private key in test case %d", i)
   212  	}
   213  }
   214  
   215  func TestECDSASecp256K1SignNewKeyDataWithInvalidInput(t *testing.T) {
   216  	km, err := registry.GetKeyManager(secp256k1SignerTypeURL)
   217  	require.NoError(t, err)
   218  
   219  	testParams := genInvalidSecp256k1Params()
   220  	for i := 0; i < len(testParams); i++ {
   221  		params := NewSecp256K1Params(testParams[i].hashType, testParams[i].curve,
   222  			secp256k1pb.Secp256K1SignatureEncoding_Bitcoin_DER)
   223  		format := newSecp256K1KeyFormat(params)
   224  
   225  		serializedFormat, e := proto.Marshal(format)
   226  		require.NoError(t, e)
   227  
   228  		_, err = km.NewKeyData(serializedFormat)
   229  		require.Errorf(t, err, "expect an error in test case  %d", i)
   230  	}
   231  
   232  	// nil input
   233  	_, err = km.NewKeyData(nil)
   234  	require.Errorf(t, err, "expect an error when input is nil")
   235  }
   236  
   237  func TestPublicKeyDataBasic(t *testing.T) {
   238  	testParams := genValidSecp256k1Params()
   239  
   240  	km, err := registry.GetKeyManager(secp256k1SignerTypeURL)
   241  	require.NoError(t, err)
   242  
   243  	pkm, ok := km.(registry.PrivateKeyManager)
   244  	require.True(t, ok, "cannot obtain private key manager")
   245  
   246  	for i := 0; i < len(testParams); i++ {
   247  		key := NewRandomSecp256K1PrivateKey(testParams[i].hashType, testParams[i].curve)
   248  		serializedKey, e := proto.Marshal(key)
   249  		require.NoError(t, e)
   250  
   251  		pubKeyData, e := pkm.PublicKeyData(serializedKey)
   252  		require.NoErrorf(t, e, "unexpect error in test case %d", i)
   253  
   254  		require.Equalf(t, pubKeyData.TypeUrl, secp256k1VerifierTypeURL, "incorrect type url: %s", pubKeyData.TypeUrl)
   255  
   256  		require.Equalf(t, pubKeyData.KeyMaterialType, tinkpb.KeyData_ASYMMETRIC_PUBLIC,
   257  			"incorrect key material type: %d", pubKeyData.KeyMaterialType)
   258  
   259  		pubKey := new(secp256k1pb.Secp256K1PublicKey)
   260  		err = proto.Unmarshal(pubKeyData.Value, pubKey)
   261  		require.NoError(t, err)
   262  	}
   263  }
   264  
   265  func TestPublicKeyDataWithInvalidInput(t *testing.T) {
   266  	km, err := registry.GetKeyManager(secp256k1SignerTypeURL)
   267  	require.NoError(t, err)
   268  
   269  	pkm, ok := km.(registry.PrivateKeyManager)
   270  	require.True(t, ok, "cannot obtain private key manager")
   271  
   272  	// modified key
   273  	key := NewRandomSecp256K1PrivateKey(commonpb.HashType_SHA256, secp256k1pb.BitcoinCurveType_SECP256K1)
   274  	serializedKey, err := proto.Marshal(key)
   275  	require.NoError(t, err)
   276  
   277  	serializedKey[0] = 0
   278  
   279  	_, err = pkm.PublicKeyData(serializedKey)
   280  	require.Error(t, err, "expect an error when input is a modified serialized key")
   281  }
   282  
   283  var errSmallKey = fmt.Errorf("private key doesn't have adequate size")
   284  
   285  func validateECDSASecp256K1PrivateKey(t *testing.T, key *secp256k1pb.Secp256K1PrivateKey,
   286  	params *secp256k1pb.Secp256K1Params) error {
   287  	require.Equalf(t, key.Version, secp256k1SignerKeyVersion, "incorrect private key's version: expect %d, got %d",
   288  		secp256k1SignerKeyVersion, key.Version)
   289  
   290  	publicKey := key.PublicKey
   291  	require.Equalf(t, publicKey.Version, secp256k1SignerKeyVersion, "incorrect public key's version: expect %d, got %d",
   292  		secp256k1SignerKeyVersion, key.Version)
   293  
   294  	if params.HashType != publicKey.Params.HashType ||
   295  		params.Curve != publicKey.Params.Curve ||
   296  		params.Encoding != publicKey.Params.Encoding {
   297  		return fmt.Errorf("incorrect params: expect %s, got %s", params, publicKey.Params)
   298  	}
   299  
   300  	if len(publicKey.X) == 0 || len(publicKey.Y) == 0 {
   301  		return fmt.Errorf("public points are not initialized")
   302  	}
   303  
   304  	// check private key's size
   305  	d := new(big.Int).SetBytes(key.KeyValue)
   306  	keySize := len(d.Bytes())
   307  
   308  	if params.Curve == secp256k1pb.BitcoinCurveType_SECP256K1 {
   309  		if keySize < 256/8-8 || keySize > 256/8+1 {
   310  			return errSmallKey
   311  		}
   312  	}
   313  
   314  	// try to sign and verify with the key
   315  	hash, curve, encoding := getSecp256K1ParamNames(publicKey.Params)
   316  	signer, err := subtle.NewSecp256K1Signer(hash, curve, encoding, key.KeyValue)
   317  	require.NoError(t, err, "unexpected error when creating Secp256K1Sign")
   318  
   319  	verifier, err := subtle.NewSecp256K1Verifier(hash, curve, encoding, publicKey.X, publicKey.Y)
   320  	require.NoError(t, err, "unexpected error when creating Secp256K1Verify")
   321  
   322  	data := random.GetRandomBytes(1281)
   323  
   324  	signature, err := signer.Sign(data)
   325  	require.NoError(t, err, "unexpected error when signing")
   326  
   327  	err = verifier.Verify(signature, data)
   328  	require.NoError(t, err, "unexpected error when verifying signature")
   329  
   330  	return nil
   331  }
   332  
   333  func genValidSecp256k1Params() []secp256k1Params {
   334  	return []secp256k1Params{
   335  		{
   336  			hashType: commonpb.HashType_SHA256,
   337  			curve:    secp256k1pb.BitcoinCurveType_SECP256K1,
   338  		},
   339  	}
   340  }
   341  
   342  func genInvalidSecp256k1Params() []secp256k1Params {
   343  	return []secp256k1Params{
   344  		{
   345  			hashType: commonpb.HashType_SHA1,
   346  			curve:    secp256k1pb.BitcoinCurveType_SECP256K1,
   347  		},
   348  		{
   349  			hashType: commonpb.HashType_SHA1,
   350  			curve:    secp256k1pb.BitcoinCurveType_INVALID_BITCOIN_CURVE,
   351  		},
   352  	}
   353  }
   354  
   355  // NewRandomSecp256K1PrivateKey creates an ECDSAPrivateKey with randomly generated key material.
   356  func NewRandomSecp256K1PrivateKey(hashType commonpb.HashType,
   357  	curve secp256k1pb.BitcoinCurveType) *secp256k1pb.Secp256K1PrivateKey {
   358  	curveName := secp256k1pb.BitcoinCurveType_name[int32(curve)]
   359  	if curveName == secp256k1pb.BitcoinCurveType_INVALID_BITCOIN_CURVE.String() {
   360  		return nil
   361  	}
   362  
   363  	priv, e := ecdsa.GenerateKey(subtle.GetCurve(curveName), rand.Reader)
   364  	if e != nil {
   365  		return nil
   366  	}
   367  
   368  	params := NewSecp256K1Params(hashType, curve, secp256k1pb.Secp256K1SignatureEncoding_Bitcoin_DER)
   369  	publicKey := newSecp256K1PublicKey(secp256k1SignerKeyVersion, params, priv.X.Bytes(), priv.Y.Bytes())
   370  
   371  	return newSecp256K1APrivateKey(secp256k1SignerKeyVersion, publicKey, priv.D.Bytes())
   372  }
   373  
   374  // NewSecp256K1Params creates a ECDSAParams with the specified parameters.
   375  func NewSecp256K1Params(hashType commonpb.HashType,
   376  	curve secp256k1pb.BitcoinCurveType,
   377  	encoding secp256k1pb.Secp256K1SignatureEncoding) *secp256k1pb.Secp256K1Params {
   378  	return &secp256k1pb.Secp256K1Params{
   379  		HashType: hashType,
   380  		Curve:    curve,
   381  		Encoding: encoding,
   382  	}
   383  }
   384  
   385  // newSecp256K1KeyFormat creates a ECDSAKeyFormat with the specified parameters.
   386  func newSecp256K1KeyFormat(params *secp256k1pb.Secp256K1Params) *secp256k1pb.Secp256K1KeyFormat {
   387  	return &secp256k1pb.Secp256K1KeyFormat{Params: params}
   388  }
   389  
   390  // newSecp256K1APrivateKey creates a ECDSAPrivateKey with the specified parameters.
   391  func newSecp256K1APrivateKey(version uint32, publicKey *secp256k1pb.Secp256K1PublicKey,
   392  	keyValue []byte) *secp256k1pb.Secp256K1PrivateKey {
   393  	return &secp256k1pb.Secp256K1PrivateKey{
   394  		Version:   version,
   395  		PublicKey: publicKey,
   396  		KeyValue:  keyValue,
   397  	}
   398  }
   399  
   400  // newSecp256K1PublicKey creates a ECDSAPublicKey with the specified parameters.
   401  func newSecp256K1PublicKey(version uint32, params *secp256k1pb.Secp256K1Params,
   402  	x []byte, y []byte) *secp256k1pb.Secp256K1PublicKey {
   403  	return &secp256k1pb.Secp256K1PublicKey{
   404  		Version: version,
   405  		Params:  params,
   406  		X:       x,
   407  		Y:       y,
   408  	}
   409  }
   410  
   411  // getSecp256K1ParamNames returns the string representations of each parameter in
   412  // the given Secp256K1Params.
   413  func getSecp256K1ParamNames(params *secp256k1pb.Secp256K1Params) (string, string, string) {
   414  	hashName := commonpb.HashType_name[int32(params.HashType)]
   415  	curveName := secp256k1pb.BitcoinCurveType_name[int32(params.Curve)]
   416  	encodingName := secp256k1pb.Secp256K1SignatureEncoding_name[int32(params.Encoding)]
   417  
   418  	return hashName, curveName, encodingName
   419  }