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