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
43
44
45
46 type issuerMaps struct {
47 byAlg map[x509.PublicKeyAlgorithm]*issuance.Issuer
48 byNameID map[issuance.IssuerNameID]*issuance.Issuer
49 }
50
51
52
53 type certificateAuthorityImpl struct {
54 capb.UnimplementedCertificateAuthorityServer
55 sa sapb.StorageAuthorityCertificateClient
56 pa core.PolicyAuthority
57 issuers issuerMaps
58
59
60
61 ecdsaAllowList *ECDSAAllowList
62 prefix int
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
75
76
77
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
84
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
95
96
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
117
118
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
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
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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238 func (ca *certificateAuthorityImpl) IssueCertificateForPrecertificate(ctx context.Context, req *capb.IssueCertificateForPrecertificateRequest) (*corepb.Certificate, error) {
239
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
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
364
365 return nil, nil, err
366 }
367
368 var issuer *issuance.Issuer
369 var ok bool
370 if issueReq.IssuerNameID == 0 {
371
372
373
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