github.com/ldc1995/fabric-ca@v2.0.0-alpha.0.20200422214819-8d49c278c386+incompatible/lib/ca.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 "bytes" 11 "crypto/dsa" 12 "crypto/ecdsa" 13 "crypto/rsa" 14 "crypto/x509" 15 "encoding/pem" 16 "fmt" 17 "io/ioutil" 18 "os" 19 "path" 20 "path/filepath" 21 "strconv" 22 "sync" 23 "time" 24 25 "github.com/cloudflare/cfssl/certdb" 26 "github.com/cloudflare/cfssl/config" 27 cfcsr "github.com/cloudflare/cfssl/csr" 28 "github.com/cloudflare/cfssl/initca" 29 "github.com/cloudflare/cfssl/log" 30 "github.com/cloudflare/cfssl/signer" 31 cflocalsigner "github.com/cloudflare/cfssl/signer/local" 32 "github.com/hyperledger/fabric-ca/api" 33 "github.com/hyperledger/fabric-ca/lib/attr" 34 "github.com/hyperledger/fabric-ca/lib/attrmgr" 35 "github.com/hyperledger/fabric-ca/lib/caerrors" 36 "github.com/hyperledger/fabric-ca/lib/common" 37 "github.com/hyperledger/fabric-ca/lib/metadata" 38 "github.com/hyperledger/fabric-ca/lib/server/db" 39 cadb "github.com/hyperledger/fabric-ca/lib/server/db" 40 cadbfactory "github.com/hyperledger/fabric-ca/lib/server/db/factory" 41 "github.com/hyperledger/fabric-ca/lib/server/db/mysql" 42 "github.com/hyperledger/fabric-ca/lib/server/db/postgres" 43 "github.com/hyperledger/fabric-ca/lib/server/db/sqlite" 44 dbutil "github.com/hyperledger/fabric-ca/lib/server/db/util" 45 idemix "github.com/hyperledger/fabric-ca/lib/server/idemix" 46 "github.com/hyperledger/fabric-ca/lib/server/ldap" 47 "github.com/hyperledger/fabric-ca/lib/server/user" 48 cadbuser "github.com/hyperledger/fabric-ca/lib/server/user" 49 "github.com/hyperledger/fabric-ca/lib/tls" 50 "github.com/hyperledger/fabric-ca/util" 51 "github.com/hyperledger/fabric/bccsp" 52 "github.com/pkg/errors" 53 ) 54 55 const ( 56 defaultDatabaseType = "sqlite3" 57 // CAChainParentFirstEnvVar is the name of the environment variable that needs to be set 58 // for server to return CA chain in parent-first order 59 CAChainParentFirstEnvVar = "CA_CHAIN_PARENT_FIRST" 60 ) 61 62 var ( 63 // Default root CA certificate expiration is 15 years (in hours). 64 defaultRootCACertificateExpiration = "131400h" 65 // Default intermediate CA certificate expiration is 5 years (in hours). 66 defaultIntermediateCACertificateExpiration = parseDuration("43800h") 67 // Default issued certificate expiration is 1 year (in hours). 68 defaultIssuedCertificateExpiration = parseDuration("8760h") 69 ) 70 71 // CA represents a certificate authority which signs, issues and revokes certificates 72 type CA struct { 73 // The home directory for the CA 74 HomeDir string 75 // The CA's configuration 76 Config *CAConfig 77 // The file path of the config file 78 ConfigFilePath string 79 // The database handle used to store certificates and optionally 80 // the user registry information, unless LDAP it enabled for the 81 // user registry function. 82 db db.FabricCADB 83 // The crypto service provider (BCCSP) 84 csp bccsp.BCCSP 85 // The certificate DB accessor 86 certDBAccessor *CertDBAccessor 87 // The user registry 88 registry user.Registry 89 // The signer used for enrollment 90 enrollSigner signer.Signer 91 // Idemix issuer 92 issuer idemix.Issuer 93 // The options to use in verifying a signature in token-based authentication 94 verifyOptions *x509.VerifyOptions 95 // The attribute manager 96 attrMgr *attrmgr.Mgr 97 // The server hosting this CA 98 server *Server 99 // DB levels 100 levels *dbutil.Levels 101 // CA mutex 102 mutex sync.Mutex 103 } 104 105 const ( 106 certificateError = "Invalid certificate in file" 107 ) 108 109 // newCA creates a new CA with the specified 110 // home directory, parent server URL, and config 111 func newCA(caFile string, config *CAConfig, server *Server, renew bool) (*CA, error) { 112 ca := new(CA) 113 ca.ConfigFilePath = caFile 114 err := initCA(ca, filepath.Dir(caFile), config, server, renew) 115 if err != nil { 116 err2 := ca.closeDB() 117 if err2 != nil { 118 log.Errorf("Close DB failed: %s", err2) 119 } 120 return nil, err 121 } 122 return ca, nil 123 } 124 125 // initCA will initialize the passed in pointer to a CA struct 126 func initCA(ca *CA, homeDir string, config *CAConfig, server *Server, renew bool) error { 127 ca.HomeDir = homeDir 128 ca.Config = config 129 ca.server = server 130 131 err := ca.init(renew) 132 if err != nil { 133 return err 134 } 135 log.Debug("Initializing Idemix issuer...") 136 ca.issuer = idemix.NewIssuer(ca.Config.CA.Name, ca.HomeDir, 137 &ca.Config.Idemix, ca.csp, idemix.NewLib()) 138 err = ca.issuer.Init(renew, ca.db, ca.levels) 139 if err != nil { 140 return errors.WithMessage(err, fmt.Sprintf("Failed to initialize Idemix issuer for CA '%s'", err.Error())) 141 } 142 return nil 143 } 144 145 // Init initializes an instance of a CA 146 func (ca *CA) init(renew bool) (err error) { 147 log.Debugf("Init CA with home %s and config %+v", ca.HomeDir, *ca.Config) 148 149 // Initialize the config, setting defaults, etc 150 err = ca.initConfig() 151 if err != nil { 152 return err 153 } 154 155 // Initialize the crypto layer (BCCSP) for this CA 156 ca.csp, err = util.InitBCCSP(&ca.Config.CSP, "", ca.HomeDir) 157 if err != nil { 158 return err 159 } 160 161 // Initialize key materials 162 err = ca.initKeyMaterial(renew) 163 if err != nil { 164 return err 165 } 166 167 // Initialize the database 168 err = ca.initDB(ca.server.dbMetrics) 169 if err != nil { 170 log.Error("Error occurred initializing database: ", err) 171 // Return if a server configuration error encountered (e.g. Invalid max enrollment for a bootstrap user) 172 if caerrors.IsFatalError(err) { 173 return err 174 } 175 } 176 // Initialize the enrollment signer 177 err = ca.initEnrollmentSigner() 178 if err != nil { 179 return err 180 } 181 // Create the attribute manager 182 ca.attrMgr = attrmgr.New() 183 log.Debug("CA initialization successful") 184 // Successful initialization 185 return nil 186 } 187 188 // Initialize the CA's key material 189 func (ca *CA) initKeyMaterial(renew bool) error { 190 log.Debug("Initialize key material") 191 192 // Make the path names absolute in the config 193 err := ca.makeFileNamesAbsolute() 194 if err != nil { 195 return err 196 } 197 198 keyFile := ca.Config.CA.Keyfile 199 certFile := ca.Config.CA.Certfile 200 201 // If we aren't renewing and the key and cert files exist, do nothing 202 if !renew { 203 // If they both exist, the CA was already initialized 204 keyFileExists := util.FileExists(keyFile) 205 certFileExists := util.FileExists(certFile) 206 if keyFileExists && certFileExists { 207 log.Info("The CA key and certificate files already exist") 208 log.Infof("Key file location: %s", keyFile) 209 log.Infof("Certificate file location: %s", certFile) 210 err = ca.validateCertAndKey(certFile, keyFile) 211 if err != nil { 212 return errors.WithMessage(err, "Validation of certificate and key failed") 213 } 214 // Load CN from existing enrollment information and set CSR accordingly 215 // CN needs to be set, having a multi CA setup requires a unique CN and can't 216 // be left blank 217 ca.Config.CSR.CN, err = ca.loadCNFromEnrollmentInfo(certFile) 218 if err != nil { 219 return err 220 } 221 return nil 222 } 223 224 // If key file does not exist but certFile does, key file is probably 225 // stored by BCCSP, so check for that now. 226 if certFileExists { 227 _, _, _, err = util.GetSignerFromCertFile(certFile, ca.csp) 228 if err != nil { 229 return errors.WithMessage(err, fmt.Sprintf("Failed to find private key for certificate in '%s'", certFile)) 230 } 231 // Yes, it is stored by BCCSP 232 log.Info("The CA key and certificate already exist") 233 log.Infof("The key is stored by BCCSP provider '%s'", ca.Config.CSP.ProviderName) 234 log.Infof("The certificate is at: %s", certFile) 235 // Load CN from existing enrollment information and set CSR accordingly 236 // CN needs to be set, having a multi CA setup requires a unique CN and can't 237 // be left blank 238 ca.Config.CSR.CN, err = ca.loadCNFromEnrollmentInfo(certFile) 239 if err != nil { 240 return errors.WithMessage(err, fmt.Sprintf("Failed to get CN for certificate in '%s'", certFile)) 241 } 242 return nil 243 } 244 log.Warning(caerrors.NewServerError(caerrors.ErrCACertFileNotFound, "The specified CA certificate file %s does not exist", certFile)) 245 } 246 247 // Get the CA cert 248 cert, err := ca.getCACert() 249 if err != nil { 250 return err 251 } 252 // Store the certificate to file 253 err = writeFile(certFile, cert, 0644) 254 if err != nil { 255 return errors.Wrap(err, "Failed to store certificate") 256 } 257 log.Infof("The CA key and certificate were generated for CA %s", ca.Config.CA.Name) 258 log.Infof("The key was stored by BCCSP provider '%s'", ca.Config.CSP.ProviderName) 259 log.Infof("The certificate is at: %s", certFile) 260 261 return nil 262 } 263 264 // Get the CA certificate for this CA 265 func (ca *CA) getCACert() (cert []byte, err error) { 266 if ca.Config.Intermediate.ParentServer.URL != "" { 267 // This is an intermediate CA, so call the parent fabric-ca-server 268 // to get the cert 269 log.Debugf("Getting CA cert; parent server URL is %s", util.GetMaskedURL(ca.Config.Intermediate.ParentServer.URL)) 270 clientCfg := ca.Config.Client 271 if clientCfg == nil { 272 clientCfg = &ClientConfig{} 273 } 274 // Copy over the intermediate configuration into client configuration 275 clientCfg.TLS = ca.Config.Intermediate.TLS 276 clientCfg.Enrollment = ca.Config.Intermediate.Enrollment 277 clientCfg.CAName = ca.Config.Intermediate.ParentServer.CAName 278 clientCfg.CSP = ca.Config.CSP 279 clientCfg.CSR = ca.Config.CSR 280 clientCfg.CSP = ca.Config.CSP 281 if ca.Config.CSR.CN != "" { 282 return nil, errors.Errorf("CN '%s' cannot be specified for an intermediate CA. Remove CN from CSR section for enrollment of intermediate CA to be successful", ca.Config.CSR.CN) 283 } 284 if clientCfg.Enrollment.Profile == "" { 285 clientCfg.Enrollment.Profile = "ca" 286 } 287 if clientCfg.Enrollment.CSR == nil { 288 clientCfg.Enrollment.CSR = &api.CSRInfo{} 289 } 290 if clientCfg.Enrollment.CSR.CA == nil { 291 clientCfg.Enrollment.CSR.CA = &cfcsr.CAConfig{PathLength: 0, PathLenZero: true} 292 } 293 log.Debugf("Intermediate enrollment request: %+v, CSR: %+v, CA: %+v", 294 clientCfg.Enrollment, clientCfg.Enrollment.CSR, clientCfg.Enrollment.CSR.CA) 295 var resp *EnrollmentResponse 296 resp, err = clientCfg.Enroll(ca.Config.Intermediate.ParentServer.URL, ca.HomeDir) 297 if err != nil { 298 return nil, err 299 } 300 // Set the CN for an intermediate server to be the ID used to enroll with root CA 301 ca.Config.CSR.CN = resp.Identity.GetName() 302 ecert := resp.Identity.GetECert() 303 if ecert == nil { 304 return nil, errors.New("No enrollment certificate returned by parent server") 305 } 306 cert = ecert.Cert() 307 // Store the chain file as the concatenation of the parent's chain plus the cert. 308 chainPath := ca.Config.CA.Chainfile 309 chain, err := ca.concatChain(resp.CAInfo.CAChain, cert) 310 if err != nil { 311 return nil, err 312 } 313 err = os.MkdirAll(path.Dir(chainPath), 0755) 314 if err != nil { 315 return nil, errors.Wrap(err, "Failed to create intermediate chain file directory") 316 } 317 err = util.WriteFile(chainPath, chain, 0644) 318 if err != nil { 319 return nil, errors.WithMessage(err, "Failed to create intermediate chain file") 320 } 321 log.Debugf("Stored intermediate certificate chain at %s", chainPath) 322 } else { 323 // This is a root CA, so create a CSR (Certificate Signing Request) 324 if ca.Config.CSR.CN == "" { 325 ca.Config.CSR.CN = "fabric-ca-server" 326 } 327 csr := &ca.Config.CSR 328 if csr.CA == nil { 329 csr.CA = &cfcsr.CAConfig{} 330 } 331 if csr.CA.Expiry == "" { 332 csr.CA.Expiry = defaultRootCACertificateExpiration 333 } 334 335 if (csr.KeyRequest == nil) || (csr.KeyRequest.Algo == "" && csr.KeyRequest.Size == 0) { 336 csr.KeyRequest = GetKeyRequest(ca.Config) 337 } 338 req := cfcsr.CertificateRequest{ 339 CN: csr.CN, 340 Names: csr.Names, 341 Hosts: csr.Hosts, 342 KeyRequest: &cfcsr.BasicKeyRequest{A: csr.KeyRequest.Algo, S: csr.KeyRequest.Size}, 343 CA: csr.CA, 344 SerialNumber: csr.SerialNumber, 345 } 346 log.Debugf("Root CA certificate request: %+v", req) 347 // Generate the key/signer 348 _, cspSigner, err := util.BCCSPKeyRequestGenerate(&req, ca.csp) 349 if err != nil { 350 return nil, err 351 } 352 // Call CFSSL to initialize the CA 353 cert, _, err = initca.NewFromSigner(&req, cspSigner) 354 if err != nil { 355 return nil, errors.WithMessage(err, "Failed to create new CA certificate") 356 } 357 } 358 return cert, nil 359 } 360 361 // Return a certificate chain which is the concatenation of chain and cert 362 func (ca *CA) concatChain(chain []byte, cert []byte) ([]byte, error) { 363 result := make([]byte, len(chain)+len(cert)) 364 parentFirst, ok := os.LookupEnv(CAChainParentFirstEnvVar) 365 parentFirstBool := false 366 // If CA_CHAIN_PARENT_FIRST env variable is set then get the boolean 367 // value 368 if ok { 369 var err error 370 parentFirstBool, err = strconv.ParseBool(parentFirst) 371 if err != nil { 372 return nil, errors.Wrapf(err, "failed to parse the environment variable '%s'", CAChainParentFirstEnvVar) 373 } 374 } 375 if parentFirstBool { 376 copy(result[:len(chain)], chain) 377 copy(result[len(chain):], cert) 378 } else { 379 copy(result[:len(cert)], cert) 380 copy(result[len(cert):], chain) 381 } 382 return result, nil 383 } 384 385 // Get the certificate chain for the CA 386 func (ca *CA) getCAChain() (chain []byte, err error) { 387 if ca.Config == nil { 388 return nil, errors.New("The server has no configuration") 389 } 390 certAuth := &ca.Config.CA 391 // If the chain file exists, we always return the chain from here 392 if util.FileExists(certAuth.Chainfile) { 393 return util.ReadFile(certAuth.Chainfile) 394 } 395 // Otherwise, if this is a root CA, we always return the contents of the CACertfile 396 if ca.Config.Intermediate.ParentServer.URL == "" { 397 return util.ReadFile(certAuth.Certfile) 398 } 399 // If this is an intermediate CA but the ca.Chainfile doesn't exist, 400 // it is an error. It should have been created during intermediate CA enrollment. 401 return nil, errors.Errorf("Chain file does not exist at %s", certAuth.Chainfile) 402 } 403 404 // Initialize the configuration for the CA setting any defaults and making filenames absolute 405 func (ca *CA) initConfig() (err error) { 406 // Init home directory if not set 407 if ca.HomeDir == "" { 408 ca.HomeDir, err = os.Getwd() 409 if err != nil { 410 return errors.Wrap(err, "Failed to initialize CA's home directory") 411 } 412 } 413 log.Debugf("CA Home Directory: %s", ca.HomeDir) 414 // Init config if not set 415 if ca.Config == nil { 416 ca.Config = new(CAConfig) 417 ca.Config.Registry.MaxEnrollments = -1 418 } 419 // Set config defaults 420 cfg := ca.Config 421 if cfg.Version == "" { 422 cfg.Version = "0" 423 } 424 if cfg.CA.Certfile == "" { 425 cfg.CA.Certfile = "ca-cert.pem" 426 } 427 if cfg.CA.Keyfile == "" { 428 cfg.CA.Keyfile = "ca-key.pem" 429 } 430 if cfg.CA.Chainfile == "" { 431 cfg.CA.Chainfile = "ca-chain.pem" 432 } 433 if cfg.CSR.CA == nil { 434 cfg.CSR.CA = &cfcsr.CAConfig{} 435 } 436 if cfg.CSR.CA.Expiry == "" { 437 cfg.CSR.CA.Expiry = defaultRootCACertificateExpiration 438 } 439 if cfg.Signing == nil { 440 cfg.Signing = &config.Signing{} 441 } 442 cs := cfg.Signing 443 if cs.Profiles == nil { 444 cs.Profiles = make(map[string]*config.SigningProfile) 445 } 446 caProfile := cs.Profiles["ca"] 447 initSigningProfile(&caProfile, 448 defaultIntermediateCACertificateExpiration, 449 true) 450 cs.Profiles["ca"] = caProfile 451 initSigningProfile( 452 &cs.Default, 453 defaultIssuedCertificateExpiration, 454 false) 455 tlsProfile := cs.Profiles["tls"] 456 initSigningProfile(&tlsProfile, 457 defaultIssuedCertificateExpiration, 458 false) 459 cs.Profiles["tls"] = tlsProfile 460 err = ca.checkConfigLevels() 461 if err != nil { 462 return err 463 } 464 // Set log level if debug is true 465 if ca.server != nil && ca.server.Config != nil && ca.server.Config.Debug { 466 log.Level = log.LevelDebug 467 } 468 ca.normalizeStringSlices() 469 470 return nil 471 } 472 473 // VerifyCertificate verifies that 'cert' was issued by this CA 474 // Return nil if successful; otherwise, return an error. 475 func (ca *CA) VerifyCertificate(cert *x509.Certificate) error { 476 opts, err := ca.getVerifyOptions() 477 if err != nil { 478 return errors.WithMessage(err, "Failed to get verify options") 479 } 480 _, err = cert.Verify(*opts) 481 if err != nil { 482 return errors.WithMessage(err, "Failed to verify certificate") 483 } 484 return nil 485 } 486 487 // Get the options to verify 488 func (ca *CA) getVerifyOptions() (*x509.VerifyOptions, error) { 489 if ca.verifyOptions != nil { 490 return ca.verifyOptions, nil 491 } 492 chain, err := ca.getCAChain() 493 if err != nil { 494 return nil, err 495 } 496 var intPool *x509.CertPool 497 var rootPool *x509.CertPool 498 499 for len(chain) > 0 { 500 var block *pem.Block 501 block, chain = pem.Decode(chain) 502 if block == nil { 503 break 504 } 505 if block.Type != "CERTIFICATE" { 506 continue 507 } 508 509 cert, err := x509.ParseCertificate(block.Bytes) 510 if err != nil { 511 return nil, errors.Wrap(err, "Failed to parse CA chain certificate") 512 } 513 514 if !cert.IsCA { 515 return nil, errors.New("A certificate in the CA chain is not a CA certificate") 516 } 517 518 // If authority key id is not present or if it is present and equal to subject key id, 519 // then it is a root certificate 520 if len(cert.AuthorityKeyId) == 0 || bytes.Equal(cert.AuthorityKeyId, cert.SubjectKeyId) { 521 if rootPool == nil { 522 rootPool = x509.NewCertPool() 523 } 524 rootPool.AddCert(cert) 525 } else { 526 if intPool == nil { 527 intPool = x509.NewCertPool() 528 } 529 intPool.AddCert(cert) 530 } 531 } 532 533 ca.verifyOptions = &x509.VerifyOptions{ 534 Roots: rootPool, 535 Intermediates: intPool, 536 KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, 537 } 538 return ca.verifyOptions, nil 539 } 540 541 // Initialize the database for the CA 542 func (ca *CA) initDB(metrics *db.Metrics) error { 543 log.Debug("Initializing DB") 544 545 // If DB is initialized, don't need to proceed further 546 if ca.db != nil && ca.db.IsInitialized() { 547 return nil 548 } 549 550 ca.mutex.Lock() 551 defer ca.mutex.Unlock() 552 553 // After obtaining a lock, check again to see if DB got initialized by another process 554 if ca.db != nil && ca.db.IsInitialized() { 555 return nil 556 } 557 558 dbCfg := &ca.Config.DB 559 dbError := false 560 var err error 561 562 if dbCfg.Type == "" || dbCfg.Type == defaultDatabaseType { 563 564 dbCfg.Type = defaultDatabaseType 565 566 if dbCfg.Datasource == "" { 567 dbCfg.Datasource = "fabric-ca-server.db" 568 } 569 570 dbCfg.Datasource, err = util.MakeFileAbs(dbCfg.Datasource, ca.HomeDir) 571 if err != nil { 572 return err 573 } 574 } 575 576 // Strip out user:pass from datasource for logging 577 ds := dbCfg.Datasource 578 ds = dbutil.MaskDBCred(ds) 579 580 log.Debugf("Initializing '%s' database at '%s'", dbCfg.Type, ds) 581 caDB, err := cadbfactory.New( 582 dbCfg.Type, 583 dbCfg.Datasource, 584 ca.Config.CA.Name, 585 &dbCfg.TLS, 586 ca.csp, 587 metrics, 588 ) 589 if err != nil { 590 return err 591 } 592 err = caDB.Connect() 593 if err != nil { 594 return err 595 } 596 sqlxdb, err := caDB.Create() 597 if err != nil { 598 return err 599 } 600 601 sqlxdb.Metrics = metrics 602 603 ca.db = sqlxdb 604 // Set the certificate DB accessor 605 ca.certDBAccessor = NewCertDBAccessor(ca.db, ca.levels.Certificate) 606 607 // If DB initialization fails and we need to reinitialize DB, need to make sure to set the DB accessor for the signer 608 if ca.enrollSigner != nil { 609 ca.enrollSigner.SetDBAccessor(ca.certDBAccessor) 610 } 611 612 // Initialize user registry to either use DB or LDAP 613 err = ca.initUserRegistry() 614 if err != nil { 615 return err 616 } 617 618 err = ca.checkDBLevels() 619 if err != nil { 620 return err 621 } 622 623 // Migrate the database 624 curLevels, err := cadb.CurrentDBLevels(ca.db) 625 if err != nil { 626 return errors.Wrap(err, "Failed to current ca levels") 627 } 628 migrator, err := getMigrator(ca.db.DriverName(), ca.db.BeginTx(), curLevels, ca.server.levels) 629 if err != nil { 630 return errors.Wrap(err, "Failed to get migrator") 631 } 632 err = db.Migrate(migrator, curLevels, ca.server.levels) 633 if err != nil { 634 return errors.Wrap(err, "Failed to migrate database") 635 } 636 637 // If not using LDAP, migrate database if needed to latest version and load the users and affiliations table 638 if !ca.Config.LDAP.Enabled { 639 err = ca.loadUsersTable() 640 if err != nil { 641 log.Error(err) 642 dbError = true 643 if caerrors.IsFatalError(err) { 644 return err 645 } 646 } 647 648 err = ca.loadAffiliationsTable() 649 if err != nil { 650 log.Error(err) 651 dbError = true 652 } 653 } 654 655 if dbError { 656 return errors.Errorf("Failed to initialize %s database at %s ", dbCfg.Type, ds) 657 } 658 659 ca.db.SetDBInitialized(true) 660 log.Infof("Initialized %s database at %s", dbCfg.Type, ds) 661 662 return nil 663 } 664 665 // Close CA's DB 666 func (ca *CA) closeDB() error { 667 if ca.db != nil { 668 err := ca.db.Close() 669 ca.db = nil 670 if err != nil { 671 return errors.Wrapf(err, "Failed to close CA database, where CA home directory is '%s'", ca.HomeDir) 672 } 673 } 674 return nil 675 } 676 677 // Initialize the user registry interface 678 func (ca *CA) initUserRegistry() error { 679 log.Debug("Initializing identity registry") 680 var err error 681 ldapCfg := &ca.Config.LDAP 682 683 if ldapCfg.Enabled { 684 // Use LDAP for the user registry 685 ca.registry, err = ldap.NewClient(ldapCfg, ca.server.csp) 686 log.Debugf("Initialized LDAP identity registry; err=%s", err) 687 if err == nil { 688 log.Info("Successfully initialized LDAP client") 689 } else { 690 log.Warningf("Failed to initialize LDAP client; err=%s", err) 691 } 692 return err 693 } 694 695 // Use the DB for the user registry 696 ca.registry = NewDBAccessor(ca.db) 697 log.Debug("Initialized DB identity registry") 698 return nil 699 } 700 701 // Initialize the enrollment signer 702 func (ca *CA) initEnrollmentSigner() (err error) { 703 log.Debug("Initializing enrollment signer") 704 c := ca.Config 705 706 // If there is a config, use its signing policy. Otherwise create a default policy. 707 var policy *config.Signing 708 if c.Signing != nil { 709 policy = c.Signing 710 } else { 711 policy = &config.Signing{ 712 Profiles: map[string]*config.SigningProfile{}, 713 Default: config.DefaultConfig(), 714 } 715 policy.Default.CAConstraint.IsCA = true 716 } 717 718 // Make sure the policy reflects the new remote 719 parentServerURL := ca.Config.Intermediate.ParentServer.URL 720 if parentServerURL != "" { 721 err = policy.OverrideRemotes(parentServerURL) 722 if err != nil { 723 return errors.Wrap(err, "Failed initializing enrollment signer") 724 } 725 } 726 727 ca.enrollSigner, err = util.BccspBackedSigner(c.CA.Certfile, c.CA.Keyfile, policy, ca.csp) 728 if err != nil { 729 return err 730 } 731 ca.enrollSigner.SetDBAccessor(ca.certDBAccessor) 732 733 // Successful enrollment 734 return nil 735 } 736 737 // loadUsersTable adds the configured users to the table if not already found 738 func (ca *CA) loadUsersTable() error { 739 log.Debug("Loading identity table") 740 registry := &ca.Config.Registry 741 for _, id := range registry.Identities { 742 log.Debugf("Loading identity '%s'", id.Name) 743 err := ca.addIdentity(&id, false) 744 if err != nil { 745 return errors.WithMessage(err, "Failed to load identity table") 746 } 747 } 748 log.Debug("Successfully loaded identity table") 749 return nil 750 } 751 752 // loadAffiliationsTable adds the configured affiliations to the table 753 func (ca *CA) loadAffiliationsTable() error { 754 log.Debug("Loading affiliations table") 755 err := ca.loadAffiliationsTableR(ca.Config.Affiliations, "") 756 if err != nil { 757 return errors.WithMessage(err, "Failed to load affiliations table") 758 } 759 log.Debug("Successfully loaded affiliations table") 760 return nil 761 } 762 763 // Recursive function to load the affiliations table hierarchy 764 func (ca *CA) loadAffiliationsTableR(val interface{}, parentPath string) (err error) { 765 var path string 766 if val == nil { 767 return nil 768 } 769 switch val.(type) { 770 case string: 771 path = affiliationPath(val.(string), parentPath) 772 err = ca.addAffiliation(path, parentPath) 773 if err != nil { 774 return err 775 } 776 case []string: 777 for _, ele := range val.([]string) { 778 err = ca.loadAffiliationsTableR(ele, parentPath) 779 if err != nil { 780 return err 781 } 782 } 783 case []interface{}: 784 for _, ele := range val.([]interface{}) { 785 err = ca.loadAffiliationsTableR(ele, parentPath) 786 if err != nil { 787 return err 788 } 789 } 790 default: 791 for name, ele := range val.(map[string]interface{}) { 792 path = affiliationPath(name, parentPath) 793 err = ca.addAffiliation(path, parentPath) 794 if err != nil { 795 return err 796 } 797 err = ca.loadAffiliationsTableR(ele, path) 798 if err != nil { 799 return err 800 } 801 } 802 } 803 return nil 804 } 805 806 // Add an identity to the registry 807 func (ca *CA) addIdentity(id *CAConfigIdentity, errIfFound bool) error { 808 var err error 809 user, _ := ca.registry.GetUser(id.Name, nil) 810 if user != nil { 811 if errIfFound { 812 return errors.Errorf("Identity '%s' is already registered", id.Name) 813 } 814 log.Debugf("Identity '%s' already registered, loaded identity", user.GetName()) 815 return nil 816 } 817 818 id.MaxEnrollments, err = getMaxEnrollments(id.MaxEnrollments, ca.Config.Registry.MaxEnrollments) 819 if err != nil { 820 return caerrors.NewFatalError(caerrors.ErrConfig, "Configuration Error: %s", err) 821 } 822 823 attrs, err := attr.ConvertAttrs(id.Attrs) 824 825 if err != nil { 826 return err 827 } 828 829 rec := cadbuser.Info{ 830 Name: id.Name, 831 Pass: id.Pass, 832 Type: id.Type, 833 Affiliation: id.Affiliation, 834 Attributes: attrs, 835 MaxEnrollments: id.MaxEnrollments, 836 Level: ca.levels.Identity, 837 } 838 err = ca.registry.InsertUser(&rec) 839 if err != nil { 840 return errors.WithMessage(err, fmt.Sprintf("Failed to insert identity '%s'", id.Name)) 841 } 842 log.Debugf("Registered identity: %+v", id) 843 return nil 844 } 845 846 func (ca *CA) addAffiliation(path, parentPath string) error { 847 return ca.registry.InsertAffiliation(path, parentPath, ca.levels.Affiliation) 848 } 849 850 // CertDBAccessor returns the certificate DB accessor for CA 851 func (ca *CA) CertDBAccessor() *CertDBAccessor { 852 return ca.certDBAccessor 853 } 854 855 // DBAccessor returns the registry DB accessor for server 856 func (ca *CA) DBAccessor() user.Registry { 857 return ca.registry 858 } 859 860 // GetDB returns pointer to database 861 func (ca *CA) GetDB() db.FabricCADB { 862 return ca.db 863 } 864 865 // GetCertificate returns a single certificate matching serial and aki, if multiple certificates 866 // found for serial and aki an error is returned 867 func (ca *CA) GetCertificate(serial, aki string) (*certdb.CertificateRecord, error) { 868 certs, err := ca.CertDBAccessor().GetCertificate(serial, aki) 869 if err != nil { 870 return nil, err 871 } 872 if len(certs) == 0 { 873 return nil, caerrors.NewAuthenticationErr(caerrors.ErrCertNotFound, "Certificate not found with AKI '%s' and serial '%s'", aki, serial) 874 } 875 if len(certs) > 1 { 876 return nil, caerrors.NewAuthenticationErr(caerrors.ErrCertNotFound, "Multiple certificates found, when only should exist with AKI '%s' and serial '%s' combination", aki, serial) 877 } 878 return &certs[0], nil 879 } 880 881 // Make all file names in the CA config absolute 882 func (ca *CA) makeFileNamesAbsolute() error { 883 log.Debug("Making CA filenames absolute") 884 885 fields := []*string{ 886 &ca.Config.CA.Certfile, 887 &ca.Config.CA.Keyfile, 888 &ca.Config.CA.Chainfile, 889 } 890 err := util.MakeFileNamesAbsolute(fields, ca.HomeDir) 891 if err != nil { 892 return err 893 } 894 err = tls.AbsTLSClient(&ca.Config.DB.TLS, ca.HomeDir) 895 if err != nil { 896 return err 897 } 898 err = tls.AbsTLSClient(&ca.Config.LDAP.TLS, ca.HomeDir) 899 if err != nil { 900 return err 901 } 902 return nil 903 } 904 905 // Convert all comma separated strings to string arrays 906 func (ca *CA) normalizeStringSlices() { 907 fields := []*[]string{ 908 &ca.Config.CSR.Hosts, 909 &ca.Config.DB.TLS.CertFiles, 910 &ca.Config.LDAP.TLS.CertFiles, 911 } 912 for _, namePtr := range fields { 913 norm := util.NormalizeStringSlice(*namePtr) 914 *namePtr = norm 915 } 916 } 917 918 // userHasAttribute returns nil error and the value of the attribute 919 // if the user has the attribute, or an appropriate error if the user 920 // does not have this attribute. 921 func (ca *CA) userHasAttribute(username, attrname string) (string, error) { 922 val, err := ca.getUserAttrValue(username, attrname) 923 if err != nil { 924 return "", err 925 } 926 if val == "" { 927 return "", errors.Errorf("Identity '%s' does not have attribute '%s'", username, attrname) 928 } 929 return val, nil 930 } 931 932 // attributeIsTrue returns nil if the attribute has 933 // one of the following values: "1", "t", "T", "true", "TRUE", "True"; 934 // otherwise it will return an error 935 func (ca *CA) attributeIsTrue(username, attrname string) error { 936 val, err := ca.userHasAttribute(username, attrname) 937 if err != nil { 938 return err 939 } 940 val2, err := strconv.ParseBool(val) 941 if err != nil { 942 return errors.Wrapf(err, "Invalid value for attribute '%s' of identity '%s'", attrname, username) 943 } 944 if val2 { 945 return nil 946 } 947 return errors.Errorf("Attribute '%s' is not set to true for identity '%s'", attrname, username) 948 } 949 950 // getUserAttrValue returns a user's value for an attribute 951 func (ca *CA) getUserAttrValue(username, attrname string) (string, error) { 952 log.Debugf("getUserAttrValue identity=%s, attr=%s", username, attrname) 953 user, err := ca.registry.GetUser(username, []string{attrname}) 954 if err != nil { 955 return "", err 956 } 957 attrval, err := user.GetAttribute(attrname) 958 if err != nil { 959 return "", errors.WithMessage(err, fmt.Sprintf("Failed to get attribute '%s' for user '%s'", attrname, user.GetName())) 960 } 961 log.Debugf("getUserAttrValue identity=%s, name=%s, value=%s", username, attrname, attrval) 962 return attrval.Value, nil 963 } 964 965 // getUserAffiliation returns a user's affiliation 966 func (ca *CA) getUserAffiliation(username string) (string, error) { 967 log.Debugf("getUserAffilliation identity=%s", username) 968 user, err := ca.registry.GetUser(username, nil) 969 if err != nil { 970 return "", err 971 } 972 aff := cadbuser.GetAffiliation(user) 973 log.Debugf("getUserAffiliation identity=%s, aff=%s", username, aff) 974 return aff, nil 975 } 976 977 // fillCAInfo fills the CA info structure appropriately 978 func (ca *CA) fillCAInfo(info *common.CAInfoResponseNet) error { 979 caChain, err := ca.getCAChain() 980 if err != nil { 981 return err 982 } 983 info.CAName = ca.Config.CA.Name 984 info.CAChain = util.B64Encode(caChain) 985 986 ipkBytes, err := ca.issuer.IssuerPublicKey() 987 if err != nil { 988 return err 989 } 990 rpkBytes, err := ca.issuer.RevocationPublicKey() 991 if err != nil { 992 return err 993 } 994 info.IssuerPublicKey = util.B64Encode(ipkBytes) 995 info.IssuerRevocationPublicKey = util.B64Encode(rpkBytes) 996 return nil 997 } 998 999 // Perfroms checks on the provided CA cert to make sure it's valid 1000 func (ca *CA) validateCertAndKey(certFile string, keyFile string) error { 1001 log.Debug("Validating the CA certificate and key") 1002 var err error 1003 var certPEM []byte 1004 1005 certPEM, err = ioutil.ReadFile(certFile) 1006 if err != nil { 1007 return errors.Wrapf(err, certificateError+" '%s'", certFile) 1008 } 1009 1010 cert, err := util.GetX509CertificateFromPEM(certPEM) 1011 if err != nil { 1012 return errors.WithMessage(err, fmt.Sprintf(certificateError+" '%s'", certFile)) 1013 } 1014 1015 if err = validateDates(cert); err != nil { 1016 return errors.WithMessage(err, fmt.Sprintf(certificateError+" '%s'", certFile)) 1017 } 1018 if err = validateUsage(cert, ca.Config.CA.Name); err != nil { 1019 return errors.WithMessage(err, fmt.Sprintf(certificateError+" '%s'", certFile)) 1020 } 1021 if err = validateIsCA(cert); err != nil { 1022 return errors.WithMessage(err, fmt.Sprintf(certificateError+" '%s'", certFile)) 1023 } 1024 if err = validateKeyType(cert); err != nil { 1025 return errors.WithMessage(err, fmt.Sprintf(certificateError+" '%s'", certFile)) 1026 } 1027 if err = validateKeySize(cert); err != nil { 1028 return errors.WithMessage(err, fmt.Sprintf(certificateError+" '%s'", certFile)) 1029 } 1030 if err = validateMatchingKeys(cert, keyFile); err != nil { 1031 return errors.WithMessage(err, fmt.Sprintf("Invalid certificate and/or key in files '%s' and '%s'", certFile, keyFile)) 1032 } 1033 log.Debug("Validation of CA certificate and key successful") 1034 1035 return nil 1036 } 1037 1038 // Returns expiration of the CA certificate 1039 func (ca *CA) getCACertExpiry() (time.Time, error) { 1040 var caexpiry time.Time 1041 signer, ok := ca.enrollSigner.(*cflocalsigner.Signer) 1042 if ok { 1043 cacert, err := signer.Certificate("", "ca") 1044 if err != nil { 1045 log.Errorf("Failed to get CA certificate for CA %s: %s", ca.Config.CA.Name, err) 1046 return caexpiry, err 1047 } else if cacert != nil { 1048 caexpiry = cacert.NotAfter 1049 } 1050 } else { 1051 log.Errorf("Not expected condition as the enrollSigner can only be cfssl/signer/local/Signer") 1052 return caexpiry, errors.New("Unexpected error while getting CA certificate expiration") 1053 } 1054 return caexpiry, nil 1055 } 1056 1057 func canSignCRL(cert *x509.Certificate) bool { 1058 return cert.KeyUsage&x509.KeyUsageCRLSign != 0 1059 } 1060 1061 func validateDates(cert *x509.Certificate) error { 1062 log.Debug("Check CA certificate for valid dates") 1063 1064 notAfter := cert.NotAfter 1065 currentTime := time.Now().UTC() 1066 1067 if currentTime.After(notAfter) { 1068 return errors.New("Certificate provided has expired") 1069 } 1070 1071 notBefore := cert.NotBefore 1072 if currentTime.Before(notBefore) { 1073 return errors.New("Certificate provided not valid until later date") 1074 } 1075 1076 return nil 1077 } 1078 1079 func validateUsage(cert *x509.Certificate, caName string) error { 1080 log.Debug("Check CA certificate for valid usages") 1081 1082 if cert.KeyUsage == 0 { 1083 return errors.New("No usage specified for certificate") 1084 } 1085 1086 if cert.KeyUsage&x509.KeyUsageCertSign == 0 { 1087 return errors.New("The 'cert sign' key usage is required") 1088 } 1089 1090 if !canSignCRL(cert) { 1091 log.Warningf("The CA certificate for the CA '%s' does not have 'crl sign' key usage, so the CA will not be able generate a CRL", caName) 1092 } 1093 return nil 1094 } 1095 1096 func validateIsCA(cert *x509.Certificate) error { 1097 log.Debug("Check CA certificate for valid IsCA value") 1098 1099 if !cert.IsCA { 1100 return errors.New("Certificate not configured to be used for CA") 1101 } 1102 1103 return nil 1104 } 1105 1106 func validateKeyType(cert *x509.Certificate) error { 1107 log.Debug("Check that key type is supported") 1108 1109 switch cert.PublicKey.(type) { 1110 case *dsa.PublicKey: 1111 return errors.New("Unsupported key type: DSA") 1112 } 1113 1114 return nil 1115 } 1116 1117 func validateKeySize(cert *x509.Certificate) error { 1118 log.Debug("Check that key size is of appropriate length") 1119 1120 switch cert.PublicKey.(type) { 1121 case *rsa.PublicKey: 1122 size := cert.PublicKey.(*rsa.PublicKey).N.BitLen() 1123 if size < 2048 { 1124 return errors.New("Key size is less than 2048 bits") 1125 } 1126 } 1127 1128 return nil 1129 } 1130 1131 func validateMatchingKeys(cert *x509.Certificate, keyFile string) error { 1132 log.Debug("Check that public key and private key match") 1133 1134 keyPEM, err := ioutil.ReadFile(keyFile) 1135 if err != nil { 1136 return err 1137 } 1138 1139 pubKey := cert.PublicKey 1140 switch pubKey.(type) { 1141 case *rsa.PublicKey: 1142 privKey, err := util.GetRSAPrivateKey(keyPEM) 1143 if err != nil { 1144 return err 1145 } 1146 1147 if privKey.PublicKey.N.Cmp(pubKey.(*rsa.PublicKey).N) != 0 { 1148 return errors.New("Public key and private key do not match") 1149 } 1150 case *ecdsa.PublicKey: 1151 privKey, err := util.GetECPrivateKey(keyPEM) 1152 if err != nil { 1153 return err 1154 } 1155 1156 if privKey.PublicKey.X.Cmp(pubKey.(*ecdsa.PublicKey).X) != 0 { 1157 return errors.New("Public key and private key do not match") 1158 } 1159 } 1160 1161 return nil 1162 } 1163 1164 // Load CN from existing enrollment information 1165 func (ca *CA) loadCNFromEnrollmentInfo(certFile string) (string, error) { 1166 log.Debug("Loading CN from existing enrollment information") 1167 cert, err := util.ReadFile(certFile) 1168 if err != nil { 1169 log.Debugf("No cert found at %s", certFile) 1170 return "", err 1171 } 1172 name, err := util.GetEnrollmentIDFromPEM(cert) 1173 if err != nil { 1174 return "", err 1175 } 1176 return name, nil 1177 } 1178 1179 // This function returns an error if the version specified in the configuration file is greater than the server version 1180 func (ca *CA) checkConfigLevels() error { 1181 var err error 1182 serverVersion := metadata.GetVersion() 1183 configVersion := ca.Config.Version 1184 log.Debugf("Checking configuration file version '%+v' against server version: '%+v'", configVersion, serverVersion) 1185 // Check configuration file version against server version to make sure that newer configuration file is not being used with server 1186 cmp, err := metadata.CmpVersion(configVersion, serverVersion) 1187 if err != nil { 1188 return errors.WithMessage(err, "Failed to compare version") 1189 } 1190 if cmp == -1 { 1191 return fmt.Errorf("Configuration file version '%s' is higher than server version '%s'", configVersion, serverVersion) 1192 } 1193 cfg, err := metadata.GetLevels(ca.Config.Version) 1194 if err != nil { 1195 return err 1196 } 1197 ca.levels = cfg 1198 return nil 1199 } 1200 1201 func (ca *CA) checkDBLevels() error { 1202 // Check database table levels against server levels to make sure that a database levels are compatible with server 1203 levels, err := db.CurrentDBLevels(ca.db) 1204 if err != nil { 1205 return err 1206 } 1207 sl, err := metadata.GetLevels(metadata.GetVersion()) 1208 if err != nil { 1209 return err 1210 } 1211 log.Debugf("Checking database levels '%+v' against server levels '%+v'", levels, sl) 1212 if (levels.Identity > sl.Identity) || (levels.Affiliation > sl.Affiliation) || (levels.Certificate > sl.Certificate) || 1213 (levels.Credential > sl.Credential) || (levels.Nonce > sl.Nonce) || (levels.RAInfo > sl.RAInfo) { 1214 return caerrors.NewFatalError(caerrors.ErrDBLevel, "The version of the database is newer than the server version. Upgrade your server.") 1215 } 1216 return nil 1217 } 1218 1219 func writeFile(file string, buf []byte, perm os.FileMode) error { 1220 err := os.MkdirAll(filepath.Dir(file), 0755) 1221 if err != nil { 1222 return err 1223 } 1224 return ioutil.WriteFile(file, buf, perm) 1225 } 1226 1227 func affiliationPath(name, parent string) string { 1228 if parent == "" { 1229 return name 1230 } 1231 return fmt.Sprintf("%s.%s", parent, name) 1232 } 1233 1234 func parseDuration(str string) time.Duration { 1235 d, err := time.ParseDuration(str) 1236 if err != nil { 1237 panic(err) 1238 } 1239 return d 1240 } 1241 1242 func initSigningProfile(spp **config.SigningProfile, expiry time.Duration, isCA bool) { 1243 sp := *spp 1244 if sp == nil { 1245 sp = &config.SigningProfile{CAConstraint: config.CAConstraint{IsCA: isCA}} 1246 *spp = sp 1247 } 1248 if sp.Usage == nil { 1249 sp.Usage = []string{"cert sign", "crl sign"} 1250 } 1251 if sp.Expiry == 0 { 1252 sp.Expiry = expiry 1253 } 1254 if sp.ExtensionWhitelist == nil { 1255 sp.ExtensionWhitelist = map[string]bool{} 1256 } 1257 // This is set so that all profiles permit an attribute extension in CFSSL 1258 sp.ExtensionWhitelist[attrmgr.AttrOIDString] = true 1259 } 1260 1261 type wallClock struct{} 1262 1263 func (wc wallClock) Now() time.Time { 1264 return time.Now() 1265 } 1266 1267 func getMigrator(driverName string, tx cadb.FabricCATx, curLevels, srvLevels *dbutil.Levels) (cadb.Migrator, error) { 1268 var migrator cadb.Migrator 1269 switch driverName { 1270 case "sqlite3": 1271 migrator = sqlite.NewMigrator(tx, curLevels, srvLevels) 1272 case "mysql": 1273 migrator = mysql.NewMigrator(tx, curLevels, srvLevels) 1274 case "postgres": 1275 migrator = postgres.NewMigrator(tx, curLevels, srvLevels) 1276 default: 1277 return nil, errors.Errorf("Unsupported database type: %s", driverName) 1278 } 1279 return migrator, nil 1280 }