github.com/silveraid/fabric-ca@v1.1.0-preview.0.20180127000700-71974f53ab08/lib/ca.go (about)

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