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