github.com/cactusblossom/fabric-ca@v0.0.0-20200611062428-0082fc643826/lib/server.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package lib
     8  
     9  import (
    10  	"context"
    11  	"crypto/tls"
    12  	"crypto/x509"
    13  	"fmt"
    14  	"io"
    15  	"io/ioutil"
    16  	"net"
    17  	"net/http"
    18  	_ "net/http/pprof" // import to support profiling
    19  	"os"
    20  	"path/filepath"
    21  	"strconv"
    22  	"strings"
    23  	"sync"
    24  	"time"
    25  
    26  	"github.com/cloudflare/cfssl/log"
    27  	"github.com/cloudflare/cfssl/revoke"
    28  	"github.com/cloudflare/cfssl/signer"
    29  	"github.com/felixge/httpsnoop"
    30  	ghandlers "github.com/gorilla/handlers"
    31  	gmux "github.com/gorilla/mux"
    32  	"github.com/hyperledger/fabric-ca/lib/attr"
    33  	"github.com/hyperledger/fabric-ca/lib/caerrors"
    34  	calog "github.com/hyperledger/fabric-ca/lib/common/log"
    35  	"github.com/hyperledger/fabric-ca/lib/metadata"
    36  	"github.com/hyperledger/fabric-ca/lib/server/db"
    37  	dbutil "github.com/hyperledger/fabric-ca/lib/server/db/util"
    38  	servermetrics "github.com/hyperledger/fabric-ca/lib/server/metrics"
    39  	"github.com/hyperledger/fabric-ca/lib/server/operations"
    40  	stls "github.com/hyperledger/fabric-ca/lib/tls"
    41  	"github.com/hyperledger/fabric-ca/util"
    42  	"github.com/hyperledger/fabric-lib-go/healthz"
    43  	"github.com/hyperledger/fabric/common/metrics"
    44  	"github.com/pkg/errors"
    45  	"github.com/spf13/viper"
    46  )
    47  
    48  const (
    49  	defaultClientAuth         = "noclientcert"
    50  	fabricCAServerProfilePort = "FABRIC_CA_SERVER_PROFILE_PORT"
    51  	allRoles                  = "peer,orderer,client,user"
    52  	apiPathPrefix             = "/api/v1/"
    53  )
    54  
    55  //go:generate counterfeiter -o mocks/operations_server.go -fake-name OperationsServer . operationsServer
    56  
    57  // operationsServer defines the contract required for an operations server
    58  type operationsServer interface {
    59  	metrics.Provider
    60  	Start() error
    61  	Stop() error
    62  	Addr() string
    63  	RegisterChecker(component string, checker healthz.HealthChecker) error
    64  }
    65  
    66  // Server is the fabric-ca server
    67  type Server struct {
    68  	// The home directory for the server.
    69  	HomeDir string
    70  	// BlockingStart determines if Start is blocking.
    71  	// It is non-blocking by default.
    72  	BlockingStart bool
    73  	// The server's configuration
    74  	Config *ServerConfig
    75  	// Metrics are the metrics that the server tracks for API calls.
    76  	Metrics servermetrics.Metrics
    77  	// Operations is responsible for the server's operation information.
    78  	Operations operationsServer
    79  	// CA is the default certificate authority for the server.
    80  	CA
    81  	// metrics for database requests
    82  	dbMetrics *db.Metrics
    83  	// mux is used to server API requests
    84  	mux *gmux.Router
    85  	// listener for this server
    86  	listener net.Listener
    87  	// An error which occurs when serving
    88  	serveError error
    89  	// caMap is a list of CAs by name
    90  	caMap map[string]*CA
    91  	// caConfigMap is a list CA configs by filename
    92  	caConfigMap map[string]*CAConfig
    93  	// levels currently supported by the server
    94  	levels *dbutil.Levels
    95  	wait   chan bool
    96  	mutex  sync.Mutex
    97  }
    98  
    99  // Init initializes a fabric-ca server
   100  func (s *Server) Init(renew bool) (err error) {
   101  	err = s.init(renew)
   102  	err2 := s.closeDB()
   103  	if err2 != nil {
   104  		log.Errorf("Close DB failed: %s", err2)
   105  	}
   106  	return err
   107  }
   108  
   109  // init initializses the server leaving the DB open
   110  func (s *Server) init(renew bool) (err error) {
   111  	s.Config.Operations.Metrics = s.Config.Metrics
   112  	s.Operations = operations.NewSystem(s.Config.Operations)
   113  	s.initMetrics()
   114  
   115  	serverVersion := metadata.GetVersion()
   116  	err = calog.SetLogLevel(s.Config.LogLevel, s.Config.Debug)
   117  	if err != nil {
   118  		return err
   119  	}
   120  	log.Infof("Server Version: %s", serverVersion)
   121  	s.levels, err = metadata.GetLevels(serverVersion)
   122  	if err != nil {
   123  		return err
   124  	}
   125  	log.Infof("Server Levels: %+v", s.levels)
   126  
   127  	s.mux = gmux.NewRouter()
   128  	// Initialize the config
   129  	err = s.initConfig()
   130  	if err != nil {
   131  		return err
   132  	}
   133  	// Initialize the default CA last
   134  	err = s.initDefaultCA(renew)
   135  	if err != nil {
   136  		return err
   137  	}
   138  	// Successful initialization
   139  	return nil
   140  }
   141  
   142  func (s *Server) initMetrics() {
   143  	s.Metrics = servermetrics.Metrics{
   144  		APICounter:  s.Operations.NewCounter(servermetrics.APICounterOpts),
   145  		APIDuration: s.Operations.NewHistogram(servermetrics.APIDurationOpts),
   146  	}
   147  	s.dbMetrics = &db.Metrics{
   148  		APICounter:  s.Operations.NewCounter(db.APICounterOpts),
   149  		APIDuration: s.Operations.NewHistogram(db.APIDurationOpts),
   150  	}
   151  }
   152  
   153  func (s *Server) startOperationsServer() error {
   154  	err := s.Operations.Start()
   155  	if err != nil {
   156  		return err
   157  	}
   158  
   159  	return nil
   160  }
   161  
   162  // Start the fabric-ca server
   163  func (s *Server) Start() (err error) {
   164  	log.Infof("Starting server in home directory: %s", s.HomeDir)
   165  
   166  	s.serveError = nil
   167  
   168  	if s.listener != nil {
   169  		return errors.New("server is already started")
   170  	}
   171  
   172  	// Initialize the server
   173  	err = s.init(false)
   174  	if err != nil {
   175  		err2 := s.closeDB()
   176  		if err2 != nil {
   177  			log.Errorf("Close DB failed: %s", err2)
   178  		}
   179  		return err
   180  	}
   181  
   182  	// Register http handlers
   183  	s.registerHandlers()
   184  
   185  	log.Debugf("%d CA instance(s) running on server", len(s.caMap))
   186  
   187  	// Start operations server
   188  	err = s.startOperationsServer()
   189  	if err != nil {
   190  		return err
   191  	}
   192  
   193  	err = s.Operations.RegisterChecker("server", s)
   194  	if err != nil {
   195  		return nil
   196  	}
   197  
   198  	// Start listening and serving
   199  	err = s.listenAndServe()
   200  	if err != nil {
   201  		err2 := s.closeDB()
   202  		if err2 != nil {
   203  			log.Errorf("Close DB failed: %s", err2)
   204  		}
   205  		return err
   206  	}
   207  
   208  	return nil
   209  }
   210  
   211  // Stop the server
   212  // WARNING: This forcefully closes the listening socket and may cause
   213  // requests in transit to fail, and so is only used for testing.
   214  // A graceful shutdown will be supported with golang 1.8.
   215  func (s *Server) Stop() error {
   216  	// Stop operations server
   217  	err := s.Operations.Stop()
   218  	if err != nil {
   219  		return err
   220  	}
   221  
   222  	if s.listener == nil {
   223  		return nil
   224  	}
   225  
   226  	_, port, err := net.SplitHostPort(s.listener.Addr().String())
   227  	if err != nil {
   228  		return err
   229  	}
   230  
   231  	err = s.closeListener()
   232  	if err != nil {
   233  		return err
   234  	}
   235  	if s.wait == nil {
   236  		return nil
   237  	}
   238  
   239  	for i := 0; i < 10; i++ {
   240  		select {
   241  		case <-s.wait:
   242  			log.Debugf("Stop: successful stop on port %s", port)
   243  			close(s.wait)
   244  			s.wait = nil
   245  			return nil
   246  		default:
   247  			log.Debugf("Stop: waiting for listener on port %s to stop", port)
   248  			time.Sleep(time.Second)
   249  		}
   250  	}
   251  	log.Debugf("Stop: timed out waiting for stop notification for port %s", port)
   252  	// make sure DB is closed
   253  	err = s.closeDB()
   254  	if err != nil {
   255  		log.Errorf("Close DB failed: %s", err)
   256  	}
   257  
   258  	return nil
   259  }
   260  
   261  // RegisterBootstrapUser registers the bootstrap user with appropriate privileges
   262  func (s *Server) RegisterBootstrapUser(user, pass, affiliation string) error {
   263  	// Initialize the config, setting defaults, etc
   264  	log.Debugf("Register bootstrap user: name=%s, affiliation=%s", user, affiliation)
   265  
   266  	if user == "" || pass == "" {
   267  		return errors.New("Empty identity name and/or pass not allowed")
   268  	}
   269  
   270  	id := CAConfigIdentity{
   271  		Name:           user,
   272  		Pass:           pass,
   273  		Type:           "client",
   274  		Affiliation:    affiliation,
   275  		MaxEnrollments: 0, // 0 means to use the server's max enrollment setting
   276  		Attrs: map[string]string{
   277  			attr.Roles:          "*",
   278  			attr.DelegateRoles:  "*",
   279  			attr.Revoker:        "true",
   280  			attr.IntermediateCA: "true",
   281  			attr.GenCRL:         "true",
   282  			attr.RegistrarAttr:  "*",
   283  			attr.AffiliationMgr: "true",
   284  		},
   285  	}
   286  
   287  	registry := &s.CA.Config.Registry
   288  	registry.Identities = append(registry.Identities, id)
   289  
   290  	log.Debugf("Registered bootstrap identity: %+v", id)
   291  	return nil
   292  }
   293  
   294  // initConfig initializes the configuration for the server
   295  func (s *Server) initConfig() (err error) {
   296  	// Home directory is current working directory by default
   297  	if s.HomeDir == "" {
   298  		s.HomeDir, err = os.Getwd()
   299  		if err != nil {
   300  			return errors.Wrap(err, "Failed to get server's home directory")
   301  		}
   302  	}
   303  	// Make home directory absolute, if not already
   304  	absoluteHomeDir, err := filepath.Abs(s.HomeDir)
   305  	if err != nil {
   306  		return fmt.Errorf("Failed to make server's home directory path absolute: %s", err)
   307  	}
   308  	s.HomeDir = absoluteHomeDir
   309  	// Create config if not set
   310  	if s.Config == nil {
   311  		s.Config = new(ServerConfig)
   312  	}
   313  	s.CA.server = s
   314  	s.CA.HomeDir = s.HomeDir
   315  	err = s.initMultiCAConfig()
   316  	if err != nil {
   317  		return err
   318  	}
   319  	revoke.SetCRLFetcher(s.fetchCRL)
   320  	// Make file names absolute
   321  	s.makeFileNamesAbsolute()
   322  
   323  	compModeStr := os.Getenv("FABRIC_CA_SERVER_COMPATIBILITY_MODE_V1_3")
   324  	if compModeStr == "" {
   325  		compModeStr = "true" // TODO: Change default to false once all clients have been updated to use the new authorization header
   326  	}
   327  
   328  	s.Config.CompMode1_3, err = strconv.ParseBool(compModeStr)
   329  	if err != nil {
   330  		return errors.WithMessage(err, "Invalid value for boolean environment variable 'FABRIC_CA_SERVER_COMPATIBILITY_MODE_V1_3'")
   331  	}
   332  
   333  	return nil
   334  }
   335  
   336  // Initialize config related to multiple CAs
   337  func (s *Server) initMultiCAConfig() (err error) {
   338  	cfg := s.Config
   339  	if cfg.CAcount != 0 && len(cfg.CAfiles) > 0 {
   340  		return errors.New("The --cacount and --cafiles options are mutually exclusive")
   341  	}
   342  	if cfg.CAcfg.Intermediate.ParentServer.URL != "" && cfg.CAcount > 0 {
   343  		return errors.New("The --cacount option is not permissible for an intermediate server; use the --cafiles option instead")
   344  	}
   345  	cfg.CAfiles, err = util.NormalizeFileList(cfg.CAfiles, s.HomeDir)
   346  	if err != nil {
   347  		return err
   348  	}
   349  	// Multi-CA related configuration initialization
   350  	s.caMap = make(map[string]*CA)
   351  	if cfg.CAcount >= 1 {
   352  		s.createDefaultCAConfigs(cfg.CAcount)
   353  	}
   354  	if len(cfg.CAfiles) != 0 {
   355  		log.Debugf("Default CA configuration, if necessary, will be used to replace missing values for additional CAs: %+v", s.Config.CAcfg)
   356  		log.Debugf("Additional CAs to be started: %s", cfg.CAfiles)
   357  		var caFiles []string
   358  		caFiles = util.NormalizeStringSlice(cfg.CAfiles)
   359  		for _, caFile := range caFiles {
   360  			err = s.loadCA(caFile, false)
   361  			if err != nil {
   362  				return err
   363  			}
   364  		}
   365  	}
   366  	return nil
   367  }
   368  
   369  func (s *Server) initDefaultCA(renew bool) error {
   370  	log.Debugf("Initializing default CA in directory %s", s.HomeDir)
   371  	ca := &s.CA
   372  	err := initCA(ca, s.HomeDir, s.CA.Config, s, renew)
   373  	if err != nil {
   374  		return err
   375  	}
   376  	err = s.addCA(ca)
   377  	if err != nil {
   378  		return err
   379  	}
   380  	log.Infof("Home directory for default CA: %s", ca.HomeDir)
   381  	return nil
   382  }
   383  
   384  // loadCAConfig loads up a CA's configuration from the specified
   385  // CA configuration file
   386  func (s *Server) loadCA(caFile string, renew bool) error {
   387  	log.Infof("Loading CA from %s", caFile)
   388  	var err error
   389  
   390  	if !util.FileExists(caFile) {
   391  		return errors.Errorf("%s file does not exist", caFile)
   392  	}
   393  
   394  	// Creating new Viper instance, to prevent any server level environment variables or
   395  	// flags from overridding the configuration options specified in the
   396  	// CA config file
   397  	cfg := &CAConfig{}
   398  	caViper := viper.New()
   399  	err = UnmarshalConfig(cfg, caViper, caFile, false)
   400  	if err != nil {
   401  		return err
   402  	}
   403  
   404  	// Need to error if no CA name provided in config file, we cannot revert to using
   405  	// the name of default CA cause CA names must be unique
   406  	caName := cfg.CA.Name
   407  	if caName == "" {
   408  		return errors.Errorf("No CA name provided in CA configuration file. CA name is required in %s", caFile)
   409  	}
   410  
   411  	// Replace missing values in CA configuration values with values from the
   412  	// defaut CA configuration
   413  	util.CopyMissingValues(s.CA.Config, cfg)
   414  
   415  	// Integers and boolean values are handled outside the util.CopyMissingValues
   416  	// because there is no way through reflect to detect if a value was explicitly
   417  	// set to 0 or false, or it is using the default value for its type. Viper is
   418  	// employed here to help detect.
   419  	if !caViper.IsSet("registry.maxenrollments") {
   420  		cfg.Registry.MaxEnrollments = s.CA.Config.Registry.MaxEnrollments
   421  	}
   422  
   423  	if !caViper.IsSet("db.tls.enabled") {
   424  		cfg.DB.TLS.Enabled = s.CA.Config.DB.TLS.Enabled
   425  	}
   426  
   427  	log.Debugf("CA configuration after checking for missing values: %+v", cfg)
   428  
   429  	ca, err := newCA(caFile, cfg, s, renew)
   430  	if err != nil {
   431  		return err
   432  	}
   433  	err = s.addCA(ca)
   434  	if err != nil {
   435  		err2 := ca.closeDB()
   436  		if err2 != nil {
   437  			log.Errorf("Close DB failed: %s", err2)
   438  		}
   439  	}
   440  	return err
   441  }
   442  
   443  // DN is the distinguished name inside a certificate
   444  type DN struct {
   445  	issuer  string
   446  	subject string
   447  }
   448  
   449  // addCA adds a CA to the server if there are no conflicts
   450  func (s *Server) addCA(ca *CA) error {
   451  	// check for conflicts
   452  	caName := ca.Config.CA.Name
   453  	for _, c := range s.caMap {
   454  		if c.Config.CA.Name == caName {
   455  			return errors.Errorf("CA name '%s' is used in '%s' and '%s'",
   456  				caName, ca.ConfigFilePath, c.ConfigFilePath)
   457  		}
   458  		err := s.compareDN(c.Config.CA.Certfile, ca.Config.CA.Certfile)
   459  		if err != nil {
   460  			return err
   461  		}
   462  	}
   463  	// no conflicts, so add it
   464  	s.caMap[caName] = ca
   465  
   466  	return nil
   467  }
   468  
   469  // closeDB closes all CA dabatases
   470  func (s *Server) closeDB() error {
   471  	log.Debugf("Closing server DBs")
   472  	// close default CA DB
   473  	err := s.CA.closeDB()
   474  	if err != nil {
   475  		return err
   476  	}
   477  	// close other CAs DB
   478  	for _, c := range s.caMap {
   479  		err = c.closeDB()
   480  		if err != nil {
   481  			return err
   482  		}
   483  	}
   484  	return nil
   485  }
   486  
   487  // createDefaultCAConfigs creates specified number of default CA configuration files
   488  func (s *Server) createDefaultCAConfigs(cacount int) error {
   489  	log.Debugf("Creating %d default CA configuration files", cacount)
   490  
   491  	cashome, err := util.MakeFileAbs("ca", s.HomeDir)
   492  	if err != nil {
   493  		return err
   494  	}
   495  
   496  	os.Mkdir(cashome, 0755)
   497  
   498  	for i := 1; i <= cacount; i++ {
   499  		cahome := fmt.Sprintf(cashome+"/ca%d", i)
   500  		cfgFileName := filepath.Join(cahome, "fabric-ca-config.yaml")
   501  
   502  		caName := fmt.Sprintf("ca%d", i)
   503  		cfg := strings.Replace(defaultCACfgTemplate, "<<<CANAME>>>", caName, 1)
   504  
   505  		cn := fmt.Sprintf("fabric-ca-server-ca%d", i)
   506  		cfg = strings.Replace(cfg, "<<<COMMONNAME>>>", cn, 1)
   507  
   508  		datasource := dbutil.GetCADataSource(s.CA.Config.DB.Type, s.CA.Config.DB.Datasource, i)
   509  		cfg = strings.Replace(cfg, "<<<DATASOURCE>>>", datasource, 1)
   510  
   511  		s.Config.CAfiles = append(s.Config.CAfiles, cfgFileName)
   512  
   513  		// Now write the file
   514  		err := os.MkdirAll(filepath.Dir(cfgFileName), 0755)
   515  		if err != nil {
   516  			return err
   517  		}
   518  
   519  		err = ioutil.WriteFile(cfgFileName, []byte(cfg), 0644)
   520  		if err != nil {
   521  			return err
   522  		}
   523  
   524  	}
   525  	return nil
   526  }
   527  
   528  // GetCA returns the CA given its name
   529  func (s *Server) GetCA(name string) (*CA, error) {
   530  	// Lookup the CA from the server
   531  	ca := s.caMap[name]
   532  	if ca == nil {
   533  		return nil, caerrors.NewHTTPErr(404, caerrors.ErrCANotFound, "CA '%s' does not exist", name)
   534  	}
   535  	return ca, nil
   536  }
   537  
   538  // Register all endpoint handlers
   539  func (s *Server) registerHandlers() {
   540  	s.mux.Use(s.cors, s.middleware)
   541  	s.registerHandler(newCAInfoEndpoint(s))
   542  	s.registerHandler(newRegisterEndpoint(s))
   543  	s.registerHandler(newEnrollEndpoint(s))
   544  	s.registerHandler(newIdemixEnrollEndpoint(s))
   545  	s.registerHandler(newIdemixCRIEndpoint(s))
   546  	s.registerHandler(newReenrollEndpoint(s))
   547  	s.registerHandler(newRevokeEndpoint(s))
   548  	s.registerHandler(newTCertEndpoint(s))
   549  	s.registerHandler(newGenCRLEndpoint(s))
   550  	s.registerHandler(newIdentitiesStreamingEndpoint(s))
   551  	s.registerHandler(newIdentitiesEndpoint(s))
   552  	s.registerHandler(newAffiliationsStreamingEndpoint(s))
   553  	s.registerHandler(newAffiliationsEndpoint(s))
   554  	s.registerHandler(newCertificateEndpoint(s))
   555  }
   556  
   557  // Register a handler
   558  func (s *Server) registerHandler(se *serverEndpoint) {
   559  	s.mux.Handle("/"+se.Path, se).Name(se.Path)
   560  	s.mux.Handle(apiPathPrefix+se.Path, se).Name(se.Path)
   561  }
   562  
   563  func (s *Server) middleware(next http.Handler) http.Handler {
   564  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   565  		metrics := httpsnoop.CaptureMetrics(next, w, r)
   566  		apiName := s.getAPIName(r)
   567  		caName := s.getCAName()
   568  		s.recordMetrics(metrics.Duration, caName, apiName, strconv.Itoa(metrics.Code))
   569  	})
   570  }
   571  
   572  func (s *Server) cors(next http.Handler) http.Handler {
   573  	if s.Config.CORS.Enabled {
   574  		return ghandlers.CORS(ghandlers.AllowedOrigins(s.Config.CORS.Origins))(next)
   575  	}
   576  	return next
   577  }
   578  
   579  func (s *Server) getAPIName(r *http.Request) string {
   580  	var apiName string
   581  	var match gmux.RouteMatch
   582  	if s.mux.Match(r, &match) {
   583  		apiName = match.Route.GetName()
   584  	}
   585  	return apiName
   586  }
   587  
   588  func (s *Server) getCAName() string {
   589  	return s.CA.Config.CA.Name
   590  }
   591  
   592  func (s *Server) recordMetrics(duration time.Duration, caName, apiName, statusCode string) {
   593  	s.Metrics.APICounter.With("ca_name", caName, "api_name", apiName, "status_code", statusCode).Add(1)
   594  	s.Metrics.APIDuration.With("ca_name", caName, "api_name", apiName, "status_code", statusCode).Observe(duration.Seconds())
   595  }
   596  
   597  // Starting listening and serving
   598  func (s *Server) listenAndServe() (err error) {
   599  
   600  	var listener net.Listener
   601  	var clientAuth tls.ClientAuthType
   602  	var ok bool
   603  
   604  	c := s.Config
   605  
   606  	// Set default listening address and port
   607  	if c.Address == "" {
   608  		c.Address = DefaultServerAddr
   609  	}
   610  	if c.Port == 0 {
   611  		c.Port = DefaultServerPort
   612  	}
   613  	addr := net.JoinHostPort(c.Address, strconv.Itoa(c.Port))
   614  	var addrStr string
   615  
   616  	if c.TLS.Enabled {
   617  		log.Debug("TLS is enabled")
   618  		addrStr = fmt.Sprintf("https://%s", addr)
   619  
   620  		// If key file is specified and it does not exist or its corresponding certificate file does not exist
   621  		// then need to return error and not start the server. The TLS key file is specified when the user
   622  		// wants the server to use custom tls key and cert and don't want server to auto generate its own. So,
   623  		// when the key file is specified, it must exist on the file system
   624  		if c.TLS.KeyFile != "" {
   625  			if !util.FileExists(c.TLS.KeyFile) {
   626  				return fmt.Errorf("File specified by 'tls.keyfile' does not exist: %s", c.TLS.KeyFile)
   627  			}
   628  			if !util.FileExists(c.TLS.CertFile) {
   629  				return fmt.Errorf("File specified by 'tls.certfile' does not exist: %s", c.TLS.CertFile)
   630  			}
   631  			log.Debugf("TLS Certificate: %s, TLS Key: %s", c.TLS.CertFile, c.TLS.KeyFile)
   632  		} else if !util.FileExists(c.TLS.CertFile) {
   633  			// TLS key file is not specified, generate TLS key and cert if they are not already generated
   634  			err = s.autoGenerateTLSCertificateKey()
   635  			if err != nil {
   636  				return fmt.Errorf("Failed to automatically generate TLS certificate and key: %s", err)
   637  			}
   638  		}
   639  
   640  		cer, err := util.LoadX509KeyPair(c.TLS.CertFile, c.TLS.KeyFile, s.csp)
   641  		if err != nil {
   642  			return err
   643  		}
   644  
   645  		if c.TLS.ClientAuth.Type == "" {
   646  			c.TLS.ClientAuth.Type = defaultClientAuth
   647  		}
   648  
   649  		log.Debugf("Client authentication type requested: %s", c.TLS.ClientAuth.Type)
   650  
   651  		authType := strings.ToLower(c.TLS.ClientAuth.Type)
   652  		if clientAuth, ok = clientAuthTypes[authType]; !ok {
   653  			return errors.New("Invalid client auth type provided")
   654  		}
   655  
   656  		var certPool *x509.CertPool
   657  		if authType != defaultClientAuth {
   658  			certPool, err = LoadPEMCertPool(c.TLS.ClientAuth.CertFiles)
   659  			if err != nil {
   660  				return err
   661  			}
   662  		}
   663  
   664  		config := &tls.Config{
   665  			Certificates: []tls.Certificate{*cer},
   666  			ClientAuth:   clientAuth,
   667  			ClientCAs:    certPool,
   668  			MinVersion:   tls.VersionTLS12,
   669  			MaxVersion:   tls.VersionTLS12,
   670  			CipherSuites: stls.DefaultCipherSuites,
   671  		}
   672  
   673  		listener, err = tls.Listen("tcp", addr, config)
   674  		if err != nil {
   675  			return errors.Wrapf(err, "TLS listen failed for %s", addrStr)
   676  		}
   677  	} else {
   678  		addrStr = fmt.Sprintf("http://%s", addr)
   679  		listener, err = net.Listen("tcp", addr)
   680  		if err != nil {
   681  			return errors.Wrapf(err, "TCP listen failed for %s", addrStr)
   682  		}
   683  	}
   684  	s.listener = listener
   685  	log.Infof("Listening on %s", addrStr)
   686  
   687  	err = s.checkAndEnableProfiling()
   688  	if err != nil {
   689  		s.closeListener()
   690  		return errors.WithMessage(err, "TCP listen for profiling failed")
   691  	}
   692  
   693  	// Start serving requests, either blocking or non-blocking
   694  	if s.BlockingStart {
   695  		return s.serve()
   696  	}
   697  	s.wait = make(chan bool)
   698  	go s.serve()
   699  
   700  	return nil
   701  }
   702  
   703  func (s *Server) serve() error {
   704  	listener := s.listener
   705  	if listener == nil {
   706  		// This can happen as follows:
   707  		// 1) listenAndServe above is called with s.BlockingStart set to false
   708  		//    and returns to the caller
   709  		// 2) the caller immediately calls s.Stop, which sets s.listener to nil
   710  		// 3) the go routine runs and calls this function
   711  		// So this prevents the panic which was reported in
   712  		// in https://jira.hyperledger.org/browse/FAB-3100.
   713  		return nil
   714  	}
   715  
   716  	s.serveError = http.Serve(listener, s.mux)
   717  
   718  	log.Errorf("Server has stopped serving: %s", s.serveError)
   719  	s.closeListener()
   720  	err := s.closeDB()
   721  	if err != nil {
   722  		log.Errorf("Close DB failed: %s", err)
   723  	}
   724  	if s.wait != nil {
   725  		s.wait <- true
   726  	}
   727  	return s.serveError
   728  }
   729  
   730  // HealthCheck pings the database to determine if it is reachable
   731  func (s *Server) HealthCheck(ctx context.Context) error {
   732  	return s.db.PingContext(ctx)
   733  }
   734  
   735  // checkAndEnableProfiling checks for FABRIC_CA_SERVER_PROFILE_PORT env variable
   736  // if it is set, starts listening for profiling requests at the port specified
   737  // by the environment variable
   738  func (s *Server) checkAndEnableProfiling() error {
   739  	// Start listening for profile requests
   740  	pport := os.Getenv(fabricCAServerProfilePort)
   741  	if pport != "" {
   742  		iport, err := strconv.Atoi(pport)
   743  		if err != nil || iport < 0 {
   744  			log.Warningf("Profile port specified by the %s environment variable is not a valid port, not enabling profiling",
   745  				fabricCAServerProfilePort)
   746  		} else {
   747  			addr := net.JoinHostPort(s.Config.Address, pport)
   748  			listener, err1 := net.Listen("tcp", addr)
   749  			log.Infof("Profiling enabled; listening for profile requests on port %s", pport)
   750  			if err1 != nil {
   751  				return err1
   752  			}
   753  			go func() {
   754  				log.Debugf("Profiling enabled; waiting for profile requests on port %s", pport)
   755  				err := http.Serve(listener, nil)
   756  				log.Errorf("Stopped serving for profiling requests on port %s: %s", pport, err)
   757  			}()
   758  		}
   759  	}
   760  	return nil
   761  }
   762  
   763  // Make all file names in the config absolute
   764  func (s *Server) makeFileNamesAbsolute() error {
   765  	log.Debug("Making server filenames absolute")
   766  	err := stls.AbsTLSServer(&s.Config.TLS, s.HomeDir)
   767  	if err != nil {
   768  		return err
   769  	}
   770  	return nil
   771  }
   772  
   773  // closeListener closes the listening endpoint
   774  func (s *Server) closeListener() error {
   775  	s.mutex.Lock()
   776  	defer s.mutex.Unlock()
   777  
   778  	if s.listener == nil {
   779  		msg := fmt.Sprintf("Stop: listener was already closed")
   780  		log.Debugf(msg)
   781  		return errors.New(msg)
   782  	}
   783  
   784  	_, port, err := net.SplitHostPort(s.listener.Addr().String())
   785  	if err != nil {
   786  		return err
   787  	}
   788  
   789  	err = s.listener.Close()
   790  	if err != nil {
   791  		log.Debugf("Stop: failed to close listener on port %s: %s", port, err)
   792  		return err
   793  	}
   794  
   795  	log.Debugf("Stop: successfully closed listener on port %s", port)
   796  	s.listener = nil
   797  
   798  	return nil
   799  }
   800  
   801  func (s *Server) compareDN(existingCACertFile, newCACertFile string) error {
   802  	log.Debugf("Comparing DNs from certificates: %s and %s", existingCACertFile, newCACertFile)
   803  	existingDN, err := s.loadDNFromCertFile(existingCACertFile)
   804  	if err != nil {
   805  		return err
   806  	}
   807  
   808  	newDN, err := s.loadDNFromCertFile(newCACertFile)
   809  	if err != nil {
   810  		return err
   811  	}
   812  
   813  	err = existingDN.equal(newDN)
   814  	if err != nil {
   815  		return errors.Wrapf(err, "a CA already exists with the following subject distinguished name: %s", newDN.subject)
   816  	}
   817  	return nil
   818  }
   819  
   820  // Read the CRL from body of http response
   821  func (s *Server) fetchCRL(r io.Reader) ([]byte, error) {
   822  	crlSizeLimit := s.Config.CRLSizeLimit
   823  	log.Debugf("CRL size limit is %d bytes", crlSizeLimit)
   824  
   825  	crl := make([]byte, crlSizeLimit)
   826  
   827  	crl, err := util.Read(r, crl)
   828  	if err != nil {
   829  		return nil, errors.WithMessage(err, fmt.Sprintf("Error reading CRL with max buffer size of %d", crlSizeLimit))
   830  	}
   831  
   832  	return crl, nil
   833  }
   834  
   835  func (s *Server) loadDNFromCertFile(certFile string) (*DN, error) {
   836  	log.Debugf("Loading DNs from certificate %s", certFile)
   837  	cert, err := util.GetX509CertificateFromPEMFile(certFile)
   838  	if err != nil {
   839  		return nil, err
   840  	}
   841  	distinguishedName := &DN{
   842  		issuer:  cert.Issuer.String(),
   843  		subject: cert.Subject.String(),
   844  	}
   845  	return distinguishedName, nil
   846  }
   847  
   848  func (s *Server) autoGenerateTLSCertificateKey() error {
   849  	log.Debug("TLS enabled but either certificate or key file does not exist, automatically generating TLS credentials")
   850  
   851  	clientCfg := &ClientConfig{
   852  		CSP: s.CA.Config.CSP,
   853  	}
   854  	client := Client{
   855  		HomeDir: s.HomeDir,
   856  		Config:  clientCfg,
   857  	}
   858  
   859  	// Generate CSR that will be used to create the TLS certificate
   860  	csrReq := s.Config.CAcfg.CSR
   861  	csrReq.CA = nil // Not requesting a CA certificate
   862  	hostname := util.Hostname()
   863  	log.Debugf("TLS CSR: %+v\n", csrReq)
   864  
   865  	// Can't use the same CN as the signing certificate CN (default: fabric-ca-server) otherwise no AKI is generated
   866  	csr, _, err := client.GenCSR(&csrReq, hostname)
   867  	if err != nil {
   868  		return fmt.Errorf("Failed to generate CSR: %s", err)
   869  	}
   870  
   871  	// Use the 'tls' profile that will return a certificate with the appropriate extensions
   872  	req := signer.SignRequest{
   873  		Profile: "tls",
   874  		Request: string(csr),
   875  	}
   876  
   877  	// Use default CA to get back signed TLS certificate
   878  	cert, err := s.CA.enrollSigner.Sign(req)
   879  	if err != nil {
   880  		return fmt.Errorf("Failed to generate TLS certificate: %s", err)
   881  	}
   882  
   883  	// Write the TLS certificate to the file system
   884  	err = ioutil.WriteFile(s.Config.TLS.CertFile, cert, 0644)
   885  	if err != nil {
   886  		return fmt.Errorf("Failed to write TLS certificate: %s", err)
   887  	}
   888  
   889  	// If c.TLS.Keyfile is specified then print out the key file path. If key file is not provided, then key generation is
   890  	// handled by BCCSP then only print out cert file path
   891  	c := s.Config
   892  	log.Debugf("Generated TLS Certificate: %s", c.TLS.CertFile)
   893  
   894  	return nil
   895  }
   896  
   897  // Log is a function required to meet the interface required by statsd
   898  func (s *Server) Log(keyvals ...interface{}) error {
   899  	log.Warning(keyvals...)
   900  	return nil
   901  }
   902  
   903  func (dn *DN) equal(checkDN *DN) error {
   904  	log.Debugf("Check to see if two DNs are equal - %+v and %+v", dn, checkDN)
   905  	if dn.issuer == checkDN.issuer {
   906  		log.Debug("Issuer distinguished name already in use, checking for unique subject distinguished name")
   907  		if dn.subject == checkDN.subject {
   908  			return errors.New("Both issuer and subject distinguished name are already in use")
   909  		}
   910  	}
   911  	return nil
   912  }