Skip to content

Commit

Permalink
Intermediate CA server support
Browse files Browse the repository at this point in the history
https://jira.hyperledger.org/browse/FAB-1465

This is implements the intermediate CA server support for
fabric-ca-server.  If the "-u <parentURL>" option is used for
"fabric-ca-server init" or "fabric-ca-server start" commands and
the CA cert and key have not yet been generated, the server acts
as an intermediate CA and gets it's certificate from the parent server.
This must be done with an identity which has the "hf.IntermediateCA"
attribute.

The main logic to get the server's CA cert and key are in the
getCACertAndKey function in lib/server.go.  It is this function which
checks for the parentServerURL.  Note that in this case, the server
uses its client object to enroll with the parent server, just as a
standalone client does.

Note the addition of the csrAuthCheck function in lib/serverenroll.go file.
If the request is for a CA certificate, the "hf.IntermediateCA" attribute
is required by the caller.

See TestIntermediateServer in lib/server_test.go for the test case.

Change-Id: Ifefc304627b58ec1fdc5fac9ebf5e9415483de4c
Signed-off-by: Keith Smith <[email protected]>
  • Loading branch information
Keith Smith committed Feb 23, 2017
1 parent 972143e commit 3f8445a
Show file tree
Hide file tree
Showing 12 changed files with 295 additions and 98 deletions.
36 changes: 14 additions & 22 deletions cmd/fabric-ca-server/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"

Expand Down Expand Up @@ -124,15 +123,16 @@ registry:
maxEnrollments: 0
# Contains user information which is used when LDAP is disabled
user:
<<<ADMIN>>>:
identities:
- name: <<<ADMIN>>>
pass: <<<ADMINPW>>>
type: client
affiliation: org1.department1
affiliation: ""
attrs:
hf.Registrar.Roles: "client,user,peer,validator,auditor,ca"
hf.Registrar.DelegateRoles: "client,user,validator,auditor"
hf.Revoker: true
hf.IntermediateCA: true
#############################################################################
# Database section
Expand Down Expand Up @@ -189,6 +189,12 @@ affiliations:
#############################################################################
signing:
profiles:
ca:
usage:
- cert sign
expiry: 8000h
caconstraint:
isca: true
default:
usage:
- cert sign
Expand Down Expand Up @@ -270,26 +276,12 @@ func configInit() (err error) {
return nil
}

// Get the default path for the config file to display in usage message
func getDefaultConfigFile() (string, error) {
var fname = fmt.Sprintf("%s-config.yaml", cmdName)
// First check home env variables
home := os.Getenv("FABRIC_CA_SERVER_HOME")
if home == "" {
home = os.Getenv("CA_CFG_PATH")
}
if home != "" {
return path.Join(home, fname), nil
}
return fname, nil
}

