github.com/silveraid/fabric-ca@v1.1.0-preview.0.20180127000700-71974f53ab08/lib/server.go (about) 1 /* 2 Copyright IBM Corp. 2017 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package lib 18 19 import ( 20 "crypto/tls" 21 "crypto/x509" 22 "crypto/x509/pkix" 23 "fmt" 24 "io" 25 "io/ioutil" 26 "net" 27 "net/http" 28 _ "net/http/pprof" // import to support profiling 29 "os" 30 "path/filepath" 31 "strconv" 32 "strings" 33 "sync" 34 "time" 35 36 "github.com/pkg/errors" 37 38 "github.com/cloudflare/cfssl/log" 39 "github.com/cloudflare/cfssl/revoke" 40 "github.com/cloudflare/cfssl/signer" 41 gmux "github.com/gorilla/mux" 42 "github.com/hyperledger/fabric-ca/lib/attr" 43 "github.com/hyperledger/fabric-ca/lib/dbutil" 44 "github.com/hyperledger/fabric-ca/lib/metadata" 45 stls "github.com/hyperledger/fabric-ca/lib/tls" 46 "github.com/hyperledger/fabric-ca/util" 47 "github.com/spf13/viper" 48 49 _ "github.com/go-sql-driver/mysql" // import to support MySQL 50 _ "github.com/lib/pq" // import to support Postgres 51 _ "github.com/mattn/go-sqlite3" // import to support SQLite3 52 ) 53 54 const ( 55 defaultClientAuth = "noclientcert" 56 fabricCAServerProfilePort = "FABRIC_CA_SERVER_PROFILE_PORT" 57 allRoles = "peer,orderer,client,user" 58 apiPathPrefix = "/api/v1/" 59 ) 60 61 // Server is the fabric-ca server 62 type Server struct { 63 // The home directory for the server 64 HomeDir string 65 // BlockingStart if true makes the Start function blocking; 66 // It is non-blocking by default. 67 BlockingStart bool 68 // The server's configuration 69 Config *ServerConfig 70 // The server mux 71 mux *gmux.Router 72 // The current listener for this server 73 listener net.Listener 74 // An error which occurs when serving 75 serveError error 76 // Server's default CA 77 CA 78 // A map of CAs stored by CA name as key 79 caMap map[string]*CA 80 // A map of CA configs stored by CA file as key 81 caConfigMap map[string]*CAConfig 82 // channel for communication between http.serve and main threads. 83 wait chan bool 84 // Server mutex 85 mutex sync.Mutex 86 // The server's current levels 87 levels *dbutil.Levels 88 } 89 90 // Init initializes a fabric-ca server 91 func (s *Server) Init(renew bool) (err error) { 92 err = s.init(renew) 93 err2 := s.closeDB() 94 if err2 != nil { 95 log.Errorf("Close DB failed: %s", err2) 96 } 97 return err 98 } 99 100 // init initializses the server leaving the DB open 101 func (s *Server) init(renew bool) (err error) { 102 serverVersion := metadata.GetVersion() 103 log.Infof("Server Version: %s", serverVersion) 104 s.levels, err = metadata.GetLevels(serverVersion) 105 if err != nil { 106 return err 107 } 108 log.Infof("Server Levels: %+v", s.levels) 109 110 // Initialize the config 111 err = s.initConfig() 112 if err != nil { 113 return err 114 } 115 // Initialize the default CA last 116 err = s.initDefaultCA(renew) 117 if err != nil { 118 return err 119 } 120 // Successful initialization 121 return nil 122 } 123 124 // Start the fabric-ca server 125 func (s *Server) Start() (err error) { 126 log.Infof("Starting server in home directory: %s", s.HomeDir) 127 128 s.serveError = nil 129 130 if s.listener != nil { 131 return errors.New("server is already started") 132 } 133 134 // Initialize the server 135 err = s.init(false) 136 if err != nil { 137 err2 := s.closeDB() 138 if err2 != nil { 139 log.Errorf("Close DB failed: %s", err2) 140 } 141 return err 142 } 143 144 // Register http handlers 145 s.registerHandlers() 146 147 log.Debugf("%d CA instance(s) running on server", len(s.caMap)) 148 149 // Start listening and serving 150 err = s.listenAndServe() 151 if err != nil { 152 err2 := s.closeDB() 153 if err2 != nil { 154 log.Errorf("Close DB failed: %s", err2) 155 } 156 return err 157 } 158 return nil 159 } 160 161 // Stop the server 162 // WARNING: This forcefully closes the listening socket and may cause 163 // requests in transit to fail, and so is only used for testing. 164 // A graceful shutdown will be supported with golang 1.8. 165 func (s *Server) Stop() error { 166 err := s.closeListener() 167 if err != nil { 168 return err 169 } 170 if s.wait == nil { 171 return nil 172 } 173 // Wait for message on wait channel from the http.serve thread. If message 174 // is not received in 10 seconds, return 175 port := s.Config.Port 176 for i := 0; i < 10; i++ { 177 select { 178 case <-s.wait: 179 log.Debugf("Stop: successful stop on port %d", port) 180 close(s.wait) 181 s.wait = nil 182 return nil 183 default: 184 log.Debugf("Stop: waiting for listener on port %d to stop", port) 185 time.Sleep(time.Second) 186 } 187 } 188 log.Debugf("Stop: timed out waiting for stop notification for port %d", port) 189 // make sure DB is closed 190 err = s.closeDB() 191 if err != nil { 192 log.Errorf("Close DB failed: %s", err) 193 } 194 return nil 195 } 196 197 // RegisterBootstrapUser registers the bootstrap user with appropriate privileges 198 func (s *Server) RegisterBootstrapUser(user, pass, affiliation string) error { 199 // Initialize the config, setting defaults, etc 200 log.Debugf("Register bootstrap user: name=%s, affiliation=%s", user, affiliation) 201 202 if user == "" || pass == "" { 203 return errors.New("Empty identity name and/or pass not allowed") 204 } 205 206 id := CAConfigIdentity{ 207 Name: user, 208 Pass: pass, 209 Type: "client", 210 Affiliation: affiliation, 211 MaxEnrollments: 0, // 0 means to use the server's max enrollment setting 212 Attrs: map[string]string{ 213 attr.Roles: allRoles, 214 attr.DelegateRoles: allRoles, 215 attr.Revoker: "true", 216 attr.IntermediateCA: "true", 217 attr.GenCRL: "true", 218 attr.RegistrarAttr: "*", 219 attr.AffiliationMgr: "true", 220 }, 221 } 222 223 registry := &s.CA.Config.Registry 224 registry.Identities = append(registry.Identities, id) 225 226 log.Debugf("Registered bootstrap identity: %+v", id) 227 return nil 228 } 229 230 // initConfig initializes the configuration for the server 231 func (s *Server) initConfig() (err error) { 232 // Home directory is current working directory by default 233 if s.HomeDir == "" { 234 s.HomeDir, err = os.Getwd() 235 if err != nil { 236 return errors.Wrap(err, "Failed to get server's home directory") 237 } 238 } 239 // Make home directory absolute, if not already 240 absoluteHomeDir, err := filepath.Abs(s.HomeDir) 241 if err != nil { 242 return fmt.Errorf("Failed to make server's home directory path absolute: %s", err) 243 } 244 s.HomeDir = absoluteHomeDir 245 // Create config if not set 246 if s.Config == nil { 247 s.Config = new(ServerConfig) 248 } 249 cfg := s.Config 250 // Set log level if debug is true 251 if cfg.Debug { 252 log.Level = log.LevelDebug 253 } 254 s.CA.server = s 255 s.CA.HomeDir = s.HomeDir 256 err = s.initMultiCAConfig() 257 if err != nil { 258 return err 259 } 260 revoke.SetCRLFetcher(s.fetchCRL) 261 // Make file names absolute 262 s.makeFileNamesAbsolute() 263 return nil 264 } 265 266 // Initialize config related to multiple CAs 267 func (s *Server) initMultiCAConfig() (err error) { 268 cfg := s.Config 269 if cfg.CAcount != 0 && len(cfg.CAfiles) > 0 { 270 return errors.New("The --cacount and --cafiles options are mutually exclusive") 271 } 272 cfg.CAfiles, err = util.NormalizeFileList(cfg.CAfiles, s.HomeDir) 273 if err != nil { 274 return err 275 } 276 // Multi-CA related configuration initialization 277 s.caMap = make(map[string]*CA) 278 if cfg.CAcount >= 1 { 279 s.createDefaultCAConfigs(cfg.CAcount) 280 } 281 if len(cfg.CAfiles) != 0 { 282 log.Debugf("Default CA configuration, if necessary, will be used to replace missing values for additional CAs: %+v", s.Config.CAcfg) 283 log.Debugf("Additional CAs to be started: %s", cfg.CAfiles) 284 var caFiles []string 285 caFiles = util.NormalizeStringSlice(cfg.CAfiles) 286 for _, caFile := range caFiles { 287 err = s.loadCA(caFile, false) 288 if err != nil { 289 return err 290 } 291 } 292 } 293 return nil 294 } 295 296 func (s *Server) initDefaultCA(renew bool) error { 297 log.Debugf("Initializing default CA in directory %s", s.HomeDir) 298 ca := &s.CA 299 err := initCA(ca, s.HomeDir, s.CA.Config, s, renew) 300 if err != nil { 301 return err 302 } 303 err = s.addCA(ca) 304 if err != nil { 305 return err 306 } 307 log.Infof("Home directory for default CA: %s", ca.HomeDir) 308 return nil 309 } 310 311 // loadCAConfig loads up a CA's configuration from the specified 312 // CA configuration file 313 func (s *Server) loadCA(caFile string, renew bool) error { 314 log.Infof("Loading CA from %s", caFile) 315 var err error 316 317 if !util.FileExists(caFile) { 318 return errors.Errorf("%s file does not exist", caFile) 319 } 320 321 // Creating new Viper instance, to prevent any server level environment variables or 322 // flags from overridding the configuration options specified in the 323 // CA config file 324 cfg := &CAConfig{} 325 caViper := viper.New() 326 err = UnmarshalConfig(cfg, caViper, caFile, false) 327 if err != nil { 328 return err 329 } 330 331 // Need to error if no CA name provided in config file, we cannot revert to using 332 // the name of default CA cause CA names must be unique 333 caName := cfg.CA.Name 334 if caName == "" { 335 return errors.Errorf("No CA name provided in CA configuration file. CA name is required in %s", caFile) 336 } 337 338 // Replace missing values in CA configuration values with values from the 339 // defaut CA configuration 340 util.CopyMissingValues(s.CA.Config, cfg) 341 342 // Integers and boolean values are handled outside the util.CopyMissingValues 343 // because there is no way through reflect to detect if a value was explicitly 344 // set to 0 or false, or it is using the default value for its type. Viper is 345 // employed here to help detect. 346 if !caViper.IsSet("registry.maxenrollments") { 347 cfg.Registry.MaxEnrollments = s.CA.Config.Registry.MaxEnrollments 348 } 349 350 if !caViper.IsSet("db.tls.enabled") { 351 cfg.DB.TLS.Enabled = s.CA.Config.DB.TLS.Enabled 352 } 353 354 log.Debugf("CA configuration after checking for missing values: %+v", cfg) 355 356 ca, err := newCA(caFile, cfg, s, renew) 357 if err != nil { 358 return err 359 } 360 err = s.addCA(ca) 361 if err != nil { 362 err2 := ca.closeDB() 363 if err2 != nil { 364 log.Errorf("Close DB failed: %s", err2) 365 } 366 } 367 return err 368 } 369 370 // DN is the distinguished name inside a certificate 371 type DN struct { 372 issuer string 373 subject string 374 } 375 376 // addCA adds a CA to the server if there are no conflicts 377 func (s *Server) addCA(ca *CA) error { 378 // check for conflicts 379 caName := ca.Config.CA.Name 380 for _, c := range s.caMap { 381 if c.Config.CA.Name == caName { 382 return errors.Errorf("CA name '%s' is used in '%s' and '%s'", 383 caName, ca.ConfigFilePath, c.ConfigFilePath) 384 } 385 err := s.compareDN(c.Config.CA.Certfile, ca.Config.CA.Certfile) 386 if err != nil { 387 return err 388 } 389 } 390 // no conflicts, so add it 391 s.caMap[caName] = ca 392 393 return nil 394 } 395 396 // closeDB closes all CA dabatases 397 func (s *Server) closeDB() error { 398 log.Debugf("Closing server DBs") 399 // close default CA DB 400 err := s.CA.closeDB() 401 if err != nil { 402 return err 403 } 404 // close other CAs DB 405 for _, c := range s.caMap { 406 err = c.closeDB() 407 if err != nil { 408 return err 409 } 410 } 411 return nil 412 } 413 414 // createDefaultCAConfigs creates specified number of default CA configuration files 415 func (s *Server) createDefaultCAConfigs(cacount int) error { 416 log.Debugf("Creating %d default CA configuration files", cacount) 417 418 cashome, err := util.MakeFileAbs("ca", s.HomeDir) 419 if err != nil { 420 return err 421 } 422 423 os.Mkdir(cashome, 0755) 424 425 for i := 1; i <= cacount; i++ { 426 cahome := fmt.Sprintf(cashome+"/ca%d", i) 427 cfgFileName := filepath.Join(cahome, "fabric-ca-config.yaml") 428 429 caName := fmt.Sprintf("ca%d", i) 430 cfg := strings.Replace(defaultCACfgTemplate, "<<<CANAME>>>", caName, 1) 431 432 cn := fmt.Sprintf("fabric-ca-server-ca%d", i) 433 cfg = strings.Replace(cfg, "<<<COMMONNAME>>>", cn, 1) 434 435 datasource := dbutil.GetCADataSource(s.CA.Config.DB.Type, s.CA.Config.DB.Datasource, i) 436 cfg = strings.Replace(cfg, "<<<DATASOURCE>>>", datasource, 1) 437 438 s.Config.CAfiles = append(s.Config.CAfiles, cfgFileName) 439 440 // Now write the file 441 err := os.MkdirAll(filepath.Dir(cfgFileName), 0755) 442 if err != nil { 443 return err 444 } 445 446 err = ioutil.WriteFile(cfgFileName, []byte(cfg), 0644) 447 if err != nil { 448 return err 449 } 450 451 } 452 return nil 453 } 454 455 // GetCA returns the CA given its name 456 func (s *Server) GetCA(name string) (*CA, error) { 457 // Lookup the CA from the server 458 ca := s.caMap[name] 459 if ca == nil { 460 return nil, newHTTPErr(404, ErrCANotFound, "CA '%s' does not exist", name) 461 } 462 return ca, nil 463 } 464 465 // Register all endpoint handlers 466 func (s *Server) registerHandlers() { 467 s.mux = gmux.NewRouter() 468 s.registerHandler("cainfo", newCAInfoEndpoint(s)) 469 s.registerHandler("register", newRegisterEndpoint(s)) 470 s.registerHandler("enroll", newEnrollEndpoint(s)) 471 s.registerHandler("reenroll", newReenrollEndpoint(s)) 472 s.registerHandler("revoke", newRevokeEndpoint(s)) 473 s.registerHandler("tcert", newTCertEndpoint(s)) 474 s.registerHandler("gencrl", newGenCRLEndpoint(s)) 475 s.registerHandler("identities", newIdentitiesStreamingEndpoint(s)) 476 s.registerHandler("identities/{id}", newIdentitiesEndpoint(s)) 477 s.registerHandler("affiliations", newAffiliationsStreamingEndpoint(s)) 478 s.registerHandler("affiliations/{affiliation}", newAffiliationsEndpoint(s)) 479 } 480 481 // Register a handler 482 func (s *Server) registerHandler(path string, se *serverEndpoint) { 483 s.mux.Handle("/"+path, se) 484 s.mux.Handle(apiPathPrefix+path, se) 485 } 486 487 // Starting listening and serving 488 func (s *Server) listenAndServe() (err error) { 489 490 var listener net.Listener 491 var clientAuth tls.ClientAuthType 492 var ok bool 493 494 c := s.Config 495 496 // Set default listening address and port 497 if c.Address == "" { 498 c.Address = DefaultServerAddr 499 } 500 if c.Port == 0 { 501 c.Port = DefaultServerPort 502 } 503 addr := net.JoinHostPort(c.Address, strconv.Itoa(c.Port)) 504 var addrStr string 505 506 if c.TLS.Enabled { 507 log.Debug("TLS is enabled") 508 addrStr = fmt.Sprintf("https://%s", addr) 509 510 // If key file is specified and it does not exist or its corresponding certificate file does not exist 511 // then need to return error and not start the server. The TLS key file is specified when the user 512 // wants the server to use custom tls key and cert and don't want server to auto generate its own. So, 513 // when the key file is specified, it must exist on the file system 514 if c.TLS.KeyFile != "" { 515 if !util.FileExists(c.TLS.KeyFile) { 516 return fmt.Errorf("File specified by 'tls.keyfile' does not exist: %s", c.TLS.KeyFile) 517 } 518 if !util.FileExists(c.TLS.CertFile) { 519 return fmt.Errorf("File specified by 'tls.certfile' does not exist: %s", c.TLS.CertFile) 520 } 521 } else if !util.FileExists(c.TLS.CertFile) { 522 // TLS key file is not specified, generate TLS key and cert if they are not already generated 523 err = s.autoGenerateTLSCertificateKey() 524 if err != nil { 525 return fmt.Errorf("Failed to automatically generate TLS certificate and key: %s", err) 526 } 527 } 528 log.Debugf("TLS Certificate: %s, TLS Key: %s", c.TLS.CertFile, c.TLS.KeyFile) 529 530 cer, err := util.LoadX509KeyPair(c.TLS.CertFile, c.TLS.KeyFile, s.csp) 531 if err != nil { 532 return err 533 } 534 535 if c.TLS.ClientAuth.Type == "" { 536 c.TLS.ClientAuth.Type = defaultClientAuth 537 } 538 539 log.Debugf("Client authentication type requested: %s", c.TLS.ClientAuth.Type) 540 541 authType := strings.ToLower(c.TLS.ClientAuth.Type) 542 if clientAuth, ok = clientAuthTypes[authType]; !ok { 543 return errors.New("Invalid client auth type provided") 544 } 545 546 var certPool *x509.CertPool 547 if authType != defaultClientAuth { 548 certPool, err = LoadPEMCertPool(c.TLS.ClientAuth.CertFiles) 549 if err != nil { 550 return err 551 } 552 } 553 554 config := &tls.Config{ 555 Certificates: []tls.Certificate{*cer}, 556 ClientAuth: clientAuth, 557 ClientCAs: certPool, 558 MinVersion: tls.VersionTLS12, 559 MaxVersion: tls.VersionTLS12, 560 } 561 562 listener, err = tls.Listen("tcp", addr, config) 563 if err != nil { 564 return errors.Wrapf(err, "TLS listen failed for %s", addrStr) 565 } 566 } else { 567 addrStr = fmt.Sprintf("http://%s", addr) 568 listener, err = net.Listen("tcp", addr) 569 if err != nil { 570 return errors.Wrapf(err, "TCP listen failed for %s", addrStr) 571 } 572 } 573 s.listener = listener 574 log.Infof("Listening on %s", addrStr) 575 576 err = s.checkAndEnableProfiling() 577 if err != nil { 578 s.closeListener() 579 return errors.WithMessage(err, "TCP listen for profiling failed") 580 } 581 582 // Start serving requests, either blocking or non-blocking 583 if s.BlockingStart { 584 return s.serve() 585 } 586 s.wait = make(chan bool) 587 go s.serve() 588 589 return nil 590 } 591 592 func (s *Server) serve() error { 593 listener := s.listener 594 if listener == nil { 595 // This can happen as follows: 596 // 1) listenAndServe above is called with s.BlockingStart set to false 597 // and returns to the caller 598 // 2) the caller immediately calls s.Stop, which sets s.listener to nil 599 // 3) the go routine runs and calls this function 600 // So this prevents the panic which was reported in 601 // in https://jira.hyperledger.org/browse/FAB-3100. 602 return nil 603 } 604 s.serveError = http.Serve(listener, s.mux) 605 log.Errorf("Server has stopped serving: %s", s.serveError) 606 s.closeListener() 607 err := s.closeDB() 608 if err != nil { 609 log.Errorf("Close DB failed: %s", err) 610 } 611 if s.wait != nil { 612 s.wait <- true 613 } 614 return s.serveError 615 } 616 617 // checkAndEnableProfiling checks for FABRIC_CA_SERVER_PROFILE_PORT env variable 618 // if it is set, starts listening for profiling requests at the port specified 619 // by the environment variable 620 func (s *Server) checkAndEnableProfiling() error { 621 // Start listening for profile requests 622 pport := os.Getenv(fabricCAServerProfilePort) 623 if pport != "" { 624 iport, err := strconv.Atoi(pport) 625 if err != nil || iport < 0 { 626 log.Warningf("Profile port specified by the %s environment variable is not a valid port, not enabling profiling", 627 fabricCAServerProfilePort) 628 } else { 629 addr := net.JoinHostPort(s.Config.Address, pport) 630 listener, err1 := net.Listen("tcp", addr) 631 log.Infof("Profiling enabled; listening for profile requests on port %s", pport) 632 if err1 != nil { 633 return err1 634 } 635 go func() { 636 log.Debugf("Profiling enabled; waiting for profile requests on port %s", pport) 637 err := http.Serve(listener, nil) 638 log.Errorf("Stopped serving for profiling requests on port %s: %s", pport, err) 639 }() 640 } 641 } 642 return nil 643 } 644 645 // Make all file names in the config absolute 646 func (s *Server) makeFileNamesAbsolute() error { 647 log.Debug("Making server filenames absolute") 648 err := stls.AbsTLSServer(&s.Config.TLS, s.HomeDir) 649 if err != nil { 650 return err 651 } 652 return nil 653 } 654 655 // closeListener closes the listening endpoint 656 func (s *Server) closeListener() error { 657 s.mutex.Lock() 658 defer s.mutex.Unlock() 659 port := s.Config.Port 660 if s.listener == nil { 661 msg := fmt.Sprintf("Stop: listener was already closed on port %d", port) 662 log.Debugf(msg) 663 return errors.New(msg) 664 } 665 err := s.listener.Close() 666 s.listener = nil 667 if err != nil { 668 log.Debugf("Stop: failed to close listener on port %d: %s", port, err) 669 return err 670 } 671 log.Debugf("Stop: successfully closed listener on port %d", port) 672 return nil 673 } 674 675 func (s *Server) compareDN(existingCACertFile, newCACertFile string) error { 676 log.Debugf("Comparing DNs from certificates: %s and %s", existingCACertFile, newCACertFile) 677 existingDN, err := s.loadDNFromCertFile(existingCACertFile) 678 if err != nil { 679 return err 680 } 681 682 newDN, err := s.loadDNFromCertFile(newCACertFile) 683 if err != nil { 684 return err 685 } 686 687 err = existingDN.equal(newDN) 688 if err != nil { 689 return errors.Wrapf(err, "Please modify CSR in %s and try adding CA again", newCACertFile) 690 } 691 return nil 692 } 693 694 // Read the CRL from body of http response 695 func (s *Server) fetchCRL(r io.Reader) ([]byte, error) { 696 crlSizeLimit := s.Config.CRLSizeLimit 697 log.Debugf("CRL size limit is %d bytes", crlSizeLimit) 698 699 crl := make([]byte, crlSizeLimit) 700 701 crl, err := util.Read(r, crl) 702 if err != nil { 703 return nil, errors.WithMessage(err, fmt.Sprintf("Error reading CRL with max buffer size of %d", crlSizeLimit)) 704 } 705 706 return crl, nil 707 } 708 709 func (s *Server) loadDNFromCertFile(certFile string) (*DN, error) { 710 log.Debugf("Loading DNs from certificate %s", certFile) 711 cert, err := util.GetX509CertificateFromPEMFile(certFile) 712 if err != nil { 713 return nil, err 714 } 715 issuerDN, err := s.getDNFromCert(cert.Issuer, "/") 716 if err != nil { 717 return nil, err 718 } 719 subjectDN, err := s.getDNFromCert(cert.Subject, "/") 720 if err != nil { 721 return nil, err 722 } 723 distinguishedName := &DN{ 724 issuer: issuerDN, 725 subject: subjectDN, 726 } 727 return distinguishedName, nil 728 } 729 730 func (s *Server) autoGenerateTLSCertificateKey() error { 731 log.Debug("TLS enabled but no certificate or key provided, automatically generate TLS credentials") 732 733 clientCfg := &ClientConfig{ 734 CSP: s.CA.Config.CSP, 735 } 736 client := Client{ 737 HomeDir: s.HomeDir, 738 Config: clientCfg, 739 } 740 741 // Generate CSR that will be used to create the TLS certificate 742 csrReq := s.Config.CAcfg.CSR 743 csrReq.CA = nil // Not requesting a CA certificate 744 hostname := util.Hostname() 745 log.Debugf("TLS CSR: %+v\n", csrReq) 746 747 // Can't use the same CN as the signing certificate CN (default: fabric-ca-server) otherwise no AKI is generated 748 csr, _, err := client.GenCSR(&csrReq, hostname) 749 if err != nil { 750 return fmt.Errorf("Failed to generate CSR: %s", err) 751 } 752 753 // Use the 'tls' profile that will return a certificate with the appropriate extensions 754 req := signer.SignRequest{ 755 Profile: "tls", 756 Request: string(csr), 757 } 758 759 // Use default CA to get back signed TLS certificate 760 cert, err := s.CA.enrollSigner.Sign(req) 761 if err != nil { 762 return fmt.Errorf("Failed to generate TLS certificate: %s", err) 763 } 764 765 // Write the TLS certificate to the file system 766 ioutil.WriteFile(s.Config.TLS.CertFile, cert, 0644) 767 768 return nil 769 } 770 771 func (dn *DN) equal(checkDN *DN) error { 772 log.Debugf("Check to see if two DNs are equal - %+v and %+v", dn, checkDN) 773 if dn.issuer == checkDN.issuer { 774 log.Debug("Issuer distinguished name already in use, checking for unique subject distinguished name") 775 if dn.subject == checkDN.subject { 776 return errors.New("Both issuer and subject distinguished name are already in use") 777 } 778 } 779 return nil 780 } 781 782 func (s *Server) getDNFromCert(namespace pkix.Name, sep string) (string, error) { 783 subject := []string{} 784 for _, s := range namespace.ToRDNSequence() { 785 for _, i := range s { 786 if v, ok := i.Value.(string); ok { 787 if name, ok := oid[i.Type.String()]; ok { 788 // <oid name>=<value> 789 subject = append(subject, fmt.Sprintf("%s=%s", name, v)) 790 } else { 791 // <oid>=<value> if no <oid name> is found 792 subject = append(subject, fmt.Sprintf("%s=%s", i.Type.String(), v)) 793 } 794 } else { 795 // <oid>=<value in default format> if value is not string 796 subject = append(subject, fmt.Sprintf("%s=%v", i.Type.String(), v)) 797 } 798 } 799 } 800 return sep + strings.Join(subject, sep), nil 801 } 802 803 var oid = map[string]string{ 804 "2.5.4.3": "CN", 805 "2.5.4.4": "SN", 806 "2.5.4.5": "serialNumber", 807 "2.5.4.6": "C", 808 "2.5.4.7": "L", 809 "2.5.4.8": "ST", 810 "2.5.4.9": "streetAddress", 811 "2.5.4.10": "O", 812 "2.5.4.11": "OU", 813 "2.5.4.12": "title", 814 "2.5.4.17": "postalCode", 815 "2.5.4.42": "GN", 816 "2.5.4.43": "initials", 817 "2.5.4.44": "generationQualifier", 818 "2.5.4.46": "dnQualifier", 819 "2.5.4.65": "pseudonym", 820 "0.9.2342.19200300.100.1.25": "DC", 821 "1.2.840.113549.1.9.1": "emailAddress", 822 "0.9.2342.19200300.100.1.1": "userid", 823 }