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