github.com/49746628/fabric-ca-gm@v2.0.0-alpha.0.20200822143404-8a07eefa7452+incompatible/lib/ca.go (about)

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