github.com/trustbloc/kms-go@v1.1.2/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_private_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 ecdh
     8  
     9  import (
    10  	"bytes"
    11  	"crypto/elliptic"
    12  	"crypto/rand"
    13  	"strings"
    14  	"testing"
    15  
    16  	"github.com/google/tink/go/aead"
    17  	hybrid "github.com/google/tink/go/hybrid/subtle"
    18  	gcmpb "github.com/google/tink/go/proto/aes_gcm_go_proto"
    19  	commonpb "github.com/google/tink/go/proto/common_go_proto"
    20  	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
    21  	"github.com/stretchr/testify/require"
    22  	"google.golang.org/protobuf/proto"
    23  
    24  	cbcaead "github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/aead"
    25  	"github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/composite"
    26  	ecdhpb "github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto"
    27  )
    28  
    29  func TestECDHNISTPAESPrivateKeyManager_Primitive(t *testing.T) {
    30  	km := newECDHNISTPAESPrivateKeyManager()
    31  
    32  	t.Run("Test private key manager Primitive() with empty serialized key", func(t *testing.T) {
    33  		p, err := km.Primitive([]byte(""))
    34  		require.EqualError(t, err, errInvalidNISTPECDHKWPrivateKey.Error(),
    35  			"nistPECDHKWPrivateKeyManager primitive from empty serialized key must fail")
    36  		require.Empty(t, p)
    37  	})
    38  
    39  	t.Run("Test private key manager Primitive() with bad serialize key", func(t *testing.T) {
    40  		p, err := km.Primitive([]byte("bad.data"))
    41  		require.EqualError(t, err, errInvalidNISTPECDHKWPrivateKey.Error(),
    42  			"nistPECDHKWPrivateKeyManager primitive from bad serialized key must fail")
    43  		require.Empty(t, p)
    44  	})
    45  
    46  	format := &gcmpb.AesGcmKeyFormat{
    47  		KeySize: 32,
    48  	}
    49  	serializedFormat, err := proto.Marshal(format)
    50  	require.NoError(t, err)
    51  
    52  	format = &gcmpb.AesGcmKeyFormat{
    53  		KeySize: 99, // bad AES128GCM size
    54  	}
    55  
    56  	badSerializedFormat, err := proto.Marshal(format)
    57  	require.NoError(t, err)
    58  
    59  	flagTests := []struct {
    60  		tcName    string
    61  		version   uint32
    62  		curveType commonpb.EllipticCurveType
    63  		keyType   ecdhpb.KeyType
    64  		ecPtFmt   commonpb.EcPointFormat
    65  		encTmp    *tinkpb.KeyTemplate
    66  	}{
    67  		{
    68  			tcName:    "private key manager Primitive() using key with bad version",
    69  			version:   9999,
    70  			curveType: commonpb.EllipticCurveType_NIST_P256,
    71  			keyType:   ecdhpb.KeyType_EC,
    72  			ecPtFmt:   commonpb.EcPointFormat_COMPRESSED,
    73  			encTmp:    aead.AES128GCMKeyTemplate(),
    74  		},
    75  		{
    76  			tcName:    "private key manager Primitive() using key with bad curve",
    77  			version:   0,
    78  			curveType: commonpb.EllipticCurveType_UNKNOWN_CURVE,
    79  			keyType:   ecdhpb.KeyType_EC,
    80  			ecPtFmt:   commonpb.EcPointFormat_COMPRESSED,
    81  			encTmp:    aead.AES128GCMKeyTemplate(),
    82  		},
    83  		{
    84  			tcName:    "private key manager Primitive() using key with bad key type",
    85  			version:   0,
    86  			curveType: commonpb.EllipticCurveType_NIST_P256,
    87  			keyType:   ecdhpb.KeyType_UNKNOWN_KEY_TYPE,
    88  			ecPtFmt:   commonpb.EcPointFormat_COMPRESSED,
    89  			encTmp:    aead.AES128GCMKeyTemplate(),
    90  		},
    91  		{
    92  			tcName:    "success private key manager Primitive()",
    93  			version:   0,
    94  			curveType: commonpb.EllipticCurveType_NIST_P256,
    95  			keyType:   ecdhpb.KeyType_EC,
    96  			ecPtFmt:   commonpb.EcPointFormat_UNCOMPRESSED,
    97  			encTmp:    aead.AES128GCMKeyTemplate(),
    98  		},
    99  		{
   100  			tcName:    "private key manager Primitive() using key with bad key template URL",
   101  			version:   0,
   102  			curveType: commonpb.EllipticCurveType_NIST_P256,
   103  			keyType:   ecdhpb.KeyType_EC,
   104  			ecPtFmt:   commonpb.EcPointFormat_COMPRESSED,
   105  			encTmp: &tinkpb.KeyTemplate{
   106  				TypeUrl:          "bad.type/url/value",
   107  				Value:            serializedFormat,
   108  				OutputPrefixType: tinkpb.OutputPrefixType_RAW,
   109  			},
   110  		},
   111  		{
   112  			tcName:    "private key manager Primitive() using key with bad dem key size",
   113  			version:   0,
   114  			curveType: commonpb.EllipticCurveType_NIST_P256,
   115  			keyType:   ecdhpb.KeyType_EC,
   116  			ecPtFmt:   commonpb.EcPointFormat_COMPRESSED,
   117  			encTmp: &tinkpb.KeyTemplate{
   118  				TypeUrl:          composite.AESGCMTypeURL,
   119  				Value:            badSerializedFormat,
   120  				OutputPrefixType: tinkpb.OutputPrefixType_RAW,
   121  			},
   122  		},
   123  	}
   124  
   125  	for _, tc := range flagTests {
   126  		tt := tc
   127  		t.Run("Test "+tt.tcName, func(t *testing.T) {
   128  			c := tt.curveType
   129  			encT := tt.encTmp
   130  			ptFmt := tt.ecPtFmt
   131  			v := tt.version
   132  
   133  			// temporarily reset curvType if its unknown type so subtle.GetCurve() below doesn't fail
   134  			if tt.curveType.String() == commonpb.EllipticCurveType_UNKNOWN_CURVE.String() {
   135  				c = commonpb.EllipticCurveType_NIST_P256
   136  			}
   137  
   138  			crv, err := hybrid.GetCurve(c.String())
   139  			require.NoError(t, err)
   140  			d, x, y, err := elliptic.GenerateKey(crv, rand.Reader)
   141  			require.NoError(t, err)
   142  
   143  			// set back curvType if it was unknown to proceed with the test
   144  			if tt.curveType.String() == commonpb.EllipticCurveType_UNKNOWN_CURVE.String() {
   145  				c = tt.curveType
   146  			}
   147  
   148  			privKeyProto := &ecdhpb.EcdhAeadPrivateKey{
   149  				Version: v,
   150  				PublicKey: &ecdhpb.EcdhAeadPublicKey{
   151  					Version: v, // if v > 0  to force an error when calling km.Primitive()
   152  					Params: &ecdhpb.EcdhAeadParams{
   153  						KwParams: &ecdhpb.EcdhKwParams{
   154  							CurveType: c,          // unknown curve type to force an error when calling km.Primitive()
   155  							KeyType:   tt.keyType, // invalid key type to force error when calling km.Primitive()
   156  						},
   157  						EncParams: &ecdhpb.EcdhAeadEncParams{
   158  							AeadEnc: encT, // invalid data enc key template to get an error when calling km.Primitive()
   159  						},
   160  						EcPointFormat: ptFmt,
   161  					},
   162  					X: x.Bytes(),
   163  					Y: y.Bytes(),
   164  				},
   165  				KeyValue: d,
   166  			}
   167  
   168  			sPrivKey, err := proto.Marshal(privKeyProto)
   169  			require.NoError(t, err)
   170  
   171  			p, err := km.Primitive(sPrivKey)
   172  			if bytes.Equal(tt.encTmp.Value, badSerializedFormat) {
   173  				require.EqualError(t, err, errInvalidNISTPECDHKWPrivateKey.Error(),
   174  					"nistPECDHKWPrivateKeyManager primitive from serialized key with invalid serialized key")
   175  				require.Empty(t, p)
   176  
   177  				return
   178  			}
   179  
   180  			if strings.Contains(tt.tcName, "success") {
   181  				require.NoError(t, err)
   182  				require.NotEmpty(t, p)
   183  				return
   184  			}
   185  
   186  			require.Errorf(t, err, tt.tcName)
   187  			require.Empty(t, p)
   188  		})
   189  	}
   190  }
   191  
   192  func TestEcdhNISTPAESPrivateKeyManager_DoesSupport(t *testing.T) {
   193  	km := newECDHNISTPAESPrivateKeyManager()
   194  	require.False(t, km.DoesSupport("bad/url"))
   195  	require.True(t, km.DoesSupport(nistpECDHKWPrivateKeyTypeURL))
   196  }
   197  
   198  func TestEcdhNISTPAESPrivateKeyManager_NewKey(t *testing.T) {
   199  	km := newECDHNISTPAESPrivateKeyManager()
   200  
   201  	t.Run("Test private key manager NewKey() with nil key", func(t *testing.T) {
   202  		k, err := km.NewKey(nil)
   203  		require.EqualError(t, err, errInvalidNISTPECDHKWPrivateKeyFormat.Error())
   204  		require.Empty(t, k)
   205  	})
   206  
   207  	t.Run("Test private key manager NewKey() with bad serialize key", func(t *testing.T) {
   208  		p, err := km.NewKey([]byte("bad.data"))
   209  		require.EqualError(t, err, errInvalidNISTPECDHKWPrivateKeyFormat.Error(),
   210  			"ECDHESPrivate NewKey() from bad serialized key must fail")
   211  		require.Empty(t, p)
   212  	})
   213  
   214  	format := &gcmpb.AesGcmKeyFormat{
   215  		KeySize: 32,
   216  	}
   217  
   218  	serializedFormat, err := proto.Marshal(format)
   219  	require.NoError(t, err)
   220  
   221  	format = &gcmpb.AesGcmKeyFormat{
   222  		KeySize: 99, // bad AES128GCM size
   223  	}
   224  
   225  	badSerializedFormat, err := proto.Marshal(format)
   226  	require.NoError(t, err)
   227  
   228  	flagTests := []struct {
   229  		tcName    string
   230  		curveType commonpb.EllipticCurveType
   231  		keyType   ecdhpb.KeyType
   232  		ecPtFmt   commonpb.EcPointFormat
   233  		encTmp    *tinkpb.KeyTemplate
   234  	}{
   235  		{
   236  			tcName:    "success private key manager NewKey() and NewKeyData()",
   237  			curveType: commonpb.EllipticCurveType_NIST_P256,
   238  			keyType:   ecdhpb.KeyType_EC,
   239  			ecPtFmt:   commonpb.EcPointFormat_COMPRESSED,
   240  			encTmp:    aead.AES128GCMKeyTemplate(),
   241  		},
   242  		{
   243  			tcName:    "private key manager NewKey() and NewKeyData() using key with bad curve",
   244  			curveType: commonpb.EllipticCurveType_UNKNOWN_CURVE,
   245  			keyType:   ecdhpb.KeyType_EC,
   246  			ecPtFmt:   commonpb.EcPointFormat_COMPRESSED,
   247  			encTmp:    aead.AES128GCMKeyTemplate(),
   248  		},
   249  		{
   250  			tcName:    "private key manager NewKey() and NewKeyData() using key with bad key type",
   251  			curveType: commonpb.EllipticCurveType_NIST_P256,
   252  			keyType:   ecdhpb.KeyType_UNKNOWN_KEY_TYPE,
   253  			ecPtFmt:   commonpb.EcPointFormat_COMPRESSED,
   254  			encTmp:    aead.AES256GCMKeyTemplate(),
   255  		},
   256  		{
   257  			tcName:    "private key manager NewKey() and NewKeyData() using key with bad key template URL",
   258  			curveType: commonpb.EllipticCurveType_NIST_P256,
   259  			keyType:   ecdhpb.KeyType_EC,
   260  			ecPtFmt:   commonpb.EcPointFormat_COMPRESSED,
   261  			encTmp: &tinkpb.KeyTemplate{
   262  				TypeUrl:          "bad.type/url/value",
   263  				Value:            serializedFormat,
   264  				OutputPrefixType: tinkpb.OutputPrefixType_RAW,
   265  			},
   266  		},
   267  		{
   268  			tcName:    "private key manager NewKey() and NewKeyData() using key with bad dem key size",
   269  			curveType: commonpb.EllipticCurveType_NIST_P256,
   270  			keyType:   ecdhpb.KeyType_EC,
   271  			ecPtFmt:   commonpb.EcPointFormat_COMPRESSED,
   272  			encTmp: &tinkpb.KeyTemplate{
   273  				TypeUrl:          composite.AESGCMTypeURL,
   274  				Value:            badSerializedFormat,
   275  				OutputPrefixType: tinkpb.OutputPrefixType_RAW,
   276  			},
   277  		},
   278  		{
   279  			tcName:    "success private key manager NewKey() and NewKeyData() with AES-CBC+HMAC encTmp",
   280  			curveType: commonpb.EllipticCurveType_NIST_P256,
   281  			keyType:   ecdhpb.KeyType_EC,
   282  			ecPtFmt:   commonpb.EcPointFormat_COMPRESSED,
   283  			encTmp:    cbcaead.AES128CBCHMACSHA256KeyTemplate(),
   284  		},
   285  	}
   286  
   287  	for _, tc := range flagTests {
   288  		tt := tc
   289  		t.Run("Test "+tt.tcName, func(t *testing.T) {
   290  			encT := tt.encTmp
   291  			ptFmt := tt.ecPtFmt
   292  
   293  			privKeyProto := &ecdhpb.EcdhAeadKeyFormat{
   294  				Params: &ecdhpb.EcdhAeadParams{
   295  					KwParams: &ecdhpb.EcdhKwParams{
   296  						CurveType: tt.curveType, // unknown curve type to force an error when calling km.NewKey()
   297  						KeyType:   tt.keyType,   // unknown curve type to force an error when calling km.NewKey()
   298  					},
   299  					EncParams: &ecdhpb.EcdhAeadEncParams{
   300  						AeadEnc: encT, // invalid data enc key template to force an error when calling km.NewKey()
   301  					},
   302  					EcPointFormat: ptFmt, // unknown EC Point format type to force an error when calling km.NewKey()
   303  				},
   304  			}
   305  
   306  			sPrivKey, err := proto.Marshal(privKeyProto)
   307  			require.NoError(t, err)
   308  
   309  			p, err := km.NewKey(sPrivKey)
   310  			if strings.Contains(tt.tcName, "success") {
   311  				require.NoError(t, err)
   312  				require.NotEmpty(t, p)
   313  
   314  				sp, e := proto.Marshal(p)
   315  				require.NoError(t, e)
   316  				require.NotEmpty(t, sp)
   317  
   318  				// try PublicKeyData() with bad serialized private key
   319  				pubK, e := km.PublicKeyData([]byte("bad serialized private key"))
   320  				require.Error(t, e)
   321  				require.Empty(t, pubK)
   322  
   323  				// try PublicKeyData() with valid serialized private key
   324  				pubK, e = km.PublicKeyData(sp)
   325  				require.NoError(t, e)
   326  				require.NotEmpty(t, pubK)
   327  			}
   328  
   329  			kd, err := km.NewKeyData(sPrivKey)
   330  			if strings.Contains(tt.tcName, "success") {
   331  				require.NoError(t, err)
   332  				require.NotEmpty(t, kd)
   333  				require.Equal(t, kd.TypeUrl, nistpECDHKWPrivateKeyTypeURL)
   334  				require.Equal(t, kd.KeyMaterialType, tinkpb.KeyData_ASYMMETRIC_PRIVATE)
   335  				return
   336  			}
   337  
   338  			if bytes.Equal(tt.encTmp.Value, badSerializedFormat) {
   339  				require.EqualError(t, err, errInvalidNISTPECDHKWPrivateKeyFormat.Error(),
   340  					"nistPECDHKWPrivateKeyManager NewKey from serialized key with invalid serialized key")
   341  				require.Empty(t, p)
   342  
   343  				return
   344  			}
   345  
   346  			require.Errorf(t, err, tt.tcName)
   347  			require.Empty(t, p)
   348  		})
   349  	}
   350  }