...

Source file src/github.com/letsencrypt/boulder/cmd/ceremony/cert.go

Documentation: github.com/letsencrypt/boulder/cmd/ceremony

     1  package main
     2  
     3  import (
     4  	"crypto"
     5  	"crypto/sha256"
     6  	"crypto/x509"
     7  	"crypto/x509/pkix"
     8  	"encoding/asn1"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"math/big"
    13  	"strconv"
    14  	"strings"
    15  	"time"
    16  )
    17  
    18  type policyInfoConfig struct {
    19  	OID string
    20  	// Deprecated: we do not include the id-qt-cps policy qualifier in our
    21  	// certificate policy extensions anymore.
    22  	CPSURI string `yaml:"cps-uri"`
    23  }
    24  
    25  // certProfile contains the information required to generate a certificate
    26  type certProfile struct {
    27  	// SignatureAlgorithm should contain one of the allowed signature algorithms
    28  	// in AllowedSigAlgs
    29  	SignatureAlgorithm string `yaml:"signature-algorithm"`
    30  
    31  	// CommonName should contain the requested subject common name
    32  	CommonName string `yaml:"common-name"`
    33  	// Organization should contain the requested subject organization
    34  	Organization string `yaml:"organization"`
    35  	// Country should contain the requested subject country code
    36  	Country string `yaml:"country"`
    37  
    38  	// NotBefore should contain the requested NotBefore date for the
    39  	// certificate in the format "2006-01-02 15:04:05". Dates will
    40  	// always be UTC.
    41  	NotBefore string `yaml:"not-before"`
    42  	// NotAfter should contain the requested NotAfter date for the
    43  	// certificate in the format "2006-01-02 15:04:05". Dates will
    44  	// always be UTC.
    45  	NotAfter string `yaml:"not-after"`
    46  
    47  	// OCSPURL should contain the URL at which a OCSP responder that
    48  	// can respond to OCSP requests for this certificate operates
    49  	OCSPURL string `yaml:"ocsp-url"`
    50  	// CRLURL should contain the URL at which CRLs for this certificate
    51  	// can be found
    52  	CRLURL string `yaml:"crl-url"`
    53  	// IssuerURL should contain the URL at which the issuing certificate
    54  	// can be found, this is only required if generating an intermediate
    55  	// certificate
    56  	IssuerURL string `yaml:"issuer-url"`
    57  
    58  	// Policies should contain any OIDs to be inserted in a certificate
    59  	// policies extension. It should be empty for Root certs, and contain the
    60  	// BRs "domain-validated" Reserved Policy Identifier for Intermediates.
    61  	Policies []policyInfoConfig `yaml:"policies"`
    62  
    63  	// KeyUsages should contain the set of key usage bits to set
    64  	KeyUsages []string `yaml:"key-usages"`
    65  }
    66  
    67  // AllowedSigAlgs contains the allowed signature algorithms
    68  var AllowedSigAlgs = map[string]x509.SignatureAlgorithm{
    69  	"SHA256WithRSA":   x509.SHA256WithRSA,
    70  	"SHA384WithRSA":   x509.SHA384WithRSA,
    71  	"SHA512WithRSA":   x509.SHA512WithRSA,
    72  	"ECDSAWithSHA256": x509.ECDSAWithSHA256,
    73  	"ECDSAWithSHA384": x509.ECDSAWithSHA384,
    74  	"ECDSAWithSHA512": x509.ECDSAWithSHA512,
    75  }
    76  
    77  type certType int
    78  
    79  const (
    80  	rootCert certType = iota
    81  	intermediateCert
    82  	ocspCert
    83  	crlCert
    84  	crossCert
    85  	requestCert
    86  )
    87  
    88  // Subject returns a pkix.Name from the appropriate certProfile fields
    89  func (profile *certProfile) Subject() pkix.Name {
    90  	return pkix.Name{
    91  		CommonName:   profile.CommonName,
    92  		Organization: []string{profile.Organization},
    93  		Country:      []string{profile.Country},
    94  	}
    95  }
    96  
    97  func (profile *certProfile) verifyProfile(ct certType) error {
    98  	if ct == requestCert {
    99  		if profile.NotBefore != "" {
   100  			return errors.New("not-before cannot be set for a CSR")
   101  		}
   102  		if profile.NotAfter != "" {
   103  			return errors.New("not-after cannot be set for a CSR")
   104  		}
   105  		if profile.SignatureAlgorithm != "" {
   106  			return errors.New("signature-algorithm cannot be set for a CSR")
   107  		}
   108  		if profile.OCSPURL != "" {
   109  			return errors.New("ocsp-url cannot be set for a CSR")
   110  		}
   111  		if profile.CRLURL != "" {
   112  			return errors.New("crl-url cannot be set for a CSR")
   113  		}
   114  		if profile.IssuerURL != "" {
   115  			return errors.New("issuer-url cannot be set for a CSR")
   116  		}
   117  		if profile.Policies != nil {
   118  			return errors.New("policies cannot be set for a CSR")
   119  		}
   120  		if profile.KeyUsages != nil {
   121  			return errors.New("key-usages cannot be set for a CSR")
   122  		}
   123  	} else {
   124  		if profile.NotBefore == "" {
   125  			return errors.New("not-before is required")
   126  		}
   127  		if profile.NotAfter == "" {
   128  			return errors.New("not-after is required")
   129  		}
   130  		if profile.SignatureAlgorithm == "" {
   131  			return errors.New("signature-algorithm is required")
   132  		}
   133  	}
   134  	if profile.CommonName == "" {
   135  		return errors.New("common-name is required")
   136  	}
   137  	if profile.Organization == "" {
   138  		return errors.New("organization is required")
   139  	}
   140  	if profile.Country == "" {
   141  		return errors.New("country is required")
   142  	}
   143  
   144  	if ct == rootCert {
   145  		if len(profile.Policies) != 0 {
   146  			return errors.New("policies should not be set on root certs")
   147  		}
   148  	}
   149  
   150  	if ct == intermediateCert || ct == crossCert {
   151  		if profile.CRLURL == "" {
   152  			return errors.New("crl-url is required for subordinate CAs")
   153  		}
   154  		if profile.IssuerURL == "" {
   155  			return errors.New("issuer-url is required for subordinate CAs")
   156  		}
   157  
   158  		// BR 7.1.2.10.5 CA Certificate Certificate Policies
   159  		// OID 2.23.140.1.2.1 is an anyPolicy
   160  		if len(profile.Policies) != 1 || profile.Policies[0].OID != "2.23.140.1.2.1" {
   161  			return errors.New("policy should be exactly BRs domain-validated for subordinate CAs")
   162  		}
   163  	}
   164  
   165  	if ct == ocspCert || ct == crlCert {
   166  		if len(profile.KeyUsages) != 0 {
   167  			return errors.New("key-usages cannot be set for a delegated signer")
   168  		}
   169  		if profile.CRLURL != "" {
   170  			return errors.New("crl-url cannot be set for a delegated signer")
   171  		}
   172  		if profile.OCSPURL != "" {
   173  			return errors.New("ocsp-url cannot be set for a delegated signer")
   174  		}
   175  	}
   176  	return nil
   177  }
   178  
   179  func parseOID(oidStr string) (asn1.ObjectIdentifier, error) {
   180  	var oid asn1.ObjectIdentifier
   181  	for _, a := range strings.Split(oidStr, ".") {
   182  		i, err := strconv.Atoi(a)
   183  		if err != nil {
   184  			return nil, err
   185  		}
   186  		if i <= 0 {
   187  			return nil, errors.New("OID components must be >= 1")
   188  		}
   189  		oid = append(oid, i)
   190  	}
   191  	return oid, nil
   192  }
   193  
   194  var stringToKeyUsage = map[string]x509.KeyUsage{
   195  	"Digital Signature": x509.KeyUsageDigitalSignature,
   196  	"CRL Sign":          x509.KeyUsageCRLSign,
   197  	"Cert Sign":         x509.KeyUsageCertSign,
   198  }
   199  
   200  var oidOCSPNoCheck = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1, 5}
   201  
   202  func generateSKID(pk []byte) ([]byte, error) {
   203  	var pkixPublicKey struct {
   204  		Algo      pkix.AlgorithmIdentifier
   205  		BitString asn1.BitString
   206  	}
   207  	if _, err := asn1.Unmarshal(pk, &pkixPublicKey); err != nil {
   208  		return nil, err
   209  	}
   210  	skid := sha256.Sum256(pkixPublicKey.BitString.Bytes)
   211  	return skid[:], nil
   212  }
   213  
   214  // makeTemplate generates the certificate template for use in x509.CreateCertificate
   215  func makeTemplate(randReader io.Reader, profile *certProfile, pubKey []byte, tbcs *x509.Certificate, ct certType) (*x509.Certificate, error) {
   216  	// Handle "unrestricted" vs "restricted" subordinate CA profile specifics.
   217  	if ct == crossCert && tbcs == nil {
   218  		return nil, fmt.Errorf("toBeCrossSigned cert field was nil, but was required to gather EKUs for the lint cert")
   219  	}
   220  
   221  	var ocspServer []string
   222  	if profile.OCSPURL != "" {
   223  		ocspServer = []string{profile.OCSPURL}
   224  	}
   225  	var crlDistributionPoints []string
   226  	if profile.CRLURL != "" {
   227  		crlDistributionPoints = []string{profile.CRLURL}
   228  	}
   229  	var issuingCertificateURL []string
   230  	if profile.IssuerURL != "" {
   231  		issuingCertificateURL = []string{profile.IssuerURL}
   232  	}
   233  
   234  	subjectKeyID, err := generateSKID(pubKey)
   235  	if err != nil {
   236  		return nil, err
   237  	}
   238  
   239  	serial := make([]byte, 16)
   240  	_, err = randReader.Read(serial)
   241  	if err != nil {
   242  		return nil, fmt.Errorf("failed to generate serial number: %s", err)
   243  	}
   244  
   245  	var ku x509.KeyUsage
   246  	for _, kuStr := range profile.KeyUsages {
   247  		kuBit, ok := stringToKeyUsage[kuStr]
   248  		if !ok {
   249  			return nil, fmt.Errorf("unknown key usage %q", kuStr)
   250  		}
   251  		ku |= kuBit
   252  	}
   253  	if ct == ocspCert {
   254  		ku = x509.KeyUsageDigitalSignature
   255  	} else if ct == crlCert {
   256  		ku = x509.KeyUsageCRLSign
   257  	}
   258  	if ku == 0 {
   259  		return nil, errors.New("at least one key usage must be set")
   260  	}
   261  
   262  	cert := &x509.Certificate{
   263  		SerialNumber:          big.NewInt(0).SetBytes(serial),
   264  		BasicConstraintsValid: true,
   265  		IsCA:                  true,
   266  		Subject:               profile.Subject(),
   267  		OCSPServer:            ocspServer,
   268  		CRLDistributionPoints: crlDistributionPoints,
   269  		IssuingCertificateURL: issuingCertificateURL,
   270  		KeyUsage:              ku,
   271  		SubjectKeyId:          subjectKeyID,
   272  	}
   273  
   274  	if ct != requestCert {
   275  		sigAlg, ok := AllowedSigAlgs[profile.SignatureAlgorithm]
   276  		if !ok {
   277  			return nil, fmt.Errorf("unsupported signature algorithm %q", profile.SignatureAlgorithm)
   278  		}
   279  		cert.SignatureAlgorithm = sigAlg
   280  		notBefore, err := time.Parse(time.DateTime, profile.NotBefore)
   281  		if err != nil {
   282  			return nil, err
   283  		}
   284  		cert.NotBefore = notBefore
   285  		notAfter, err := time.Parse(time.DateTime, profile.NotAfter)
   286  		if err != nil {
   287  			return nil, err
   288  		}
   289  		cert.NotAfter = notAfter
   290  	}
   291  
   292  	switch ct {
   293  	// rootCert does not get EKU or MaxPathZero.
   294  	// 		BR 7.1.2.1.2 Root CA Extensions
   295  	// 		Extension 	Presence 	Critical 	Description
   296  	// 		extKeyUsage 	MUST NOT 	N 	-
   297  	case ocspCert:
   298  		cert.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageOCSPSigning}
   299  		// ASN.1 NULL is 0x05, 0x00
   300  		ocspNoCheckExt := pkix.Extension{Id: oidOCSPNoCheck, Value: []byte{5, 0}}
   301  		cert.ExtraExtensions = append(cert.ExtraExtensions, ocspNoCheckExt)
   302  		cert.IsCA = false
   303  	case crlCert:
   304  		cert.IsCA = false
   305  	case requestCert, intermediateCert:
   306  		// id-kp-serverAuth and id-kp-clientAuth are included in intermediate
   307  		// certificates in order to technically constrain them. id-kp-serverAuth
   308  		// is required by 7.1.2.2.g of the CABF Baseline Requirements, but
   309  		// id-kp-clientAuth isn't. We include id-kp-clientAuth as we also include
   310  		// it in our end-entity certificates.
   311  		cert.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}
   312  		cert.MaxPathLenZero = true
   313  	case crossCert:
   314  		cert.ExtKeyUsage = tbcs.ExtKeyUsage
   315  		cert.MaxPathLenZero = tbcs.MaxPathLenZero
   316  	}
   317  
   318  	for _, policyConfig := range profile.Policies {
   319  		oid, err := parseOID(policyConfig.OID)
   320  		if err != nil {
   321  			return nil, err
   322  		}
   323  		cert.PolicyIdentifiers = append(cert.PolicyIdentifiers, oid)
   324  	}
   325  
   326  	return cert, nil
   327  }
   328  
   329  // failReader exists to be passed to x509.CreateCertificate which requires
   330  // a source of randomness for signing methods that require a source of
   331  // randomness. Since HSM based signing will generate its own randomness
   332  // we don't need a real reader. Instead of passing a nil reader we use one
   333  // that always returns errors in case the internal usage of this reader
   334  // changes.
   335  type failReader struct{}
   336  
   337  func (fr *failReader) Read([]byte) (int, error) {
   338  	return 0, errors.New("empty reader used by x509.CreateCertificate")
   339  }
   340  
   341  func generateCSR(profile *certProfile, signer crypto.Signer) ([]byte, error) {
   342  	csrDER, err := x509.CreateCertificateRequest(&failReader{}, &x509.CertificateRequest{
   343  		Subject: profile.Subject(),
   344  	}, signer)
   345  	if err != nil {
   346  		return nil, fmt.Errorf("failed to create and sign CSR: %s", err)
   347  	}
   348  	return csrDER, nil
   349  }
   350  

View as plain text