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