func createDefaultConfigFile() error {
// Create a default config, but only if they provided a
// bootstrap user ID and password
// Create a default config, but only if they provided an administrative
// user ID and password
up := viper.GetString("boot")
if up == "" {
return fmt.Errorf("The '-b user:pass' option is required; see '%s init -h'", cmdName)
return errors.New("The '-b user:pass' option is required")
}
ups := strings.Split(up, ":")
if len(ups) < 2 {
Expand All @@ -316,7 +308,7 @@ func createDefaultConfigFile() error {
cfg = strings.Replace(cfg, "<<<ADMINPW>>>", pass, 1)
cfg = strings.Replace(cfg, "<<<MYHOST>>>", myhost, 1)
// Now write the file
err = os.MkdirAll(filepath.Dir(cfgFileName), 0644)
err = os.MkdirAll(filepath.Dir(cfgFileName), 0755)
if err != nil {
return err
}
Expand Down
8 changes: 1 addition & 7 deletions cmd/fabric-ca-server/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,9 @@ package main

import (
"fmt"
"path/filepath"

"github.com/cloudflare/cfssl/csr"
"github.com/cloudflare/cfssl/log"
"github.com/hyperledger/fabric-ca/lib"
"github.com/hyperledger/fabric-ca/util"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -51,11 +49,7 @@ func runInit(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
return fmt.Errorf("Usage: too many arguments.\n%s", initCmd.UsageString())
}
server := lib.Server{
HomeDir: filepath.Dir(cfgFileName),
Config: serverCfg,
}
err := server.Init(false)
err := getServer().Init(false)
if err != nil {
util.Fatal("Initialization failure: %s", err)
}
Expand Down
13 changes: 12 additions & 1 deletion cmd/fabric-ca-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package main

import (
"os"
"path/filepath"
"strings"

"github.com/hyperledger/fabric-ca/lib"
Expand Down Expand Up @@ -57,7 +58,7 @@ func init() {
pflags.StringVarP(&cfgFileName, "config", "c", cfg, "Configuration file")
util.FlagString(pflags, "url", "u", "", "URL of the parent fabric-ca-server")
util.FlagString(pflags, "boot", "b", "",
"The user:pass for bootstrap admin (required to build default config file")
"The user:pass for bootstrap admin which is required to build default config file")

// Register flags for all tagged and exported fields in the config
serverCfg = &lib.ServerConfig{}
Expand Down Expand Up @@ -104,3 +105,13 @@ func registerCommonFlags(flags *pflag.FlagSet) {
util.FlagString(flags, "tls.certfile", "", "cert.pem",
"PEM-encoded certificate file used for TLS")
}

// Get a server for the init and start commands
func getServer() *lib.Server {
return &lib.Server{
HomeDir: filepath.Dir(cfgFileName),
Config: serverCfg,
BlockingStart: blockingStart,
ParentServerURL: viper.GetString("url"),
}
}
4 changes: 3 additions & 1 deletion cmd/fabric-ca-server/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"fmt"
"os"
"testing"

"github.com/hyperledger/fabric-ca/util"
)

const (
Expand Down Expand Up @@ -78,7 +80,7 @@ func TestBogus(t *testing.T) {
}

func TestClean(t *testing.T) {
defYaml, _ := getDefaultConfigFile()
defYaml := util.GetDefaultConfigFile(cmdName)
os.Remove(defYaml)
os.Remove(testYaml)
os.Remove("ca-key.pem")
Expand Down
8 changes: 1 addition & 7 deletions cmd/fabric-ca-server/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package main

import (
"fmt"
"path/filepath"

"github.com/hyperledger/fabric-ca/lib"
"github.com/hyperledger/fabric-ca/util"
Expand All @@ -45,12 +44,7 @@ func runStart(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
return fmt.Errorf("Usage: too many arguments.\n%s", startCmd.UsageString())
}
server := lib.Server{
HomeDir: filepath.Dir(cfgFileName),
Config: serverCfg,
BlockingStart: blockingStart,
}
err := server.Start()
err := getServer().Start()
if err != nil {
return err
}
Expand Down
33 changes: 30 additions & 3 deletions lib/clientconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,37 @@ limitations under the License.

package lib

import "github.com/hyperledger/fabric-ca/lib/tls"
import (
"net/url"

"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 `mapstructure:"url"`
TLS tls.ClientTLSConfig `mapstructure:"tls"`
URL string `yaml:"url,omitempty"`
TLS tls.ClientTLSConfig `yaml:"tls,omitempty"`
Enrollment api.EnrollmentRequest `yaml:"enrollment,omitempty"`
}

// Enroll a client given the server's URL and the client's home directory.
// The URL may be of the form: http://user:pass@host:port where user and pass
// are the enrollment ID and secret, respectively.
func (c *ClientConfig) Enroll(rawurl, home string) (id *Identity, err error) {
purl, err := url.Parse(rawurl)
if err != nil {
return nil, err
}
if purl.User != nil {
name := purl.User.Username()
secret, _ := purl.User.Password()
c.Enrollment.Name = name
c.Enrollment.Secret = secret
purl.User = nil
}
c.URL = purl.String()
c.TLS.Enabled = purl.Scheme == "https"
client := &Client{HomeDir: home, Config: c}
return client.Enroll(&c.Enrollment)
}
Loading

0 comments on commit 3f8445a

Please sign in to comment.