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