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

     1  // Package csr implements certificate requests for CFSSL.
     2  package csr
     3  
     4  import (
     5  	"crypto"
     6  	"crypto/elliptic"
     7  	"crypto/rand"
     8  	"crypto/rsa"
     9  	"encoding/asn1"
    10  	"encoding/pem"
    11  	"errors"
    12  	"github.com/hellobchain/newcryptosm/ecdsa"
    13  	"github.com/hellobchain/newcryptosm/sm2"
    14  	"github.com/hellobchain/newcryptosm/x509"
    15  	"github.com/hellobchain/newcryptosm/x509/pkix"
    16  	"net"
    17  	"net/mail"
    18  	"strings"
    19  
    20  	cferr "github.com/hellobchain/third_party/cloudflare/cfssl/errors"
    21  	"github.com/hellobchain/third_party/cloudflare/cfssl/helpers"
    22  	"github.com/hellobchain/third_party/cloudflare/cfssl/log"
    23  )
    24  
    25  const (
    26  	curveP256 = 256
    27  	curveP384 = 384
    28  	curveP521 = 521
    29  )
    30  
    31  // A Name contains the SubjectInfo fields.
    32  type Name struct {
    33  	C            string // Country
    34  	ST           string // State
    35  	L            string // Locality
    36  	O            string // OrganisationName
    37  	OU           string // OrganisationalUnitName
    38  	SerialNumber string
    39  }
    40  
    41  // A KeyRequest is a generic request for a new key.
    42  type KeyRequest interface {
    43  	Algo() string
    44  	Size() int
    45  	Generate() (crypto.PrivateKey, error)
    46  	SigAlgo() x509.SignatureAlgorithm
    47  }
    48  
    49  // A BasicKeyRequest contains the algorithm and key size for a new private key.
    50  type BasicKeyRequest struct {
    51  	A string `json:"algo" yaml:"algo"`
    52  	S int    `json:"size" yaml:"size"`
    53  }
    54  
    55  // NewBasicKeyRequest returns a default BasicKeyRequest.
    56  func NewBasicKeyRequest(algo string) *BasicKeyRequest {
    57  	return &BasicKeyRequest{algo, curveP256}
    58  }
    59  
    60  // Algo returns the requested key algorithm represented as a string.
    61  func (kr *BasicKeyRequest) Algo() string {
    62  	return kr.A
    63  }
    64  
    65  // Size returns the requested key size.
    66  func (kr *BasicKeyRequest) Size() int {
    67  	return kr.S
    68  }
    69  
    70  // Generate generates a key as specified in the request. Currently,
    71  // only ECDSA and RSA are supported.
    72  func (kr *BasicKeyRequest) Generate() (crypto.PrivateKey, error) {
    73  	log.Debugf("generate key from request: algo=%s, size=%d", kr.Algo(), kr.Size())
    74  	switch kr.Algo() {
    75  	case "rsa":
    76  		if kr.Size() < 2048 {
    77  			return nil, errors.New("RSA key is too weak")
    78  		}
    79  		if kr.Size() > 8192 {
    80  			return nil, errors.New("RSA key size too large")
    81  		}
    82  		return rsa.GenerateKey(rand.Reader, kr.Size())
    83  	case "ecdsa":
    84  		var curve elliptic.Curve
    85  		switch kr.Size() {
    86  		case curveP256:
    87  			curve = elliptic.P256()
    88  		case curveP384:
    89  			curve = elliptic.P384()
    90  		case curveP521:
    91  			curve = elliptic.P521()
    92  		default:
    93  			return nil, errors.New("invalid curve")
    94  		}
    95  		return ecdsa.GenerateKey(curve, rand.Reader)
    96  	case "sm2":
    97  		var curve elliptic.Curve
    98  		switch kr.Size() {
    99  		case curveP256:
   100  			curve = sm2.SM2()
   101  		default:
   102  			return nil, errors.New("invalid curve")
   103  		}
   104  		return ecdsa.GenerateKey(curve, rand.Reader)
   105  	default:
   106  		return nil, errors.New("invalid algorithm")
   107  	}
   108  }
   109  
   110  // SigAlgo returns an appropriate X.509 signature algorithm given the
   111  // key request's type and size.
   112  func (kr *BasicKeyRequest) SigAlgo() x509.SignatureAlgorithm {
   113  	switch kr.Algo() {
   114  	case "rsa":
   115  		switch {
   116  		case kr.Size() >= 4096:
   117  			return x509.SHA512WithRSA
   118  		case kr.Size() >= 3072:
   119  			return x509.SHA384WithRSA
   120  		case kr.Size() >= 2048:
   121  			return x509.SHA256WithRSA
   122  		default:
   123  			return x509.SHA1WithRSA
   124  		}
   125  	case "ecdsa":
   126  		switch kr.Size() {
   127  		case curveP521:
   128  			return x509.ECDSAWithSHA512
   129  		case curveP384:
   130  			return x509.ECDSAWithSHA384
   131  		case curveP256:
   132  			return x509.ECDSAWithSHA256
   133  		default:
   134  			return x509.ECDSAWithSHA1
   135  		}
   136  	case "sm2":
   137  		switch kr.Size() {
   138  		case curveP256:
   139  			return x509.SM2WithSM3
   140  		default:
   141  			return x509.SM2WithSHA1
   142  		}
   143  	default:
   144  		return x509.UnknownSignatureAlgorithm
   145  	}
   146  }
   147  
   148  // CAConfig is a section used in the requests initialising a new CA.
   149  type CAConfig struct {
   150  	PathLength  int    `json:"pathlen" yaml:"pathlen"`
   151  	PathLenZero bool   `json:"pathlenzero" yaml:"pathlenzero"`
   152  	Expiry      string `json:"expiry" yaml:"expiry"`
   153  }
   154  
   155  // A CertificateRequest encapsulates the API interface to the
   156  // certificate request functionality.
   157  type CertificateRequest struct {
   158  	CN           string
   159  	Names        []Name     `json:"names" yaml:"names"`
   160  	Hosts        []string   `json:"hosts" yaml:"hosts"`
   161  	KeyRequest   KeyRequest `json:"key,omitempty" yaml:"key,omitempty"`
   162  	CA           *CAConfig  `json:"ca,omitempty" yaml:"ca,omitempty"`
   163  	SerialNumber string     `json:"serialnumber,omitempty" yaml:"serialnumber,omitempty"`
   164  }
   165  
   166  // New returns a new, empty CertificateRequest with a
   167  // BasicKeyRequest.
   168  func New(algo string) *CertificateRequest {
   169  	return &CertificateRequest{
   170  		KeyRequest: NewBasicKeyRequest(algo),
   171  	}
   172  }
   173  
   174  // appendIf appends to a if s is not an empty string.
   175  func appendIf(s string, a *[]string) {
   176  	if s != "" {
   177  		*a = append(*a, s)
   178  	}
   179  }
   180  
   181  // Name returns the PKIX name for the request.
   182  func (cr *CertificateRequest) Name() pkix.Name {
   183  	var name pkix.Name
   184  	name.CommonName = cr.CN
   185  
   186  	for _, n := range cr.Names {
   187  		appendIf(n.C, &name.Country)
   188  		appendIf(n.ST, &name.Province)
   189  		appendIf(n.L, &name.Locality)
   190  		appendIf(n.O, &name.Organization)
   191  		appendIf(n.OU, &name.OrganizationalUnit)
   192  	}
   193  	name.SerialNumber = cr.SerialNumber
   194  	return name
   195  }
   196  
   197  // BasicConstraints CSR information RFC 5280, 4.2.1.9
   198  type BasicConstraints struct {
   199  	IsCA       bool `asn1:"optional"`
   200  	MaxPathLen int  `asn1:"optional,default:-1"`
   201  }
   202  
   203  // ParseRequest takes a certificate request and generates a key and
   204  // CSR from it. It does no validation -- caveat emptor. It will,
   205  // however, fail if the key request is not valid (i.e., an unsupported
   206  // curve or RSA key size). The lack of validation was specifically
   207  // chosen to allow the end user to define a policy and validate the
   208  // request appropriately before calling this function.
   209  func ParseRequest(defaultAlgo string, req *CertificateRequest) (csr, key []byte, err error) {
   210  	log.Info("received CSR")
   211  	if req.KeyRequest == nil {
   212  		req.KeyRequest = NewBasicKeyRequest(defaultAlgo)
   213  	}
   214  
   215  	log.Infof("generating key: %s-%d", req.KeyRequest.Algo(), req.KeyRequest.Size())
   216  	priv, err := req.KeyRequest.Generate()
   217  	if err != nil {
   218  		err = cferr.Wrap(cferr.PrivateKeyError, cferr.GenerationFailed, err)
   219  		return
   220  	}
   221  
   222  	switch priv := priv.(type) {
   223  	case *rsa.PrivateKey:
   224  		key = x509.MarshalPKCS1PrivateKey(priv)
   225  		block := pem.Block{
   226  			Type:  "RSA PRIVATE KEY",
   227  			Bytes: key,
   228  		}
   229  		key = pem.EncodeToMemory(&block)
   230  	case *ecdsa.PrivateKey:
   231  		key, err = x509.MarshalECPrivateKey(priv)
   232  		if err != nil {
   233  			err = cferr.Wrap(cferr.PrivateKeyError, cferr.Unknown, err)
   234  			return
   235  		}
   236  		block := pem.Block{
   237  			Type:  "EC PRIVATE KEY",
   238  			Bytes: key,
   239  		}
   240  		key = pem.EncodeToMemory(&block)
   241  	default:
   242  		panic("Generate should have failed to produce a valid key.")
   243  	}
   244  
   245  	csr, err = Generate(priv.(crypto.Signer), req)
   246  	if err != nil {
   247  		log.Errorf("failed to generate a CSR: %v", err)
   248  		err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err)
   249  	}
   250  	return
   251  }
   252  
   253  // ExtractCertificateRequest extracts a CertificateRequest from
   254  // x509.Certificate. It is aimed to used for generating a new certificate
   255  // from an existing certificate. For a root certificate, the CA expiry
   256  // length is calculated as the duration between cert.NotAfter and cert.NotBefore.
   257  func ExtractCertificateRequest(defaultAlgo string, cert *x509.Certificate) *CertificateRequest {
   258  	req := New(defaultAlgo)
   259  	req.CN = cert.Subject.CommonName
   260  	req.Names = getNames(cert.Subject)
   261  	req.Hosts = getHosts(cert)
   262  	req.SerialNumber = cert.Subject.SerialNumber
   263  
   264  	if cert.IsCA {
   265  		req.CA = new(CAConfig)
   266  		// CA expiry length is calculated based on the input cert
   267  		// issue date and expiry date.
   268  		req.CA.Expiry = cert.NotAfter.Sub(cert.NotBefore).String()
   269  		req.CA.PathLength = cert.MaxPathLen
   270  		req.CA.PathLenZero = cert.MaxPathLenZero
   271  	}
   272  
   273  	return req
   274  }
   275  
   276  func getHosts(cert *x509.Certificate) []string {
   277  	var hosts []string
   278  	for _, ip := range cert.IPAddresses {
   279  		hosts = append(hosts, ip.String())
   280  	}
   281  	for _, dns := range cert.DNSNames {
   282  		hosts = append(hosts, dns)
   283  	}
   284  	for _, email := range cert.EmailAddresses {
   285  		hosts = append(hosts, email)
   286  	}
   287  
   288  	return hosts
   289  }
   290  
   291  // getNames returns an array of Names from the certificate
   292  // It onnly cares about Country, Organization, OrganizationalUnit, Locality, Province
   293  func getNames(sub pkix.Name) []Name {
   294  	// anonymous func for finding the max of a list of interger
   295  	max := func(v1 int, vn ...int) (max int) {
   296  		max = v1
   297  		for i := 0; i < len(vn); i++ {
   298  			if vn[i] > max {
   299  				max = vn[i]
   300  			}
   301  		}
   302  		return max
   303  	}
   304  
   305  	nc := len(sub.Country)
   306  	norg := len(sub.Organization)
   307  	nou := len(sub.OrganizationalUnit)
   308  	nl := len(sub.Locality)
   309  	np := len(sub.Province)
   310  
   311  	n := max(nc, norg, nou, nl, np)
   312  
   313  	names := make([]Name, n)
   314  	for i := range names {
   315  		if i < nc {
   316  			names[i].C = sub.Country[i]
   317  		}
   318  		if i < norg {
   319  			names[i].O = sub.Organization[i]
   320  		}
   321  		if i < nou {
   322  			names[i].OU = sub.OrganizationalUnit[i]
   323  		}
   324  		if i < nl {
   325  			names[i].L = sub.Locality[i]
   326  		}
   327  		if i < np {
   328  			names[i].ST = sub.Province[i]
   329  		}
   330  	}
   331  	return names
   332  }
   333  
   334  // A Generator is responsible for validating certificate requests.
   335  type Generator struct {
   336  	Validator func(*CertificateRequest) error
   337  }
   338  
   339  // ProcessRequest validates and processes the incoming request. It is
   340  // a wrapper around a validator and the ParseRequest function.
   341  func (g *Generator) ProcessRequest(defaultAlgo string, req *CertificateRequest) (csr, key []byte, err error) {
   342  
   343  	log.Info("generate received request")
   344  	err = g.Validator(req)
   345  	if err != nil {
   346  		log.Warningf("invalid request: %v", err)
   347  		return nil, nil, err
   348  	}
   349  
   350  	csr, key, err = ParseRequest(defaultAlgo, req)
   351  	if err != nil {
   352  		return nil, nil, err
   353  	}
   354  	return
   355  }
   356  
   357  // IsNameEmpty returns true if the name has no identifying information in it.
   358  func IsNameEmpty(n Name) bool {
   359  	empty := func(s string) bool { return strings.TrimSpace(s) == "" }
   360  
   361  	if empty(n.C) && empty(n.ST) && empty(n.L) && empty(n.O) && empty(n.OU) {
   362  		return true
   363  	}
   364  	return false
   365  }
   366  
   367  // Regenerate uses the provided CSR as a template for signing a new
   368  // CSR using priv.
   369  func Regenerate(priv crypto.Signer, csr []byte) ([]byte, error) {
   370  	req, extra, err := helpers.ParseCSR(csr)
   371  	if err != nil {
   372  		return nil, err
   373  	} else if len(extra) > 0 {
   374  		return nil, errors.New("csr: trailing data in certificate request")
   375  	}
   376  
   377  	return x509.CreateCertificateRequest(rand.Reader, req, priv)
   378  }
   379  
   380  // Generate creates a new CSR from a CertificateRequest structure and
   381  // an existing key. The KeyRequest field is ignored.
   382  func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err error) {
   383  	sigAlgo := helpers.SignerAlgo(priv)
   384  	if sigAlgo == x509.UnknownSignatureAlgorithm {
   385  		return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable)
   386  	}
   387  
   388  	var tpl = x509.CertificateRequest{
   389  		Subject:            req.Name(),
   390  		SignatureAlgorithm: sigAlgo,
   391  	}
   392  
   393  	for i := range req.Hosts {
   394  		if ip := net.ParseIP(req.Hosts[i]); ip != nil {
   395  			tpl.IPAddresses = append(tpl.IPAddresses, ip)
   396  		} else if email, err := mail.ParseAddress(req.Hosts[i]); err == nil && email != nil {
   397  			tpl.EmailAddresses = append(tpl.EmailAddresses, email.Address)
   398  		} else {
   399  			tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i])
   400  		}
   401  	}
   402  
   403  	if req.CA != nil {
   404  		err = appendCAInfoToCSR(req.CA, &tpl)
   405  		if err != nil {
   406  			err = cferr.Wrap(cferr.CSRError, cferr.GenerationFailed, err)
   407  			return
   408  		}
   409  	}
   410  
   411  	csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
   412  	if err != nil {
   413  		log.Errorf("failed to generate a CSR: %v", err)
   414  		err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err)
   415  		return
   416  	}
   417  	block := pem.Block{
   418  		Type:  "CERTIFICATE REQUEST",
   419  		Bytes: csr,
   420  	}
   421  
   422  	log.Info("encoded CSR")
   423  	csr = pem.EncodeToMemory(&block)
   424  	return
   425  }
   426  
   427  // appendCAInfoToCSR appends CAConfig BasicConstraint extension to a CSR
   428  func appendCAInfoToCSR(reqConf *CAConfig, csr *x509.CertificateRequest) error {
   429  	pathlen := reqConf.PathLength
   430  	if pathlen == 0 && !reqConf.PathLenZero {
   431  		pathlen = -1
   432  	}
   433  	val, err := asn1.Marshal(BasicConstraints{true, pathlen})
   434  
   435  	if err != nil {
   436  		return err
   437  	}
   438  
   439  	csr.ExtraExtensions = []pkix.Extension{
   440  		{
   441  			Id:       asn1.ObjectIdentifier{2, 5, 29, 19},
   442  			Value:    val,
   443  			Critical: true,
   444  		},
   445  	}
   446  
   447  	return nil
   448  }