github.com/trustbloc/kms-go@v1.1.2/kms/webkms/remotekms_test.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package webkms
     8  
     9  import (
    10  	"crypto/ecdsa"
    11  	"crypto/ed25519"
    12  	"crypto/elliptic"
    13  	"crypto/rand"
    14  	"crypto/tls"
    15  	"crypto/x509"
    16  	"encoding/json"
    17  	"encoding/pem"
    18  	"errors"
    19  	"fmt"
    20  	"io"
    21  	"io/ioutil"
    22  	"net"
    23  	"net/http"
    24  	"path/filepath"
    25  	"strings"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/stretchr/testify/require"
    30  
    31  	kmsapi "github.com/trustbloc/kms-go/spi/kms"
    32  )
    33  
    34  const (
    35  	certPrefix        = "testdata/"
    36  	clientTimeout     = 5 * time.Second
    37  	controller        = "did:example:123456789"
    38  	defaultKeyStoreID = "12345"
    39  	defaultKID        = "99999"
    40  )
    41  
    42  func TestRemoteKeyStore(t *testing.T) {
    43  	xRootCapabilityHeaderValue := []byte("DUMMY")
    44  
    45  	secret := make([]byte, 10)
    46  	_, err := rand.Read(secret)
    47  	require.NoError(t, err)
    48  
    49  	pvKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    50  	require.NoError(t, err)
    51  
    52  	marshalledPubKey := elliptic.Marshal(pvKey.PublicKey.Curve, pvKey.PublicKey.X, pvKey.PublicKey.Y)
    53  
    54  	hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    55  		err = processPOSTRequest(w, r, defaultKeyStoreID, defaultKID, marshalledPubKey, kmsapi.ECDSAP256TypeIEEEP1363)
    56  		w.WriteHeader(http.StatusCreated)
    57  		require.NoError(t, err)
    58  	})
    59  
    60  	server, url, client := CreateMockHTTPServerAndClient(t, hf)
    61  	defaultKeystoreURL := fmt.Sprintf("%s/%s", strings.ReplaceAll(KeystoreEndpoint,
    62  		"{serverEndpoint}", url), defaultKeyStoreID)
    63  
    64  	defer func() {
    65  		e := server.Close()
    66  		require.NoError(t, e)
    67  	}()
    68  
    69  	t.Run("CreateKeyStore failures", func(t *testing.T) {
    70  		blankClient := &http.Client{}
    71  		_, _, err = CreateKeyStore(blankClient, url, controller, "", nil)
    72  		require.Contains(t, err.Error(), "posting Create keystore failed")
    73  
    74  		_, _, err = CreateKeyStore(blankClient, "``#$%", controller, "", nil)
    75  		require.EqualError(t, err, "build request for Create keystore error: parse \"``#$%/v1/keystores\": "+
    76  			"invalid URL escape \"%/v\"")
    77  	})
    78  
    79  	t.Run("CreateKeyStore API error", func(t *testing.T) {
    80  		_hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    81  			w.WriteHeader(http.StatusInternalServerError)
    82  			_, err = w.Write([]byte(`{"errMessage": "api error msg"}`))
    83  			require.NoError(t, err)
    84  		})
    85  
    86  		srv, _url, _client := CreateMockHTTPServerAndClient(t, _hf)
    87  
    88  		defer func() { require.NoError(t, srv.Close()) }()
    89  
    90  		_, _, err = CreateKeyStore(_client, _url, controller, "", nil)
    91  		require.Contains(t, err.Error(), "api error msg")
    92  	})
    93  
    94  	t.Run("CreateKeyStore json error", func(t *testing.T) {
    95  		_hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    96  			w.WriteHeader(http.StatusInternalServerError)
    97  			_, err = w.Write([]byte(`[]`))
    98  			require.NoError(t, err)
    99  		})
   100  
   101  		srv, _url, _client := CreateMockHTTPServerAndClient(t, _hf)
   102  
   103  		defer func() { require.NoError(t, srv.Close()) }()
   104  
   105  		_, _, err = CreateKeyStore(_client, _url, controller, "", nil)
   106  		require.Contains(t, err.Error(), "cannot unmarshal array into Go value")
   107  	})
   108  
   109  	t.Run("CreateKeyStore json marshal failure", func(t *testing.T) {
   110  		_, _, err = CreateKeyStore(client, url, controller, "", nil, WithMarshalFn(failingMarshal))
   111  		require.Contains(t, err.Error(), "failed to marshal Create keystore request")
   112  		require.Contains(t, err.Error(), "failingMarshal always fails")
   113  	})
   114  
   115  	t.Run("CreateKeyStore success", func(t *testing.T) {
   116  		ksID, capability, e := CreateKeyStore(client, url, controller, "vaultID", []byte("capability"))
   117  		require.NoError(t, e)
   118  		require.Equal(t, capability, xRootCapabilityHeaderValue)
   119  		require.EqualValues(t, defaultKeystoreURL, ksID)
   120  	})
   121  
   122  	t.Run("Create API error", func(t *testing.T) {
   123  		_hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   124  			w.WriteHeader(http.StatusInternalServerError)
   125  			_, err = w.Write([]byte(`{"errMessage": "api error msg"}`))
   126  			require.NoError(t, err)
   127  		})
   128  
   129  		srv, _url, _client := CreateMockHTTPServerAndClient(t, _hf)
   130  
   131  		defer func() { require.NoError(t, srv.Close()) }()
   132  
   133  		tmpKMS := New(_url, _client)
   134  
   135  		_, _, err = tmpKMS.Create(kmsapi.ED25519Type)
   136  		require.Contains(t, err.Error(), "api error msg")
   137  	})
   138  
   139  	t.Run("Create Key failure", func(t *testing.T) {
   140  		blankClient := &http.Client{}
   141  		tmpKMS := New(defaultKeystoreURL, blankClient)
   142  
   143  		_, _, err = tmpKMS.Create(kmsapi.ED25519Type)
   144  		require.Contains(t, err.Error(), "posting Create key failed")
   145  
   146  		_, _, err = tmpKMS.CreateAndExportPubKeyBytes(kmsapi.ED25519Type)
   147  		require.Contains(t, err.Error(), "posting Create key failed")
   148  
   149  		tmpKMS = New("``#$%", blankClient)
   150  		_, _, err = tmpKMS.Create(kmsapi.ED25519Type)
   151  		require.EqualError(t, err, "posting Create key failed [``#$%/keys, build post request error: parse"+
   152  			" \"``#$%/keys\": invalid URL escape \"%/k\"]")
   153  	})
   154  
   155  	t.Run("New, Create, Get, Export/Import success, all other functions should fail", func(t *testing.T) {
   156  		remoteKMS := New(defaultKeystoreURL, client)
   157  
   158  		kid, keyURL, err := remoteKMS.Create(kmsapi.ECDSAP256TypeIEEEP1363)
   159  		require.NoError(t, err)
   160  		require.Equal(t, defaultKID, kid)
   161  		require.Contains(t, keyURL, fmt.Sprintf("%s/keys/%s", defaultKeystoreURL, defaultKID))
   162  
   163  		t.Run("CreateKey json marshal failure", func(t *testing.T) {
   164  			remoteKMS2 := New(defaultKeystoreURL, client)
   165  
   166  			remoteKMS2.marshalFunc = failingMarshal
   167  			_, _, err = remoteKMS2.Create(kmsapi.ED25519Type)
   168  			require.Contains(t, err.Error(), "failed to marshal Create key request")
   169  			require.Contains(t, err.Error(), "failingMarshal always fails")
   170  		})
   171  
   172  		kh, err := remoteKMS.Get(kid)
   173  		require.NoError(t, err)
   174  		require.EqualValues(t, keyURL, kh)
   175  
   176  		pubKey, kt, err := remoteKMS.ExportPubKeyBytes(kid)
   177  		require.NoError(t, err)
   178  		require.EqualValues(t, marshalledPubKey, pubKey)
   179  		require.Equal(t, kmsapi.ECDSAP256TypeIEEEP1363, kt)
   180  
   181  		t.Run("ExportPubKeyBytes API error", func(t *testing.T) {
   182  			_hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   183  				w.WriteHeader(http.StatusInternalServerError)
   184  				_, err = w.Write([]byte(`{"errMessage": "api error msg"}`))
   185  				require.NoError(t, err)
   186  			})
   187  
   188  			srv, _url, _client := CreateMockHTTPServerAndClient(t, _hf)
   189  
   190  			defer func() { require.NoError(t, srv.Close()) }()
   191  
   192  			tmpKMS := New(_url, _client)
   193  
   194  			_, _, err = tmpKMS.ExportPubKeyBytes("kid")
   195  			require.Contains(t, err.Error(), "api error msg")
   196  		})
   197  
   198  		t.Run("ExportPubKeyBytes json unmarshal failure", func(t *testing.T) {
   199  			remoteKMS3 := New(defaultKeystoreURL, client)
   200  
   201  			kid1, keyURL1, e := remoteKMS3.Create(kmsapi.ED25519Type)
   202  			require.NoError(t, e)
   203  			require.Equal(t, defaultKID, kid1)
   204  			require.Contains(t, keyURL1, fmt.Sprintf("%s/keys/%s", defaultKeystoreURL, defaultKID))
   205  
   206  			// switch the marshaller in remoteKMS3 to force an error in ExportPubKeyBytes
   207  			remoteKMS3.unmarshalFunc = failingUnmarshal
   208  			_, _, err = remoteKMS3.ExportPubKeyBytes(kid1)
   209  			require.Contains(t, err.Error(), "unmarshal failed")
   210  			require.Contains(t, err.Error(), "failingUnmarshal always fails")
   211  
   212  			remoteKMS3.unmarshalFunc = json.Unmarshal
   213  
   214  			t.Logf("kid1 : %v", kid1)
   215  
   216  			// test GET http function failure
   217  			remoteKMS3.keystoreURL = "``#$%"
   218  			_, _, err = remoteKMS3.ExportPubKeyBytes(kid1)
   219  			require.Contains(t, err.Error(), "posting GET ExportPubKeyBytes key failed")
   220  			require.Contains(t, err.Error(), "build get request error")
   221  		})
   222  
   223  		nKID, _, err := remoteKMS.CreateAndExportPubKeyBytes(kmsapi.AES128GCMType)
   224  		require.NoError(t, err)
   225  		require.Equal(t, kid, nKID)
   226  
   227  		t.Run("ExportPubKeyBytes should fail with bad http client", func(t *testing.T) {
   228  			blankClient := &http.Client{}
   229  			remoteKMS2 := New(defaultKeystoreURL, blankClient)
   230  
   231  			_, _, err = remoteKMS2.ExportPubKeyBytes(kid)
   232  			require.Contains(t, err.Error(), "posting GET ExportPubKeyBytes key failed")
   233  		})
   234  
   235  		_, _, err = remoteKMS.Rotate(kmsapi.AES128GCMType, "")
   236  		require.EqualError(t, err, "function Rotate is not implemented in remoteKMS")
   237  
   238  		_, err = remoteKMS.PubKeyBytesToHandle(nil, kmsapi.AES128GCMType)
   239  		require.EqualError(t, err, "function PubKeyBytesToHandle is not implemented in remoteKMS")
   240  	})
   241  }
   242  
   243  func TestCreateKeyWithLocationInResponseBody(t *testing.T) {
   244  	secret := make([]byte, 10)
   245  	_, err := rand.Read(secret)
   246  	require.NoError(t, err)
   247  
   248  	hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   249  		err = processPOSTRequestForCreateWithResponseBody(w, r, defaultKeyStoreID, defaultKID)
   250  		require.NoError(t, err)
   251  	})
   252  
   253  	server, url, client := CreateMockHTTPServerAndClient(t, hf)
   254  	defaultKeystoreURL := fmt.Sprintf("%s/%s", strings.ReplaceAll(KeystoreEndpoint,
   255  		"{serverEndpoint}", url), defaultKeyStoreID)
   256  
   257  	defer func() {
   258  		e := server.Close()
   259  		require.NoError(t, e)
   260  	}()
   261  
   262  	remoteKMS := New(defaultKeystoreURL, client)
   263  
   264  	kid1, keyURL1, err := remoteKMS.Create(kmsapi.ED25519Type)
   265  	require.NoError(t, err)
   266  	require.Equal(t, defaultKID, kid1)
   267  	require.Contains(t, keyURL1, fmt.Sprintf("%s/keys/%s", defaultKeystoreURL, defaultKID))
   268  
   269  	// no error if options passed
   270  	_, _, err = remoteKMS.Create(kmsapi.ED25519Type, kmsapi.WithAttrs([]string{"attr1"}))
   271  	require.NoError(t, err)
   272  	_, _, err = remoteKMS.CreateAndExportPubKeyBytes(kmsapi.ED25519Type, kmsapi.WithAttrs([]string{"attr2"}))
   273  	require.NoError(t, err)
   274  
   275  	remoteKMS.unmarshalFunc = failingUnmarshal
   276  	_, _, err = remoteKMS.Create(kmsapi.ED25519Type)
   277  	require.Contains(t, err.Error(), "unmarshal failed")
   278  	require.Contains(t, err.Error(), "failingUnmarshal always fails")
   279  }
   280  
   281  func TestHealthCheck(t *testing.T) {
   282  	hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   283  		w.WriteHeader(http.StatusServiceUnavailable)
   284  	})
   285  
   286  	server, url, client := CreateMockHTTPServerAndClient(t, hf)
   287  	defaultKeystoreURL := fmt.Sprintf("%s/%s", strings.ReplaceAll(KeystoreEndpoint,
   288  		"{serverEndpoint}", url), defaultKeyStoreID)
   289  
   290  	defer func() {
   291  		e := server.Close()
   292  		require.NoError(t, e)
   293  	}()
   294  
   295  	remoteKMS := New(defaultKeystoreURL, client)
   296  
   297  	err := remoteKMS.HealthCheck()
   298  	require.Error(t, err)
   299  	require.Contains(t, err.Error(), "kms health check return 503 status code")
   300  }
   301  
   302  func TestRemoteKeyStoreWithHeadersFunc(t *testing.T) {
   303  	xRootCapabilityHeaderValue := []byte("DUMMY")
   304  
   305  	secret := make([]byte, 10)
   306  	_, err := rand.Read(secret)
   307  	require.NoError(t, err)
   308  
   309  	pvKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
   310  	require.NoError(t, err)
   311  
   312  	marshalledPubKey := elliptic.Marshal(pvKey.PublicKey.Curve, pvKey.PublicKey.X, pvKey.PublicKey.Y)
   313  
   314  	hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   315  		err = processPOSTRequest(w, r, defaultKeyStoreID, defaultKID, marshalledPubKey, kmsapi.ECDSAP256TypeIEEEP1363)
   316  		w.WriteHeader(http.StatusCreated)
   317  		require.NoError(t, err)
   318  	})
   319  
   320  	server, url, client := CreateMockHTTPServerAndClient(t, hf)
   321  	defaultKeystoreURL := fmt.Sprintf("%s/%s", strings.ReplaceAll(KeystoreEndpoint,
   322  		"{serverEndpoint}", url), defaultKeyStoreID)
   323  
   324  	defer func() {
   325  		e := server.Close()
   326  		require.NoError(t, e)
   327  	}()
   328  
   329  	t.Run("CreateKeyStore with http header opt success", func(t *testing.T) {
   330  		ksID, capability, e := CreateKeyStore(client, url, controller, "vaultID", []byte("capability"),
   331  			WithHeaders(mockAddHeadersFuncSuccess), WithCache(1))
   332  		require.NoError(t, e)
   333  		require.Equal(t, capability, xRootCapabilityHeaderValue)
   334  		require.EqualValues(t, defaultKeystoreURL, ksID)
   335  	})
   336  
   337  	t.Run("CreateKeyStore with http header opt failure", func(t *testing.T) {
   338  		_, _, e := CreateKeyStore(client, url, controller, "vaultID", []byte("capability"),
   339  			WithHeaders(mockAddHeadersFuncError))
   340  		require.EqualError(t, e, fmt.Errorf("add optional request headers error: %w", errAddHeadersFunc).Error())
   341  	})
   342  
   343  	t.Run("test New with valid http header func option", func(t *testing.T) {
   344  		remoteKMS := New(defaultKeystoreURL, client, WithHeaders(mockAddHeadersFuncSuccess))
   345  
   346  		kid, keyURL, e := remoteKMS.Create(kmsapi.ED25519Type)
   347  		require.NoError(t, e)
   348  		require.Equal(t, defaultKID, kid)
   349  		require.Contains(t, keyURL, fmt.Sprintf("/v1/keystores/%s/keys/%s", defaultKeyStoreID, defaultKID))
   350  	})
   351  
   352  	t.Run("test New with invalid http header func option", func(t *testing.T) {
   353  		remoteKMS := New(defaultKeystoreURL, client, WithHeaders(mockAddHeadersFuncError))
   354  
   355  		_, _, err = remoteKMS.Create(kmsapi.ED25519Type)
   356  		require.EqualError(t, err, fmt.Errorf("posting Create key failed [%s/keys, add optional request "+
   357  			"headers error: %w]", defaultKeystoreURL, errAddHeadersFunc).Error())
   358  	})
   359  }
   360  
   361  func TestImportPrivateKey(t *testing.T) {
   362  	secret := make([]byte, 10)
   363  	_, err := rand.Read(secret)
   364  	require.NoError(t, err)
   365  
   366  	hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   367  		err = processPOSTRequestForImportKey(w, r, defaultKeyStoreID, defaultKID)
   368  		require.NoError(t, err)
   369  	})
   370  
   371  	server, url, client := CreateMockHTTPServerAndClient(t, hf)
   372  	defaultKeystoreURL := fmt.Sprintf("%s/%s", strings.ReplaceAll(KeystoreEndpoint,
   373  		"{serverEndpoint}", url), defaultKeyStoreID)
   374  
   375  	defer func() {
   376  		e := server.Close()
   377  		require.NoError(t, e)
   378  	}()
   379  
   380  	remoteKMS := New(defaultKeystoreURL, client)
   381  
   382  	_, privateKey, err := ed25519.GenerateKey(rand.Reader)
   383  	require.NoError(t, err)
   384  
   385  	keyID, keyURL, err := remoteKMS.ImportPrivateKey(privateKey, kmsapi.ED25519Type)
   386  	require.NoError(t, err)
   387  	require.Equal(t, defaultKID, keyID)
   388  	require.Contains(t, keyURL, fmt.Sprintf("%s/keys/%s", defaultKeystoreURL, defaultKID))
   389  
   390  	_, _, err = remoteKMS.ImportPrivateKey([]byte("invalid key bytes"), kmsapi.ED25519Type)
   391  	require.Contains(t, err.Error(), "failed to marshal private key")
   392  
   393  	remoteKMS.marshalFunc = failingMarshal
   394  
   395  	_, _, err = remoteKMS.ImportPrivateKey(privateKey, kmsapi.ED25519Type)
   396  	require.Contains(t, err.Error(), "failed to marshal ImportKey request")
   397  	require.Contains(t, err.Error(), "failingMarshal always fails")
   398  
   399  	remoteKMS.marshalFunc = json.Marshal
   400  
   401  	remoteKMS.unmarshalFunc = failingUnmarshal
   402  
   403  	_, _, err = remoteKMS.ImportPrivateKey(privateKey, kmsapi.ED25519Type)
   404  	require.Contains(t, err.Error(), "unmarshal failed")
   405  	require.Contains(t, err.Error(), "failingUnmarshal always fails")
   406  
   407  	remoteKMS.unmarshalFunc = json.Unmarshal
   408  
   409  	t.Run("ImportPrivateKey API error", func(t *testing.T) {
   410  		_hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   411  			w.WriteHeader(http.StatusInternalServerError)
   412  			_, err = w.Write([]byte(`{"errMessage": "api error msg"}`))
   413  			require.NoError(t, err)
   414  		})
   415  
   416  		srv, _url, _client := CreateMockHTTPServerAndClient(t, _hf)
   417  
   418  		defer func() { require.NoError(t, srv.Close()) }()
   419  
   420  		tmpKMS := New(_url, _client)
   421  
   422  		_, _, err = tmpKMS.ImportPrivateKey(privateKey, kmsapi.ED25519Type)
   423  		require.Contains(t, err.Error(), "api error msg")
   424  	})
   425  }
   426  
   427  func TestCloseResponseBody(t *testing.T) {
   428  	closeResponseBody(&errFailingCloser{}, "testing close fail should log: errFailingCloser always fails")
   429  }
   430  
   431  func processPOSTRequest(w http.ResponseWriter, r *http.Request, keysetID, kid string,
   432  	defaultExportPubKey []byte, defaultExportKeyType kmsapi.KeyType) error {
   433  	xRootCapabilityHeaderValue := []byte("DUMMY")
   434  
   435  	if valid := validateHTTPMethod(w, r); !valid {
   436  		return errors.New("http method invalid")
   437  	}
   438  
   439  	if valid := validatePostPayload(r, w); !valid {
   440  		return errors.New("http request body invalid")
   441  	}
   442  
   443  	if strings.LastIndex(r.URL.Path, "/keys") == len(r.URL.Path)-len("/keys") {
   444  		return processCreateKeyRequest(w, r, keysetID, kid, defaultExportPubKey)
   445  	}
   446  
   447  	if strings.LastIndex(r.URL.Path, "/export") == len(r.URL.Path)-len("/export") {
   448  		return processExportKeyRequest(w, defaultExportPubKey, defaultExportKeyType)
   449  	}
   450  
   451  	resp := &createKeyStoreResp{
   452  		KeyStoreURL: fmt.Sprintf("https://%s/v1/keystores/%s", r.Host, keysetID),
   453  		Capability:  xRootCapabilityHeaderValue,
   454  	}
   455  
   456  	mResp, err := json.Marshal(resp)
   457  	if err != nil {
   458  		return err
   459  	}
   460  
   461  	_, err = w.Write(mResp)
   462  	if err != nil {
   463  		return err
   464  	}
   465  
   466  	return nil
   467  }
   468  
   469  func processCreateKeyRequest(w http.ResponseWriter, r *http.Request, keysetID, kid string,
   470  	defaultExportPubKey []byte) error {
   471  	var req createKeyReq
   472  	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
   473  		return err
   474  	}
   475  
   476  	resp := &createKeyResp{
   477  		KeyURL:    fmt.Sprintf("https://%s/v1/keystores/%s/keys/%s", r.Host, keysetID, kid),
   478  		PublicKey: defaultExportPubKey,
   479  	}
   480  
   481  	mResp, err := json.Marshal(resp)
   482  	if err != nil {
   483  		return err
   484  	}
   485  
   486  	_, err = w.Write(mResp)
   487  	if err != nil {
   488  		return err
   489  	}
   490  
   491  	return nil
   492  }
   493  
   494  func processExportKeyRequest(w io.Writer, defaultExportPubKey []byte, defaultExportKeyType kmsapi.KeyType) error {
   495  	resp := &exportKeyResp{
   496  		PublicKey: defaultExportPubKey,
   497  		KeyType:   string(defaultExportKeyType),
   498  	}
   499  
   500  	mResp, err := json.Marshal(resp)
   501  	if err != nil {
   502  		return err
   503  	}
   504  
   505  	_, err = w.Write(mResp)
   506  	if err != nil {
   507  		return err
   508  	}
   509  
   510  	return nil
   511  }
   512  
   513  func processPOSTRequestForCreateWithResponseBody(w http.ResponseWriter, r *http.Request, keysetID, kid string) error {
   514  	if valid := validateHTTPMethod(w, r); !valid {
   515  		return errors.New("http method invalid")
   516  	}
   517  
   518  	if valid := validatePostPayload(r, w); !valid {
   519  		return errors.New("http request body invalid")
   520  	}
   521  
   522  	locationHeaderURL := "https://" + r.Host + "/v1/keystores/" + keysetID
   523  
   524  	if strings.LastIndex(r.URL.Path, "/keys") == len(r.URL.Path)-len("/keys") {
   525  		locationHeaderURL += "/keys/" + kid
   526  
   527  		resp := &createKeyResp{
   528  			KeyURL: locationHeaderURL,
   529  		}
   530  
   531  		mResp, err := json.Marshal(resp)
   532  		if err != nil {
   533  			return err
   534  		}
   535  
   536  		_, err = w.Write(mResp)
   537  		if err != nil {
   538  			return err
   539  		}
   540  	}
   541  
   542  	return nil
   543  }
   544  
   545  func processPOSTRequestForImportKey(w http.ResponseWriter, r *http.Request, keysetID, kid string) error {
   546  	if valid := validateHTTPMethod(w, r); !valid {
   547  		return errors.New("http method invalid")
   548  	}
   549  
   550  	if valid := validatePostPayload(r, w); !valid {
   551  		return errors.New("http request body invalid")
   552  	}
   553  
   554  	locationHeaderURL := "https://" + r.Host + "/v1/keystores/" + keysetID
   555  
   556  	if strings.LastIndex(r.URL.Path, "/keys") == len(r.URL.Path)-len("/keys") {
   557  		locationHeaderURL += "/keys/" + kid
   558  
   559  		resp := &importKeyResp{
   560  			KeyURL: locationHeaderURL,
   561  		}
   562  
   563  		mResp, err := json.Marshal(resp)
   564  		if err != nil {
   565  			return err
   566  		}
   567  
   568  		_, err = w.Write(mResp)
   569  		if err != nil {
   570  			return err
   571  		}
   572  	}
   573  
   574  	return nil
   575  }
   576  
   577  // validateHTTPMethod validate HTTP method and content-type.
   578  func validateHTTPMethod(w http.ResponseWriter, r *http.Request) bool {
   579  	switch r.Method {
   580  	case http.MethodPost, http.MethodPut, http.MethodGet:
   581  	default:
   582  		http.Error(w, "HTTP Method not allowed", http.StatusMethodNotAllowed)
   583  		return false
   584  	}
   585  
   586  	ct := r.Header.Get("Content-type")
   587  	if ct != ContentType && r.Method == http.MethodPost {
   588  		http.Error(w, fmt.Sprintf("Unsupported Content-type \"%s\"", ct), http.StatusUnsupportedMediaType)
   589  		return false
   590  	}
   591  
   592  	return true
   593  }
   594  
   595  // validatePayload validate and get the payload from the request.
   596  func validatePostPayload(r *http.Request, w http.ResponseWriter) bool {
   597  	if r.ContentLength == 0 && r.Method == http.MethodPost { // empty payload should not be accepted for POST request
   598  		http.Error(w, "Empty payload", http.StatusBadRequest)
   599  		return false
   600  	}
   601  
   602  	return true
   603  }
   604  
   605  // CreateMockHTTPServerAndClient creates mock http server and client using tls and returns them.
   606  func CreateMockHTTPServerAndClient(t *testing.T, inHandler http.Handler) (net.Listener, string, *http.Client) {
   607  	server := startMockServer(inHandler)
   608  	port := getServerPort(server)
   609  	serverURL := fmt.Sprintf("https://localhost:%d", port)
   610  
   611  	// build a mock cert pool
   612  	cp := x509.NewCertPool()
   613  	err := addCertsToCertPool(cp)
   614  	require.NoError(t, err)
   615  
   616  	// build a tls.Config instance to be used by the outbound transport
   617  	tlsConfig := &tls.Config{ //nolint:gosec
   618  		RootCAs:      cp,
   619  		Certificates: nil,
   620  	}
   621  
   622  	// create an http client to communicate with the server that has our inbound handlers set above
   623  	client := &http.Client{
   624  		Timeout: clientTimeout,
   625  		Transport: &http.Transport{
   626  			TLSClientConfig: tlsConfig,
   627  		},
   628  	}
   629  
   630  	return server, serverURL, client
   631  }
   632  
   633  func startMockServer(handler http.Handler) net.Listener {
   634  	// ":0" will make the listener auto assign a free port
   635  	listener, err := net.Listen("tcp", "127.0.0.1:0")
   636  	if err != nil {
   637  		errorLogger.Fatalf("HTTP listener failed to start: %s", err)
   638  	}
   639  
   640  	go func() {
   641  		err := http.ServeTLS(listener, handler, certPrefix+"ec-pubCert1.pem", certPrefix+"ec-key1.pem")
   642  		if err != nil && !strings.Contains(err.Error(), "use of closed network connection") {
   643  			errorLogger.Fatalf("HTTP server failed to start: %s", err)
   644  		}
   645  	}()
   646  
   647  	return listener
   648  }
   649  
   650  func getServerPort(server net.Listener) int {
   651  	// read dynamic port assigned to the server to be used by the client
   652  	return server.Addr().(*net.TCPAddr).Port
   653  }
   654  
   655  func addCertsToCertPool(pool *x509.CertPool) error {
   656  	var rawCerts []string
   657  
   658  	// add contents of ec-pubCert(1, 2 and 3).pem to rawCerts
   659  	for i := 1; i <= 3; i++ {
   660  		certPath := fmt.Sprintf("%sec-pubCert%d.pem", certPrefix, i)
   661  		// Create a pool with server certificates
   662  		cert, e := ioutil.ReadFile(filepath.Clean(certPath))
   663  		if e != nil {
   664  			return fmt.Errorf("reading certificate failed: %w", e)
   665  		}
   666  
   667  		rawCerts = append(rawCerts, string(cert))
   668  	}
   669  
   670  	certs := decodeCerts(rawCerts)
   671  	for i := range certs {
   672  		pool.AddCert(certs[i])
   673  	}
   674  
   675  	return nil
   676  }
   677  
   678  // decodeCerts will decode a list of pemCertsList (string) into a list of x509 certificates.
   679  func decodeCerts(pemCertsList []string) []*x509.Certificate {
   680  	var certs []*x509.Certificate
   681  
   682  	for _, pemCertsString := range pemCertsList {
   683  		pemCerts := []byte(pemCertsString)
   684  		for len(pemCerts) > 0 {
   685  			var block *pem.Block
   686  
   687  			block, pemCerts = pem.Decode(pemCerts)
   688  			if block == nil {
   689  				break
   690  			}
   691  
   692  			if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
   693  				continue
   694  			}
   695  
   696  			cert, err := x509.ParseCertificate(block.Bytes)
   697  			if err != nil {
   698  				continue
   699  			}
   700  
   701  			certs = append(certs, cert)
   702  		}
   703  	}
   704  
   705  	return certs
   706  }
   707  
   708  var errFailingMarshal = errors.New("failingMarshal always fails")
   709  
   710  func failingMarshal(interface{}) ([]byte, error) {
   711  	return nil, errFailingMarshal
   712  }
   713  
   714  var errFailingUnmarshal = errors.New("failingUnmarshal always fails")
   715  
   716  func failingUnmarshal([]byte, interface{}) error {
   717  	return errFailingUnmarshal
   718  }
   719  
   720  type errFailingCloser struct{}
   721  
   722  func (c *errFailingCloser) Close() error {
   723  	return errors.New("errFailingCloser always fails")
   724  }
   725  
   726  func mockAddHeadersFuncSuccess(req *http.Request) (*http.Header, error) {
   727  	// mocking a call to an auth server to get necessary credentials.
   728  	// It only sets mock http.Header entries for testing purposes.
   729  	req.Header.Set("controller", "mockController")
   730  	req.Header.Set("authServerURL", "mockAuthServerURL")
   731  	req.Header.Set("secret", "mockSecret")
   732  
   733  	return &req.Header, nil
   734  }
   735  
   736  var errAddHeadersFunc = errors.New("mockAddHeadersFuncError always fails")
   737  
   738  func mockAddHeadersFuncError(_ *http.Request) (*http.Header, error) {
   739  	return nil, errAddHeadersFunc
   740  }