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