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