github.com/zcqzcg/fabric-ca@v2.0.0-alpha.0.20200416163940-d878ee6db75a+incompatible/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(newGenCRLEndpoint(s))
   549  	s.registerHandler(newIdentitiesStreamingEndpoint(s))
   550  	s.registerHandler(newIdentitiesEndpoint(s))
   551  	s.registerHandler(newAffiliationsStreamingEndpoint(s))
   552  	s.registerHandler(newAffiliationsEndpoint(s))
   553  	s.registerHandler(newCertificateEndpoint(s))
   554  }
   555  
   556  // Register a handler
   557  func (s *Server) registerHandler(se *serverEndpoint) {
   558  	s.mux.Handle("/"+se.Path, se).Name(se.Path)
   559  	s.mux.Handle(apiPathPrefix+se.Path, se).Name(se.Path)
   560  }
   561  
   562  func (s *Server) middleware(next http.Handler) http.Handler {
   563  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   564  		metrics := httpsnoop.CaptureMetrics(next, w, r)
   565  		apiName := s.getAPIName(r)
   566  		caName := s.getCAName()
   567  		s.recordMetrics(metrics.Duration, caName, apiName, strconv.Itoa(metrics.Code))
   568  	})
   569  }
   570  
   571  func (s *Server) cors(next http.Handler) http.Handler {
   572  	if s.Config.CORS.Enabled {
   573  		return ghandlers.CORS(ghandlers.AllowedOrigins(s.Config.CORS.Origins))(next)
   574  	}
   575  	return next
   576  }
   577  
   578  func (s *Server) getAPIName(r *http.Request) string {
   579  	var apiName string
   580  	var match gmux.RouteMatch
   581  	if s.mux.Match(r, &match) {
   582  		apiName = match.Route.GetName()
   583  	}
   584  	return apiName
   585  }
   586  
   587  func (s *Server) getCAName() string {
   588  	return s.CA.Config.CA.Name
   589  }
   590  
   591  func (s *Server) recordMetrics(duration time.Duration, caName, apiName, statusCode string) {
   592  	s.Metrics.APICounter.With("ca_name", caName, "api_name", apiName, "status_code", statusCode).Add(1)
   593  	s.Metrics.APIDuration.With("ca_name", caName, "api_name", apiName, "status_code", statusCode).Observe(duration.Seconds())
   594  }
   595  
   596  // Starting listening and serving
   597  func (s *Server) listenAndServe() (err error) {
   598  
   599  	var listener net.Listener
   600  	var clientAuth tls.ClientAuthType
   601  	var ok bool
   602  
   603  	c := s.Config
   604  
   605  	// Set default listening address and port
   606  	if c.Address == "" {
   607  		c.Address = DefaultServerAddr
   608  	}
   609  	if c.Port == 0 {
   610  		c.Port = DefaultServerPort
   611  	}
   612  	addr := net.JoinHostPort(c.Address, strconv.Itoa(c.Port))
   613  	var addrStr string
   614  
   615  	if c.TLS.Enabled {
   616  		log.Debug("TLS is enabled")
   617  		addrStr = fmt.Sprintf("https://%s", addr)
   618  
   619  		// If key file is specified and it does not exist or its corresponding certificate file does not exist
   620  		// then need to return error and not start the server. The TLS key file is specified when the user
   621  		// wants the server to use custom tls key and cert and don't want server to auto generate its own. So,
   622  		// when the key file is specified, it must exist on the file system
   623  		if c.TLS.KeyFile != "" {
   624  			if !util.FileExists(c.TLS.KeyFile) {
   625  				return fmt.Errorf("File specified by 'tls.keyfile' does not exist: %s", c.TLS.KeyFile)
   626  			}
   627  			if !util.FileExists(c.TLS.CertFile) {
   628  				return fmt.Errorf("File specified by 'tls.certfile' does not exist: %s", c.TLS.CertFile)
   629  			}
   630  			log.Debugf("TLS Certificate: %s, TLS Key: %s", c.TLS.CertFile, c.TLS.KeyFile)
   631  		} else if !util.FileExists(c.TLS.CertFile) {
   632  			// TLS key file is not specified, generate TLS key and cert if they are not already generated
   633  			err = s.autoGenerateTLSCertificateKey()
   634  			if err != nil {
   635  				return fmt.Errorf("Failed to automatically generate TLS certificate and key: %s", err)
   636  			}
   637  		}
   638  
   639  		cer, err := util.LoadX509KeyPair(c.TLS.CertFile, c.TLS.KeyFile, s.csp)
   640  		if err != nil {
   641  			return err
   642  		}
   643  
   644  		if c.TLS.ClientAuth.Type == "" {
   645  			c.TLS.ClientAuth.Type = defaultClientAuth
   646  		}
   647  
   648  		log.Debugf("Client authentication type requested: %s", c.TLS.ClientAuth.Type)
   649  
   650  		authType := strings.ToLower(c.TLS.ClientAuth.Type)
   651  		if clientAuth, ok = clientAuthTypes[authType]; !ok {
   652  			return errors.New("Invalid client auth type provided")
   653  		}
   654  
   655  		var certPool *x509.CertPool
   656  		if authType != defaultClientAuth {
   657  			certPool, err = LoadPEMCertPool(c.TLS.ClientAuth.CertFiles)
   658  			if err != nil {
   659  				return err
   660  			}
   661  		}
   662  
   663  		config := &tls.Config{
   664  			Certificates: []tls.Certificate{*cer},
   665  			ClientAuth:   clientAuth,
   666  			ClientCAs:    certPool,
   667  			MinVersion:   tls.VersionTLS12,
   668  			MaxVersion:   tls.VersionTLS13,
   669  			CipherSuites: stls.DefaultCipherSuites,
   670  		}
   671  
   672  		listener, err = tls.Listen("tcp", addr, config)
   673  		if err != nil {
   674  			return errors.Wrapf(err, "TLS listen failed for %s", addrStr)
   675  		}
   676  	} else {
   677  		addrStr = fmt.Sprintf("http://%s", addr)
   678  		listener, err = net.Listen("tcp", addr)
   679  		if err != nil {
   680  			return errors.Wrapf(err, "TCP listen failed for %s", addrStr)
   681  		}
   682  	}
   683  	s.listener = listener
   684  	log.Infof("Listening on %s", addrStr)
   685  
   686  	err = s.checkAndEnableProfiling()
   687  	if err != nil {
   688  		s.closeListener()
   689  		return errors.WithMessage(err, "TCP listen for profiling failed")
   690  	}
   691  
   692  	// Start serving requests, either blocking or non-blocking
   693  	if s.BlockingStart {
   694  		return s.serve()
   695  	}
   696  	s.wait = make(chan bool)
   697  	go s.serve()
   698  
   699  	return nil
   700  }
   701  
   702  func (s *Server) serve() error {
   703  	listener := s.listener
   704  	if listener == nil {
   705  		// This can happen as follows:
   706  		// 1) listenAndServe above is called with s.BlockingStart set to false
   707  		//    and returns to the caller
   708  		// 2) the caller immediately calls s.Stop, which sets s.listener to nil
   709  		// 3) the go routine runs and calls this function
   710  		// So this prevents the panic which was reported in
   711  		// in https://jira.hyperledger.org/browse/FAB-3100.
   712  		return nil
   713  	}
   714  
   715  	s.serveError = http.Serve(listener, s.mux)
   716  
   717  	log.Errorf("Server has stopped serving: %s", s.serveError)
   718  	s.closeListener()
   719  	err := s.closeDB()
   720  	if err != nil {
   721  		log.Errorf("Close DB failed: %s", err)
   722  	}
   723  	if s.wait != nil {
   724  		s.wait <- true
   725  	}
   726  	return s.serveError
   727  }
   728  
   729  // HealthCheck pings the database to determine if it is reachable
   730  func (s *Server) HealthCheck(ctx context.Context) error {
   731  	return s.db.PingContext(ctx)
   732  }
   733  
   734  // checkAndEnableProfiling checks for FABRIC_CA_SERVER_PROFILE_PORT env variable
   735  // if it is set, starts listening for profiling requests at the port specified
   736  // by the environment variable
   737  func (s *Server) checkAndEnableProfiling() error {
   738  	// Start listening for profile requests
   739  	pport := os.Getenv(fabricCAServerProfilePort)
   740  	if pport != "" {
   741  		iport, err := strconv.Atoi(pport)
   742  		if err != nil || iport < 0 {
   743  			log.Warningf("Profile port specified by the %s environment variable is not a valid port, not enabling profiling",
   744  				fabricCAServerProfilePort)
   745  		} else {
   746  			addr := net.JoinHostPort(s.Config.Address, pport)
   747  			listener, err1 := net.Listen("tcp", addr)
   748  			log.Infof("Profiling enabled; listening for profile requests on port %s", pport)
   749  			if err1 != nil {
   750  				return err1
   751  			}
   752  			go func() {
   753  				log.Debugf("Profiling enabled; waiting for profile requests on port %s", pport)
   754  				err := http.Serve(listener, nil)
   755  				log.Errorf("Stopped serving for profiling requests on port %s: %s", pport, err)
   756  			}()
   757  		}
   758  	}
   759  	return nil
   760  }
   761  
   762  // Make all file names in the config absolute
   763  func (s *Server) makeFileNamesAbsolute() error {
   764  	log.Debug("Making server filenames absolute")
   765  	err := stls.AbsTLSServer(&s.Config.TLS, s.HomeDir)
   766  	if err != nil {
   767  		return err
   768  	}
   769  	return nil
   770  }
   771  
   772  // closeListener closes the listening endpoint
   773  func (s *Server) closeListener() error {
   774  	s.mutex.Lock()
   775  	defer s.mutex.Unlock()
   776  
   777  	if s.listener == nil {
   778  		msg := fmt.Sprintf("Stop: listener was already closed")
   779  		log.Debugf(msg)
   780  		return errors.New(msg)
   781  	}
   782  
   783  	_, port, err := net.SplitHostPort(s.listener.Addr().String())
   784  	if err != nil {
   785  		return err
   786  	}
   787  
   788  	err = s.listener.Close()
   789  	if err != nil {
   790  		log.Debugf("Stop: failed to close listener on port %s: %s", port, err)
   791  		return err
   792  	}
   793  
   794  	log.Debugf("Stop: successfully closed listener on port %s", port)
   795  	s.listener = nil
   796  
   797  	return nil
   798  }
   799  
   800  func (s *Server) compareDN(existingCACertFile, newCACertFile string) error {
   801  	log.Debugf("Comparing DNs from certificates: %s and %s", existingCACertFile, newCACertFile)
   802  	existingDN, err := s.loadDNFromCertFile(existingCACertFile)
   803  	if err != nil {
   804  		return err
   805  	}
   806  
   807  	newDN, err := s.loadDNFromCertFile(newCACertFile)
   808  	if err != nil {
   809  		return err
   810  	}
   811  
   812  	err = existingDN.equal(newDN)
   813  	if err != nil {
   814  		return errors.Wrapf(err, "a CA already exists with the following subject distinguished name: %s", newDN.subject)
   815  	}
   816  	return nil
   817  }
   818  
   819  // Read the CRL from body of http response
   820  func (s *Server) fetchCRL(r io.Reader) ([]byte, error) {
   821  	crlSizeLimit := s.Config.CRLSizeLimit
   822  	log.Debugf("CRL size limit is %d bytes", crlSizeLimit)
   823  
   824  	crl := make([]byte, crlSizeLimit)
   825  
   826  	crl, err := util.Read(r, crl)
   827  	if err != nil {
   828  		return nil, errors.WithMessage(err, fmt.Sprintf("Error reading CRL with max buffer size of %d", crlSizeLimit))
   829  	}
   830  
   831  	return crl, nil
   832  }
   833  
   834  func (s *Server) loadDNFromCertFile(certFile string) (*DN, error) {
   835  	log.Debugf("Loading DNs from certificate %s", certFile)
   836  	cert, err := util.GetX509CertificateFromPEMFile(certFile)
   837  	if err != nil {
   838  		return nil, err
   839  	}
   840  	distinguishedName := &DN{
   841  		issuer:  cert.Issuer.String(),
   842  		subject: cert.Subject.String(),
   843  	}
   844  	return distinguishedName, nil
   845  }
   846  
   847  func (s *Server) autoGenerateTLSCertificateKey() error {
   848  	log.Debug("TLS enabled but either certificate or key file does not exist, automatically generating TLS credentials")
   849  
   850  	clientCfg := &ClientConfig{
   851  		CSP: s.CA.Config.CSP,
   852  	}
   853  	client := Client{
   854  		HomeDir: s.HomeDir,
   855  		Config:  clientCfg,
   856  	}
   857  
   858  	// Generate CSR that will be used to create the TLS certificate
   859  	csrReq := s.Config.CAcfg.CSR
   860  	csrReq.CA = nil // Not requesting a CA certificate
   861  	hostname := util.Hostname()
   862  	log.Debugf("TLS CSR: %+v\n", csrReq)
   863  
   864  	// Can't use the same CN as the signing certificate CN (default: fabric-ca-server) otherwise no AKI is generated
   865  	csr, _, err := client.GenCSR(&csrReq, hostname)
   866  	if err != nil {
   867  		return fmt.Errorf("Failed to generate CSR: %s", err)
   868  	}
   869  
   870  	// Use the 'tls' profile that will return a certificate with the appropriate extensions
   871  	req := signer.SignRequest{
   872  		Profile: "tls",
   873  		Request: string(csr),
   874  	}
   875  
   876  	// Use default CA to get back signed TLS certificate
   877  	cert, err := s.CA.enrollSigner.Sign(req)
   878  	if err != nil {
   879  		return fmt.Errorf("Failed to generate TLS certificate: %s", err)
   880  	}
   881  
   882  	// Write the TLS certificate to the file system
   883  	err = ioutil.WriteFile(s.Config.TLS.CertFile, cert, 0644)
   884  	if err != nil {
   885  		return fmt.Errorf("Failed to write TLS certificate: %s", err)
   886  	}
   887  
   888  	// If c.TLS.Keyfile is specified then print out the key file path. If key file is not provided, then key generation is
   889  	// handled by BCCSP then only print out cert file path
   890  	c := s.Config
   891  	log.Debugf("Generated TLS Certificate: %s", c.TLS.CertFile)
   892  
   893  	return nil
   894  }
   895  
   896  // Log is a function required to meet the interface required by statsd
   897  func (s *Server) Log(keyvals ...interface{}) error {
   898  	log.Warning(keyvals...)
   899  	return nil
   900  }
   901  
   902  func (dn *DN) equal(checkDN *DN) error {
   903  	log.Debugf("Check to see if two DNs are equal - %+v and %+v", dn, checkDN)
   904  	if dn.issuer == checkDN.issuer {
   905  		log.Debug("Issuer distinguished name already in use, checking for unique subject distinguished name")
   906  		if dn.subject == checkDN.subject {
   907  			return errors.New("Both issuer and subject distinguished name are already in use")
   908  		}
   909  	}
   910  	return nil
   911  }