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