github.com/hyperledger/fabric-ca@v2.0.0-alpha.0.20201120210307-7b4f34729db1+incompatible/internal/pkg/util/util_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package util
     8  
     9  import (
    10  	"bytes"
    11  	"crypto/ecdsa"
    12  	"crypto/elliptic"
    13  	"crypto/rand"
    14  	"crypto/rsa"
    15  	"crypto/x509"
    16  	"encoding/pem"
    17  	"fmt"
    18  	"io"
    19  	"io/ioutil"
    20  	"math/big"
    21  	"net/http"
    22  	"os"
    23  	"path/filepath"
    24  	"strings"
    25  	"testing"
    26  
    27  	"github.com/hyperledger/fabric/bccsp/factory"
    28  	_ "github.com/mattn/go-sqlite3"
    29  	"github.com/spf13/viper"
    30  	"github.com/stretchr/testify/assert"
    31  )
    32  
    33  func TestGetEnrollmentIDFromPEM(t *testing.T) {
    34  	cert, err := ioutil.ReadFile(filepath.Join("testdata", "ec.pem"))
    35  	if err != nil {
    36  		t.Fatalf("TestGetEnrollmentIDFromPEM.ReadFile failed: %s", err)
    37  	}
    38  	_, err = GetEnrollmentIDFromPEM(cert)
    39  	if err != nil {
    40  		t.Fatalf("Failed to get enrollment ID from PEM: %s", err)
    41  	}
    42  }
    43  
    44  func TestECCreateToken(t *testing.T) {
    45  	cert, _ := ioutil.ReadFile(filepath.Join("testdata", "ec.pem"))
    46  	bccsp := GetDefaultBCCSP()
    47  	privKey, err := ImportBCCSPKeyFromPEM(filepath.Join("testdata", "ec-key.pem"), bccsp, true)
    48  	if err != nil {
    49  		t.Logf("Failed importing key %s", err)
    50  	}
    51  	body := []byte("request byte array")
    52  
    53  	ECtoken, err := CreateToken(bccsp, cert, privKey, "GET", "/enroll", body)
    54  	if err != nil {
    55  		t.Fatalf("CreatToken failed: %s", err)
    56  	}
    57  
    58  	os.Setenv("FABRIC_CA_SERVER_COMPATIBILITY_MODE_V1_3", "false") // Test new token
    59  	_, err = VerifyToken(bccsp, ECtoken, "GET", "/enroll", body, false)
    60  	if err != nil {
    61  		t.Fatalf("VerifyToken failed: %s", err)
    62  	}
    63  
    64  	_, err = VerifyToken(nil, ECtoken, "GET", "/enroll", body, false)
    65  	if err == nil {
    66  		t.Fatal("VerifyToken should have failed as no instance of csp is passed")
    67  	}
    68  
    69  	_, err = VerifyToken(bccsp, "", "GET", "/enroll", body, false)
    70  	if err == nil {
    71  		t.Fatal("VerifyToken should have failed as no EC Token is passed")
    72  	}
    73  
    74  	_, err = VerifyToken(bccsp, ECtoken, "GET", "/enroll", nil, false)
    75  	if err == nil {
    76  		t.Fatal("VerifyToken should have failed as no body is passed")
    77  	}
    78  
    79  	_, err = VerifyToken(bccsp, ECtoken, "POST", "/enroll", nil, false)
    80  	if err == nil {
    81  		t.Fatal("VerifyToken should have failed as method was tampered")
    82  	}
    83  
    84  	_, err = VerifyToken(bccsp, ECtoken, "GET", "/affiliations", nil, false)
    85  	if err == nil {
    86  		t.Fatal("VerifyToken should have failed as path was tampered")
    87  	}
    88  
    89  	verifiedByte := []byte("TEST")
    90  	body = append(body, verifiedByte[0])
    91  	_, err = VerifyToken(bccsp, ECtoken, "GET", "/enroll", body, false)
    92  	if err == nil {
    93  		t.Fatal("VerifyToken should have failed as body was tampered")
    94  	}
    95  
    96  	ski, skierror := ioutil.ReadFile(filepath.Join("testdata", "ec-key.ski"))
    97  	if skierror != nil {
    98  		t.Fatalf("SKI File Read failed with error : %s", skierror)
    99  	}
   100  	ECtoken, err = CreateToken(bccsp, ski, privKey, "GET", "/enroll", body)
   101  	if (err == nil) || (ECtoken != "") {
   102  		t.Fatal("CreatToken should have failed as certificate passed is not correct")
   103  	}
   104  
   105  	// With comptability mode disabled, using old token should fail
   106  	b64Cert := B64Encode(cert)
   107  	payload := B64Encode(body) + "." + b64Cert
   108  	oldToken, err := genECDSAToken(bccsp, privKey, b64Cert, payload)
   109  	FatalError(t, err, "Failed to create token")
   110  	_, err = VerifyToken(bccsp, oldToken, "GET", "/enroll", body, false)
   111  	assert.Error(t, err)
   112  
   113  	// Test that by default with no environment variable set, the old token is considered valid
   114  	os.Unsetenv("FABRIC_CA_SERVER_COMPATIBILITY_MODE_V1_3")
   115  	_, err = VerifyToken(bccsp, oldToken, "GET", "/enroll", body, true)
   116  	assert.NoError(t, err, "Failed to verify token using old token type")
   117  }
   118  
   119  func TestDecodeToken(t *testing.T) {
   120  	token := "x.y.z"
   121  	_, _, _, err := DecodeToken(token)
   122  	assert.Error(t, err, "Decode should fail if the token has more than two parts")
   123  
   124  	token = "x"
   125  	_, _, _, err = DecodeToken(token)
   126  	assert.Error(t, err, "Decode should fail if the token has less than two parts")
   127  
   128  	token = "x.y"
   129  	_, _, _, err = DecodeToken(token)
   130  	assert.Error(t, err, "Decode should fail if the 1st part of the token is not in base64 encoded format")
   131  
   132  	fakecert := B64Encode([]byte("hello"))
   133  	token = fakecert + ".y"
   134  	_, _, _, err = DecodeToken(token)
   135  	assert.Error(t, err, "Decode should fail if the 1st part of the token is not base64 bytes of a X509 cert")
   136  }
   137  func TestGetX509CertFromPem(t *testing.T) {
   138  
   139  	certBuffer, error := ioutil.ReadFile(filepath.Join("testdata", "ec.pem"))
   140  	if error != nil {
   141  		t.Fatalf("Certificate File Read from file failed with error : %s", error)
   142  	}
   143  	certificate, err := GetX509CertificateFromPEM(certBuffer)
   144  	if err != nil {
   145  		t.Fatalf("GetX509CertificateFromPEM failed with error : %s", err)
   146  	}
   147  	if certificate == nil {
   148  		t.Fatal("Certificate cannot be nil")
   149  	}
   150  
   151  	skiBuffer, skiError := ioutil.ReadFile(filepath.Join("testdata", "ec-key.ski"))
   152  	if skiError != nil {
   153  		t.Fatalf("SKI File read failed with error : %s", skiError)
   154  	}
   155  
   156  	certificate, err = GetX509CertificateFromPEM(skiBuffer)
   157  	if err == nil {
   158  		t.Fatal("GetX509CertificateFromPEM should have failed as bytes passed was not in correct format")
   159  	}
   160  	if certificate != nil {
   161  		t.Fatalf("GetX509CertificateFromPEM should have failed as bytes passed was not in correct format")
   162  	}
   163  }
   164  
   165  func TestGetX509CertsFromPem(t *testing.T) {
   166  	certBuffer, error := ioutil.ReadFile(filepath.Join("testdata", "ec.pem"))
   167  	if error != nil {
   168  		t.Fatalf("Certificate File Read from file failed with error : %s", error)
   169  	}
   170  	certificates, err := GetX509CertificatesFromPEM(certBuffer)
   171  	assert.NoError(t, err, "GetX509CertificatesFromPEM failed")
   172  	assert.NotNil(t, certificates)
   173  	assert.Equal(t, 1, len(certificates), "GetX509CertificatesFromPEM should have returned 1 certificate")
   174  
   175  	skiBuffer, skiError := ioutil.ReadFile(filepath.Join("testdata", "ec-key.ski"))
   176  	if skiError != nil {
   177  		t.Fatalf("SKI File read failed with error : %s", skiError)
   178  	}
   179  
   180  	certificates, err = GetX509CertificatesFromPEM(skiBuffer)
   181  	if err == nil {
   182  		t.Fatal("GetX509CertificatesFromPEM should have failed as bytes passed was not in correct format")
   183  	}
   184  	if certificates != nil {
   185  		t.Fatalf("GetX509CertificatesFromPEM should have failed as bytes passed was not in correct format")
   186  	}
   187  }
   188  
   189  // This test case has been removed temporarily
   190  // as BCCSP does not have support for RSA private key import
   191  /*
   192  func TestRSACreateToken(t *testing.T) {
   193  	cert, _ := ioutil.ReadFile(filepath.Join("testdata","rsa.pem"))
   194  	privKey, _ := ioutil.ReadFile(filepath.Join("testdata","rsa-key.pem"))
   195  	body := []byte("request byte array")
   196  
   197  	csp := factory.GetDefault()
   198  	RSAtoken, err := CreateToken(csp, cert, privKey, body)
   199  	if err != nil {
   200  		t.Fatalf("CreatToken failed with error : %s", err)
   201  	}
   202  
   203  	_, err = VerifyToken(csp, RSAtoken, body)
   204  	if err != nil {
   205  		t.Fatalf("VerifyToken failed with error : %s", err)
   206  	}
   207  }
   208  */
   209  
   210  func TestCreateTokenDiffKey(t *testing.T) {
   211  	cert, _ := ioutil.ReadFile(filepath.Join("testdata", "ec.pem"))
   212  	bccsp := GetDefaultBCCSP()
   213  	privKey, _ := ImportBCCSPKeyFromPEM(filepath.Join("testdata", "rsa-key.pem"), bccsp, true)
   214  	body := []byte("request byte array")
   215  	_, err := CreateToken(bccsp, cert, privKey, "POST", "/enroll", body)
   216  	if err == nil {
   217  		t.Fatalf("TestCreateTokenDiffKey passed but should have failed")
   218  	}
   219  }
   220  
   221  // TestCreateTokenDiffKey2 has been commeted out right now
   222  // As there BCCSP does not have support fot RSA private Key
   223  // import. This will be uncommented when the support is in.
   224  /*
   225  func TestCreateTokenDiffKey2(t *testing.T) {
   226  	cert, _ := ioutil.ReadFile(filepath.Join("testdata","rsa.pem"))
   227  	privKey, _ := ioutil.ReadFile(filepath.Join("testdata","ec-key.pem"))
   228  	body := []byte("request byte array")
   229  
   230  	csp := factory.GetDefault()
   231  	_, err := CreateToken(csp, cert, privKey, body)
   232  	if err == nil {
   233  		t.Fatalf("TestCreateTokenDiffKey2 passed but should have failed")
   234  	}
   235  }
   236  */
   237  
   238  func TestEmptyToken(t *testing.T) {
   239  	body := []byte("request byte array")
   240  
   241  	csp := factory.GetDefault()
   242  	_, err := VerifyToken(csp, "", "POST", "/enroll", body, true)
   243  	if err == nil {
   244  		t.Fatalf("TestEmptyToken passed but should have failed")
   245  	}
   246  }
   247  
   248  func TestEmptyCert(t *testing.T) {
   249  	cert, _ := ioutil.ReadFile(filepath.Join("testdata", "ec.pem"))
   250  	body := []byte("request byte array")
   251  
   252  	csp := factory.GetDefault()
   253  	_, err := CreateToken(csp, cert, nil, "POST", "/enroll", body)
   254  	if err == nil {
   255  		t.Fatalf("TestEmptyCert passed but should have failed")
   256  	}
   257  }
   258  
   259  func TestEmptyKey(t *testing.T) {
   260  	bccsp := GetDefaultBCCSP()
   261  	privKey, _ := ImportBCCSPKeyFromPEM(filepath.Join("testdata", "ec-key.pem"), bccsp, true)
   262  	body := []byte("request byte array")
   263  	_, err := CreateToken(bccsp, []byte(""), privKey, "POST", "/enroll", body)
   264  	if err == nil {
   265  		t.Fatalf("TestEmptyKey passed but should have failed")
   266  	}
   267  }
   268  
   269  func TestEmptyBody(t *testing.T) {
   270  	bccsp := GetDefaultBCCSP()
   271  	privKey, _ := ImportBCCSPKeyFromPEM(filepath.Join("testdata", "ec-key.pem"), bccsp, true)
   272  	cert, _ := ioutil.ReadFile(filepath.Join("testdata", "ec.pem"))
   273  	_, err := CreateToken(bccsp, cert, privKey, "POST", "/enroll", []byte(""))
   274  	if err != nil {
   275  		t.Fatalf("CreateToken failed: %s", err)
   276  	}
   277  }
   278  
   279  func TestRandomString(t *testing.T) {
   280  	str := RandomString(10)
   281  	if str == "" {
   282  		t.Fatalf("RandomString failure")
   283  	}
   284  }
   285  
   286  func TestRemoveQuotes(t *testing.T) {
   287  	str := RemoveQuotes(`"a"`)
   288  	if str != "a" {
   289  		t.Fatalf("TestRemoveQuotes failed")
   290  	}
   291  }
   292  
   293  func TestRemoveQuotesNone(t *testing.T) {
   294  	str := RemoveQuotes(`a`)
   295  	if str != "a" {
   296  		t.Fatalf("TestRemoveQuotesNone failed")
   297  	}
   298  }
   299  
   300  func TestCreateHome(t *testing.T) {
   301  	t.Log("Test Creating Home Directory")
   302  	os.Unsetenv("COP_HOME")
   303  	tempDir, err := ioutil.TempDir("", "test")
   304  	if err != nil {
   305  		t.Errorf("Failed to create temp directory [error: %s]", err)
   306  	}
   307  	os.Setenv("HOME", tempDir)
   308  
   309  	dir, err := CreateClientHome()
   310  	if err != nil {
   311  		t.Errorf("Failed to create home directory, error: %s", err)
   312  	}
   313  
   314  	if _, err = os.Stat(dir); err != nil {
   315  		if os.IsNotExist(err) {
   316  			t.Error("Failed to create home directory")
   317  		}
   318  	}
   319  
   320  	os.RemoveAll(dir)
   321  }
   322  
   323  func TestGetDefaultConfigFile(t *testing.T) {
   324  	os.Unsetenv("FABRIC_CA_HOME")
   325  	os.Unsetenv("FABRIC_CA_CLIENT_HOME")
   326  	os.Unsetenv("FABRIC_CA_SERVER_HOME")
   327  	os.Unsetenv("CA_CFG_PATH")
   328  
   329  	const clientConfig = "fabric-ca-client-config.yaml"
   330  	const serverConfig = "fabric-ca-server-config.yaml"
   331  
   332  	os.Setenv("HOME", "/tmp")
   333  
   334  	expected := filepath.Join("/tmp/.fabric-ca-client/", clientConfig)
   335  	real := GetDefaultConfigFile("fabric-ca-client")
   336  	if real != expected {
   337  		t.Errorf("Incorrect default config path retrieved; expected %s but found %s",
   338  			expected, real)
   339  	}
   340  
   341  	os.Setenv("FABRIC_CA_HOME", "/tmp")
   342  	expected = filepath.Join("/tmp", clientConfig)
   343  	real = GetDefaultConfigFile("fabric-ca-client")
   344  	if real != expected {
   345  		t.Errorf("Incorrect default config path retrieved; expected %s but found %s",
   346  			expected, real)
   347  	}
   348  
   349  	expected = filepath.Join("/tmp", serverConfig)
   350  	real = GetDefaultConfigFile("fabric-ca-server")
   351  	if real != expected {
   352  		t.Errorf("Incorrect default config path retrieved; expected %s but found %s",
   353  			expected, real)
   354  	}
   355  
   356  	os.Setenv("FABRIC_CA_CLIENT_HOME", "/tmp/client")
   357  	expected = filepath.Join("/tmp/client", clientConfig)
   358  	real = GetDefaultConfigFile("fabric-ca-client")
   359  	if real != expected {
   360  		t.Errorf("Incorrect default config path retrieved; expected %s but found %s",
   361  			expected, real)
   362  	}
   363  
   364  	os.Setenv("FABRIC_CA_SERVER_HOME", "/tmp/server")
   365  	expected = filepath.Join("/tmp/server", serverConfig)
   366  	real = GetDefaultConfigFile("fabric-ca-server")
   367  	if real != expected {
   368  		t.Errorf("Incorrect default config path retrieved; expected %s but found %s",
   369  			expected, real)
   370  	}
   371  }
   372  
   373  func TestUnmarshal(t *testing.T) {
   374  	byteArray := []byte(`{"text":"foo"}`)
   375  	type test struct {
   376  		text string
   377  	}
   378  	var Test test
   379  	err := Unmarshal(byteArray, &Test, "testing unmarshal")
   380  	if err != nil {
   381  		t.Error("Failed to unmarshal, error: ", err)
   382  	}
   383  }
   384  
   385  func TestMarshal(t *testing.T) {
   386  	var x interface{}
   387  	_, err := Marshal(x, "testing marshal")
   388  	if err != nil {
   389  		t.Error("Failed to marshal, error: ", err)
   390  	}
   391  }
   392  
   393  func TestReadFile(t *testing.T) {
   394  	_, err := ReadFile(filepath.Join("testdata", "csr.json"))
   395  	if err != nil {
   396  		t.Error("Failed to read file, error: ", err)
   397  	}
   398  }
   399  
   400  func TestWriteFile(t *testing.T) {
   401  	testdir, err := ioutil.TempDir(".", "writefiletest")
   402  	if err != nil {
   403  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   404  	}
   405  	defer os.RemoveAll(testdir)
   406  	testData := []byte("foo")
   407  	err = WriteFile(filepath.Join(testdir, "test.txt"), testData, 0777)
   408  	assert.NoError(t, err)
   409  	readOnlyDir := filepath.Join(testdir, "readonlydir")
   410  	err = os.MkdirAll(readOnlyDir, 4444)
   411  	if err != nil {
   412  		t.Fatalf("Failed to create directory: %s", err.Error())
   413  	}
   414  	err = WriteFile(filepath.Join(readOnlyDir, "test/test.txt"), testData, 0777)
   415  	assert.Error(t, err, "Should fail to create 'test' directory as the parent directory is read only")
   416  }
   417  
   418  func TestStrContained(t *testing.T) {
   419  	strs := []string{"one", "two", "three"}
   420  	str := "one"
   421  	result := StrContained(str, strs)
   422  	if result != true {
   423  		t.Error("Should have result in true")
   424  	}
   425  }
   426  
   427  func TestFileExists(t *testing.T) {
   428  	name := "testdata/csr.json"
   429  	exists := FileExists(name)
   430  	if exists == false {
   431  		t.Error("File does not exist")
   432  	}
   433  	name = "better-not-exist"
   434  	exists = FileExists(name)
   435  	if exists == true {
   436  		t.Error("File 'better-not-exist' should not exist")
   437  	}
   438  }
   439  
   440  func TestMakeFileAbs(t *testing.T) {
   441  	testMakeFileAbs(t, "", "", "")
   442  	testMakeFileAbs(t, "/a/b/c", "", "/a/b/c")
   443  	testMakeFileAbs(t, "c", "/a/b", "/a/b/c")
   444  	testMakeFileAbs(t, "../c", "/a/b", "/a/c")
   445  }
   446  
   447  func TestMakeFilesAbs(t *testing.T) {
   448  	file1 := "a"
   449  	file2 := "a/b"
   450  	file3 := "/a/b"
   451  	files := []*string{&file1, &file2, &file3}
   452  	err := MakeFileNamesAbsolute(files, "/tmp")
   453  	if err != nil {
   454  		t.Fatalf("MakeFilesAbsolute failed: %s", err)
   455  	}
   456  	if file1 != "/tmp/a" {
   457  		t.Errorf("TestMakeFilesAbs failure: expecting /tmp/a but found %s", file1)
   458  	}
   459  	if file2 != "/tmp/a/b" {
   460  		t.Errorf("TestMakeFilesAbs failure: expecting /tmp/a/b but found %s", file2)
   461  	}
   462  	if file3 != "/a/b" {
   463  		t.Errorf("TestMakeFilesAbs failure: expecting /a/b but found %s", file3)
   464  	}
   465  }
   466  
   467  func TestB64(t *testing.T) {
   468  	buf := []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
   469  	str := B64Encode(buf)
   470  	buf2, err := B64Decode(str)
   471  	if err != nil {
   472  		t.Errorf("Failed base64 decoding standard: %s", err)
   473  	}
   474  	if !bytes.Equal(buf, buf2) {
   475  		t.Error("Failed base64 decoding standard bytes aren't equal")
   476  	}
   477  }
   478  
   479  func TestGetUser(t *testing.T) {
   480  	os.Unsetenv("FABRIC_CA_CLIENT_URL")
   481  	viper.BindEnv("url", "FABRIC_CA_CLIENT_URL")
   482  	os.Setenv("FABRIC_CA_CLIENT_URL", "http://localhost:7054")
   483  	_, _, err := GetUser(viper.GetViper())
   484  	assert.Error(t, err, "Should have failed no username and password provided")
   485  
   486  	os.Setenv("FABRIC_CA_CLIENT_URL", "http://:pass@localhost:7054")
   487  	_, _, err = GetUser(viper.GetViper())
   488  	assert.Error(t, err, "Should have failed no username provided")
   489  
   490  	os.Setenv("FABRIC_CA_CLIENT_URL", "http://user:@localhost:7054")
   491  	_, _, err = GetUser(viper.GetViper())
   492  	assert.Error(t, err, "Should have failed no password provided")
   493  
   494  	os.Setenv("FABRIC_CA_CLIENT_URL", "http://foo:bar@localhost:7054")
   495  
   496  	user, pass, err := GetUser(viper.GetViper())
   497  	assert.NoError(t, err)
   498  
   499  	if user != "foo" {
   500  		t.Error("Failed to retrieve correct username")
   501  	}
   502  
   503  	if pass != "bar" {
   504  		t.Error("Failed to retrieve correct password")
   505  	}
   506  }
   507  
   508  type configID struct {
   509  	Name string `mask:"username"`
   510  	Addr string `json:"address"`
   511  	Pass string `mask:"password"`
   512  	URL  string `mask:"url"`
   513  	ID   int    `mask:"url"`
   514  }
   515  
   516  func (cc configID) String() string {
   517  	return StructToString(&cc)
   518  }
   519  
   520  func TestStructToString(t *testing.T) {
   521  	var obj configID
   522  	obj.Name = "foo"
   523  	addr := "101, penn ave"
   524  	obj.Addr = addr
   525  	obj.Pass = "bar"
   526  	str := StructToString(&obj)
   527  	if strings.Index(str, "bar") > 0 {
   528  		t.Errorf("Password is not masked by the StructToString function: %s", str)
   529  	}
   530  	if strings.Index(str, "foo") > 0 {
   531  		t.Errorf("Name is not masked by the StructToString function: %s", str)
   532  	}
   533  	if strings.Index(str, addr) < 0 {
   534  		t.Errorf("Addr is masked by the StructToString function: %s", str)
   535  	}
   536  
   537  	type registry struct {
   538  		MaxEnrollments int
   539  		Identities     []configID
   540  	}
   541  	type config struct {
   542  		Registry     registry
   543  		Affiliations map[string]interface{}
   544  	}
   545  	affiliations := map[string]interface{}{"org1": nil}
   546  	caConfig := config{
   547  		Affiliations: affiliations,
   548  		Registry: registry{
   549  			MaxEnrollments: -1,
   550  			Identities: []configID{
   551  				configID{
   552  					Name: "foo",
   553  					Pass: "foopwd",
   554  					Addr: "user",
   555  					URL:  "http://foo:foopwd@localhost:7054",
   556  					ID:   2,
   557  				},
   558  				configID{
   559  					Name: "bar",
   560  					Pass: "barpwd",
   561  					Addr: "user",
   562  					URL:  "ldap://foo:foopwd@localhost:7054",
   563  					ID:   3,
   564  				},
   565  			},
   566  		},
   567  	}
   568  	caConfigStr := fmt.Sprintf("caConfig=%+v", caConfig)
   569  	assert.NotContains(t, caConfigStr, "foopwd", "Identity password is not masked in the output")
   570  	assert.NotContains(t, caConfigStr, "barpwd", "Identity password is not masked in the output")
   571  	idStr := fmt.Sprintf("Identity[0]=%+v", caConfig.Registry.Identities[0])
   572  	assert.NotContains(t, idStr, "foopwd", "Identity password is not masked in the output")
   573  	idStr = fmt.Sprintf("Identity[1]=%+v", &caConfig.Registry.Identities[1])
   574  	assert.NotContains(t, idStr, "barpwd", "Identity password is not masked in the output")
   575  }
   576  
   577  func TestNormalizeStringSlice(t *testing.T) {
   578  	var tests = []struct {
   579  		slice    []string
   580  		expected []string
   581  	}{
   582  		{
   583  			slice:    []string{"string1"},
   584  			expected: []string{"string1"},
   585  		},
   586  		{
   587  			slice:    []string{" string1"},
   588  			expected: []string{"string1"},
   589  		},
   590  		{
   591  			slice:    []string{" string1   "},
   592  			expected: []string{"string1"},
   593  		},
   594  		{
   595  			slice:    []string{" string1   "},
   596  			expected: []string{"string1"},
   597  		},
   598  		{
   599  			slice:    []string{"string1", "string2"},
   600  			expected: []string{"string1", "string2"},
   601  		},
   602  		{
   603  			slice:    []string{"string1", "   string2"},
   604  			expected: []string{"string1", "string2"},
   605  		},
   606  	}
   607  
   608  	for _, test := range tests {
   609  		actual := NormalizeStringSlice(test.slice)
   610  		assert.Equal(t, test.expected, actual)
   611  	}
   612  }
   613  
   614  // Test file list with multiple and single entries both with and without brackets
   615  func TestNormalizeFileList(t *testing.T) {
   616  	slice := []string{"[file0,file1]", "file2,file3", "file4", "[file5]"}
   617  	slice, err := NormalizeFileList(slice, "testdata")
   618  	if err != nil {
   619  		t.Fatalf("Failed to normalize files list, error: %s", err)
   620  	}
   621  	assert.Equal(t, 6, len(slice), "Invalid slice length")
   622  	for i := range slice {
   623  		if !strings.HasSuffix(slice[i], fmt.Sprintf("file%d", i)) {
   624  			t.Errorf("Failed to normalize files list for element %d; found '%s'", i, slice[i])
   625  		}
   626  	}
   627  }
   628  
   629  func testMakeFileAbs(t *testing.T, file, dir, expect string) {
   630  	path, err := MakeFileAbs(file, dir)
   631  	if err != nil {
   632  		t.Errorf("Failed to make %s absolute: %s", file, err)
   633  	}
   634  	// make expected path platform specific to work on Windows
   635  	if expect != "" {
   636  		expect, _ = filepath.Abs(expect)
   637  	}
   638  	if path != expect {
   639  		t.Errorf("Absolute of file=%s with dir=%s expected %s but was %s", file, dir, expect, path)
   640  	}
   641  }
   642  
   643  func TestRemoveQuotesInvalidArgs(t *testing.T) {
   644  	res := RemoveQuotes("")
   645  	assert.Equal(t, "", res)
   646  }
   647  
   648  func TestUnmarshalInvalidArgs(t *testing.T) {
   649  	err := Unmarshal(nil, nil, "")
   650  	assert.Error(t, err)
   651  	assert.Contains(t, err.Error(), "Failed to unmarshal ")
   652  }
   653  
   654  func TestStrContainedInvalidArgs(t *testing.T) {
   655  	res := StrContained("Hello World", nil)
   656  	assert.False(t, res)
   657  }
   658  
   659  func TestGetSerialAsHex(t *testing.T) {
   660  	res := GetSerialAsHex(big.NewInt(101))
   661  	assert.Equal(t, "65", res)
   662  }
   663  
   664  func TestECPrivateKey(t *testing.T) {
   665  	_, err := GetECPrivateKey(getPEM(filepath.Join("testdata", "ec-key.pem"), t))
   666  	assert.NoError(t, err)
   667  
   668  	rsaKey, err := rsa.GenerateKey(rand.Reader, 256)
   669  	if err != nil {
   670  		t.Fatalf("Failed to create rsa key: %s", err.Error())
   671  	}
   672  	encodedPK, err := x509.MarshalPKCS8PrivateKey(rsaKey)
   673  	if err != nil {
   674  		t.Fatalf("Failed to marshal RSA private key: %s", err.Error())
   675  	}
   676  
   677  	pemEncodedPK := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: encodedPK})
   678  	_, err = GetECPrivateKey(pemEncodedPK)
   679  	assert.Error(t, err)
   680  
   681  	_, err = GetECPrivateKey([]byte("hello"))
   682  	assert.Error(t, err)
   683  
   684  	_, err = GetECPrivateKey(pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: []byte("hello")}))
   685  	assert.Error(t, err)
   686  }
   687  
   688  func TestPKCS8WrappedECPrivateKey(t *testing.T) {
   689  	_, err := GetECPrivateKey(getPEM(filepath.Join("testdata", "pkcs8eckey.pem"), t))
   690  	assert.NoError(t, err)
   691  }
   692  
   693  func TestRSAPrivateKey(t *testing.T) {
   694  	_, err := GetRSAPrivateKey([]byte("hello"))
   695  	assert.Error(t, err)
   696  
   697  	_, err = GetRSAPrivateKey(getPEM(filepath.Join("testdata", "rsa-key.pem"), t))
   698  	assert.NoError(t, err)
   699  
   700  	rsaKey, err := rsa.GenerateKey(rand.Reader, 256)
   701  	if err != nil {
   702  		t.Fatalf("Failed to create rsa key: %s", err.Error())
   703  	}
   704  	encodedPK, err := x509.MarshalPKCS8PrivateKey(rsaKey)
   705  	if err != nil {
   706  		t.Fatalf("Failed to marshal RSA private key: %s", err.Error())
   707  	}
   708  
   709  	pemEncodedPK := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: encodedPK})
   710  	_, err = GetRSAPrivateKey(pemEncodedPK)
   711  	assert.NoError(t, err)
   712  
   713  	_, err = GetRSAPrivateKey(pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: []byte("hello")}))
   714  	assert.Error(t, err)
   715  
   716  	ecdsaKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
   717  	if err != nil {
   718  		t.Fatalf("Failed to create rsa key: %s", err.Error())
   719  	}
   720  	encodedPK, err = x509.MarshalPKCS8PrivateKey(ecdsaKey)
   721  	if err != nil {
   722  		t.Fatalf("Failed to marshal RSA private key: %s", err.Error())
   723  	}
   724  
   725  	pemEncodedPK = pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: encodedPK})
   726  	_, err = GetRSAPrivateKey(pemEncodedPK)
   727  	assert.Error(t, err)
   728  }
   729  
   730  func TestCheckHostsInCert(t *testing.T) {
   731  	err := CheckHostsInCert("testdata/doesnotexist.pem", "")
   732  	assert.Error(t, err)
   733  
   734  	err = CheckHostsInCert(filepath.Join("testdata", "tls_server-cert.pem"), "localhost")
   735  	assert.NoError(t, err, fmt.Sprintf("Failed to find 'localhost' for host in certificate: %s", err))
   736  
   737  	err = CheckHostsInCert("testdata/tls_server-cert.pem", "localhost", "fakehost")
   738  	assert.Error(t, err, "Certificate does not contain 'fakehost', should have failed")
   739  
   740  	err = CheckHostsInCert("testdata/root.pem", "x")
   741  	assert.Error(t, err, "Certificate contained no host, should have failed")
   742  }
   743  
   744  func TestCertDuration(t *testing.T) {
   745  	d, err := GetCertificateDurationFromFile(filepath.Join("testdata", "ec.pem"))
   746  	assert.NoError(t, err)
   747  	assert.True(t, d.Hours() == 43800, "Expected certificate duration of 43800h in ec.pem")
   748  	_, err = GetCertificateDurationFromFile("bogus.pem")
   749  	assert.Error(t, err)
   750  }
   751  
   752  type MyReader struct {
   753  	buf                   []byte
   754  	maxPerRead, bytesRead int
   755  }
   756  
   757  func (r *MyReader) Read(data []byte) (int, error) {
   758  	if r.bytesRead >= len(r.buf) {
   759  		return 0, io.EOF
   760  	}
   761  	buf := r.buf[r.bytesRead:]
   762  	count := 0
   763  	for i, v := range buf {
   764  		if i >= len(data) || count > r.maxPerRead {
   765  			break
   766  		}
   767  		data[i] = v
   768  		count++
   769  	}
   770  	r.bytesRead = r.bytesRead + count
   771  	return count, nil
   772  }
   773  
   774  func TestRead(t *testing.T) {
   775  	myReader := MyReader{
   776  		buf:        []byte("123456789012345"),
   777  		maxPerRead: 6,
   778  	}
   779  
   780  	// Test with a buffer that is too small to fit data
   781  	buf := make([]byte, 10)
   782  	data, err := Read(&myReader, buf)
   783  	assert.Error(t, err, "Should have errored, the data passed is bigger than the buffer")
   784  
   785  	// Test with a buffer that is big enough to fit data
   786  	buf = make([]byte, 25)
   787  	myReader.bytesRead = 0
   788  	data, err = Read(&myReader, buf)
   789  	if assert.NoError(t, err, fmt.Sprintf("Error occured during read: %s", err)) {
   790  		if string(data) != string(myReader.buf) {
   791  			t.Error("The data returned does not match")
   792  		}
   793  	}
   794  
   795  	// Test with a buffer with exact size of data
   796  	buf = make([]byte, len(myReader.buf))
   797  	myReader.bytesRead = 0
   798  	data, err = Read(&myReader, buf)
   799  	if assert.NoError(t, err, fmt.Sprintf("Error occured during exact size read: %s", err)) {
   800  		if string(data) != string(myReader.buf) {
   801  			t.Error("The data returned does not match")
   802  		}
   803  	}
   804  }
   805  
   806  func getPEM(file string, t *testing.T) []byte {
   807  	buf, err := ioutil.ReadFile(file)
   808  	assert.NoError(t, err)
   809  	return buf
   810  }
   811  
   812  func TestIsSubsetOf(t *testing.T) {
   813  	testIsSubsetOf(t, "a,b", "b,a,c", true)
   814  	testIsSubsetOf(t, "a,b", "b,a", true)
   815  	testIsSubsetOf(t, "a,b,c", "a,b", false)
   816  	testIsSubsetOf(t, "a,b,c", "", false)
   817  }
   818  
   819  func testIsSubsetOf(t *testing.T, small, large string, expectToPass bool) {
   820  	err := IsSubsetOf(small, large)
   821  	if expectToPass {
   822  		if err != nil {
   823  			t.Errorf("IsSubsetOf('%s','%s') failed: %s", small, large, err)
   824  		}
   825  	} else {
   826  		if err == nil {
   827  			t.Errorf("IsSubsetOf('%s','%s') expected error but passed", small, large)
   828  		}
   829  	}
   830  }
   831  
   832  func TestHostname(t *testing.T) {
   833  	host := Hostname()
   834  	assert.NotEqual(t, "", host, "Hostname should not be empty")
   835  }
   836  
   837  func TestHTTPRequestToString(t *testing.T) {
   838  	url := "http://localhost:7054"
   839  	reqBody := "Hello"
   840  	req, err := http.NewRequest("POST", url, strings.NewReader(reqBody))
   841  	if err != nil {
   842  		t.Errorf("Failed to create a request: %s", err)
   843  	} else {
   844  		reqStr := HTTPRequestToString(req)
   845  		assert.Contains(t, reqStr, url)
   846  		assert.Contains(t, reqStr, "POST")
   847  		assert.Contains(t, reqStr, reqBody)
   848  	}
   849  }
   850  
   851  func TestValidateAndReturnAbsConf(t *testing.T) {
   852  	var err error
   853  	var filename, homeDir string
   854  
   855  	filename, _, err = ValidateAndReturnAbsConf("/tmp/test.yaml", "/tmp/homeDir", "fabric-ca-client")
   856  	assert.NoError(t, err, "Should not have errored out, this is a valid configuration")
   857  
   858  	if filename != "/tmp/test.yaml" {
   859  		t.Error("Failed to get correct path for configuration file")
   860  	}
   861  
   862  	filename, homeDir, err = ValidateAndReturnAbsConf("", "testdata/tmp", "fabric-ca-client")
   863  	assert.NoError(t, err, "Should not have errored out, this is a valid configuration")
   864  
   865  	homeDirAbs, err := filepath.Abs("testdata/tmp")
   866  	if err != nil {
   867  		t.Fatal("Error occured getting absolute path: ", err)
   868  	}
   869  
   870  	if homeDir != homeDirAbs {
   871  		t.Error("Failed to get correct path for home directory")
   872  	}
   873  
   874  	if filename != filepath.Join(homeDirAbs, "fabric-ca-client-config.yaml") {
   875  		t.Error("Failed to get correct path for configuration file")
   876  	}
   877  
   878  	// Test with no home directory set
   879  	filename, _, err = ValidateAndReturnAbsConf("/tmp/test.yaml", "", "fabric-ca-client")
   880  	assert.NoError(t, err, "Should not have errored out, this is a valid configuration")
   881  
   882  	if filename != "/tmp/test.yaml" {
   883  		t.Error("Failed to get correct path for configuration file")
   884  	}
   885  
   886  	filename, homeDir, err = ValidateAndReturnAbsConf("testdata/tmp/test.yaml", "", "fabric-ca-client")
   887  	assert.NoError(t, err, "Should not have errored out, this is a valid configuration")
   888  
   889  	homeDirAbs, err = filepath.Abs("testdata/tmp")
   890  	if err != nil {
   891  		t.Fatal("Error occured getting absolute path: ", err)
   892  	}
   893  
   894  	if homeDir != homeDirAbs {
   895  		t.Error("Failed to get correct path for home directory")
   896  	}
   897  
   898  	if filename != filepath.Join(homeDirAbs, "test.yaml") {
   899  		t.Error("Failed to get correct path for configuration file")
   900  	}
   901  }
   902  
   903  func TestListContains(t *testing.T) {
   904  	list := "peer, client,orderer, *"
   905  	found := ListContains(list, "*")
   906  	assert.Equal(t, found, true)
   907  
   908  	list = "peer, client,orderer"
   909  	found = ListContains(list, "*")
   910  	assert.Equal(t, found, false)
   911  }