...

Source file src/github.com/letsencrypt/boulder/ca/ca.go

Documentation: github.com/letsencrypt/boulder/ca

     1  package ca
     2  
     3  import (
     4  	"context"
     5  	"crypto/rand"
     6  	"crypto/x509"
     7  	"encoding/hex"
     8  	"errors"
     9  	"fmt"
    10  	"math/big"
    11  	"strings"
    12  	"time"
    13  
    14  	ct "github.com/google/certificate-transparency-go"
    15  	cttls "github.com/google/certificate-transparency-go/tls"
    16  	"github.com/jmhodges/clock"
    17  	"github.com/miekg/pkcs11"
    18  	"github.com/prometheus/client_golang/prometheus"
    19  	"golang.org/x/crypto/ocsp"
    20  	"google.golang.org/protobuf/types/known/timestamppb"
    21  
    22  	capb "github.com/letsencrypt/boulder/ca/proto"
    23  	"github.com/letsencrypt/boulder/core"
    24  	corepb "github.com/letsencrypt/boulder/core/proto"
    25  	csrlib "github.com/letsencrypt/boulder/csr"
    26  	berrors "github.com/letsencrypt/boulder/errors"
    27  	"github.com/letsencrypt/boulder/features"
    28  	"github.com/letsencrypt/boulder/goodkey"
    29  	"github.com/letsencrypt/boulder/issuance"
    30  	"github.com/letsencrypt/boulder/linter"
    31  	blog "github.com/letsencrypt/boulder/log"
    32  	sapb "github.com/letsencrypt/boulder/sa/proto"
    33  )
    34  
    35  type certificateType string
    36  
    37  const (
    38  	precertType = certificateType("precertificate")
    39  	certType    = certificateType("certificate")
    40  )
    41  
    42  // Two maps of keys to Issuers. Lookup by PublicKeyAlgorithm is useful for
    43  // determining which issuer to use to sign a given (pre)cert, based on its
    44  // PublicKeyAlgorithm. Lookup by NameID is useful for looking up the appropriate
    45  // issuer based on the issuer of a given (pre)certificate.
    46  type issuerMaps struct {
    47  	byAlg    map[x509.PublicKeyAlgorithm]*issuance.Issuer
    48  	byNameID map[issuance.IssuerNameID]*issuance.Issuer
    49  }
    50  
    51  // certificateAuthorityImpl represents a CA that signs certificates.
    52  // It can sign OCSP responses as well, but only via delegation to an ocspImpl.
    53  type certificateAuthorityImpl struct {
    54  	capb.UnimplementedCertificateAuthorityServer
    55  	sa      sapb.StorageAuthorityCertificateClient
    56  	pa      core.PolicyAuthority
    57  	issuers issuerMaps
    58  
    59  	// This is temporary, and will be used for testing and slow roll-out
    60  	// of ECDSA issuance, but will then be removed.
    61  	ecdsaAllowList *ECDSAAllowList
    62  	prefix         int // Prepended to the serial number
    63  	validityPeriod time.Duration
    64  	backdate       time.Duration
    65  	maxNames       int
    66  	keyPolicy      goodkey.KeyPolicy
    67  	clk            clock.Clock
    68  	log            blog.Logger
    69  	signatureCount *prometheus.CounterVec
    70  	signErrorCount *prometheus.CounterVec
    71  	lintErrorCount prometheus.Counter
    72  }
    73  
    74  // makeIssuerMaps processes a list of issuers into a set of maps, mapping
    75  // nearly-unique identifiers of those issuers to the issuers themselves. Note
    76  // that, if two issuers have the same nearly-unique ID, the *latter* one in
    77  // the input list "wins".
    78  func makeIssuerMaps(issuers []*issuance.Issuer) issuerMaps {
    79  	issuersByAlg := make(map[x509.PublicKeyAlgorithm]*issuance.Issuer, 2)
    80  	issuersByNameID := make(map[issuance.IssuerNameID]*issuance.Issuer, len(issuers))
    81  	for _, issuer := range issuers {
    82  		for _, alg := range issuer.Algs() {
    83  			// TODO(#5259): Enforce that there is only one issuer for each algorithm,
    84  			// instead of taking the first issuer for each algorithm type.
    85  			if issuersByAlg[alg] == nil {
    86  				issuersByAlg[alg] = issuer
    87  			}
    88  		}
    89  		issuersByNameID[issuer.Cert.NameID()] = issuer
    90  	}
    91  	return issuerMaps{issuersByAlg, issuersByNameID}
    92  }
    93  
    94  // NewCertificateAuthorityImpl creates a CA instance that can sign certificates
    95  // from any number of issuance.Issuers according to their profiles, and can sign
    96  // OCSP (via delegation to an ocspImpl and its issuers).
    97  func NewCertificateAuthorityImpl(
    98  	sa sapb.StorageAuthorityCertificateClient,
    99  	pa core.PolicyAuthority,
   100  	boulderIssuers []*issuance.Issuer,
   101  	ecdsaAllowList *ECDSAAllowList,
   102  	certExpiry time.Duration,
   103  	certBackdate time.Duration,
   104  	serialPrefix int,
   105  	maxNames int,
   106  	keyPolicy goodkey.KeyPolicy,
   107  	logger blog.Logger,
   108  	stats prometheus.Registerer,
   109  	signatureCount *prometheus.CounterVec,
   110  	signErrorCount *prometheus.CounterVec,
   111  	clk clock.Clock,
   112  ) (*certificateAuthorityImpl, error) {
   113  	var ca *certificateAuthorityImpl
   114  	var err error
   115  
   116  	// TODO(briansmith): Make the backdate setting mandatory after the
   117  	// production ca.json has been updated to include it. Until then, manually
   118  	// default to 1h, which is the backdating duration we currently use.
   119  	if certBackdate == 0 {
   120  		certBackdate = time.Hour
   121  	}
   122  
   123  	if serialPrefix <= 0 || serialPrefix >= 256 {
   124  		err = errors.New("Must have a positive non-zero serial prefix less than 256 for CA.")
   125  		return nil, err
   126  	}
   127  
   128  	if len(boulderIssuers) == 0 {
   129  		return nil, errors.New("must have at least one issuer")
   130  	}
   131  
   132  	issuers := makeIssuerMaps(boulderIssuers)
   133  
   134  	lintErrorCount := prometheus.NewCounter(
   135  		prometheus.CounterOpts{
   136  			Name: "lint_errors",
   137  			Help: "Number of issuances that were halted by linting errors",
   138  		})
   139  	stats.MustRegister(lintErrorCount)
   140  
   141  	ca = &certificateAuthorityImpl{
   142  		sa:             sa,
   143  		pa:             pa,
   144  		issuers:        issuers,
   145  		validityPeriod: certExpiry,
   146  		backdate:       certBackdate,
   147  		prefix:         serialPrefix,
   148  		maxNames:       maxNames,
   149  		keyPolicy:      keyPolicy,
   150  		log:            logger,
   151  		signatureCount: signatureCount,
   152  		signErrorCount: signErrorCount,
   153  		lintErrorCount: lintErrorCount,
   154  		clk:            clk,
   155  		ecdsaAllowList: ecdsaAllowList,
   156  	}
   157  
   158  	return ca, nil
   159  }
   160  
   161  // noteSignError is called after operations that may cause a PKCS11 signing error.
   162  func (ca *certificateAuthorityImpl) noteSignError(err error) {
   163  	var pkcs11Error *pkcs11.Error
   164  	if errors.As(err, &pkcs11Error) {
   165  		ca.signErrorCount.WithLabelValues("HSM").Inc()
   166  	}
   167  }
   168  
   169  var ocspStatusToCode = map[string]int{
   170  	"good":    ocsp.Good,
   171  	"revoked": ocsp.Revoked,
   172  	"unknown": ocsp.Unknown,
   173  }
   174  
   175  func (ca *certificateAuthorityImpl) IssuePrecertificate(ctx context.Context, issueReq *capb.IssueCertificateRequest) (*capb.IssuePrecertificateResponse, error) {
   176  	// issueReq.orderID may be zero, for ACMEv1 requests.
   177  	if core.IsAnyNilOrZero(issueReq, issueReq.Csr, issueReq.RegistrationID) {
   178  		return nil, berrors.InternalServerError("Incomplete issue certificate request")
   179  	}
   180  
   181  	serialBigInt, validity, err := ca.generateSerialNumberAndValidity()
   182  	if err != nil {
   183  		return nil, err
   184  	}
   185  
   186  	serialHex := core.SerialToString(serialBigInt)
   187  	regID := issueReq.RegistrationID
   188  	now := ca.clk.Now()
   189  	_, err = ca.sa.AddSerial(ctx, &sapb.AddSerialRequest{
   190  		Serial:    serialHex,
   191  		RegID:     regID,
   192  		CreatedNS: now.UnixNano(),
   193  		Created:   timestamppb.New(now),
   194  		ExpiresNS: validity.NotAfter.UnixNano(),
   195  		Expires:   timestamppb.New(validity.NotAfter),
   196  	})
   197  	if err != nil {
   198  		return nil, err
   199  	}
   200  
   201  	precertDER, _, err := ca.issuePrecertificateInner(ctx, issueReq, serialBigInt, validity)
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  
   206  	_, err = ca.sa.SetCertificateStatusReady(ctx, &sapb.Serial{Serial: serialHex})
   207  	if err != nil {
   208  		return nil, err
   209  	}
   210  
   211  	return &capb.IssuePrecertificateResponse{
   212  		DER: precertDER,
   213  	}, nil
   214  }
   215  
   216  // IssueCertificateForPrecertificate takes a precertificate and a set
   217  // of SCTs for that precertificate and uses the signer to create and
   218  // sign a certificate from them. The poison extension is removed and a
   219  // SCT list extension is inserted in its place. Except for this and the
   220  // signature the certificate exactly matches the precertificate. After
   221  // the certificate is signed a OCSP response is generated and the
   222  // response and certificate are stored in the database.
   223  //
   224  // It's critical not to sign two different final certificates for the same
   225  // precertificate. This can happen, for instance, if the caller provides a
   226  // different set of SCTs on subsequent calls to  IssueCertificateForPrecertificate.
   227  // We rely on the RA not to call IssueCertificateForPrecertificate twice for the
   228  // same serial. This is accomplished by the fact that
   229  // IssueCertificateForPrecertificate is only ever called in a straight-through
   230  // RPC path without retries. If there is any error, including a networking
   231  // error, the whole certificate issuance attempt fails and any subsequent
   232  // issuance will use a different serial number.
   233  //
   234  // We also check that the provided serial number does not already exist as a
   235  // final certificate, but this is just a belt-and-suspenders measure, since
   236  // there could be race conditions where two goroutines are issuing for the same
   237  // serial number at the same time.
   238  func (ca *certificateAuthorityImpl) IssueCertificateForPrecertificate(ctx context.Context, req *capb.IssueCertificateForPrecertificateRequest) (*corepb.Certificate, error) {
   239  	// issueReq.orderID may be zero, for ACMEv1 requests.
   240  	if core.IsAnyNilOrZero(req, req.DER, req.SCTs, req.RegistrationID) {
   241  		return nil, berrors.InternalServerError("Incomplete cert for precertificate request")
   242  	}
   243  
   244  	precert, err := x509.ParseCertificate(req.DER)
   245  	if err != nil {
   246  		return nil, err
   247  	}
   248  
   249  	serialHex := core.SerialToString(precert.SerialNumber)
   250  	if _, err = ca.sa.GetCertificate(ctx, &sapb.Serial{Serial: serialHex}); err == nil {
   251  		err = berrors.InternalServerError("issuance of duplicate final certificate requested: %s", serialHex)
   252  		ca.log.AuditErr(err.Error())
   253  		return nil, err
   254  	} else if !errors.Is(err, berrors.NotFound) {
   255  		return nil, fmt.Errorf("error checking for duplicate issuance of %s: %s", serialHex, err)
   256  	}
   257  	var scts []ct.SignedCertificateTimestamp
   258  	for _, sctBytes := range req.SCTs {
   259  		var sct ct.SignedCertificateTimestamp
   260  		_, err = cttls.Unmarshal(sctBytes, &sct)
   261  		if err != nil {
   262  			return nil, err
   263  		}
   264  		scts = append(scts, sct)
   265  	}
   266  
   267  	issuer, ok := ca.issuers.byNameID[issuance.GetIssuerNameID(precert)]
   268  	if !ok {
   269  		return nil, berrors.InternalServerError("no issuer found for Issuer Name %s", precert.Issuer)
   270  	}
   271  
   272  	issuanceReq, err := issuance.RequestFromPrecert(precert, scts)
   273  	if err != nil {
   274  		return nil, err
   275  	}
   276  
   277  	names := strings.Join(issuanceReq.DNSNames, ", ")
   278  
   279  	ca.log.AuditInfof("Signing cert: serial=[%s] regID=[%d] names=[%s] precert=[%s]",
   280  		serialHex, req.RegistrationID, names, hex.EncodeToString(precert.Raw))
   281  
   282  	_, issuanceToken, err := issuer.Prepare(issuanceReq)
   283  	if err != nil {
   284  		ca.log.AuditErrf("Preparing cert failed: serial=[%s] regID=[%d] names=[%s] err=[%v]",
   285  			serialHex, req.RegistrationID, names, err)
   286  		return nil, berrors.InternalServerError("failed to prepare certificate signing: %s", err)
   287  	}
   288  
   289  	certDER, err := issuer.Issue(issuanceToken)
   290  	if err != nil {
   291  		ca.noteSignError(err)
   292  		ca.log.AuditErrf("Signing cert failed: serial=[%s] regID=[%d] names=[%s] err=[%v]",
   293  			serialHex, req.RegistrationID, names, err)
   294  		return nil, berrors.InternalServerError("failed to sign certificate: %s", err)
   295  	}
   296  
   297  	ca.signatureCount.With(prometheus.Labels{"purpose": string(certType), "issuer": issuer.Name()}).Inc()
   298  	ca.log.AuditInfof("Signing cert success: serial=[%s] regID=[%d] names=[%s] certificate=[%s]",
   299  		serialHex, req.RegistrationID, names, hex.EncodeToString(certDER))
   300  
   301  	now := ca.clk.Now()
   302  	_, err = ca.sa.AddCertificate(ctx, &sapb.AddCertificateRequest{
   303  		Der:      certDER,
   304  		RegID:    req.RegistrationID,
   305  		IssuedNS: now.UnixNano(),
   306  		Issued:   timestamppb.New(now),
   307  	})
   308  	if err != nil {
   309  		ca.log.AuditErrf("Failed RPC to store at SA: serial=[%s], cert=[%s], issuerID=[%d], regID=[%d], orderID=[%d], err=[%v]",
   310  			serialHex, hex.EncodeToString(certDER), int64(issuer.Cert.NameID()), req.RegistrationID, req.OrderID, err)
   311  		return nil, err
   312  	}
   313  
   314  	return &corepb.Certificate{
   315  		RegistrationID: req.RegistrationID,
   316  		Serial:         core.SerialToString(precert.SerialNumber),
   317  		Der:            certDER,
   318  		Digest:         core.Fingerprint256(certDER),
   319  		IssuedNS:       precert.NotBefore.UnixNano(),
   320  		Issued:         timestamppb.New(precert.NotBefore),
   321  		ExpiresNS:      precert.NotAfter.UnixNano(),
   322  		Expires:        timestamppb.New(precert.NotAfter),
   323  	}, nil
   324  }
   325  
   326  type validity struct {
   327  	NotBefore time.Time
   328  	NotAfter  time.Time
   329  }
   330  
   331  func (ca *certificateAuthorityImpl) generateSerialNumberAndValidity() (*big.Int, validity, error) {
   332  	// We want 136 bits of random number, plus an 8-bit instance id prefix.
   333  	const randBits = 136
   334  	serialBytes := make([]byte, randBits/8+1)
   335  	serialBytes[0] = byte(ca.prefix)
   336  	_, err := rand.Read(serialBytes[1:])
   337  	if err != nil {
   338  		err = berrors.InternalServerError("failed to generate serial: %s", err)
   339  		ca.log.AuditErrf("Serial randomness failed, err=[%v]", err)
   340  		return nil, validity{}, err
   341  	}
   342  	serialBigInt := big.NewInt(0)
   343  	serialBigInt = serialBigInt.SetBytes(serialBytes)
   344  
   345  	notBefore := ca.clk.Now().Add(-ca.backdate)
   346  	validity := validity{
   347  		NotBefore: notBefore,
   348  		NotAfter:  notBefore.Add(ca.validityPeriod - time.Second),
   349  	}
   350  
   351  	return serialBigInt, validity, nil
   352  }
   353  
   354  func (ca *certificateAuthorityImpl) issuePrecertificateInner(ctx context.Context, issueReq *capb.IssueCertificateRequest, serialBigInt *big.Int, validity validity) ([]byte, *issuance.Issuer, error) {
   355  	csr, err := x509.ParseCertificateRequest(issueReq.Csr)
   356  	if err != nil {
   357  		return nil, nil, err
   358  	}
   359  
   360  	err = csrlib.VerifyCSR(ctx, csr, ca.maxNames, &ca.keyPolicy, ca.pa)
   361  	if err != nil {
   362  		ca.log.AuditErr(err.Error())
   363  		// VerifyCSR returns berror instances that can be passed through as-is
   364  		// without wrapping.
   365  		return nil, nil, err
   366  	}
   367  
   368  	var issuer *issuance.Issuer
   369  	var ok bool
   370  	if issueReq.IssuerNameID == 0 {
   371  		// Use the issuer which corresponds to the algorithm of the public key
   372  		// contained in the CSR, unless we have an allowlist of registration IDs
   373  		// for ECDSA, in which case switch all not-allowed accounts to RSA issuance.
   374  		alg := csr.PublicKeyAlgorithm
   375  		if alg == x509.ECDSA && !features.Enabled(features.ECDSAForAll) && ca.ecdsaAllowList != nil && !ca.ecdsaAllowList.permitted(issueReq.RegistrationID) {
   376  			alg = x509.RSA
   377  		}
   378  		issuer, ok = ca.issuers.byAlg[alg]
   379  		if !ok {
   380  			return nil, nil, berrors.InternalServerError("no issuer found for public key algorithm %s", csr.PublicKeyAlgorithm)
   381  		}
   382  	} else {
   383  		issuer, ok = ca.issuers.byNameID[issuance.IssuerNameID(issueReq.IssuerNameID)]
   384  		if !ok {
   385  			return nil, nil, berrors.InternalServerError("no issuer found for IssuerNameID %d", issueReq.IssuerNameID)
   386  		}
   387  	}
   388  
   389  	if issuer.Cert.NotAfter.Before(validity.NotAfter) {
   390  		err = berrors.InternalServerError("cannot issue a certificate that expires after the issuer certificate")
   391  		ca.log.AuditErr(err.Error())
   392  		return nil, nil, err
   393  	}
   394  
   395  	serialHex := core.SerialToString(serialBigInt)
   396  
   397  	ca.log.AuditInfof("Signing precert: serial=[%s] regID=[%d] names=[%s] csr=[%s]",
   398  		serialHex, issueReq.RegistrationID, strings.Join(csr.DNSNames, ", "), hex.EncodeToString(csr.Raw))
   399  
   400  	names := csrlib.NamesFromCSR(csr)
   401  	req := &issuance.IssuanceRequest{
   402  		PublicKey:         csr.PublicKey,
   403  		Serial:            serialBigInt.Bytes(),
   404  		DNSNames:          names.SANs,
   405  		CommonName:        names.CN,
   406  		IncludeCTPoison:   true,
   407  		IncludeMustStaple: issuance.ContainsMustStaple(csr.Extensions),
   408  		NotBefore:         validity.NotBefore,
   409  		NotAfter:          validity.NotAfter,
   410  	}
   411  
   412  	lintCertBytes, issuanceToken, err := issuer.Prepare(req)
   413  	if err != nil {
   414  		ca.log.AuditErrf("Preparing precert failed: serial=[%s] regID=[%d] names=[%s] err=[%v]",
   415  			serialHex, issueReq.RegistrationID, strings.Join(csr.DNSNames, ", "), err)
   416  		if errors.Is(err, linter.ErrLinting) {
   417  			ca.lintErrorCount.Inc()
   418  		}
   419  		return nil, nil, berrors.InternalServerError("failed to prepare precertificate signing: %s", err)
   420  	}
   421  
   422  	now := ca.clk.Now()
   423  	_, err = ca.sa.AddPrecertificate(context.Background(), &sapb.AddCertificateRequest{
   424  		Der:          lintCertBytes,
   425  		RegID:        issueReq.RegistrationID,
   426  		IssuedNS:     now.UnixNano(),
   427  		Issued:       timestamppb.New(now),
   428  		IssuerNameID: int64(issuer.Cert.NameID()),
   429  		OcspNotReady: true,
   430  	})
   431  	if err != nil {
   432  		return nil, nil, err
   433  	}
   434  
   435  	certDER, err := issuer.Issue(issuanceToken)
   436  	if err != nil {
   437  		ca.noteSignError(err)
   438  		ca.log.AuditErrf("Signing precert failed: serial=[%s] regID=[%d] names=[%s] err=[%v]",
   439  			serialHex, issueReq.RegistrationID, strings.Join(csr.DNSNames, ", "), err)
   440  		return nil, nil, berrors.InternalServerError("failed to sign precertificate: %s", err)
   441  	}
   442  
   443  	ca.signatureCount.With(prometheus.Labels{"purpose": string(precertType), "issuer": issuer.Name()}).Inc()
   444  	ca.log.AuditInfof("Signing precert success: serial=[%s] regID=[%d] names=[%s] precertificate=[%s]",
   445  		serialHex, issueReq.RegistrationID, strings.Join(csr.DNSNames, ", "), hex.EncodeToString(certDER))
   446  
   447  	return certDER, issuer, nil
   448  }
   449  

View as plain text