github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/cloudflare/cfssl/initca/initca.go (about)

     1  // Package initca contains code to initialise a certificate authority,
     2  // generating a new root key and certificate.
     3  package initca
     4  
     5  import (
     6  	"crypto"
     7  	"crypto/rsa"
     8  	"errors"
     9  	"github.com/hellobchain/newcryptosm/ecdsa"
    10  	"github.com/hellobchain/newcryptosm/x509"
    11  	"time"
    12  
    13  	"github.com/hellobchain/third_party/cloudflare/cfssl/config"
    14  	"github.com/hellobchain/third_party/cloudflare/cfssl/csr"
    15  	cferr "github.com/hellobchain/third_party/cloudflare/cfssl/errors"
    16  	"github.com/hellobchain/third_party/cloudflare/cfssl/helpers"
    17  	"github.com/hellobchain/third_party/cloudflare/cfssl/log"
    18  	"github.com/hellobchain/third_party/cloudflare/cfssl/signer"
    19  	"github.com/hellobchain/third_party/cloudflare/cfssl/signer/local"
    20  )
    21  
    22  // validator contains the default validation logic for certificate
    23  // authority certificates. The only requirement here is that the
    24  // certificate have a non-empty subject field.
    25  func validator(req *csr.CertificateRequest) error {
    26  	if req.CN != "" {
    27  		return nil
    28  	}
    29  
    30  	if len(req.Names) == 0 {
    31  		return cferr.Wrap(cferr.PolicyError, cferr.InvalidRequest, errors.New("missing subject information"))
    32  	}
    33  
    34  	for i := range req.Names {
    35  		if csr.IsNameEmpty(req.Names[i]) {
    36  			return cferr.Wrap(cferr.PolicyError, cferr.InvalidRequest, errors.New("missing subject information"))
    37  		}
    38  	}
    39  
    40  	return nil
    41  }
    42  
    43  // New creates a new root certificate from the certificate request.
    44  func New(defaultAlgo string, req *csr.CertificateRequest) (cert, csrPEM, key []byte, err error) {
    45  	policy := CAPolicy()
    46  	if req.CA != nil {
    47  		if req.CA.Expiry != "" {
    48  			policy.Default.ExpiryString = req.CA.Expiry
    49  			policy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry)
    50  			if err != nil {
    51  				return
    52  			}
    53  		}
    54  
    55  		policy.Default.CAConstraint.MaxPathLen = req.CA.PathLength
    56  		if req.CA.PathLength != 0 && req.CA.PathLenZero {
    57  			log.Infof("ignore invalid 'pathlenzero' value")
    58  		} else {
    59  			policy.Default.CAConstraint.MaxPathLenZero = req.CA.PathLenZero
    60  		}
    61  	}
    62  
    63  	g := &csr.Generator{Validator: validator}
    64  	csrPEM, key, err = g.ProcessRequest(defaultAlgo, req)
    65  	if err != nil {
    66  		log.Errorf("failed to process request: %v", err)
    67  		key = nil
    68  		return
    69  	}
    70  
    71  	priv, err := helpers.ParsePrivateKeyPEM(key)
    72  	if err != nil {
    73  		log.Errorf("failed to parse private key: %v", err)
    74  		return
    75  	}
    76  
    77  	s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), policy)
    78  	if err != nil {
    79  		log.Errorf("failed to create signer: %v", err)
    80  		return
    81  	}
    82  
    83  	signReq := signer.SignRequest{Hosts: req.Hosts, Request: string(csrPEM)}
    84  	cert, err = s.Sign(signReq)
    85  
    86  	return
    87  
    88  }
    89  
    90  // NewFromPEM creates a new root certificate from the key file passed in.
    91  func NewFromPEM(req *csr.CertificateRequest, keyFile string) (cert, csrPEM []byte, err error) {
    92  	privData, err := helpers.ReadBytes(keyFile)
    93  	if err != nil {
    94  		return nil, nil, err
    95  	}
    96  
    97  	priv, err := helpers.ParsePrivateKeyPEM(privData)
    98  	if err != nil {
    99  		return nil, nil, err
   100  	}
   101  
   102  	return NewFromSigner(req, priv)
   103  }
   104  
   105  // RenewFromPEM re-creates a root certificate from the CA cert and key
   106  // files. The resulting root certificate will have the input CA certificate
   107  // as the template and have the same expiry length. E.g. the exsiting CA
   108  // is valid for a year from Jan 01 2015 to Jan 01 2016, the renewed certificate
   109  // will be valid from now and expire in one year as well.
   110  func RenewFromPEM(caFile, keyFile string) ([]byte, error) {
   111  	caBytes, err := helpers.ReadBytes(caFile)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  
   116  	ca, err := helpers.ParseCertificatePEM(caBytes)
   117  	if err != nil {
   118  		return nil, err
   119  	}
   120  
   121  	keyBytes, err := helpers.ReadBytes(keyFile)
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	key, err := helpers.ParsePrivateKeyPEM(keyBytes)
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  
   131  	return RenewFromSigner(ca, key)
   132  }
   133  
   134  // NewFromSigner creates a new root certificate from a crypto.Signer.
   135  func NewFromSigner(req *csr.CertificateRequest, priv crypto.Signer) (cert, csrPEM []byte, err error) {
   136  	policy := CAPolicy()
   137  	if req.CA != nil {
   138  		if req.CA.Expiry != "" {
   139  			policy.Default.ExpiryString = req.CA.Expiry
   140  			policy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry)
   141  			if err != nil {
   142  				return nil, nil, err
   143  			}
   144  		}
   145  
   146  		policy.Default.CAConstraint.MaxPathLen = req.CA.PathLength
   147  		if req.CA.PathLength != 0 && req.CA.PathLenZero == true {
   148  			log.Infof("ignore invalid 'pathlenzero' value")
   149  		} else {
   150  			policy.Default.CAConstraint.MaxPathLenZero = req.CA.PathLenZero
   151  		}
   152  	}
   153  
   154  	csrPEM, err = csr.Generate(priv, req)
   155  	if err != nil {
   156  		return nil, nil, err
   157  	}
   158  
   159  	s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), policy)
   160  	if err != nil {
   161  		log.Errorf("failed to create signer: %v", err)
   162  		return
   163  	}
   164  
   165  	signReq := signer.SignRequest{Request: string(csrPEM)}
   166  	cert, err = s.Sign(signReq)
   167  	return
   168  }
   169  
   170  // RenewFromSigner re-creates a root certificate from the CA cert and crypto.Signer.
   171  // The resulting root certificate will have ca certificate
   172  // as the template and have the same expiry length. E.g. the exsiting CA
   173  // is valid for a year from Jan 01 2015 to Jan 01 2016, the renewed certificate
   174  // will be valid from now and expire in one year as well.
   175  func RenewFromSigner(ca *x509.Certificate, priv crypto.Signer) ([]byte, error) {
   176  	if !ca.IsCA {
   177  		return nil, errors.New("input certificate is not a CA cert")
   178  	}
   179  	var defaultAlgo string
   180  	// matching certificate public key vs private key
   181  	switch {
   182  	case ca.PublicKeyAlgorithm == x509.RSA:
   183  
   184  		var rsaPublicKey *rsa.PublicKey
   185  		var ok bool
   186  		if rsaPublicKey, ok = priv.Public().(*rsa.PublicKey); !ok {
   187  			return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
   188  		}
   189  		if ca.PublicKey.(*rsa.PublicKey).N.Cmp(rsaPublicKey.N) != 0 {
   190  			return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
   191  		}
   192  		defaultAlgo = "rsa"
   193  	case ca.PublicKeyAlgorithm == x509.ECDSA:
   194  		var ecdsaPublicKey *ecdsa.PublicKey
   195  		var ok bool
   196  		if ecdsaPublicKey, ok = priv.Public().(*ecdsa.PublicKey); !ok {
   197  			return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
   198  		}
   199  		if ca.PublicKey.(*ecdsa.PublicKey).X.Cmp(ecdsaPublicKey.X) != 0 {
   200  			return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
   201  		}
   202  		defaultAlgo = "ecdsa"
   203  	case ca.PublicKeyAlgorithm == x509.SM2:
   204  		var ecdsaPublicKey *ecdsa.PublicKey
   205  		var ok bool
   206  		if ecdsaPublicKey, ok = priv.Public().(*ecdsa.PublicKey); !ok {
   207  			return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
   208  		}
   209  		if ca.PublicKey.(*ecdsa.PublicKey).X.Cmp(ecdsaPublicKey.X) != 0 {
   210  			return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
   211  		}
   212  		defaultAlgo = "sm2"
   213  	default:
   214  		return nil, cferr.New(cferr.PrivateKeyError, cferr.NotRSAOrECC)
   215  	}
   216  
   217  	req := csr.ExtractCertificateRequest(defaultAlgo, ca)
   218  
   219  	cert, _, err := NewFromSigner(req, priv)
   220  	return cert, err
   221  
   222  }
   223  
   224  // CAPolicy contains the CA issuing policy as default policy.
   225  var CAPolicy = func() *config.Signing {
   226  	return &config.Signing{
   227  		Default: &config.SigningProfile{
   228  			Usage:        []string{"cert sign", "crl sign"},
   229  			ExpiryString: "43800h",
   230  			Expiry:       5 * helpers.OneYear,
   231  			CAConstraint: config.CAConstraint{IsCA: true},
   232  		},
   233  	}
   234  }