github.com/trustbloc/kms-go@v1.1.2/kms/localkms/localkms_test.go (about)

     1  /*
     2   Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4   SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package localkms
     8  
     9  import (
    10  	"crypto/ecdsa"
    11  	"crypto/ed25519"
    12  	"crypto/elliptic"
    13  	"crypto/rand"
    14  	"crypto/sha256"
    15  	"crypto/x509"
    16  	"encoding/base64"
    17  	"encoding/json"
    18  	"errors"
    19  	"fmt"
    20  	"io/ioutil"
    21  	"os"
    22  	"strings"
    23  	"testing"
    24  
    25  	"github.com/btcsuite/btcd/btcec/v2"
    26  	"github.com/google/tink/go/keyset"
    27  	"github.com/google/tink/go/subtle/random"
    28  	"github.com/stretchr/testify/require"
    29  	"github.com/trustbloc/bbs-signature-go/bbs12381g2pub"
    30  
    31  	"github.com/trustbloc/kms-go/spi/crypto"
    32  	kmsapi "github.com/trustbloc/kms-go/spi/kms"
    33  	"github.com/trustbloc/kms-go/spi/secretlock"
    34  
    35  	"github.com/trustbloc/kms-go/crypto/tinkcrypto"
    36  	"github.com/trustbloc/kms-go/kms"
    37  	"github.com/trustbloc/kms-go/kms/localkms/internal/keywrapper"
    38  	mocksecretlock "github.com/trustbloc/kms-go/mock/secretlock"
    39  	"github.com/trustbloc/kms-go/secretlock/local"
    40  	"github.com/trustbloc/kms-go/secretlock/local/masterlock/hkdf"
    41  	"github.com/trustbloc/kms-go/secretlock/noop"
    42  )
    43  
    44  const testMasterKeyURI = keywrapper.LocalKeyURIPrefix + "test/key/uri"
    45  
    46  type inMemoryKMSStore struct {
    47  	keys map[string][]byte
    48  }
    49  
    50  func newInMemoryKMSStore() *inMemoryKMSStore {
    51  	return &inMemoryKMSStore{keys: make(map[string][]byte)}
    52  }
    53  
    54  func (i *inMemoryKMSStore) Put(keysetID string, key []byte) error {
    55  	i.keys[keysetID] = key
    56  
    57  	return nil
    58  }
    59  
    60  func (i *inMemoryKMSStore) Get(keysetID string) ([]byte, error) {
    61  	key, found := i.keys[keysetID]
    62  	if !found {
    63  		return nil, kms.ErrKeyNotFound
    64  	}
    65  
    66  	return key, nil
    67  }
    68  
    69  func (i *inMemoryKMSStore) Delete(keysetID string) error {
    70  	delete(i.keys, keysetID)
    71  
    72  	return nil
    73  }
    74  
    75  type mockStore struct {
    76  	errPut error
    77  	errGet error
    78  }
    79  
    80  func (m *mockStore) Put(string, []byte) error {
    81  	return m.errPut
    82  }
    83  
    84  func (m *mockStore) Get(string) ([]byte, error) {
    85  	return nil, m.errGet
    86  }
    87  
    88  func (m *mockStore) Delete(string) error {
    89  	return nil
    90  }
    91  
    92  func TestNewKMS_Failure(t *testing.T) {
    93  	t.Run("test New() fail without masterkeyURI", func(t *testing.T) {
    94  		kmsStorage, err := New("", &mockProvider{
    95  			storage: newInMemoryKMSStore(),
    96  			secretLock: &mocksecretlock.MockSecretLock{
    97  				ValEncrypt: "",
    98  				ValDecrypt: "",
    99  			},
   100  		})
   101  		require.Error(t, err)
   102  		require.Empty(t, kmsStorage)
   103  	})
   104  
   105  	t.Run("test New() error creating new KMS client with bad master key prefix", func(t *testing.T) {
   106  		badKeyURI := "://test/key/uri"
   107  
   108  		kmsStorage, err := New(badKeyURI, &mockProvider{
   109  			storage: newInMemoryKMSStore(),
   110  			secretLock: &mocksecretlock.MockSecretLock{
   111  				ValEncrypt: "",
   112  				ValDecrypt: "",
   113  			},
   114  		})
   115  		require.Error(t, err)
   116  		require.Empty(t, kmsStorage)
   117  	})
   118  }
   119  
   120  func TestCreateGetRotateKey_Failure(t *testing.T) {
   121  	t.Run("test failure Create() and Rotate() calls with bad key template string", func(t *testing.T) {
   122  		kmsStorage, err := New(testMasterKeyURI, &mockProvider{
   123  			storage: newInMemoryKMSStore(),
   124  			secretLock: &mocksecretlock.MockSecretLock{
   125  				ValEncrypt: "",
   126  				ValDecrypt: "",
   127  			},
   128  		})
   129  		require.NoError(t, err)
   130  		require.NotEmpty(t, kmsStorage)
   131  
   132  		id, kh, err := kmsStorage.Create("")
   133  		require.Error(t, err)
   134  		require.Empty(t, kh)
   135  		require.Empty(t, id)
   136  
   137  		id, kh, err = kmsStorage.Create("unsupported")
   138  		require.Error(t, err)
   139  		require.Empty(t, kh)
   140  		require.Empty(t, id)
   141  
   142  		// create a valid key to test Rotate()
   143  		id, kh, err = kmsStorage.Create(kmsapi.AES128GCMType)
   144  		require.NoError(t, err)
   145  		require.NotEmpty(t, kh)
   146  		require.NotEmpty(t, id)
   147  
   148  		newID, kh, err := kmsStorage.Rotate("", id)
   149  		require.Error(t, err)
   150  		require.Empty(t, kh)
   151  		require.Empty(t, newID)
   152  
   153  		newID, kh, err = kmsStorage.Rotate("unsupported", id)
   154  		require.Error(t, err)
   155  		require.Empty(t, kh)
   156  		require.Empty(t, newID)
   157  	})
   158  
   159  	t.Run("test Create() with failure to store key", func(t *testing.T) {
   160  		putErr := fmt.Errorf("failed to put data")
   161  		errGet := kms.ErrKeyNotFound
   162  		mockStore := &mockStore{
   163  			errPut: putErr,
   164  			errGet: errGet,
   165  		}
   166  
   167  		kmsStorage, err := New(testMasterKeyURI, &mockProvider{
   168  			storage: mockStore,
   169  			secretLock: &mocksecretlock.MockSecretLock{
   170  				ValEncrypt: "",
   171  				ValDecrypt: "",
   172  			},
   173  		})
   174  		require.NoError(t, err)
   175  
   176  		id, kh, err := kmsStorage.Create(kmsapi.AES128GCMType)
   177  		require.True(t, errors.Is(err, putErr))
   178  		require.Empty(t, kh)
   179  		require.Empty(t, id)
   180  	})
   181  
   182  	t.Run("test Create() success to store key but fail to get key from store", func(t *testing.T) {
   183  		kmsStorage, err := New(testMasterKeyURI, &mockProvider{
   184  			storage: newInMemoryKMSStore(),
   185  			secretLock: &mocksecretlock.MockSecretLock{
   186  				ValEncrypt: "",
   187  				ValDecrypt: "",
   188  			},
   189  		})
   190  		require.NoError(t, err)
   191  
   192  		id, kh, err := kmsStorage.Create(kmsapi.AES128GCMType)
   193  		require.NoError(t, err)
   194  		require.NotEmpty(t, kh)
   195  		require.NotEmpty(t, id)
   196  
   197  		// new create a new client with a store throwing an error during a Get()
   198  		errGet := errors.New("failed to get data")
   199  		mockStore := &mockStore{
   200  			errGet: errGet,
   201  		}
   202  
   203  		kmsStorage3, err := New(testMasterKeyURI, &mockProvider{
   204  			storage: mockStore,
   205  			secretLock: &mocksecretlock.MockSecretLock{
   206  				ValEncrypt: "",
   207  				ValDecrypt: "",
   208  			},
   209  		})
   210  		require.NoError(t, err)
   211  
   212  		kh, err = kmsStorage3.Get(id)
   213  		require.Contains(t, err.Error(), "failed to get data")
   214  		require.Empty(t, kh)
   215  
   216  		newID, kh, err := kmsStorage3.Rotate(kmsapi.AES128GCMType, id)
   217  		require.Contains(t, err.Error(), "failed to get data")
   218  		require.Empty(t, kh)
   219  		require.Empty(t, newID)
   220  	})
   221  
   222  	t.Run("create valid key but not available for Export", func(t *testing.T) {
   223  		kmsStorage, err := New(testMasterKeyURI, &mockProvider{
   224  			storage:    newInMemoryKMSStore(),
   225  			secretLock: &noop.NoLock{},
   226  		})
   227  		require.NoError(t, err)
   228  
   229  		kid, _, err := kmsStorage.Create(kmsapi.AES128GCM)
   230  		require.NoError(t, err)
   231  
   232  		_, _, err = kmsStorage.ExportPubKeyBytes(kid)
   233  		require.EqualError(t, err, "exportPubKeyBytes: failed to export marshalled key: exportPubKeyBytes: "+
   234  			"failed to get public keyset handle: keyset.Handle: keyset.Handle: keyset contains a non-private key")
   235  	})
   236  
   237  	t.Run("create And Export invalid key", func(t *testing.T) {
   238  		kmsStorage, err := New(testMasterKeyURI, &mockProvider{
   239  			storage:    newInMemoryKMSStore(),
   240  			secretLock: &noop.NoLock{},
   241  		})
   242  		require.NoError(t, err)
   243  
   244  		// try to create and export an unsupported key type.
   245  		_, _, err = kmsStorage.CreateAndExportPubKeyBytes("unsupported")
   246  		require.EqualError(t, err, "createAndExportPubKeyBytes: failed to create new key: create: failed to "+
   247  			"getKeyTemplate: getKeyTemplate: key type 'unsupported' unrecognized")
   248  
   249  		// try to create and export a supported key type, but does not support export.
   250  		_, _, err = kmsStorage.CreateAndExportPubKeyBytes(kmsapi.HMACSHA256Tag256)
   251  		require.EqualError(t, err, "createAndExportPubKeyBytes: failed to export new public key bytes: "+
   252  			"exportPubKeyBytes: failed to export marshalled key: exportPubKeyBytes: failed to get public keyset "+
   253  			"handle: keyset.Handle: keyset.Handle: keyset contains a non-private key")
   254  	})
   255  }
   256  
   257  func TestEncryptRotateDecrypt_Success(t *testing.T) {
   258  	// create a real (not mocked) master key and secret lock to test the KMS end to end
   259  	sl := createMasterKeyAndSecretLock(t)
   260  
   261  	// test New()
   262  	kmsService, err := New(testMasterKeyURI, &mockProvider{
   263  		storage:    newInMemoryKMSStore(),
   264  		secretLock: sl,
   265  	})
   266  	require.NoError(t, err)
   267  	require.NotEmpty(t, kmsService)
   268  
   269  	keyTemplates := []kmsapi.KeyType{
   270  		kmsapi.AES128GCMType,
   271  		kmsapi.AES256GCMNoPrefixType,
   272  		kmsapi.AES256GCMType,
   273  		kmsapi.ChaCha20Poly1305,
   274  		kmsapi.XChaCha20Poly1305,
   275  	}
   276  
   277  	for _, v := range keyTemplates {
   278  		// test Create() a new key
   279  		keyID, keyHandle, e := kmsService.Create(v)
   280  		require.NoError(t, e, "failed on template %v", v)
   281  		require.NotEmpty(t, keyHandle)
   282  		require.NotEmpty(t, keyID)
   283  
   284  		c := tinkcrypto.Crypto{}
   285  		msg := []byte("Test Rotation Message")
   286  		aad := []byte("some additional data")
   287  
   288  		cipherText, nonce, e := c.Encrypt(msg, aad, keyHandle)
   289  		require.NoError(t, e)
   290  
   291  		newKeyID, rotatedKeyHandle, e := kmsService.Rotate(v, keyID)
   292  		require.NoError(t, e)
   293  		require.NotEmpty(t, rotatedKeyHandle)
   294  		require.NotEqual(t, newKeyID, keyID)
   295  
   296  		decryptedMsg, e := c.Decrypt(cipherText, aad, nonce, rotatedKeyHandle)
   297  		require.NoError(t, e)
   298  		require.Equal(t, msg, decryptedMsg)
   299  	}
   300  }
   301  
   302  func TestLocalKMS_Success(t *testing.T) {
   303  	// create a real (not mocked) master key and secret lock to test the KMS end to end
   304  	sl := createMasterKeyAndSecretLock(t)
   305  
   306  	keys := make(map[string][]byte)
   307  
   308  	testStore := newInMemoryKMSStore()
   309  
   310  	testStore.keys = keys
   311  
   312  	// test New()
   313  	kmsService, err := New(testMasterKeyURI, &mockProvider{
   314  		storage:    testStore,
   315  		secretLock: sl,
   316  	})
   317  	require.NoError(t, err)
   318  	require.NotEmpty(t, kmsService)
   319  
   320  	keyTemplates := []kmsapi.KeyType{
   321  		kmsapi.AES128GCMType,
   322  		kmsapi.AES256GCMNoPrefixType,
   323  		kmsapi.AES256GCMType,
   324  		kmsapi.ChaCha20Poly1305Type,
   325  		kmsapi.XChaCha20Poly1305Type,
   326  		kmsapi.ECDSAP256TypeDER,
   327  		kmsapi.ECDSAP384TypeDER,
   328  		kmsapi.ECDSAP521TypeDER,
   329  		kmsapi.ECDSAP256TypeIEEEP1363,
   330  		kmsapi.ECDSAP384TypeIEEEP1363,
   331  		kmsapi.ECDSAP521TypeIEEEP1363,
   332  		kmsapi.ED25519Type,
   333  		kmsapi.NISTP256ECDHKWType,
   334  		kmsapi.NISTP384ECDHKWType,
   335  		kmsapi.NISTP521ECDHKWType,
   336  		kmsapi.X25519ECDHKWType,
   337  		kmsapi.BLS12381G2Type,
   338  		kmsapi.ECDSASecp256k1DER,
   339  		kmsapi.ECDSASecp256k1IEEEP1363,
   340  	}
   341  
   342  	for _, v := range keyTemplates {
   343  		if v == kmsapi.ECDSASecp256k1DER {
   344  			t.Logf("testing create for %s", v)
   345  			_, _, e := kmsService.Create(v)
   346  			require.EqualError(t, e, "create: Unable to create kms key: Secp256K1 is not supported by DER format")
   347  
   348  			continue
   349  		}
   350  
   351  		// test Create() a new key
   352  		keyID, newKeyHandle, e := kmsService.Create(v)
   353  		require.NoError(t, e, "failed on template %v", v)
   354  		require.NotEmpty(t, newKeyHandle)
   355  		require.NotEmpty(t, keyID)
   356  
   357  		ks, ok := keys[keyID]
   358  		require.True(t, ok)
   359  		require.NotEmpty(t, ks)
   360  
   361  		// get key handle primitives
   362  		newKHPrimitives, e := newKeyHandle.(*keyset.Handle).Primitives()
   363  		require.NoError(t, e)
   364  		require.NotEmpty(t, newKHPrimitives)
   365  
   366  		// test Get() an existing keyhandle (it should match newKeyHandle above)
   367  		loadedKeyHandle, e := kmsService.Get(keyID)
   368  		require.NoError(t, e)
   369  		require.NotEmpty(t, loadedKeyHandle)
   370  
   371  		readKHPrimitives, e := loadedKeyHandle.(*keyset.Handle).Primitives()
   372  		require.NoError(t, e)
   373  		require.NotEmpty(t, newKHPrimitives)
   374  
   375  		require.Equal(t, len(newKHPrimitives.Entries), len(readKHPrimitives.Entries))
   376  
   377  		// finally test Rotate()
   378  		// with unsupported key type - should fail
   379  		newKeyID, rotatedKeyHandle, e := kmsService.Rotate("unsupported", keyID)
   380  		require.Error(t, e)
   381  		require.Empty(t, rotatedKeyHandle)
   382  		require.Empty(t, newKeyID)
   383  
   384  		// with valid key type - should succeed
   385  		newKeyID, rotatedKeyHandle, e = kmsService.Rotate(v, keyID)
   386  		require.NoError(t, e)
   387  		require.NotEmpty(t, rotatedKeyHandle)
   388  		require.NotEqual(t, newKeyID, keyID)
   389  
   390  		rotatedKHPrimitives, e := loadedKeyHandle.(*keyset.Handle).Primitives()
   391  		require.NoError(t, e)
   392  		require.NotEmpty(t, newKHPrimitives)
   393  		require.Equal(t, len(newKHPrimitives.Entries), len(rotatedKHPrimitives.Entries))
   394  		require.Equal(t, len(readKHPrimitives.Entries), len(rotatedKHPrimitives.Entries))
   395  
   396  		if strings.Contains(string(v), "ECDSA") || v == kmsapi.ED25519Type || v == kmsapi.BLS12381G2Type {
   397  			pubKeyBytes, kt, e := kmsService.ExportPubKeyBytes(keyID)
   398  			require.Errorf(t, e, "KeyID has been rotated. An error must be returned")
   399  			require.Empty(t, pubKeyBytes)
   400  			require.Empty(t, kt)
   401  
   402  			pubKeyBytes, kt, e = kmsService.ExportPubKeyBytes(newKeyID)
   403  			require.NoError(t, e)
   404  			require.NotEmpty(t, pubKeyBytes)
   405  			require.Equal(t, v, kt)
   406  
   407  			kh, e := kmsService.PubKeyBytesToHandle(pubKeyBytes, v)
   408  			require.NoError(t, e)
   409  			require.NotEmpty(t, kh)
   410  
   411  			// test create and export key in one function
   412  			_, _, e = kmsService.CreateAndExportPubKeyBytes(v)
   413  			require.NoError(t, e)
   414  		}
   415  	}
   416  }
   417  
   418  func TestLocalKMS_ImportPrivateKey(t *testing.T) { // nolint:gocyclo
   419  	// create a real (not mocked) master key and secret lock to test the KMS end to end
   420  	sl := createMasterKeyAndSecretLock(t)
   421  
   422  	// test New()
   423  	kmsService, e := New(testMasterKeyURI, &mockProvider{
   424  		storage:    newInMemoryKMSStore(),
   425  		secretLock: sl,
   426  	})
   427  	require.NoError(t, e)
   428  	require.NotEmpty(t, kmsService)
   429  
   430  	// test import with nil key
   431  	_, _, err := kmsService.ImportPrivateKey(nil, kmsapi.ECDSAP256TypeDER)
   432  	require.EqualError(t, err, "import private key does not support this key type or key is public")
   433  
   434  	flagTests := []struct {
   435  		tcName  string
   436  		keyType kmsapi.KeyType
   437  		curve   elliptic.Curve
   438  		setID   bool
   439  		ksID    string
   440  	}{
   441  		{
   442  			tcName:  "import private key using ECDSAP256DER type",
   443  			keyType: kmsapi.ECDSAP256TypeDER,
   444  			curve:   elliptic.P256(),
   445  		},
   446  		{
   447  			tcName:  "import private key using ECDSAP384TypeDER type",
   448  			keyType: kmsapi.ECDSAP384TypeDER,
   449  			curve:   elliptic.P384(),
   450  		},
   451  		{
   452  			tcName:  "import private key using ECDSAP521TypeDER type",
   453  			keyType: kmsapi.ECDSAP521TypeDER,
   454  			curve:   elliptic.P521(),
   455  		},
   456  		{
   457  			tcName:  "import private key using NISTP256ECDHKW type",
   458  			keyType: kmsapi.NISTP256ECDHKWType,
   459  			curve:   elliptic.P256(),
   460  		},
   461  		{
   462  			tcName:  "import private key using NISTP384ECDHKW type",
   463  			keyType: kmsapi.NISTP384ECDHKWType,
   464  			curve:   elliptic.P384(),
   465  		},
   466  		{
   467  			tcName:  "import private key using NISTP521ECDHKW type",
   468  			keyType: kmsapi.NISTP521ECDHKWType,
   469  			curve:   elliptic.P521(),
   470  		},
   471  		{
   472  			tcName:  "import private key using ECDSAP256TypeIEEEP1363 type",
   473  			keyType: kmsapi.ECDSAP256TypeIEEEP1363,
   474  			curve:   elliptic.P256(),
   475  		},
   476  		{
   477  			tcName:  "import private key using ECDSAP384TypeIEEEP1363 type",
   478  			keyType: kmsapi.ECDSAP384TypeIEEEP1363,
   479  			curve:   elliptic.P384(),
   480  		},
   481  		{
   482  			tcName:  "import private key using ECDSAP521TypeIEEEP1363 type",
   483  			keyType: kmsapi.ECDSAP521TypeIEEEP1363,
   484  			curve:   elliptic.P521(),
   485  		},
   486  		/*{
   487  			tcName:  "import private key using ECDSAP256DER type",
   488  			keyType: kms.ECDSASecp256k1DER,
   489  			curve:   btcec.S256(),
   490  		},*/
   491  		{
   492  			tcName:  "import private key using ECDSAP256IEEEP1363 type",
   493  			keyType: kmsapi.ECDSASecp256k1IEEEP1363,
   494  			curve:   btcec.S256(),
   495  		},
   496  		{
   497  			tcName:  "import private key using ED25519Type type",
   498  			keyType: kmsapi.ED25519Type,
   499  		},
   500  		{
   501  			tcName:  "import private key using BLS12381G2Type type",
   502  			keyType: kmsapi.BLS12381G2Type,
   503  		},
   504  		{
   505  			tcName:  "import private key using ECDSAP256DER type and a set empty KeyID",
   506  			keyType: kmsapi.ECDSAP256TypeDER,
   507  			curve:   elliptic.P256(),
   508  			setID:   true,
   509  			ksID:    "",
   510  		},
   511  		{
   512  			tcName:  "import private key using ECDSAP256DER type and a set non empty KeyID",
   513  			keyType: kmsapi.ECDSAP256TypeDER,
   514  			curve:   elliptic.P256(),
   515  			setID:   true,
   516  			ksID: base64.RawURLEncoding.EncodeToString(random.GetRandomBytes(
   517  				uint32(base64.RawURLEncoding.DecodedLen(maxKeyIDLen)))),
   518  		},
   519  		{
   520  			tcName:  "import private key using ECDSAP256DER type and a set non KeyID larger than maxKeyIDLen",
   521  			keyType: kmsapi.ECDSAP256TypeDER,
   522  			curve:   elliptic.P256(),
   523  			setID:   true,
   524  			ksID: base64.RawURLEncoding.EncodeToString(random.GetRandomBytes(
   525  				uint32(base64.RawURLEncoding.DecodedLen(30)))),
   526  		},
   527  	}
   528  
   529  	for _, tc := range flagTests {
   530  		tt := tc
   531  		t.Run(tt.tcName, func(t *testing.T) {
   532  			if tt.keyType == kmsapi.ED25519Type {
   533  				pubKey, privKey, err := ed25519.GenerateKey(rand.Reader)
   534  				require.NoError(t, err)
   535  
   536  				ksID, _, err := kmsService.ImportPrivateKey(privKey, tt.keyType)
   537  				require.NoError(t, err)
   538  
   539  				pubKeyBytes, kt, err := kmsService.ExportPubKeyBytes(ksID)
   540  				require.NoError(t, err)
   541  				require.EqualValues(t, pubKey, pubKeyBytes)
   542  				require.Equal(t, tt.keyType, kt)
   543  				return
   544  			}
   545  
   546  			if tt.keyType == kmsapi.BLS12381G2Type {
   547  				seed := make([]byte, 32)
   548  
   549  				_, err := rand.Read(seed)
   550  				require.NoError(t, err)
   551  
   552  				pubKey, privKey, err := bbs12381g2pub.GenerateKeyPair(sha256.New, seed)
   553  				require.NoError(t, err)
   554  
   555  				ksID, _, err := kmsService.ImportPrivateKey(privKey, tt.keyType)
   556  				require.NoError(t, err)
   557  
   558  				pubKeyBytes, kt, err := kmsService.ExportPubKeyBytes(ksID)
   559  				require.NoError(t, err)
   560  				require.Equal(t, tt.keyType, kt)
   561  
   562  				expectedPubKeyBytes, err := pubKey.Marshal()
   563  				require.NoError(t, err)
   564  				require.EqualValues(t, expectedPubKeyBytes, pubKeyBytes)
   565  				return
   566  			}
   567  
   568  			privKey, err := ecdsa.GenerateKey(tt.curve, rand.Reader)
   569  			require.NoError(t, err)
   570  
   571  			var ksID string
   572  
   573  			// test ImportPrivateKey
   574  			if tt.setID {
   575  				// with set keyset ID
   576  				ksID, _, err = kmsService.ImportPrivateKey(privKey, tt.keyType, kmsapi.WithKeyID(tt.ksID))
   577  				require.NoError(t, err)
   578  				// calling ImportPrivatekeyt and WithKeyID("") will ignore the set KeyID and generate a new one
   579  				if tt.ksID != "" {
   580  					require.Equal(t, tt.ksID, ksID)
   581  				}
   582  			} else {
   583  				// generate a new keyset ID
   584  				ksID, _, err = kmsService.ImportPrivateKey(privKey, tt.keyType)
   585  				require.NoError(t, err)
   586  			}
   587  
   588  			// export marshaled public key to verify it against the original public key (marshalled)
   589  			actualPubKey, kt, err := kmsService.ExportPubKeyBytes(ksID)
   590  			require.NoError(t, err)
   591  			require.Equal(t, tt.keyType, kt)
   592  
   593  			var expectedPubKey []byte
   594  
   595  			switch tt.keyType {
   596  			case kmsapi.ECDSAP256TypeDER, kmsapi.ECDSAP384TypeDER, kmsapi.ECDSAP521TypeDER, kmsapi.ECDSASecp256k1TypeDER:
   597  				expectedPubKey, err = x509.MarshalPKIXPublicKey(privKey.Public())
   598  				require.NoError(t, err)
   599  			case kmsapi.ECDSAP256TypeIEEEP1363, kmsapi.ECDSAP384TypeIEEEP1363, kmsapi.ECDSAP521TypeIEEEP1363,
   600  				kmsapi.ECDSASecp256k1TypeIEEEP1363:
   601  				expectedPubKey = elliptic.Marshal(tt.curve, privKey.X, privKey.Y)
   602  			case kmsapi.NISTP256ECDHKWType, kmsapi.NISTP384ECDHKWType, kmsapi.NISTP521ECDHKWType:
   603  				var curveName string
   604  
   605  				switch tt.curve.Params().Name {
   606  				case "P-256":
   607  					curveName = "NIST_P256"
   608  				case "P-384":
   609  					curveName = "NIST_P384"
   610  				case "P-521":
   611  					curveName = "NIST_P521"
   612  				case "secp256k1":
   613  					curveName = "SECP256K1"
   614  				}
   615  
   616  				cryptoKey := &crypto.PublicKey{
   617  					KID:   ksID,
   618  					X:     privKey.PublicKey.X.Bytes(),
   619  					Y:     privKey.PublicKey.Y.Bytes(),
   620  					Curve: curveName,
   621  					Type:  "EC",
   622  				}
   623  
   624  				expectedPubKey, err = json.Marshal(cryptoKey)
   625  				require.NoError(t, err)
   626  			}
   627  
   628  			require.EqualValues(t, expectedPubKey, actualPubKey)
   629  		})
   630  	}
   631  }
   632  
   633  func TestLocalKMS_getKeyTemplate(t *testing.T) {
   634  	keyTemplate, err := getKeyTemplate(kmsapi.HMACSHA256Tag256Type)
   635  	require.NoError(t, err)
   636  	require.NotNil(t, keyTemplate)
   637  	require.Equal(t, "type.googleapis.com/google.crypto.tink.HmacKey", keyTemplate.TypeUrl)
   638  }
   639  
   640  func createMasterKeyAndSecretLock(t *testing.T) secretlock.Service {
   641  	t.Helper()
   642  
   643  	masterKeyFilePath := "masterKey_file.txt"
   644  	tmpfile, err := ioutil.TempFile("", masterKeyFilePath)
   645  	require.NoError(t, err)
   646  
   647  	defer func() {
   648  		// close file
   649  		require.NoError(t, tmpfile.Close())
   650  		// clean up file
   651  		require.NoError(t, os.Remove(tmpfile.Name()))
   652  	}()
   653  
   654  	masterKeyContent := random.GetRandomBytes(uint32(32))
   655  	require.NotEmpty(t, masterKeyContent)
   656  
   657  	// first create a master lock to use in our secret lock and encrypt the master key
   658  	passphrase := "secretPassphrase"
   659  	keySize := sha256.Size
   660  	// salt is optional, it can be nil
   661  	salt := make([]byte, keySize)
   662  	_, err = rand.Read(salt)
   663  	require.NoError(t, err)
   664  
   665  	masterLocker, err := hkdf.NewMasterLock(passphrase, sha256.New, salt)
   666  	require.NoError(t, err)
   667  	require.NotEmpty(t, masterLocker)
   668  
   669  	// now encrypt masterKeyContent
   670  	masterLockEnc, err := masterLocker.Encrypt("", &secretlock.EncryptRequest{
   671  		Plaintext: string(masterKeyContent),
   672  	})
   673  	require.NoError(t, err)
   674  	require.NotEmpty(t, masterLockEnc)
   675  
   676  	// and write it to tmpfile
   677  	n, err := tmpfile.Write([]byte(masterLockEnc.Ciphertext))
   678  	require.NoError(t, err)
   679  	require.Equal(t, len(masterLockEnc.Ciphertext), n)
   680  
   681  	// now get a reader from path
   682  	r, err := local.MasterKeyFromPath(tmpfile.Name())
   683  	require.NoError(t, err)
   684  	require.NotEmpty(t, r)
   685  
   686  	// finally create lock service with the master lock created above to encrypt decrypt keys using
   687  	// a protected (encrypted) master key
   688  	s, err := local.NewService(r, masterLocker)
   689  	require.NoError(t, err)
   690  	require.NotEmpty(t, s)
   691  
   692  	return s
   693  }
   694  
   695  // mockProvider mocks a provider for KMS storage.
   696  type mockProvider struct {
   697  	storage    kmsapi.Store
   698  	secretLock secretlock.Service
   699  }
   700  
   701  func (m *mockProvider) StorageProvider() kmsapi.Store {
   702  	return m.storage
   703  }
   704  
   705  func (m *mockProvider) SecretLock() secretlock.Service {
   706  	return m.secretLock
   707  }