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