diff --git a/api/client.go b/api/client.go index ccb6f4d0b..7b29065a2 100644 --- a/api/client.go +++ b/api/client.go @@ -52,17 +52,17 @@ type RegistrationResponse struct { // EnrollmentRequest is a request to enroll an identity type EnrollmentRequest struct { // The identity name to enroll - Name string `json:"name"` + Name string `json:"name" skip:"true"` // The secret returned via Register - Secret string `json:"secret,omitempty"` + Secret string `json:"secret,omitempty" skip:"true"` // Hosts is a comma-separated host list in the CSR - Hosts string `json:"hosts,omitempty"` + Hosts string `json:"hosts,omitempty" help:"Comma-separated host list"` // Profile is the name of the signing profile to use in issuing the certificate - Profile string `json:"profile,omitempty"` + Profile string `json:"profile,omitempty" help:"Name of the signing profile to use in issuing the certificate"` // Label is the label to use in HSM operations - Label string `json:"label,omitempty"` + Label string `json:"label,omitempty" help:"Label to use in HSM operations"` // CSR is Certificate Signing Request info - CSR *CSRInfo `json:"csr,omitempty"` + CSR *CSRInfo `json:"csr,omitempty" help:"Certificate Signing Request info"` } // ReenrollmentRequest is a request to reenroll an identity. diff --git a/cli/server/config.go b/cli/server/config.go index a7976b21e..384b66b34 100644 --- a/cli/server/config.go +++ b/cli/server/config.go @@ -180,7 +180,7 @@ func configInit(cfg *cli.Config) { // Make TLS client files absolute func absTLSClient(cfg *tls.ClientTLSConfig) { for i := 0; i < len(cfg.CertFiles); i++ { - cfg.CertFiles[i] = abs(cfg.CertFiles[i]) + cfg.CertFilesList[i] = abs(cfg.CertFilesList[i]) } cfg.Client.CertFile = abs(cfg.Client.CertFile) cfg.Client.KeyFile = abs(cfg.Client.KeyFile) diff --git a/cmd/fabric-ca-client/config.go b/cmd/fabric-ca-client/config.go index a3ae46800..b76c0d6ef 100644 --- a/cmd/fabric-ca-client/config.go +++ b/cmd/fabric-ca-client/config.go @@ -26,6 +26,7 @@ import ( "github.com/cloudflare/cfssl/log" "github.com/hyperledger/fabric-ca/lib" + "github.com/hyperledger/fabric-ca/lib/tls" "github.com/hyperledger/fabric-ca/util" "github.com/spf13/viper" ) @@ -76,39 +77,39 @@ const ( ############################################################################# # URL of the Fabric-ca-server (default: http://localhost:7054) -serverURL: <<>> +URL: <<>> ############################################################################# # TLS section for the client's listenting port ############################################################################# tls: - # Enable TLS (default: false) - enabled: false + # Enable TLS (default: false) + enabled: false - # TLS for the client's listenting port (default: false) - certfiles: - client: - certfile: - keyfile: + # TLS for the client's listenting port (default: false) + certfiles: # Comma Separated (e.g. root.pem, root2.pem) + client: + certfile: + keyfile: ############################################################################# # Certificate Signing Request section for generating the CSR for # an enrollment certificate (ECert) ############################################################################# csr: - cn: <<>> - names: - - C: US - ST: "North Carolina" - L: - O: Hyperledger - OU: Fabric - hosts: - - <<>> - ca: - pathlen: - pathlenzero: - expiry: + cn: <<>> + names: + - C: US + ST: "North Carolina" + L: + O: Hyperledger + OU: Fabric + hosts: + - <<>> + ca: + pathlen: + pathlenzero: + expiry: ` ) @@ -157,12 +158,20 @@ func configInit() error { } // Unmarshal the config into 'clientCfg' - clientCfg = new(lib.ClientConfig) err = viper.Unmarshal(clientCfg) if err != nil { util.Fatal("Failed to unmarshall client config: %s", err) } + purl, err := url.Parse(clientCfg.URL) + if err != nil { + return err + } + + clientCfg.TLS.Enabled = purl.Scheme == "https" + + processCertFiles(&clientCfg.TLS) + return nil } @@ -194,3 +203,13 @@ func createDefaultConfigFile() error { // Now write the file return ioutil.WriteFile(cfgFileName, []byte(cfg), 0755) } + +// processCertFiles parses comma seperated string to generate a string array +func processCertFiles(cfg *tls.ClientTLSConfig) { + CertFiles := strings.Split(cfg.CertFiles, ",") + cfg.CertFilesList = make([]string, 0) + + for i := range CertFiles { + cfg.CertFilesList = append(cfg.CertFilesList, strings.TrimSpace(CertFiles[i])) + } +} diff --git a/cmd/fabric-ca-client/enroll.go b/cmd/fabric-ca-client/enroll.go index b938b33c4..869ab9e71 100644 --- a/cmd/fabric-ca-client/enroll.go +++ b/cmd/fabric-ca-client/enroll.go @@ -18,13 +18,13 @@ package main import ( "fmt" + "io/ioutil" "path/filepath" + "strings" "github.com/cloudflare/cfssl/log" - "github.com/hyperledger/fabric-ca/api" - "github.com/hyperledger/fabric-ca/lib" - "github.com/hyperledger/fabric-ca/util" "github.com/spf13/cobra" + "github.com/spf13/viper" ) var ( @@ -59,22 +59,20 @@ func init() { func runEnroll() error { log.Debug("Entered Enroll") - user, pass, err := util.GetUser() + rawurl := viper.GetString("url") + ID, err := clientCfg.Enroll(rawurl, filepath.Dir(cfgFileName)) if err != nil { return err } - req := &api.EnrollmentRequest{ - Name: user, - Secret: pass, + cfgFile, err := ioutil.ReadFile(cfgFileName) + if err != nil { + return err } - client := lib.Client{ - HomeDir: filepath.Dir(cfgFileName), - Config: clientCfg, - } + cfg := strings.Replace(string(cfgFile), "<<>>", ID.GetName(), 1) - ID, err := client.Enroll(req) + err = ioutil.WriteFile(cfgFileName, []byte(cfg), 0644) if err != nil { return err } @@ -85,7 +83,7 @@ func runEnroll() error { } log.Infof("Enrollment information was successfully stored in %s and %s", - client.GetMyKeyFile(), client.GetMyCertFile()) + ID.GetMyKeyFile(), ID.GetMyCertFile()) return nil } diff --git a/cmd/fabric-ca-client/main.go b/cmd/fabric-ca-client/main.go index 8fb3d529f..4ee723966 100644 --- a/cmd/fabric-ca-client/main.go +++ b/cmd/fabric-ca-client/main.go @@ -21,6 +21,7 @@ import ( "strings" "github.com/cloudflare/cfssl/log" + "github.com/hyperledger/fabric-ca/lib" "github.com/hyperledger/fabric-ca/util" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -38,6 +39,9 @@ var rootCmd = &cobra.Command{ } util.CmdRunBegin() + + log.Debugf("Client configuration settings: %+v", clientCfg) + return nil }, } @@ -54,8 +58,6 @@ func init() { viper.SetEnvPrefix(envVarPrefix) viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) - url := util.GetServerURL() - host, err := os.Hostname() if err != nil { log.Error(err) @@ -64,10 +66,18 @@ func init() { // Set global flags used by all commands pflags := rootCmd.PersistentFlags() pflags.StringVarP(&cfgFileName, "config", "c", cfg, "Configuration file") - util.FlagString(pflags, "url", "u", url, "URL of the Fabric-ca server") util.FlagString(pflags, "myhost", "m", host, "Hostname to include in the certificate signing request during enrollment") - util.FlagBool(pflags, "debug", "d", false, "Enable debug logging") + + clientCfg = &lib.ClientConfig{} + tags := map[string]string{ + "help.csr.cn": "The common name field of the certificate signing request to a parent fabric-ca-server", + "help.csr.serialnumber": "The serial number in a certificate signing request to a parent fabric-ca-server", + } + err = util.RegisterFlags(pflags, clientCfg, tags) + if err != nil { + panic(err) + } } diff --git a/cmd/fabric-ca-client/main_test.go b/cmd/fabric-ca-client/main_test.go index 86f3b6259..3d2ccbc9d 100644 --- a/cmd/fabric-ca-client/main_test.go +++ b/cmd/fabric-ca-client/main_test.go @@ -17,39 +17,37 @@ limitations under the License. package main import ( - "fmt" "io/ioutil" "os" "path" "path/filepath" "strings" "testing" - "time" - "github.com/hyperledger/fabric-ca/cli/server" + "github.com/cloudflare/cfssl/csr" + "github.com/hyperledger/fabric-ca/lib" "github.com/hyperledger/fabric-ca/util" ) const ( testYaml = "test.yaml" myhost = "hostname" + certfile = "ec.pem" + keyfile = "ec-key.pem" + tdDir = "../../testdata" + db = "fabric-ca-server.db" ) var ( - defYaml string - tdDir = "../../testdata" - cfgFile = "testconfig.json" - fabricCADB = path.Join(tdDir, "fabric-ca.db") - clientConfig = path.Join(tdDir, "client-config.json") - rrFile = path.Join(tdDir, "registerrequest.json") - serverStarted bool - serverExitCode = 0 + defYaml string + fabricCADB = path.Join(tdDir, db) + rrFile = path.Join(tdDir, "registerrequest.json") ) // TestCreateDefaultConfigFile test to make sure default config file gets generated correctly func TestCreateDefaultConfigFile(t *testing.T) { defYaml = util.GetDefaultConfigFile("fabric-ca-client") - os.RemoveAll(defYaml) + os.Remove(defYaml) fabricCAServerURL := "http://localhost:7058" @@ -73,36 +71,71 @@ func TestCreateDefaultConfigFile(t *testing.T) { t.Error("Failed to update default config file with host name") } - os.RemoveAll(defYaml) + os.Remove(defYaml) } -func startServer() { - if !serverStarted { - os.Remove(fabricCADB) - serverStarted = true - fmt.Println("starting fabric-ca server ...") - go runServer() - time.Sleep(10 * time.Second) - fmt.Println("fabric-ca server started") - } else { - fmt.Println("fabric-ca server already started") +func TestClientCommandsNoTLS(t *testing.T) { + os.Remove(fabricCADB) + + srv := getServer() + srv.HomeDir = tdDir + + err := srv.RegisterBootstrapUser("admin", "adminpw", "bank1") + if err != nil { + t.Errorf("Failed to register bootstrap user: %s", err) + } + + err = srv.RegisterBootstrapUser("admin2", "adminpw2", "bank1") + if err != nil { + t.Errorf("Failed to register bootstrap user: %s", err) + } + + aff := make(map[string]interface{}) + aff["bank_a"] = "banks" + + srv.Config.Affiliations = aff + + err = srv.Start() + if err != nil { + t.Errorf("Server start failed: %s", err) + } + + testEnroll(t) + testReenroll(t) + testRegister(t) + testRevoke(t) + testBogus(t) + + err = srv.Stop() + if err != nil { + t.Errorf("Server stop failed: %s", err) } } -func runServer() { - os.Setenv("FABRIC_CA_DEBUG", "true") - s := new(server.Server) - s.ConfigDir = tdDir - s.ConfigFile = cfgFile - s.StartFromConfig = false - s.Start() +func getServer() *lib.Server { + return &lib.Server{ + HomeDir: ".", + Config: getServerConfig(), + } } -// TestEnroll tests fabric-ca-client enroll -func TestEnroll(t *testing.T) { - startServer() +func getServerConfig() *lib.ServerConfig { + return &lib.ServerConfig{ + Debug: true, + Port: 7054, + CA: lib.ServerConfigCA{ + Keyfile: keyfile, + Certfile: certfile, + }, + CSR: csr.CertificateRequest{ + CN: "TestCN", + }, + } +} +// TestEnroll tests fabric-ca-client enroll +func testEnroll(t *testing.T) { t.Log("Testing Enroll CMD") defYaml = util.GetDefaultConfigFile("fabric-ca-client") @@ -136,7 +169,7 @@ func TestEnroll(t *testing.T) { } // TestReenroll tests fabric-ca-client reenroll -func TestReenroll(t *testing.T) { +func testReenroll(t *testing.T) { t.Log("Testing Reenroll CMD") defYaml = util.GetDefaultConfigFile("fabric-ca-client") @@ -155,7 +188,7 @@ func TestReenroll(t *testing.T) { } // TestRegister tests fabric-ca-client register -func TestRegister(t *testing.T) { +func testRegister(t *testing.T) { t.Log("Testing Register CMD") defYaml = util.GetDefaultConfigFile("fabric-ca-client") @@ -164,14 +197,14 @@ func TestRegister(t *testing.T) { t.Error("Should have failed, no register request file provided") } - err = RunMain([]string{cmdName, "register", "-f", "../../testdata/registerrequest.json"}) + err = RunMain([]string{cmdName, "register", "-f", rrFile}) if err != nil { t.Errorf("client register -f failed: %s", err) } os.Remove(defYaml) // Delete default config file - err = RunMain([]string{cmdName, "register", "--url", "http://localhost:7055", "-f", "../../testdata/registerrequest.json"}) + err = RunMain([]string{cmdName, "register", "--url", "http://localhost:7055", "-f", rrFile}) if err == nil { t.Error("Should have failed, client config file should have incorrect port (7055) for server") } @@ -181,7 +214,7 @@ func TestRegister(t *testing.T) { } // TestRevoke tests fabric-ca-client revoke -func TestRevoke(t *testing.T) { +func testRevoke(t *testing.T) { t.Log("Testing Revoke CMD") defYaml = util.GetDefaultConfigFile("fabric-ca-client") @@ -210,15 +243,133 @@ func TestRevoke(t *testing.T) { } // TestBogus tests a negative test case -func TestBogus(t *testing.T) { +func testBogus(t *testing.T) { err := RunMain([]string{cmdName, "bogus"}) if err == nil { t.Errorf("client bogus passed but should have failed") } } +func TestClientCommandsUsingConfigFile(t *testing.T) { + os.Remove(fabricCADB) + + srv := getServer() + srv.Config.Debug = true + + err := srv.RegisterBootstrapUser("admin", "adminpw", "bank1") + if err != nil { + t.Errorf("Failed to register bootstrap user: %s", err) + } + + srv.HomeDir = tdDir + srv.Config.TLS.Enabled = true + srv.Config.TLS.CertFile = "tls_server-cert.pem" + srv.Config.TLS.KeyFile = "tls_server-key.pem" + + err = srv.Start() + if err != nil { + t.Errorf("Server start failed: %s", err) + } + + err = RunMain([]string{cmdName, "enroll", "-c", "../../testdata/fabric-ca-client-config.yaml", "-u", "https://admin:adminpw@localhost:7054", "-d"}) + if err != nil { + t.Errorf("client enroll -c -u failed: %s", err) + } + + err = srv.Stop() + if err != nil { + t.Errorf("Server stop failed: %s", err) + } +} + +func TestClientCommandsTLSEnvVar(t *testing.T) { + os.Remove(fabricCADB) + + srv := getServer() + srv.Config.Debug = true + + err := srv.RegisterBootstrapUser("admin", "adminpw", "bank1") + if err != nil { + t.Errorf("Failed to register bootstrap user: %s", err) + } + + err = srv.RegisterBootstrapUser("admin2", "adminpw2", "bank1") + if err != nil { + t.Errorf("Failed to register bootstrap user: %s", err) + } + + srv.HomeDir = tdDir + srv.Config.TLS.Enabled = true + srv.Config.TLS.CertFile = "tls_server-cert.pem" + srv.Config.TLS.KeyFile = "tls_server-key.pem" + + err = srv.Start() + if err != nil { + t.Errorf("Server start failed: %s", err) + } + + os.Setenv("FABRIC_CA_CLIENT_TLS_CERTFILES", "root.pem") + os.Setenv("FABRIC_CA_CLIENT_TLS_CLIENT_KEYFILE", "tls_client-key.pem") + os.Setenv("FABRIC_CA_CLIENT_TLS_CLIENT_CERTFILE", "tls_client-cert.pem") + + err = RunMain([]string{cmdName, "enroll", "-c", "../../testdata/test.yaml", "-u", "https://admin:adminpw@localhost:7054", "-d"}) + if err != nil { + t.Errorf("client enroll -c -u failed: %s", err) + } + + err = srv.Stop() + if err != nil { + t.Errorf("Server stop failed: %s", err) + } + + os.Unsetenv("FABRIC_CA_CLIENT_TLS_CERTFILES") + os.Unsetenv("FABRIC_CA_CLIENT_TLS_CLIENT_KEYFILE") + os.Unsetenv("FABRIC_CA_CLIENT_TLS_CLIENT_CERTFILE") + +} + +func TestClientCommandsTLS(t *testing.T) { + os.Remove(fabricCADB) + + srv := getServer() + srv.Config.Debug = true + + err := srv.RegisterBootstrapUser("admin", "adminpw", "bank1") + if err != nil { + t.Errorf("Failed to register bootstrap user: %s", err) + } + + err = srv.RegisterBootstrapUser("admin2", "adminpw2", "bank1") + if err != nil { + t.Errorf("Failed to register bootstrap user: %s", err) + } + + srv.HomeDir = tdDir + srv.Config.TLS.Enabled = true + srv.Config.TLS.CertFile = "tls_server-cert.pem" + srv.Config.TLS.KeyFile = "tls_server-key.pem" + + err = srv.Start() + if err != nil { + t.Errorf("Server start failed: %s", err) + } + + err = RunMain([]string{cmdName, "enroll", "-c", "../../testdata/test.yaml", "--tls.certfiles", "root.pem", "--tls.client.keyfile", "tls_client-key.pem", "--tls.client.certfile", "tls_client-cert.pem", "-u", "https://admin:adminpw@localhost:7054", "-d"}) + if err != nil { + t.Errorf("client enroll -c -u failed: %s", err) + } + + err = srv.Stop() + if err != nil { + t.Errorf("Server stop failed: %s", err) + } +} + func TestCleanUp(t *testing.T) { os.Remove("cert.pem") os.Remove("key.pem") + os.Remove("../../testdata/cert.pem") + os.Remove("../../testdata/key.pem") + os.Remove("../../testdata/test.yaml") os.Remove(fabricCADB) } diff --git a/lib/client.go b/lib/client.go index 71cac4e88..973e40973 100644 --- a/lib/client.go +++ b/lib/client.go @@ -290,13 +290,22 @@ func (c *Client) SendPost(req *http.Request) (interface{}, error) { reqStr := util.HTTPRequestToString(req) log.Debugf("Sending request\n%s", reqStr) - tlsConfig, err := tls.GetClientTLSConfig(&c.Config.TLS) - if err != nil { - return nil, fmt.Errorf("Failed to get client TLS config [%s]; not sending\n%s", err, reqStr) - } + var tr = new(http.Transport) + + if c.Config.TLS.Enabled { + log.Info("TLS Enabled") + + err := tls.AbsTLSClient(&c.Config.TLS, c.HomeDir) + if err != nil { + return nil, err + } + + tlsConfig, err := tls.GetClientTLSConfig(&c.Config.TLS) + if err != nil { + return nil, fmt.Errorf("Failed to get client TLS config: %s", err) + } - tr := &http.Transport{ - TLSClientConfig: tlsConfig, + tr.TLSClientConfig = tlsConfig } httpClient := &http.Client{Transport: tr} diff --git a/lib/client_test.go b/lib/client_test.go index 90118bc56..11c1cc5e3 100644 --- a/lib/client_test.go +++ b/lib/client_test.go @@ -37,7 +37,7 @@ var ( fcaDB = path.Join(tdDir, "fabric-ca.db") cfgFile = path.Join(tdDir, "config.json") testCfgFile = "testconfig.json" - clientConfig = path.Join(tdDir, "client-config2.json") + clientConfig = path.Join(tdDir, "client-config.json") csrFile = path.Join(tdDir, "csr.json") ) diff --git a/lib/clientconfig.go b/lib/clientconfig.go index 5df638f8b..1f3f65b66 100644 --- a/lib/clientconfig.go +++ b/lib/clientconfig.go @@ -19,15 +19,18 @@ package lib import ( "net/url" + "github.com/cloudflare/cfssl/csr" "github.com/hyperledger/fabric-ca/api" "github.com/hyperledger/fabric-ca/lib/tls" ) // ClientConfig is the fabric-ca client's config type ClientConfig struct { - URL string `yaml:"url,omitempty"` - TLS tls.ClientTLSConfig `yaml:"tls,omitempty"` - Enrollment api.EnrollmentRequest `yaml:"enrollment,omitempty"` + Debug bool `def:"false" opt:"d" help:"Enable debug level logging"` + URL string `def:"http://localhost:7054" opt:"u" help:"URL of fabric-ca-server"` + TLS tls.ClientTLSConfig + Enrollment api.EnrollmentRequest + CSR csr.CertificateRequest } // Enroll a client given the server's URL and the client's home directory. diff --git a/lib/dbutil/dbutil.go b/lib/dbutil/dbutil.go index 556b33b36..f660895dd 100644 --- a/lib/dbutil/dbutil.go +++ b/lib/dbutil/dbutil.go @@ -102,8 +102,8 @@ func NewUserRegistryPostgres(datasource string, clientTLSConfig *tls.ClientTLSCo connStr := getConnStr(datasource) if clientTLSConfig != nil { - if len(clientTLSConfig.CertFiles) > 0 { - root := clientTLSConfig.CertFiles[0] + if len(clientTLSConfig.CertFilesList) > 0 { + root := clientTLSConfig.CertFilesList[0] connStr = fmt.Sprintf("%s sslrootcert=%s", connStr, root) } diff --git a/lib/identity.go b/lib/identity.go index 94bb30fb3..72f8bcbf5 100644 --- a/lib/identity.go +++ b/lib/identity.go @@ -219,3 +219,13 @@ func getDefaultBCCSPInstance() (bccsp.BCCSP, error) { return defaultBccsp, nil } + +// GetMyKeyFile returns the path to this identity's key file +func (i *Identity) GetMyKeyFile() string { + return i.client.GetMyKeyFile() +} + +// GetMyCertFile returns the path to this identity's key file +func (i *Identity) GetMyCertFile() string { + return i.client.GetMyCertFile() +} diff --git a/lib/server_test.go b/lib/server_test.go index 60a2c0fb6..9d0da2ec5 100644 --- a/lib/server_test.go +++ b/lib/server_test.go @@ -26,6 +26,7 @@ import ( "github.com/hyperledger/fabric-ca/api" "github.com/hyperledger/fabric-ca/lib" + "github.com/hyperledger/fabric-ca/lib/tls" ) const ( @@ -33,6 +34,7 @@ const ( rootDir = "rootDir" intermediatePort = 7056 intermediateDir = "intDir" + testdataDir = "../testdata" ) func TestServerInit(t *testing.T) { @@ -171,6 +173,41 @@ func TestIntermediateServer(t *testing.T) { t.Errorf("Root server stop failed: %s", err) } } +func TestRunningTLSServer(t *testing.T) { + srv := getServer(rootPort, testdataDir, "", t) + + srv.Config.TLS.Enabled = true + srv.Config.TLS.CertFile = "../testdata/tls_server-cert.pem" + srv.Config.TLS.KeyFile = "../testdata/tls_server-key.pem" + + err := srv.Start() + if err != nil { + t.Errorf("Server start failed: %s", err) + } + + clientConfig := &lib.ClientConfig{ + URL: fmt.Sprintf("https://localhost:%d", rootPort), + TLS: tls.ClientTLSConfig{ + CertFilesList: []string{"../testdata/root.pem"}, + Client: tls.KeyCertFiles{ + KeyFile: "../testdata/tls_client-key.pem", + CertFile: "../testdata/tls_client-cert.pem", + }, + }, + } + + rawURL := fmt.Sprintf("https://admin:adminpw@localhost:%d", rootPort) + + _, err = clientConfig.Enroll(rawURL, testdataDir) + if err != nil { + t.Errorf("Failed to enroll over TLS: %s", err) + } + + err = srv.Stop() + if err != nil { + t.Errorf("Server stop failed: %s", err) + } +} func testIntermediateServer(idx int, t *testing.T) { // Init the intermediate server @@ -193,6 +230,9 @@ func testIntermediateServer(idx int, t *testing.T) { } func TestEnd(t *testing.T) { + os.Remove("../testdata/ca-cert.pem") + os.Remove("../testdata/ca-key.pem") + os.Remove("../testdata/fabric-ca-server.db") os.RemoveAll(rootDir) os.RemoveAll(intermediateDir) } @@ -214,7 +254,9 @@ func getIntermediateServer(idx int, t *testing.T) *lib.Server { } func getServer(port int, home, parentURL string, t *testing.T) *lib.Server { - os.RemoveAll(home) + if home != testdataDir { + os.RemoveAll(home) + } affiliations := map[string]interface{}{ "hyperledger": map[string]interface{}{ "fabric": []string{"ledger", "orderer", "security"}, @@ -253,6 +295,6 @@ func getIntermediateClient() *lib.Client { func getTestClient(port int) *lib.Client { return &lib.Client{ Config: &lib.ClientConfig{URL: fmt.Sprintf("http://localhost:%d", port)}, - HomeDir: "../testdata", + HomeDir: testdataDir, } } diff --git a/lib/tls/tls.go b/lib/tls/tls.go index 73d2a7e76..53cf0e0ef 100644 --- a/lib/tls/tls.go +++ b/lib/tls/tls.go @@ -19,10 +19,12 @@ package tls import ( "crypto/tls" "crypto/x509" + "errors" "fmt" "io/ioutil" "github.com/cloudflare/cfssl/log" + "github.com/hyperledger/fabric-ca/util" ) // ServerTLSConfig defines key material for a TLS server @@ -34,9 +36,10 @@ type ServerTLSConfig struct { // ClientTLSConfig defines the key material for a TLS client type ClientTLSConfig struct { - Enabled bool `help:"Enable TLS for client connection"` - CertFiles []string `help:"PEM-encoded list of trusted certificate files"` - Client KeyCertFiles + Enabled bool `help:"Enable TLS for client connection"` + CertFiles string `help:"PEM-encoded comma separated list of trusted certificate files (e.g. root1.pem, root2.pem)"` + CertFilesList []string + Client KeyCertFiles } // KeyCertFiles defines the files need for client on TLS @@ -47,9 +50,6 @@ type KeyCertFiles struct { // GetClientTLSConfig creates a tls.Config object from certs and roots func GetClientTLSConfig(cfg *ClientTLSConfig) (*tls.Config, error) { - //if !cfg.Enabled { - // return nil, nil - //} var certs []tls.Certificate log.Debugf("CA Files: %s\n", cfg.CertFiles) @@ -57,18 +57,18 @@ func GetClientTLSConfig(cfg *ClientTLSConfig) (*tls.Config, error) { log.Debugf("Client Key File: %s\n", cfg.Client.KeyFile) clientCert, err := tls.LoadX509KeyPair(cfg.Client.CertFile, cfg.Client.KeyFile) if err != nil { - log.Debugf("Client Cert or Key not provided, if server requires mutual TLS, the connection will fail [error: %s]", err) + log.Debugf("Client Cert or Key not provided, if server requires mutual TLS, the connection will fail: %s", err) } certs = append(certs, clientCert) rootCAPool := x509.NewCertPool() - if len(cfg.CertFiles) == 0 { - log.Debug("No CA cert files provided. If server requires TLS, connection will fail") + if len(cfg.CertFilesList) == 0 { + return nil, errors.New("No CA certificate files provided") } - for _, cacert := range cfg.CertFiles { + for _, cacert := range cfg.CertFilesList { caCert, err := ioutil.ReadFile(cacert) if err != nil { return nil, err @@ -86,3 +86,28 @@ func GetClientTLSConfig(cfg *ClientTLSConfig) (*tls.Config, error) { return config, nil } + +// AbsTLSClient makes TLS client files absolute +func AbsTLSClient(cfg *ClientTLSConfig, configDir string) error { + var err error + + for i := 0; i < len(cfg.CertFilesList); i++ { + cfg.CertFilesList[i], err = util.MakeFileAbs(cfg.CertFilesList[i], configDir) + if err != nil { + return err + } + + } + + cfg.Client.CertFile, err = util.MakeFileAbs(cfg.Client.CertFile, configDir) + if err != nil { + return err + } + + cfg.Client.KeyFile, err = util.MakeFileAbs(cfg.Client.KeyFile, configDir) + if err != nil { + return err + } + + return nil +} diff --git a/lib/tls/tls_test.go b/lib/tls/tls_test.go index 0acdbd61a..9ab72037e 100644 --- a/lib/tls/tls_test.go +++ b/lib/tls/tls_test.go @@ -16,26 +16,34 @@ limitations under the License. package tls -import ( - "encoding/json" - "io/ioutil" - "testing" +import "testing" + +const ( + configDir = "../../testdata" + caCert = "root.pem" + certFile = "tls_client-cert.pem" + keyFile = "tls_client-key.pem" ) -const clientConfig = "../../testdata/client-config.json" +type testTLSConfig struct { + TLS *ClientTLSConfig +} func TestGetClientTLSConfig(t *testing.T) { - tlsConfig, err := ioutil.ReadFile(clientConfig) - if err != nil { - t.Errorf("Failed to read in TLS configuration file [error: %s]", err) + + cfg := &ClientTLSConfig{ + CertFilesList: []string{"root.pem"}, + Client: KeyCertFiles{ + KeyFile: "tls_client-key.pem", + CertFile: "tls_client-cert.pem", + }, } - var cfg = new(ClientTLSConfig) - json.Unmarshal(tlsConfig, cfg) + AbsTLSClient(cfg, configDir) - _, err = GetClientTLSConfig(cfg) + _, err := GetClientTLSConfig(cfg) if err != nil { - t.Errorf("Failed to get TLS Config [error: %s]", err) + t.Errorf("Failed to get TLS Config: %s", err) } } diff --git a/testdata/cert.pem b/testdata/cert.pem deleted file mode 100644 index cdc039804..000000000 --- a/testdata/cert.pem +++ /dev/null @@ -1,25 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEMzCCAxugAwIBAgIJAPjglM6s674UMA0GCSqGSIb3DQEBCwUAMG4xCzAJBgNV -BAYTAlVTMQswCQYDVQQIEwJuYzEPMA0GA1UEBxMGRHVyaGFtMSEwHwYDVQQKExhJ -bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDDAKBgNVBAsTA1NXRzEQMA4GA1UEAxMH -YWJjLmNvbTAeFw0xNjA5MzAxNzU4MjZaFw0xNzA5MzAxNzU4MjZaMG4xCzAJBgNV -BAYTAlVTMQswCQYDVQQIEwJuYzEPMA0GA1UEBxMGRHVyaGFtMSEwHwYDVQQKExhJ -bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDDAKBgNVBAsTA1NXRzEQMA4GA1UEAxMH -YWJjLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL5vRZQTeAP/ -auw9FZ75tCq7Lpuy88sRsFmDzgAWzg3WEGTd0QOXFNInHx3O3SU6Va4fftuee78B -OVmAcVChRO6qsPO72E097msG9N1s5gCz0HmMPGGTKXaxQtnsVicqmNrVesxj91vM -fdVQiUsNt5QUoEhqUk/OgGq3Y71WPTB6Lbj0mWscUtSGJsQrwK6BivvPsamPHPTl -fOaRitwccuMKkgUuRDd1KVwqCwMabwR81tONffyoF+poF2pB6rw1Ku2jT1pEAL8K -BjA4Bf5j2Od6nRcVqwVuRWalPWBxVGc527qQGK8hMpbDHjAirJhTatugoQwIbyuD -rsd0qGINFQsCAwEAAaOB0zCB0DAdBgNVHQ4EFgQUsH/ZTJS5vMBlOhZmBFMtoToL -hZcwgaAGA1UdIwSBmDCBlYAUsH/ZTJS5vMBlOhZmBFMtoToLhZehcqRwMG4xCzAJ -BgNVBAYTAlVTMQswCQYDVQQIEwJuYzEPMA0GA1UEBxMGRHVyaGFtMSEwHwYDVQQK -ExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDDAKBgNVBAsTA1NXRzEQMA4GA1UE -AxMHYWJjLmNvbYIJAPjglM6s674UMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggEBAHkkwZto8jxz609UrzLNi0vrf4fW1pFh8yBNRmMFAwMBNE1vEjAwxvMy -aq6Eszt17JMlR84dOYM73dg9c6BoHrNHCbZ+J+p8CN7D35Po8auOQ/l2YeUIrPe2 -ekMH2clbIoFi81OTcoMbuhUdD4S1jc4hEWdvgAIbfCcEuT3fZrfba1AMjLaobR9/ -vyOQbqXLbrFzZa3wmwF3C2GBJyDV9XnHRWvSH7Q5myjsAfHbbBO4FcoxIQ53zvzk -9kjEOqgC4qvgjlpw4od2vZ2xxCalYpLckT4lL/SOWzHk+7vHZFqB0wWDsWaEk/Hp -Wrdm7D4UEdTdvU29u4gW8koAfTLUYEE= ------END CERTIFICATE----- diff --git a/testdata/client-config.json b/testdata/client-config.json index bcc10587e..5995241eb 100644 --- a/testdata/client-config.json +++ b/testdata/client-config.json @@ -1,8 +1,11 @@ { "serverURL":"http://localhost:7054", - "certfiles":["../../testdata/root.pem"], - "client": { - "keyfile":"../../testdata/tls_client-key.pem", - "certfile":"../../testdata/tls_client-cert.pem" + "tls":{ + "enabled":false, + "ca_certfiles":["root.pem"], + "client":{ + "keyfile":"tls_client-key.pem", + "certfile":"tls_client-cert.pem" + } } } diff --git a/testdata/client-config2.json b/testdata/client-config2.json deleted file mode 100644 index 698f3c883..000000000 --- a/testdata/client-config2.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "serverURL":"http://localhost:7054", - "ca_certfiles":["../testdata/root.pem"], - "keyfile":"../testdata/tls_client-key.pem", - "certfile":"../testdata/tls_client-cert.pem" -} diff --git a/testdata/fabric-ca-client-config.yaml b/testdata/fabric-ca-client-config.yaml new file mode 100644 index 000000000..a953ba256 --- /dev/null +++ b/testdata/fabric-ca-client-config.yaml @@ -0,0 +1,70 @@ + +############################################################################# +# This is a configuration file for the fabric-ca-client command. +# +# COMMAND LINE ARGUMENTS AND ENVIRONMENT VARIABLES +# ------------------------------------------------ +# Each configuration element can be overridden via command line +# arguments or environment variables. The precedence for determining +# the value of each element is as follows: +# 1) command line argument +# Examples: +# a) --url https://localhost:7054 +# To set the fabric-ca server url +# 2) environment variable +# Examples: +# a) FABRIC_CA_CLIENT_URL=https://localhost:7054 +# To set the fabric-ca server url +# 3) configuration file +# 4) default value (if there is one) +# All default values are shown beside each element below. +# +# FILE NAME ELEMENTS +# ------------------ +# All filename elements below end with the word "file". +# For example, see "certfile" and "keyfile" in the "ca" section. +# The value of each filename element can be a simple filename, a +# relative path, or an absolute path. If the value is not an +# absolute path, it is interpretted as being relative to the location +# of this configuration file. +# +############################################################################# + +############################################################################# +# Client Configuration +############################################################################# + +# URL of the Fabric-ca-server (default: http://localhost:7054) +URL: http://localhost:7054 + +############################################################################# +# TLS section for the client's listenting port +############################################################################# +tls: + # Enable TLS (default: false) + enabled: false + + # TLS for the client's listenting port (default: false) + certfiles: root.pem # Comma Separated (e.g. root.pem, root2.pem) + client: + certfile: tls_client-cert.pem + keyfile: tls_client-key.pem + +############################################################################# +# Certificate Signing Request section for generating the CSR for +# an enrollment certificate (ECert) +############################################################################# +csr: + cn: admin + names: + - C: US + ST: "North Carolina" + L: + O: Hyperledger + OU: Fabric + hosts: + - saads-mbp.raleigh.ibm.com + ca: + pathlen: + pathlenzero: + expiry: diff --git a/util/util.go b/util/util.go index 0ba632a52..4754d435d 100644 --- a/util/util.go +++ b/util/util.go @@ -384,7 +384,7 @@ func HTTPResponseToString(resp *http.Response) string { // CreateClientHome will create a home directory if it does not exist func CreateClientHome() (string, error) { log.Debug("CreateHome") - home := filepath.Join(GetDefaultConfigFile("fabric-ca-client")) + home := filepath.Dir(GetDefaultConfigFile("fabric-ca-client")) if _, err := os.Stat(home); err != nil { if os.IsNotExist(err) {