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