1 package ra
2
3 import (
4 "bytes"
5 "context"
6 "crypto/ecdsa"
7 "crypto/elliptic"
8 "crypto/rand"
9 "crypto/rsa"
10 "crypto/sha256"
11 "crypto/x509"
12 "crypto/x509/pkix"
13 "encoding/json"
14 "encoding/pem"
15 "errors"
16 "fmt"
17 "math/big"
18 mrand "math/rand"
19 "net"
20 "regexp"
21 "strconv"
22 "strings"
23 "sync"
24 "testing"
25 "time"
26
27 ctasn1 "github.com/google/certificate-transparency-go/asn1"
28 ctx509 "github.com/google/certificate-transparency-go/x509"
29 ctpkix "github.com/google/certificate-transparency-go/x509/pkix"
30 "github.com/jmhodges/clock"
31 "github.com/prometheus/client_golang/prometheus"
32 "github.com/weppos/publicsuffix-go/publicsuffix"
33 "golang.org/x/crypto/ocsp"
34 "google.golang.org/grpc"
35 "google.golang.org/protobuf/types/known/emptypb"
36 "google.golang.org/protobuf/types/known/timestamppb"
37 "gopkg.in/go-jose/go-jose.v2"
38
39 akamaipb "github.com/letsencrypt/boulder/akamai/proto"
40 capb "github.com/letsencrypt/boulder/ca/proto"
41 "github.com/letsencrypt/boulder/config"
42 "github.com/letsencrypt/boulder/core"
43 corepb "github.com/letsencrypt/boulder/core/proto"
44 "github.com/letsencrypt/boulder/ctpolicy"
45 "github.com/letsencrypt/boulder/ctpolicy/loglist"
46 berrors "github.com/letsencrypt/boulder/errors"
47 "github.com/letsencrypt/boulder/goodkey"
48 bgrpc "github.com/letsencrypt/boulder/grpc"
49 "github.com/letsencrypt/boulder/identifier"
50 "github.com/letsencrypt/boulder/issuance"
51 blog "github.com/letsencrypt/boulder/log"
52 "github.com/letsencrypt/boulder/metrics"
53 "github.com/letsencrypt/boulder/mocks"
54 "github.com/letsencrypt/boulder/policy"
55 pubpb "github.com/letsencrypt/boulder/publisher/proto"
56 rapb "github.com/letsencrypt/boulder/ra/proto"
57 "github.com/letsencrypt/boulder/ratelimit"
58 "github.com/letsencrypt/boulder/ratelimits"
59 "github.com/letsencrypt/boulder/sa"
60 sapb "github.com/letsencrypt/boulder/sa/proto"
61 "github.com/letsencrypt/boulder/test"
62 isa "github.com/letsencrypt/boulder/test/inmem/sa"
63 "github.com/letsencrypt/boulder/test/vars"
64 vapb "github.com/letsencrypt/boulder/va/proto"
65 )
66
67 func TestImplementation(t *testing.T) {
68 test.AssertImplementsGRPCServer(t, &RegistrationAuthorityImpl{}, rapb.UnimplementedRegistrationAuthorityServer{})
69 }
70
71 func createPendingAuthorization(t *testing.T, sa sapb.StorageAuthorityClient, domain string, exp time.Time) *corepb.Authorization {
72 t.Helper()
73
74 authz := core.Authorization{
75 Identifier: identifier.DNSIdentifier(domain),
76 RegistrationID: Registration.Id,
77 Status: "pending",
78 Expires: &exp,
79 Challenges: []core.Challenge{
80 {
81 Token: core.NewToken(),
82 Type: core.ChallengeTypeHTTP01,
83 Status: core.StatusPending,
84 },
85 {
86 Token: core.NewToken(),
87 Type: core.ChallengeTypeDNS01,
88 Status: core.StatusPending,
89 },
90 {
91 Token: core.NewToken(),
92 Type: core.ChallengeTypeTLSALPN01,
93 Status: core.StatusPending,
94 },
95 },
96 }
97 authzPB, err := bgrpc.AuthzToPB(authz)
98 test.AssertNotError(t, err, "AuthzToPB failed")
99
100 res, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{
101 NewOrder: &sapb.NewOrderRequest{
102 RegistrationID: Registration.Id,
103 ExpiresNS: exp.UnixNano(),
104 Expires: timestamppb.New(exp),
105 Names: []string{domain},
106 },
107 NewAuthzs: []*corepb.Authorization{authzPB},
108 })
109 test.AssertNotError(t, err, "sa.NewOrderAndAuthzs failed")
110
111 return getAuthorization(t, fmt.Sprint(res.V2Authorizations[0]), sa)
112 }
113
114 func createFinalizedAuthorization(t *testing.T, sa sapb.StorageAuthorityClient, domain string, exp time.Time, chall core.AcmeChallenge, attemptedAt time.Time) int64 {
115 t.Helper()
116 pending := createPendingAuthorization(t, sa, domain, exp)
117 pendingID, err := strconv.ParseInt(pending.Id, 10, 64)
118 test.AssertNotError(t, err, "strconv.ParseInt failed")
119 _, err = sa.FinalizeAuthorization2(context.Background(), &sapb.FinalizeAuthorizationRequest{
120 Id: pendingID,
121 Status: "valid",
122 ExpiresNS: exp.UnixNano(),
123 Expires: timestamppb.New(exp),
124 Attempted: string(chall),
125 AttemptedAtNS: attemptedAt.UnixNano(),
126 AttemptedAt: timestamppb.New(attemptedAt),
127 })
128 test.AssertNotError(t, err, "sa.FinalizeAuthorizations2 failed")
129 return pendingID
130 }
131
132 func getAuthorization(t *testing.T, id string, sa sapb.StorageAuthorityClient) *corepb.Authorization {
133 t.Helper()
134 idInt, err := strconv.ParseInt(id, 10, 64)
135 test.AssertNotError(t, err, "strconv.ParseInt failed")
136 dbAuthz, err := sa.GetAuthorization2(ctx, &sapb.AuthorizationID2{Id: idInt})
137 test.AssertNotError(t, err, "Could not fetch authorization from database")
138 return dbAuthz
139 }
140
141 func dnsChallIdx(t *testing.T, challenges []*corepb.Challenge) int64 {
142 t.Helper()
143 var challIdx int64
144 var set bool
145 for i, ch := range challenges {
146 if core.AcmeChallenge(ch.Type) == core.ChallengeTypeDNS01 {
147 challIdx = int64(i)
148 set = true
149 break
150 }
151 }
152 if !set {
153 t.Errorf("dnsChallIdx didn't find challenge of type DNS-01")
154 }
155 return challIdx
156 }
157
158 func numAuthorizations(o *corepb.Order) int {
159 return len(o.V2Authorizations)
160 }
161
162 type DummyValidationAuthority struct {
163 request chan *vapb.PerformValidationRequest
164 ResultError error
165 ResultReturn *vapb.ValidationResult
166 }
167
168 func (dva *DummyValidationAuthority) PerformValidation(ctx context.Context, req *vapb.PerformValidationRequest, _ ...grpc.CallOption) (*vapb.ValidationResult, error) {
169 dva.request <- req
170 return dva.ResultReturn, dva.ResultError
171 }
172
173 var (
174
175 AccountKeyJSONA = []byte(`{
176 "kty":"RSA",
177 "n":"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
178 "e":"AQAB"
179 }`)
180 AccountKeyA = jose.JSONWebKey{}
181
182 AccountKeyJSONB = []byte(`{
183 "kty":"RSA",
184 "n":"z8bp-jPtHt4lKBqepeKF28g_QAEOuEsCIou6sZ9ndsQsEjxEOQxQ0xNOQezsKa63eogw8YS3vzjUcPP5BJuVzfPfGd5NVUdT-vSSwxk3wvk_jtNqhrpcoG0elRPQfMVsQWmxCAXCVRz3xbcFI8GTe-syynG3l-g1IzYIIZVNI6jdljCZML1HOMTTW4f7uJJ8mM-08oQCeHbr5ejK7O2yMSSYxW03zY-Tj1iVEebROeMv6IEEJNFSS4yM-hLpNAqVuQxFGetwtwjDMC1Drs1dTWrPuUAAjKGrP151z1_dE74M5evpAhZUmpKv1hY-x85DC6N0hFPgowsanmTNNiV75w",
185 "e":"AQAB"
186 }`)
187 AccountKeyB = jose.JSONWebKey{}
188
189 AccountKeyJSONC = []byte(`{
190 "kty":"RSA",
191 "n":"rFH5kUBZrlPj73epjJjyCxzVzZuV--JjKgapoqm9pOuOt20BUTdHqVfC2oDclqM7HFhkkX9OSJMTHgZ7WaVqZv9u1X2yjdx9oVmMLuspX7EytW_ZKDZSzL-sCOFCuQAuYKkLbsdcA3eHBK_lwc4zwdeHFMKIulNvLqckkqYB9s8GpgNXBDIQ8GjR5HuJke_WUNjYHSd8jY1LU9swKWsLQe2YoQUz_ekQvBvBCoaFEtrtRaSJKNLIVDObXFr2TLIiFiM0Em90kK01-eQ7ZiruZTKomll64bRFPoNo4_uwubddg3xTqur2vdF3NyhTrYdvAgTem4uC0PFjEQ1bK_djBQ",
192 "e":"AQAB"
193 }`)
194 AccountKeyC = jose.JSONWebKey{}
195
196
197 AccountPrivateKeyJSON = []byte(`{
198 "kty":"RSA",
199 "n":"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
200 "e":"AQAB",
201 "d":"X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqijwp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBznbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFzme1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q",
202 "p":"83i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQBQxtPVnwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7XOuVIYQyqVWlWEh6dN36GVZYk93N8Bc9vY41xy8B9RzzOGVQzXvNEvn7O0nVbfs",
203 "q":"3dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3vobLyumqjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgxkIdrecRezsZ-1kYd_s1qDbxtkDEgfAITAG9LUnADun4vIcb6yelxk",
204 "dp":"G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0oimYwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA77Qe_NmtuYZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUms6rY3Ob8YeiKkTiBj0",
205 "dq":"s9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA6huUUvMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvWrX-L18txXw494Q_cgk",
206 "qi":"GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfmt0FoYzgUIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_mHZGJ11rxyR8O55XLSe3SPmRfKwZI6yU24ZxvQKFYItdldUKGzO6Ia6zTKhAVRU"
207 }`)
208 AccountPrivateKey = jose.JSONWebKey{}
209
210 ShortKeyJSON = []byte(`{
211 "e": "AQAB",
212 "kty": "RSA",
213 "n": "tSwgy3ORGvc7YJI9B2qqkelZRUC6F1S5NwXFvM4w5-M0TsxbFsH5UH6adigV0jzsDJ5imAechcSoOhAh9POceCbPN1sTNwLpNbOLiQQ7RD5mY_"
214 }`)
215
216 ShortKey = jose.JSONWebKey{}
217
218 ResponseIndex = 0
219
220 ExampleCSR = &x509.CertificateRequest{}
221
222 Registration = &corepb.Registration{Id: 1}
223
224 Identifier = "not-example.com"
225
226 log = blog.UseMock()
227 )
228
229 var testKeyPolicy = goodkey.KeyPolicy{
230 AllowRSA: true,
231 AllowECDSANISTP256: true,
232 AllowECDSANISTP384: true,
233 }
234
235 var ctx = context.Background()
236
237
238
239 type dummyRateLimitConfig struct {
240 CertificatesPerNamePolicy ratelimit.RateLimitPolicy
241 RegistrationsPerIPPolicy ratelimit.RateLimitPolicy
242 RegistrationsPerIPRangePolicy ratelimit.RateLimitPolicy
243 PendingAuthorizationsPerAccountPolicy ratelimit.RateLimitPolicy
244 NewOrdersPerAccountPolicy ratelimit.RateLimitPolicy
245 InvalidAuthorizationsPerAccountPolicy ratelimit.RateLimitPolicy
246 CertificatesPerFQDNSetPolicy ratelimit.RateLimitPolicy
247 CertificatesPerFQDNSetFastPolicy ratelimit.RateLimitPolicy
248 }
249
250 func (r *dummyRateLimitConfig) CertificatesPerName() ratelimit.RateLimitPolicy {
251 return r.CertificatesPerNamePolicy
252 }
253
254 func (r *dummyRateLimitConfig) RegistrationsPerIP() ratelimit.RateLimitPolicy {
255 return r.RegistrationsPerIPPolicy
256 }
257
258 func (r *dummyRateLimitConfig) RegistrationsPerIPRange() ratelimit.RateLimitPolicy {
259 return r.RegistrationsPerIPRangePolicy
260 }
261
262 func (r *dummyRateLimitConfig) PendingAuthorizationsPerAccount() ratelimit.RateLimitPolicy {
263 return r.PendingAuthorizationsPerAccountPolicy
264 }
265
266 func (r *dummyRateLimitConfig) NewOrdersPerAccount() ratelimit.RateLimitPolicy {
267 return r.NewOrdersPerAccountPolicy
268 }
269
270 func (r *dummyRateLimitConfig) InvalidAuthorizationsPerAccount() ratelimit.RateLimitPolicy {
271 return r.InvalidAuthorizationsPerAccountPolicy
272 }
273
274 func (r *dummyRateLimitConfig) CertificatesPerFQDNSet() ratelimit.RateLimitPolicy {
275 return r.CertificatesPerFQDNSetPolicy
276 }
277
278 func (r *dummyRateLimitConfig) CertificatesPerFQDNSetFast() ratelimit.RateLimitPolicy {
279 return r.CertificatesPerFQDNSetFastPolicy
280 }
281
282 func (r *dummyRateLimitConfig) LoadPolicies(contents []byte) error {
283 return nil
284 }
285
286 func parseAndMarshalIP(t *testing.T, ip string) []byte {
287 ipBytes, err := net.ParseIP(ip).MarshalText()
288 test.AssertNotError(t, err, "failed to marshal ip")
289 return ipBytes
290 }
291
292 func newAcctKey(t *testing.T) []byte {
293 key := &jose.JSONWebKey{Key: testKey()}
294 acctKey, err := key.MarshalJSON()
295 test.AssertNotError(t, err, "failed to marshal account key")
296 return acctKey
297 }
298
299 func initAuthorities(t *testing.T) (*DummyValidationAuthority, sapb.StorageAuthorityClient, *RegistrationAuthorityImpl, clock.FakeClock, func()) {
300 err := json.Unmarshal(AccountKeyJSONA, &AccountKeyA)
301 test.AssertNotError(t, err, "Failed to unmarshal public JWK")
302 err = json.Unmarshal(AccountKeyJSONB, &AccountKeyB)
303 test.AssertNotError(t, err, "Failed to unmarshal public JWK")
304 err = json.Unmarshal(AccountKeyJSONC, &AccountKeyC)
305 test.AssertNotError(t, err, "Failed to unmarshal public JWK")
306
307 err = json.Unmarshal(AccountPrivateKeyJSON, &AccountPrivateKey)
308 test.AssertNotError(t, err, "Failed to unmarshal private JWK")
309
310 err = json.Unmarshal(ShortKeyJSON, &ShortKey)
311 test.AssertNotError(t, err, "Failed to unmarshal JWK")
312
313 fc := clock.NewFake()
314
315 fc.Set(time.Date(2015, 3, 4, 5, 0, 0, 0, time.UTC))
316
317 dbMap, err := sa.DBMapForTest(vars.DBConnSA)
318 if err != nil {
319 t.Fatalf("Failed to create dbMap: %s", err)
320 }
321 ssa, err := sa.NewSQLStorageAuthority(dbMap, dbMap, nil, 1, 0, fc, log, metrics.NoopRegisterer)
322 if err != nil {
323 t.Fatalf("Failed to create SA: %s", err)
324 }
325 sa := &isa.SA{Impl: ssa}
326
327 saDBCleanUp := test.ResetBoulderTestDatabase(t)
328
329 va := &DummyValidationAuthority{request: make(chan *vapb.PerformValidationRequest, 1)}
330
331 pa, err := policy.New(map[core.AcmeChallenge]bool{
332 core.ChallengeTypeHTTP01: true,
333 core.ChallengeTypeDNS01: true,
334 }, blog.NewMock())
335 test.AssertNotError(t, err, "Couldn't create PA")
336 err = pa.LoadHostnamePolicyFile("../test/hostname-policy.yaml")
337 test.AssertNotError(t, err, "Couldn't set hostname policy")
338
339 stats := metrics.NoopRegisterer
340
341 ca := &mocks.MockCA{
342 PEM: eeCertPEM,
343 }
344 cleanUp := func() {
345 saDBCleanUp()
346 }
347
348 block, _ := pem.Decode(CSRPEM)
349 ExampleCSR, _ = x509.ParseCertificateRequest(block.Bytes)
350
351 initialIP, err := net.ParseIP("3.2.3.3").MarshalText()
352 test.AssertNotError(t, err, "Couldn't create initial IP")
353 Registration, _ = ssa.NewRegistration(ctx, &corepb.Registration{
354 Key: AccountKeyJSONA,
355 InitialIP: initialIP,
356 Status: string(core.StatusValid),
357 })
358
359 ctp := ctpolicy.New(&mocks.PublisherClient{}, loglist.List{
360 "OperA": {
361 "LogA1": {Url: "UrlA1", Key: "KeyA1"},
362 },
363 "OperB": {
364 "LogB1": {Url: "UrlB1", Key: "KeyB1"},
365 },
366 }, nil, nil, 0, log, metrics.NoopRegisterer)
367
368 ra := NewRegistrationAuthorityImpl(
369 fc, log, stats,
370 1, testKeyPolicy, 100,
371 300*24*time.Hour, 7*24*time.Hour,
372 nil, noopCAA{},
373 0, 5*time.Minute,
374 ctp, nil, nil)
375 ra.SA = sa
376 ra.VA = va
377 ra.CA = ca
378 ra.OCSP = &mocks.MockOCSPGenerator{}
379 ra.PA = pa
380 return va, sa, ra, fc, cleanUp
381 }
382
383 func TestValidateContacts(t *testing.T) {
384 _, _, ra, _, cleanUp := initAuthorities(t)
385 defer cleanUp()
386
387 ansible := "ansible:earth.sol.milkyway.laniakea/letsencrypt"
388 validEmail := "mailto:admin@email.com"
389 otherValidEmail := "mailto:other-admin@email.com"
390 malformedEmail := "mailto:admin.com"
391 nonASCII := "mailto:seƱor@email.com"
392 unparsable := "mailto:a@email.com, b@email.com"
393 forbidden := "mailto:a@example.org"
394
395 err := ra.validateContacts([]string{})
396 test.AssertNotError(t, err, "No Contacts")
397
398 err = ra.validateContacts([]string{validEmail, otherValidEmail})
399 test.AssertError(t, err, "Too Many Contacts")
400
401 err = ra.validateContacts([]string{validEmail})
402 test.AssertNotError(t, err, "Valid Email")
403
404 err = ra.validateContacts([]string{malformedEmail})
405 test.AssertError(t, err, "Malformed Email")
406
407 err = ra.validateContacts([]string{ansible})
408 test.AssertError(t, err, "Unknown scheme")
409
410 err = ra.validateContacts([]string{""})
411 test.AssertError(t, err, "Empty URL")
412
413 err = ra.validateContacts([]string{nonASCII})
414 test.AssertError(t, err, "Non ASCII email")
415
416 err = ra.validateContacts([]string{unparsable})
417 test.AssertError(t, err, "Unparsable email")
418
419 err = ra.validateContacts([]string{forbidden})
420 test.AssertError(t, err, "Forbidden email")
421
422 err = ra.validateContacts([]string{"mailto:admin@localhost"})
423 test.AssertError(t, err, "Forbidden email")
424
425 err = ra.validateContacts([]string{"mailto:admin@example.not.a.iana.suffix"})
426 test.AssertError(t, err, "Forbidden email")
427
428 err = ra.validateContacts([]string{"mailto:admin@1.2.3.4"})
429 test.AssertError(t, err, "Forbidden email")
430
431 err = ra.validateContacts([]string{"mailto:admin@[1.2.3.4]"})
432 test.AssertError(t, err, "Forbidden email")
433
434 err = ra.validateContacts([]string{"mailto:admin@a.com?no-reminder-emails"})
435 test.AssertError(t, err, "No hfields in email")
436
437 err = ra.validateContacts([]string{"mailto:example@a.com?"})
438 test.AssertError(t, err, "No hfields in email")
439
440 err = ra.validateContacts([]string{"mailto:example@a.com#"})
441 test.AssertError(t, err, "No fragment")
442
443 err = ra.validateContacts([]string{"mailto:example@a.com#optional"})
444 test.AssertError(t, err, "No fragment")
445
446
447
448
449 var longStringBuf strings.Builder
450 longStringBuf.WriteString("mailto:")
451 for i := 0; i < 175; i++ {
452 longStringBuf.WriteRune('a')
453 }
454 longStringBuf.WriteString("@a.com")
455
456 err = ra.validateContacts([]string{longStringBuf.String()})
457 test.AssertError(t, err, "Too long contacts")
458 }
459
460 func TestNewRegistration(t *testing.T) {
461 _, sa, ra, _, cleanUp := initAuthorities(t)
462 defer cleanUp()
463 mailto := "mailto:foo@letsencrypt.org"
464 acctKeyB, err := AccountKeyB.MarshalJSON()
465 test.AssertNotError(t, err, "failed to marshal account key")
466 input := &corepb.Registration{
467 Contact: []string{mailto},
468 ContactsPresent: true,
469 Key: acctKeyB,
470 InitialIP: parseAndMarshalIP(t, "7.6.6.5"),
471 }
472
473 result, err := ra.NewRegistration(ctx, input)
474 if err != nil {
475 t.Fatalf("could not create new registration: %s", err)
476 }
477 test.AssertByteEquals(t, result.Key, acctKeyB)
478 test.Assert(t, len(result.Contact) == 1, "Wrong number of contacts")
479 test.Assert(t, mailto == (result.Contact)[0], "Contact didn't match")
480 test.Assert(t, result.Agreement == "", "Agreement didn't default empty")
481
482 reg, err := sa.GetRegistration(ctx, &sapb.RegistrationID{Id: result.Id})
483 test.AssertNotError(t, err, "Failed to retrieve registration")
484 test.AssertByteEquals(t, reg.Key, acctKeyB)
485 }
486
487 func TestNewRegistrationContactsPresent(t *testing.T) {
488 _, _, ra, _, cleanUp := initAuthorities(t)
489 defer cleanUp()
490 testCases := []struct {
491 Name string
492 Reg *corepb.Registration
493 ExpectedErr error
494 }{
495 {
496 Name: "No contacts provided by client ContactsPresent false",
497 Reg: &corepb.Registration{
498 Key: newAcctKey(t),
499 InitialIP: parseAndMarshalIP(t, "7.6.6.5"),
500 },
501 ExpectedErr: nil,
502 },
503 {
504 Name: "Empty contact provided by client ContactsPresent true",
505 Reg: &corepb.Registration{
506 Contact: []string{},
507 ContactsPresent: true,
508 Key: newAcctKey(t),
509 InitialIP: parseAndMarshalIP(t, "7.6.6.4"),
510 },
511 ExpectedErr: nil,
512 },
513 {
514 Name: "Valid contact provided by client ContactsPresent true",
515 Reg: &corepb.Registration{
516 Contact: []string{"mailto:foo@letsencrypt.org"},
517 ContactsPresent: true,
518 Key: newAcctKey(t),
519 InitialIP: parseAndMarshalIP(t, "7.6.4.3"),
520 },
521 ExpectedErr: nil,
522 },
523 {
524 Name: "Valid contact provided by client ContactsPresent false",
525 Reg: &corepb.Registration{
526 Contact: []string{"mailto:foo@letsencrypt.org"},
527 ContactsPresent: false,
528 Key: newAcctKey(t),
529 InitialIP: parseAndMarshalIP(t, "7.6.6.2"),
530 },
531 ExpectedErr: fmt.Errorf("account contacts present but contactsPresent false"),
532 },
533 }
534
535
536 for _, tc := range testCases {
537 t.Run(tc.Name, func(t *testing.T) {
538
539 _, err := ra.NewRegistration(ctx, tc.Reg)
540
541 if tc.ExpectedErr == nil {
542 test.AssertNotError(t, err, "expected no error for NewRegistration")
543 } else {
544 test.AssertError(t, err, "expected error for NewRegistration")
545 test.AssertEquals(t, err.Error(), tc.ExpectedErr.Error())
546 }
547 })
548 }
549 }
550
551 type mockSAFailsNewRegistration struct {
552 mocks.StorageAuthority
553 }
554
555 func (sa *mockSAFailsNewRegistration) NewRegistration(_ context.Context, _ *corepb.Registration, _ ...grpc.CallOption) (*corepb.Registration, error) {
556 return &corepb.Registration{}, fmt.Errorf("too bad")
557 }
558
559 func TestNewRegistrationSAFailure(t *testing.T) {
560 _, _, ra, _, cleanUp := initAuthorities(t)
561 defer cleanUp()
562 ra.SA = &mockSAFailsNewRegistration{}
563 acctKeyB, err := AccountKeyB.MarshalJSON()
564 test.AssertNotError(t, err, "failed to marshal account key")
565 input := corepb.Registration{
566 Contact: []string{"mailto:test@example.com"},
567 ContactsPresent: true,
568 Key: acctKeyB,
569 InitialIP: parseAndMarshalIP(t, "7.6.6.5"),
570 }
571 result, err := ra.NewRegistration(ctx, &input)
572 if err == nil {
573 t.Fatalf("NewRegistration should have failed when SA.NewRegistration failed %#v", result.Key)
574 }
575 }
576
577 func TestNewRegistrationNoFieldOverwrite(t *testing.T) {
578 _, _, ra, _, cleanUp := initAuthorities(t)
579 defer cleanUp()
580 mailto := "mailto:foo@letsencrypt.org"
581 acctKeyC, err := AccountKeyC.MarshalJSON()
582 test.AssertNotError(t, err, "failed to marshal account key")
583 input := &corepb.Registration{
584 Id: 23,
585 Key: acctKeyC,
586 Contact: []string{mailto},
587 ContactsPresent: true,
588 Agreement: "I agreed",
589 InitialIP: parseAndMarshalIP(t, "5.0.5.0"),
590 }
591
592 result, err := ra.NewRegistration(ctx, input)
593 test.AssertNotError(t, err, "Could not create new registration")
594 test.Assert(t, result.Id != 23, "ID shouldn't be set by user")
595
596
597 }
598
599 func TestNewRegistrationBadKey(t *testing.T) {
600 _, _, ra, _, cleanUp := initAuthorities(t)
601 defer cleanUp()
602 mailto := "mailto:foo@letsencrypt.org"
603 shortKey, err := ShortKey.MarshalJSON()
604 test.AssertNotError(t, err, "failed to marshal account key")
605 input := &corepb.Registration{
606 Contact: []string{mailto},
607 ContactsPresent: true,
608 Key: shortKey,
609 }
610 _, err = ra.NewRegistration(ctx, input)
611 test.AssertError(t, err, "Should have rejected authorization with short key")
612 }
613
614
615 func testKey() *rsa.PublicKey {
616 key, _ := rsa.GenerateKey(rand.Reader, 2048)
617 return &key.PublicKey
618 }
619
620 func TestNewRegistrationRateLimit(t *testing.T) {
621 _, _, ra, _, cleanUp := initAuthorities(t)
622 defer cleanUp()
623
624
625
626 ra.rlPolicies = &dummyRateLimitConfig{
627 RegistrationsPerIPPolicy: ratelimit.RateLimitPolicy{
628 Threshold: 1,
629 Window: config.Duration{Duration: 24 * 90 * time.Hour},
630 },
631 RegistrationsPerIPRangePolicy: ratelimit.RateLimitPolicy{
632 Threshold: 2,
633 Window: config.Duration{Duration: 24 * 90 * time.Hour},
634 },
635 }
636
637
638 mailto := "mailto:foo@letsencrypt.org"
639 reg := &corepb.Registration{
640 Contact: []string{mailto},
641 ContactsPresent: true,
642 Key: newAcctKey(t),
643 InitialIP: parseAndMarshalIP(t, "7.6.6.5"),
644 }
645
646 _, err := ra.NewRegistration(ctx, reg)
647 test.AssertNotError(t, err, "Unexpected error adding new IPv4 registration")
648 test.AssertMetricWithLabelsEquals(t, ra.rlCheckLatency, prometheus.Labels{"limit": ratelimit.RegistrationsPerIP, "decision": ratelimits.Allowed}, 1)
649
650
651 test.AssertMetricWithLabelsEquals(t, ra.rlOverrideUsageGauge, prometheus.Labels{"limit": ratelimit.RegistrationsPerIP, "override_key": "7.6.6.5"}, 0)
652
653
654 reg.Key = newAcctKey(t)
655
656
657
658 _, err = ra.NewRegistration(ctx, reg)
659 test.AssertError(t, err, "No error adding duplicate IPv4 registration")
660 test.AssertEquals(t, err.Error(), "too many registrations for this IP: see https://letsencrypt.org/docs/too-many-registrations-for-this-ip/")
661 test.AssertMetricWithLabelsEquals(t, ra.rlCheckLatency, prometheus.Labels{"limit": ratelimit.RegistrationsPerIP, "decision": ratelimits.Denied}, 1)
662
663
664 reg.Key = newAcctKey(t)
665 reg.InitialIP = parseAndMarshalIP(t, "2001:cdba:1234:5678:9101:1121:3257:9652")
666
667
668 _, err = ra.NewRegistration(ctx, reg)
669 test.AssertNotError(t, err, "Unexpected error adding a new IPv6 registration")
670 test.AssertMetricWithLabelsEquals(t, ra.rlCheckLatency, prometheus.Labels{"limit": ratelimit.RegistrationsPerIP, "decision": ratelimits.Allowed}, 2)
671
672
673 reg.Key = newAcctKey(t)
674
675
676
677 _, err = ra.NewRegistration(ctx, reg)
678 test.AssertError(t, err, "No error adding duplicate IPv6 registration")
679 test.AssertEquals(t, err.Error(), "too many registrations for this IP: see https://letsencrypt.org/docs/too-many-registrations-for-this-ip/")
680 test.AssertMetricWithLabelsEquals(t, ra.rlCheckLatency, prometheus.Labels{"limit": ratelimit.RegistrationsPerIP, "decision": ratelimits.Denied}, 2)
681
682
683 reg.Key = newAcctKey(t)
684 reg.InitialIP = parseAndMarshalIP(t, "2001:cdba:1234:5678:9101:1121:3257:9653")
685
686
687
688 _, err = ra.NewRegistration(ctx, reg)
689 test.AssertNotError(t, err, "Unexpected error adding second IPv6 registration in the same /48")
690 test.AssertMetricWithLabelsEquals(t, ra.rlCheckLatency, prometheus.Labels{"limit": ratelimit.RegistrationsPerIPRange, "decision": ratelimits.Allowed}, 2)
691
692
693 reg.Key = newAcctKey(t)
694 reg.InitialIP = parseAndMarshalIP(t, "2001:cdba:1234:5678:9101:1121:3257:9654")
695
696
697
698 _, err = ra.NewRegistration(ctx, reg)
699 test.AssertError(t, err, "No error adding a third IPv6 registration in the same /48")
700 test.AssertEquals(t, err.Error(), "too many registrations for this IP range: see https://letsencrypt.org/docs/rate-limits/")
701 test.AssertMetricWithLabelsEquals(t, ra.rlCheckLatency, prometheus.Labels{"limit": ratelimit.RegistrationsPerIPRange, "decision": ratelimits.Denied}, 1)
702 }
703
704 func TestRegistrationsPerIPOverrideUsage(t *testing.T) {
705 _, _, ra, _, cleanUp := initAuthorities(t)
706 defer cleanUp()
707
708 regIP := net.ParseIP("4.5.6.7")
709 rlp := ratelimit.RateLimitPolicy{
710 Threshold: 2,
711 Window: config.Duration{Duration: 23 * time.Hour},
712 Overrides: map[string]int64{
713 regIP.String(): 3,
714 },
715 }
716
717 mockCounterAlwaysTwo := func(context.Context, *sapb.CountRegistrationsByIPRequest, ...grpc.CallOption) (*sapb.Count, error) {
718 return &sapb.Count{Count: 2}, nil
719 }
720
721
722
723 err := ra.checkRegistrationIPLimit(ctx, rlp, regIP, mockCounterAlwaysTwo)
724 test.AssertNotError(t, err, "Unexpected error checking RegistrationsPerIPRange limit")
725
726
727 test.AssertMetricWithLabelsEquals(t, ra.rlOverrideUsageGauge, prometheus.Labels{"limit": ratelimit.RegistrationsPerIP, "override_key": regIP.String()}, 0.6666666666666666)
728
729 mockCounterAlwaysThree := func(context.Context, *sapb.CountRegistrationsByIPRequest, ...grpc.CallOption) (*sapb.Count, error) {
730 return &sapb.Count{Count: 3}, nil
731 }
732
733
734
735 err = ra.checkRegistrationIPLimit(ctx, rlp, regIP, mockCounterAlwaysThree)
736 test.AssertError(t, err, "Expected error checking RegistrationsPerIPRange limit")
737
738
739 test.AssertMetricWithLabelsEquals(t, ra.rlOverrideUsageGauge, prometheus.Labels{"limit": ratelimit.RegistrationsPerIP, "override_key": regIP.String()}, 1)
740 }
741
742 type NoUpdateSA struct {
743 mocks.StorageAuthority
744 }
745
746 func (sa NoUpdateSA) UpdateRegistration(_ context.Context, _ *corepb.Registration, _ ...grpc.CallOption) (*emptypb.Empty, error) {
747 return nil, fmt.Errorf("UpdateRegistration() is mocked to always error")
748 }
749
750 func TestUpdateRegistrationSame(t *testing.T) {
751 _, _, ra, _, cleanUp := initAuthorities(t)
752 defer cleanUp()
753 mailto := "mailto:foo@letsencrypt.org"
754
755
756 acctKeyC, err := AccountKeyC.MarshalJSON()
757 test.AssertNotError(t, err, "failed to marshal account key")
758 reg := &corepb.Registration{
759 Key: acctKeyC,
760 Contact: []string{mailto},
761 ContactsPresent: true,
762 Agreement: "I agreed",
763 InitialIP: parseAndMarshalIP(t, "5.0.5.0"),
764 }
765 result, err := ra.NewRegistration(ctx, reg)
766 test.AssertNotError(t, err, "Could not create new registration")
767
768
769 ra.SA = &NoUpdateSA{}
770
771
772 updateSame := &corepb.Registration{
773 Id: result.Id,
774 Key: acctKeyC,
775 Contact: []string{mailto},
776 ContactsPresent: true,
777 Agreement: "I agreed",
778 }
779
780
781
782
783 _, err = ra.UpdateRegistration(ctx, &rapb.UpdateRegistrationRequest{Base: result, Update: updateSame})
784 test.AssertNotError(t, err, "Error updating registration")
785 }
786
787 func TestPerformValidationExpired(t *testing.T) {
788 _, sa, ra, fc, cleanUp := initAuthorities(t)
789 defer cleanUp()
790
791 authz := createPendingAuthorization(t, sa, Identifier, fc.Now().Add(-2*time.Hour))
792
793 _, err := ra.PerformValidation(ctx, &rapb.PerformValidationRequest{
794 Authz: authz,
795 ChallengeIndex: int64(ResponseIndex),
796 })
797 test.AssertError(t, err, "Updated expired authorization")
798 }
799
800 func TestPerformValidationAlreadyValid(t *testing.T) {
801 va, _, ra, _, cleanUp := initAuthorities(t)
802 defer cleanUp()
803
804
805 exp := ra.clk.Now().Add(365 * 24 * time.Hour)
806 authz := core.Authorization{
807 ID: "1337",
808 Identifier: identifier.DNSIdentifier("not-example.com"),
809 RegistrationID: 1,
810 Status: "valid",
811 Expires: &exp,
812 Challenges: []core.Challenge{
813 {
814 Token: core.NewToken(),
815 Type: core.ChallengeTypeHTTP01,
816 Status: core.StatusPending,
817 },
818 },
819 }
820 authzPB, err := bgrpc.AuthzToPB(authz)
821 test.AssertNotError(t, err, "bgrpc.AuthzToPB failed")
822
823 va.ResultReturn = &vapb.ValidationResult{
824 Records: []*corepb.ValidationRecord{
825 {
826 AddressUsed: []byte("192.168.0.1"),
827 Hostname: "example.com",
828 Port: "8080",
829 Url: "http://example.com/",
830 },
831 },
832 Problems: nil,
833 }
834
835
836
837 val, err := ra.PerformValidation(ctx, &rapb.PerformValidationRequest{
838 Authz: authzPB,
839 ChallengeIndex: int64(ResponseIndex),
840 })
841 test.Assert(t, core.AcmeStatus(val.Status) == core.StatusValid, "Validation should have been valid")
842 test.AssertNotError(t, err, "Error was not nil, but should have been nil")
843 }
844
845 func TestPerformValidationSuccess(t *testing.T) {
846 va, sa, ra, fc, cleanUp := initAuthorities(t)
847 defer cleanUp()
848
849
850 authzPB := createPendingAuthorization(t, sa, Identifier, fc.Now().Add(12*time.Hour))
851
852 va.ResultReturn = &vapb.ValidationResult{
853 Records: []*corepb.ValidationRecord{
854 {
855 AddressUsed: []byte("192.168.0.1"),
856 Hostname: "example.com",
857 Port: "8080",
858 Url: "http://example.com/",
859 },
860 },
861 Problems: nil,
862 }
863
864 now := fc.Now()
865 challIdx := dnsChallIdx(t, authzPB.Challenges)
866 authzPB, err := ra.PerformValidation(ctx, &rapb.PerformValidationRequest{
867 Authz: authzPB,
868 ChallengeIndex: challIdx,
869 })
870 test.AssertNotError(t, err, "PerformValidation failed")
871
872 var vaRequest *vapb.PerformValidationRequest
873 select {
874 case r := <-va.request:
875 vaRequest = r
876 case <-time.After(time.Second):
877 t.Fatal("Timed out waiting for DummyValidationAuthority.PerformValidation to complete")
878 }
879
880
881 test.AssertEquals(t, authzPB.Challenges[challIdx].Type, vaRequest.Challenge.Type)
882 test.AssertEquals(t, authzPB.Challenges[challIdx].Token, vaRequest.Challenge.Token)
883
884
885 time.Sleep(100 * time.Millisecond)
886
887 dbAuthzPB := getAuthorization(t, authzPB.Id, sa)
888 t.Log("dbAuthz:", dbAuthzPB)
889
890
891 challIdx = dnsChallIdx(t, dbAuthzPB.Challenges)
892 challenge, err := bgrpc.PBToChallenge(dbAuthzPB.Challenges[challIdx])
893 test.AssertNotError(t, err, "Failed to marshall corepb.Challenge to core.Challenge.")
894
895 test.AssertNotNil(t, vaRequest.Challenge, "Request passed to VA has no challenge")
896 test.Assert(t, challenge.Status == core.StatusValid, "challenge was not marked as valid")
897
898
899
900 test.AssertEquals(t, dbAuthzPB.ExpiresNS, now.Add(ra.authorizationLifetime).UnixNano())
901 test.AssertEquals(t, dbAuthzPB.Expires.AsTime(), now.Add(ra.authorizationLifetime))
902
903
904 expectedValidated := fc.Now()
905 test.Assert(t, *challenge.Validated == expectedValidated, "Validated timestamp incorrect or missing")
906 }
907
908 func TestPerformValidationVAError(t *testing.T) {
909 va, sa, ra, fc, cleanUp := initAuthorities(t)
910 defer cleanUp()
911
912 authzPB := createPendingAuthorization(t, sa, Identifier, fc.Now().Add(12*time.Hour))
913
914 va.ResultError = fmt.Errorf("Something went wrong")
915
916 challIdx := dnsChallIdx(t, authzPB.Challenges)
917 authzPB, err := ra.PerformValidation(ctx, &rapb.PerformValidationRequest{
918 Authz: authzPB,
919 ChallengeIndex: challIdx,
920 })
921
922 test.AssertNotError(t, err, "PerformValidation completely failed")
923
924 var vaRequest *vapb.PerformValidationRequest
925 select {
926 case r := <-va.request:
927 vaRequest = r
928 case <-time.After(time.Second):
929 t.Fatal("Timed out waiting for DummyValidationAuthority.PerformValidation to complete")
930 }
931
932
933 test.AssertEquals(t, authzPB.Challenges[challIdx].Type, vaRequest.Challenge.Type)
934 test.AssertEquals(t, authzPB.Challenges[challIdx].Token, vaRequest.Challenge.Token)
935
936
937 time.Sleep(100 * time.Millisecond)
938
939 dbAuthzPB := getAuthorization(t, authzPB.Id, sa)
940 t.Log("dbAuthz:", dbAuthzPB)
941
942
943 challIdx = dnsChallIdx(t, dbAuthzPB.Challenges)
944 challenge, err := bgrpc.PBToChallenge(dbAuthzPB.Challenges[challIdx])
945 test.AssertNotError(t, err, "Failed to marshall corepb.Challenge to core.Challenge.")
946 test.Assert(t, challenge.Status == core.StatusInvalid, "challenge was not marked as invalid")
947 test.AssertContains(t, challenge.Error.Error(), "Could not communicate with VA")
948 test.Assert(t, challenge.ValidationRecord == nil, "challenge had a ValidationRecord")
949
950
951 expectedValidated := fc.Now()
952 test.Assert(t, *challenge.Validated == expectedValidated, "Validated timestamp incorrect or missing")
953 }
954
955 func TestCertificateKeyNotEqualAccountKey(t *testing.T) {
956 _, sa, ra, _, cleanUp := initAuthorities(t)
957 defer cleanUp()
958
959 exp := ra.clk.Now().Add(365 * 24 * time.Hour)
960
961 authzID := createFinalizedAuthorization(t, sa, "www.example.com", exp, core.ChallengeTypeHTTP01, ra.clk.Now())
962
963 order, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{
964 NewOrder: &sapb.NewOrderRequest{
965 RegistrationID: Registration.Id,
966 ExpiresNS: exp.UnixNano(),
967 Expires: timestamppb.New(exp),
968 Names: []string{"www.example.com"},
969 V2Authorizations: []int64{authzID},
970 },
971 })
972 test.AssertNotError(t, err, "Could not add test order with finalized authz IDs, ready status")
973
974 csrBytes, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{
975
976 PublicKey: AccountKeyA.Key,
977 SignatureAlgorithm: x509.SHA256WithRSA,
978 DNSNames: []string{"www.example.com"},
979 }, AccountPrivateKey.Key)
980 test.AssertNotError(t, err, "Failed to sign CSR")
981
982 _, err = ra.FinalizeOrder(ctx, &rapb.FinalizeOrderRequest{
983 Order: &corepb.Order{
984 Status: string(core.StatusReady),
985 Names: []string{"www.example.com"},
986 Id: order.Id,
987 RegistrationID: Registration.Id,
988 },
989 Csr: csrBytes,
990 })
991 test.AssertError(t, err, "Should have rejected cert with key = account key")
992 test.AssertEquals(t, err.Error(), "certificate public key must be different than account key")
993 }
994
995 func TestNewOrderRateLimiting(t *testing.T) {
996 _, _, ra, fc, cleanUp := initAuthorities(t)
997 defer cleanUp()
998 ra.orderLifetime = 5 * 24 * time.Hour
999
1000 rateLimitDuration := 5 * time.Minute
1001
1002
1003
1004 ra.rlPolicies = &dummyRateLimitConfig{
1005 NewOrdersPerAccountPolicy: ratelimit.RateLimitPolicy{
1006 Threshold: 1,
1007 Window: config.Duration{Duration: rateLimitDuration},
1008 },
1009 }
1010
1011 orderOne := &rapb.NewOrderRequest{
1012 RegistrationID: Registration.Id,
1013 Names: []string{"first.example.com"},
1014 }
1015 orderTwo := &rapb.NewOrderRequest{
1016 RegistrationID: Registration.Id,
1017 Names: []string{"second.example.com"},
1018 }
1019
1020
1021 _, err := ra.NewOrder(ctx, orderOne)
1022 test.AssertNotError(t, err, "NewOrder for orderOne failed")
1023
1024
1025 fc.Add(time.Second)
1026
1027
1028
1029 _, err = ra.NewOrder(ctx, orderTwo)
1030 test.AssertError(t, err, "NewOrder for orderTwo succeeded, should have been ratelimited")
1031
1032
1033
1034 _, err = ra.NewOrder(ctx, orderOne)
1035 test.AssertNotError(t, err, "Reuse of orderOne failed")
1036
1037
1038
1039 fc.Add(2 * rateLimitDuration)
1040 _, err = ra.NewOrder(ctx, orderTwo)
1041 test.AssertNotError(t, err, "NewOrder for orderTwo failed after advancing clock")
1042 }
1043
1044
1045
1046 func TestEarlyOrderRateLimiting(t *testing.T) {
1047 _, _, ra, _, cleanUp := initAuthorities(t)
1048 defer cleanUp()
1049 ra.orderLifetime = 5 * 24 * time.Hour
1050
1051 rateLimitDuration := 5 * time.Minute
1052
1053 domain := "early-ratelimit-example.com"
1054
1055
1056
1057 ra.rlPolicies = &dummyRateLimitConfig{
1058 CertificatesPerNamePolicy: ratelimit.RateLimitPolicy{
1059 Threshold: 10,
1060 Window: config.Duration{Duration: rateLimitDuration},
1061
1062
1063 Overrides: map[string]int64{
1064 domain: 0,
1065 },
1066 },
1067 NewOrdersPerAccountPolicy: ratelimit.RateLimitPolicy{
1068 Threshold: 10,
1069 Window: config.Duration{Duration: rateLimitDuration},
1070 },
1071 }
1072
1073
1074 newOrder := &rapb.NewOrderRequest{
1075 RegistrationID: Registration.Id,
1076 Names: []string{domain},
1077 }
1078
1079
1080
1081 _, err := ra.NewOrder(ctx, newOrder)
1082 test.AssertError(t, err, "NewOrder did not apply cert rate limits with feature flag enabled")
1083
1084 var bErr *berrors.BoulderError
1085 test.Assert(t, errors.As(err, &bErr), "NewOrder did not return a boulder error")
1086 test.AssertEquals(t, bErr.RetryAfter, rateLimitDuration)
1087
1088
1089 expected := "too many certificates already issued for \"early-ratelimit-example.com\". Retry after 2015-03-04T05:05:00Z: see https://letsencrypt.org/docs/rate-limits/"
1090 test.AssertEquals(t, bErr.Error(), expected)
1091 }
1092
1093 func TestAuthzFailedRateLimitingNewOrder(t *testing.T) {
1094 _, _, ra, _, cleanUp := initAuthorities(t)
1095 defer cleanUp()
1096
1097 ra.rlPolicies = &dummyRateLimitConfig{
1098 InvalidAuthorizationsPerAccountPolicy: ratelimit.RateLimitPolicy{
1099 Threshold: 1,
1100 Window: config.Duration{Duration: 1 * time.Hour},
1101 },
1102 }
1103
1104 testcase := func() {
1105 limit := ra.rlPolicies.InvalidAuthorizationsPerAccount()
1106 ra.SA = &mockInvalidAuthorizationsAuthority{domainWithFailures: "all.i.do.is.lose.com"}
1107 err := ra.checkInvalidAuthorizationLimits(ctx, Registration.Id,
1108 []string{"charlie.brown.com", "all.i.do.is.lose.com"}, limit)
1109 test.AssertError(t, err, "checkInvalidAuthorizationLimits did not encounter expected rate limit error")
1110 test.AssertEquals(t, err.Error(), "too many failed authorizations recently: see https://letsencrypt.org/docs/failed-validation-limit/")
1111 }
1112
1113 testcase()
1114 }
1115
1116 func TestDomainsForRateLimiting(t *testing.T) {
1117 domains := domainsForRateLimiting([]string{})
1118 test.AssertEquals(t, len(domains), 0)
1119
1120 domains = domainsForRateLimiting([]string{"www.example.com", "example.com"})
1121 test.AssertDeepEquals(t, domains, []string{"example.com"})
1122
1123 domains = domainsForRateLimiting([]string{"www.example.com", "example.com", "www.example.co.uk"})
1124 test.AssertDeepEquals(t, domains, []string{"example.co.uk", "example.com"})
1125
1126 domains = domainsForRateLimiting([]string{"www.example.com", "example.com", "www.example.co.uk", "co.uk"})
1127 test.AssertDeepEquals(t, domains, []string{"co.uk", "example.co.uk", "example.com"})
1128
1129 domains = domainsForRateLimiting([]string{"foo.bar.baz.www.example.com", "baz.example.com"})
1130 test.AssertDeepEquals(t, domains, []string{"example.com"})
1131
1132 domains = domainsForRateLimiting([]string{"github.io", "foo.github.io", "bar.github.io"})
1133 test.AssertDeepEquals(t, domains, []string{"bar.github.io", "foo.github.io", "github.io"})
1134 }
1135
1136 type mockSAWithNameCounts struct {
1137 mocks.StorageAuthority
1138 nameCounts *sapb.CountByNames
1139 t *testing.T
1140 clk clock.FakeClock
1141 }
1142
1143 func (m mockSAWithNameCounts) CountCertificatesByNames(ctx context.Context, req *sapb.CountCertificatesByNamesRequest, _ ...grpc.CallOption) (*sapb.CountByNames, error) {
1144 expectedLatest := m.clk.Now()
1145 if req.Range.LatestNS != expectedLatest.UnixNano() {
1146 m.t.Errorf("incorrect latestNS: got '%d', expected '%d'", req.Range.LatestNS, expectedLatest.UnixNano())
1147 }
1148 if req.Range.Latest.AsTime() != expectedLatest {
1149 m.t.Errorf("incorrect latest: got '%v', expected '%v'", req.Range.Latest.AsTime(), expectedLatest)
1150 }
1151 expectedEarliest := m.clk.Now().Add(-23 * time.Hour)
1152 if req.Range.EarliestNS != expectedEarliest.UnixNano() {
1153 m.t.Errorf("incorrect earliestNS: got '%d', expected '%d'", req.Range.EarliestNS, expectedEarliest.UnixNano())
1154 }
1155 if req.Range.Earliest.AsTime() != expectedEarliest {
1156 m.t.Errorf("incorrect earliest: got '%v', expected '%v'", req.Range.Earliest.AsTime(), expectedEarliest)
1157 }
1158 counts := make(map[string]int64)
1159 for _, name := range req.Names {
1160 if count, ok := m.nameCounts.Counts[name]; ok {
1161 counts[name] = count
1162 }
1163 }
1164 return &sapb.CountByNames{Counts: counts}, nil
1165 }
1166
1167 func TestCheckCertificatesPerNameLimit(t *testing.T) {
1168 _, _, ra, fc, cleanUp := initAuthorities(t)
1169 defer cleanUp()
1170
1171 rlp := ratelimit.RateLimitPolicy{
1172 Threshold: 3,
1173 Window: config.Duration{Duration: 23 * time.Hour},
1174 Overrides: map[string]int64{
1175 "bigissuer.com": 100,
1176 "smallissuer.co.uk": 1,
1177 },
1178 }
1179
1180 mockSA := &mockSAWithNameCounts{
1181 nameCounts: &sapb.CountByNames{Counts: map[string]int64{"example.com": 1}},
1182 clk: fc,
1183 t: t,
1184 }
1185
1186 ra.SA = mockSA
1187
1188
1189 err := ra.checkCertificatesPerNameLimit(ctx, []string{"www.example.com", "example.com"}, rlp, 99)
1190 test.AssertNotError(t, err, "rate limited example.com incorrectly")
1191
1192
1193 mockSA.nameCounts.Counts["example.com"] = 10
1194 mockSA.nameCounts.Counts["good-example.com"] = 1
1195 err = ra.checkCertificatesPerNameLimit(ctx, []string{"www.example.com", "example.com", "good-example.com"}, rlp, 99)
1196 test.AssertError(t, err, "incorrectly failed to rate limit example.com")
1197 test.AssertErrorIs(t, err, berrors.RateLimit)
1198
1199
1200 test.AssertMetricWithLabelsEquals(t, ra.rlOverrideUsageGauge, prometheus.Labels{"limit": ratelimit.CertificatesPerName, "override_key": "example.com"}, 0)
1201
1202 test.AssertEquals(t, err.Error(), "too many certificates already issued for \"example.com\". Retry after 1970-01-01T23:00:00Z: see https://letsencrypt.org/docs/rate-limits/")
1203 var bErr *berrors.BoulderError
1204 test.AssertErrorWraps(t, err, &bErr)
1205 test.AssertEquals(t, len(bErr.SubErrors), 0)
1206
1207
1208 mockSA.nameCounts.Counts["example.com"] = 10
1209 mockSA.nameCounts.Counts["other-example.com"] = 10
1210 mockSA.nameCounts.Counts["good-example.com"] = 1
1211 err = ra.checkCertificatesPerNameLimit(ctx, []string{"example.com", "other-example.com", "good-example.com"}, rlp, 99)
1212 test.AssertError(t, err, "incorrectly failed to rate limit example.com, other-example.com")
1213 test.AssertErrorIs(t, err, berrors.RateLimit)
1214
1215 test.AssertEquals(t, err.Error(), "too many certificates already issued for multiple names (\"example.com\" and 2 others). Retry after 1970-01-01T23:00:00Z: see https://letsencrypt.org/docs/rate-limits/")
1216 test.AssertErrorWraps(t, err, &bErr)
1217 test.AssertEquals(t, len(bErr.SubErrors), 2)
1218
1219
1220 err = ra.checkCertificatesPerNameLimit(ctx, []string{"zombo.com", "www.example.com", "example.com"}, rlp, 99)
1221 test.AssertError(t, err, "incorrectly failed to error on misbehaving SA")
1222
1223
1224 mockSA.nameCounts.Counts["example.com"] = 0
1225 mockSA.nameCounts.Counts["bigissuer.com"] = 50
1226 err = ra.checkCertificatesPerNameLimit(ctx, []string{"www.example.com", "subdomain.bigissuer.com"}, rlp, 99)
1227 test.AssertNotError(t, err, "incorrectly rate limited bigissuer")
1228
1229
1230
1231 test.AssertMetricWithLabelsEquals(t, ra.rlOverrideUsageGauge, prometheus.Labels{"limit": ratelimit.CertificatesPerName, "override_key": "bigissuer.com"}, .5)
1232
1233
1234 mockSA.nameCounts.Counts["example.com"] = 10
1235 mockSA.nameCounts.Counts["bigissuer.com"] = 100
1236 err = ra.checkCertificatesPerNameLimit(ctx, []string{"www.example.com", "subdomain.bigissuer.com"}, rlp, 99)
1237 test.AssertError(t, err, "incorrectly failed to rate limit bigissuer")
1238 test.AssertErrorIs(t, err, berrors.RateLimit)
1239
1240
1241 test.AssertMetricWithLabelsEquals(t, ra.rlOverrideUsageGauge, prometheus.Labels{"limit": ratelimit.CertificatesPerName, "override_key": "bigissuer.com"}, 1)
1242
1243
1244 mockSA.nameCounts.Counts["smallissuer.co.uk"] = 1
1245 err = ra.checkCertificatesPerNameLimit(ctx, []string{"www.smallissuer.co.uk"}, rlp, 99)
1246 test.AssertError(t, err, "incorrectly failed to rate limit smallissuer")
1247 test.AssertErrorIs(t, err, berrors.RateLimit)
1248
1249
1250 test.AssertMetricWithLabelsEquals(t, ra.rlOverrideUsageGauge, prometheus.Labels{"limit": ratelimit.CertificatesPerName, "override_key": "smallissuer.co.uk"}, 1)
1251 }
1252
1253
1254
1255 func TestCheckExactCertificateLimit(t *testing.T) {
1256 _, _, ra, _, cleanUp := initAuthorities(t)
1257 defer cleanUp()
1258
1259
1260 const dupeCertLimit = 3
1261 rlp := ratelimit.RateLimitPolicy{
1262 Threshold: dupeCertLimit,
1263 Window: config.Duration{Duration: 24 * time.Hour},
1264 }
1265
1266
1267
1268 firstIssuanceTimestamp := ra.clk.Now().Add(-rlp.Window.Duration)
1269 fITS2 := firstIssuanceTimestamp.Add(time.Hour * 23)
1270 fITS3 := firstIssuanceTimestamp.Add(time.Hour * 16)
1271 fITS4 := firstIssuanceTimestamp.Add(time.Hour * 8)
1272 issuanceTimestampsNS := []int64{
1273 fITS2.UnixNano(),
1274 fITS3.UnixNano(),
1275 fITS4.UnixNano(),
1276 firstIssuanceTimestamp.UnixNano(),
1277 }
1278 issuanceTimestamps := []*timestamppb.Timestamp{
1279 timestamppb.New(fITS2),
1280 timestamppb.New(fITS3),
1281 timestamppb.New(fITS4),
1282 timestamppb.New(firstIssuanceTimestamp),
1283 }
1284
1285
1286
1287 expectRetryAfterNS := time.Unix(0, issuanceTimestampsNS[0]).Add(time.Hour * 8).Format(time.RFC3339)
1288 expectRetryAfter := issuanceTimestamps[0].AsTime().Add(time.Hour * 8).Format(time.RFC3339)
1289 test.AssertEquals(t, expectRetryAfterNS, expectRetryAfter)
1290 ra.SA = &mockSAWithFQDNSet{
1291 issuanceTimestamps: map[string]*sapb.Timestamps{
1292 "none.example.com": {TimestampsNS: []int64{}, Timestamps: []*timestamppb.Timestamp{}},
1293 "under.example.com": {TimestampsNS: issuanceTimestampsNS[3:3], Timestamps: issuanceTimestamps[3:3]},
1294 "equalbutvalid.example.com": {TimestampsNS: issuanceTimestampsNS[1:3], Timestamps: issuanceTimestamps[1:3]},
1295 "over.example.com": {TimestampsNS: issuanceTimestampsNS[0:3], Timestamps: issuanceTimestamps[0:3]},
1296 },
1297 t: t,
1298 }
1299
1300 testCases := []struct {
1301 Name string
1302 Domain string
1303 ExpectedErr error
1304 }{
1305 {
1306 Name: "FQDN set issuances none",
1307 Domain: "none.example.com",
1308 ExpectedErr: nil,
1309 },
1310 {
1311 Name: "FQDN set issuances less than limit",
1312 Domain: "under.example.com",
1313 ExpectedErr: nil,
1314 },
1315 {
1316 Name: "FQDN set issuances equal to limit",
1317 Domain: "equalbutvalid.example.com",
1318 ExpectedErr: nil,
1319 },
1320 {
1321 Name: "FQDN set issuances above limit NS",
1322 Domain: "over.example.com",
1323 ExpectedErr: fmt.Errorf(
1324 "too many certificates (3) already issued for this exact set of domains in the last 24 hours: over.example.com, retry after %s: see https://letsencrypt.org/docs/duplicate-certificate-limit/",
1325 expectRetryAfterNS,
1326 ),
1327 },
1328 {
1329 Name: "FQDN set issuances above limit",
1330 Domain: "over.example.com",
1331 ExpectedErr: fmt.Errorf(
1332 "too many certificates (3) already issued for this exact set of domains in the last 24 hours: over.example.com, retry after %s: see https://letsencrypt.org/docs/duplicate-certificate-limit/",
1333 expectRetryAfter,
1334 ),
1335 },
1336 }
1337
1338
1339
1340 for _, tc := range testCases {
1341 t.Run(tc.Name, func(t *testing.T) {
1342 result := ra.checkCertificatesPerFQDNSetLimit(ctx, []string{tc.Domain}, rlp, 0)
1343 if tc.ExpectedErr == nil {
1344 test.AssertNotError(t, result, fmt.Sprintf("Expected no error for %q", tc.Domain))
1345 } else {
1346 test.AssertError(t, result, fmt.Sprintf("Expected error for %q", tc.Domain))
1347 test.AssertEquals(t, result.Error(), tc.ExpectedErr.Error())
1348 }
1349 })
1350 }
1351 }
1352
1353 func TestRegistrationUpdate(t *testing.T) {
1354 oldURL := "http://old.invalid"
1355 newURL := "http://new.invalid"
1356 base := &corepb.Registration{
1357 Id: 1,
1358 Contact: []string{oldURL},
1359 Agreement: "",
1360 }
1361 update := &corepb.Registration{
1362 Contact: []string{newURL},
1363 ContactsPresent: true,
1364 Agreement: "totally!",
1365 }
1366
1367 res, changed := mergeUpdate(base, update)
1368 test.AssertEquals(t, changed, true)
1369 test.AssertEquals(t, res.Contact[0], update.Contact[0])
1370 test.AssertEquals(t, res.Agreement, update.Agreement)
1371
1372
1373
1374 emptyUpdate := &corepb.Registration{
1375 Contact: []string{""},
1376 ContactsPresent: true,
1377 Agreement: "totally!",
1378 }
1379 _, changed = mergeUpdate(res, emptyUpdate)
1380 test.AssertEquals(t, changed, true)
1381 }
1382
1383 func TestRegistrationContactUpdate(t *testing.T) {
1384 contactURL := "mailto://example@example.com"
1385
1386
1387
1388 base := &corepb.Registration{
1389 Id: 1,
1390 Contact: []string{contactURL},
1391 Agreement: "totally!",
1392 }
1393 update := &corepb.Registration{
1394 Id: 1,
1395 Contact: []string{},
1396 ContactsPresent: true,
1397 Agreement: "totally!",
1398 }
1399 res, changed := mergeUpdate(base, update)
1400 test.AssertEquals(t, changed, true)
1401 test.Assert(t, len(res.Contact) == 0, "Contact was not deleted in update")
1402
1403
1404
1405 base = &corepb.Registration{
1406 Id: 1,
1407 Contact: []string{contactURL},
1408 Agreement: "totally!",
1409 }
1410 update = &corepb.Registration{
1411 Id: 1,
1412 Agreement: "totally!",
1413 }
1414 res, changed = mergeUpdate(base, update)
1415 test.AssertEquals(t, changed, false)
1416 test.Assert(t, len(res.Contact) == 1, "len(Contact) was updated unexpectedly")
1417 test.Assert(t, (res.Contact)[0] == contactURL, "Contact was changed unexpectedly")
1418 }
1419
1420 func TestRegistrationKeyUpdate(t *testing.T) {
1421 oldKey, err := rsa.GenerateKey(rand.Reader, 512)
1422 test.AssertNotError(t, err, "rsa.GenerateKey() for oldKey failed")
1423 oldKeyJSON, err := jose.JSONWebKey{Key: oldKey}.MarshalJSON()
1424 test.AssertNotError(t, err, "MarshalJSON for oldKey failed")
1425
1426 base := &corepb.Registration{Key: oldKeyJSON}
1427 update := &corepb.Registration{}
1428 _, changed := mergeUpdate(base, update)
1429 test.Assert(t, !changed, "mergeUpdate changed the key with empty update")
1430
1431 newKey, err := rsa.GenerateKey(rand.Reader, 1024)
1432 test.AssertNotError(t, err, "rsa.GenerateKey() for newKey failed")
1433 newKeyJSON, err := jose.JSONWebKey{Key: newKey}.MarshalJSON()
1434 test.AssertNotError(t, err, "MarshalJSON for newKey failed")
1435
1436 update = &corepb.Registration{Key: newKeyJSON}
1437 res, changed := mergeUpdate(base, update)
1438 test.Assert(t, changed, "mergeUpdate didn't change the key with non-empty update")
1439 test.AssertByteEquals(t, res.Key, update.Key)
1440 }
1441
1442
1443
1444
1445 type mockSAWithFQDNSet struct {
1446 mocks.StorageAuthority
1447 fqdnSet map[string]bool
1448 issuanceTimestamps map[string]*sapb.Timestamps
1449
1450 t *testing.T
1451 }
1452
1453
1454
1455
1456 func (m mockSAWithFQDNSet) hashNames(names []string) string {
1457 names = core.UniqueLowerNames(names)
1458 hash := sha256.Sum256([]byte(strings.Join(names, ",")))
1459 return string(hash[:])
1460 }
1461
1462
1463 func (m mockSAWithFQDNSet) addFQDNSet(names []string) {
1464 hash := m.hashNames(names)
1465 m.fqdnSet[hash] = true
1466 }
1467
1468
1469 func (m mockSAWithFQDNSet) FQDNSetExists(_ context.Context, req *sapb.FQDNSetExistsRequest, _ ...grpc.CallOption) (*sapb.Exists, error) {
1470 hash := m.hashNames(req.Domains)
1471 if _, exists := m.fqdnSet[hash]; exists {
1472 return &sapb.Exists{Exists: true}, nil
1473 }
1474 return &sapb.Exists{Exists: false}, nil
1475 }
1476
1477
1478 func (m mockSAWithFQDNSet) CountCertificatesByNames(ctx context.Context, req *sapb.CountCertificatesByNamesRequest, _ ...grpc.CallOption) (*sapb.CountByNames, error) {
1479 counts := make(map[string]int64)
1480 for _, name := range req.Names {
1481 entry, ok := m.issuanceTimestamps[name]
1482 if ok {
1483 counts[name] = int64(len(entry.TimestampsNS))
1484 }
1485 }
1486 return &sapb.CountByNames{Counts: counts}, nil
1487 }
1488
1489 func (m mockSAWithFQDNSet) CountFQDNSets(_ context.Context, req *sapb.CountFQDNSetsRequest, _ ...grpc.CallOption) (*sapb.Count, error) {
1490 var total int64
1491 for _, name := range req.Domains {
1492 entry, ok := m.issuanceTimestamps[name]
1493 if ok {
1494 total += int64(len(entry.TimestampsNS))
1495 }
1496 }
1497 return &sapb.Count{Count: total}, nil
1498 }
1499
1500 func (m mockSAWithFQDNSet) FQDNSetTimestampsForWindow(_ context.Context, req *sapb.CountFQDNSetsRequest, _ ...grpc.CallOption) (*sapb.Timestamps, error) {
1501 if len(req.Domains) == 1 {
1502 return m.issuanceTimestamps[req.Domains[0]], nil
1503 } else {
1504 return nil, fmt.Errorf("FQDNSetTimestampsForWindow mock only supports a single domain")
1505 }
1506 }
1507
1508
1509
1510
1511
1512
1513
1514
1515 func TestCheckFQDNSetRateLimitOverride(t *testing.T) {
1516 _, _, ra, _, cleanUp := initAuthorities(t)
1517 defer cleanUp()
1518
1519
1520 certsPerNamePolicy := ratelimit.RateLimitPolicy{
1521 Threshold: 1,
1522 Window: config.Duration{Duration: 24 * time.Hour},
1523 }
1524
1525
1526 now := ra.clk.Now()
1527 tsNS := now.UnixNano()
1528 ts := timestamppb.New(now)
1529 mockSA := &mockSAWithFQDNSet{
1530 issuanceTimestamps: map[string]*sapb.Timestamps{
1531 "example.com": {TimestampsNS: []int64{tsNS, tsNS}, Timestamps: []*timestamppb.Timestamp{ts, ts}},
1532 "zombo.com": {TimestampsNS: []int64{tsNS, tsNS}, Timestamps: []*timestamppb.Timestamp{ts, ts}},
1533 },
1534 fqdnSet: map[string]bool{},
1535 t: t,
1536 }
1537 ra.SA = mockSA
1538
1539
1540
1541
1542 err := ra.checkCertificatesPerNameLimit(ctx, []string{"www.example.com", "example.com", "www.zombo.com"}, certsPerNamePolicy, 99)
1543 test.AssertError(t, err, "certificate per name rate limit not applied correctly")
1544
1545
1546 mockSA.addFQDNSet([]string{"www.example.com", "example.com", "www.zombo.com"})
1547
1548
1549
1550
1551 err = ra.checkCertificatesPerNameLimit(ctx, []string{"www.example.com", "example.com", "www.zombo.com"}, certsPerNamePolicy, 99)
1552 test.AssertNotError(t, err, "FQDN set certificate per name exemption not applied correctly")
1553 }
1554
1555
1556
1557
1558 func TestExactPublicSuffixCertLimit(t *testing.T) {
1559 _, _, ra, fc, cleanUp := initAuthorities(t)
1560 defer cleanUp()
1561
1562
1563 certsPerNamePolicy := ratelimit.RateLimitPolicy{
1564 Threshold: 2,
1565 Window: config.Duration{Duration: 23 * time.Hour},
1566 }
1567
1568
1569
1570
1571 _, err := publicsuffix.Domain("dedyn.io")
1572 test.AssertError(t, err, "dedyn.io was not on the public suffix list, invaliding the test")
1573 _, err = publicsuffix.Domain("dynv6.net")
1574 test.AssertError(t, err, "dynv6.net was not on the public suffix list, invaliding the test")
1575
1576
1577
1578
1579
1580
1581 mockSA := &mockSAWithNameCounts{
1582 nameCounts: &sapb.CountByNames{
1583 Counts: map[string]int64{
1584 "test.dedyn.io": 1,
1585 "test2.dedyn.io": 1,
1586 "test3.dedyn.io": 0,
1587 "dedyn.io": 0,
1588 "dynv6.net": 2,
1589 },
1590 },
1591 clk: fc,
1592 t: t,
1593 }
1594 ra.SA = mockSA
1595
1596
1597
1598
1599 err = ra.checkCertificatesPerNameLimit(ctx, []string{"test3.dedyn.io", "dedyn.io"}, certsPerNamePolicy, 99)
1600 test.AssertNotError(t, err, "certificate per name rate limit not applied correctly")
1601
1602
1603
1604
1605 err = ra.checkCertificatesPerNameLimit(ctx, []string{"test3.dedyn.io", "dynv6.net"}, certsPerNamePolicy, 99)
1606 test.AssertError(t, err, "certificate per name rate limit not applied correctly")
1607 }
1608
1609 func TestDeactivateAuthorization(t *testing.T) {
1610 _, sa, ra, _, cleanUp := initAuthorities(t)
1611 defer cleanUp()
1612
1613 exp := ra.clk.Now().Add(365 * 24 * time.Hour)
1614 authzID := createFinalizedAuthorization(t, sa, "not-example.com", exp, core.ChallengeTypeHTTP01, ra.clk.Now())
1615 dbAuthzPB := getAuthorization(t, fmt.Sprint(authzID), sa)
1616 _, err := ra.DeactivateAuthorization(ctx, dbAuthzPB)
1617 test.AssertNotError(t, err, "Could not deactivate authorization")
1618 deact, err := sa.GetAuthorization2(ctx, &sapb.AuthorizationID2{Id: authzID})
1619 test.AssertNotError(t, err, "Could not get deactivated authorization with ID "+dbAuthzPB.Id)
1620 test.AssertEquals(t, deact.Status, string(core.StatusDeactivated))
1621 }
1622
1623 func TestDeactivateRegistration(t *testing.T) {
1624 _, _, ra, _, cleanUp := initAuthorities(t)
1625 defer cleanUp()
1626
1627
1628 _, err := ra.DeactivateRegistration(context.Background(), &corepb.Registration{})
1629 test.AssertDeepEquals(t, err, fmt.Errorf("incomplete gRPC request message"))
1630
1631
1632 _, err = ra.DeactivateRegistration(context.Background(),
1633 &corepb.Registration{Id: 1, Status: string(core.StatusDeactivated)})
1634 test.AssertError(t, err, "DeactivateRegistration failed with a non-valid registration")
1635
1636
1637 _, err = ra.DeactivateRegistration(context.Background(),
1638 &corepb.Registration{Id: 1, Status: string(core.StatusValid)})
1639 test.AssertNotError(t, err, "DeactivateRegistration failed")
1640
1641
1642 dbReg, err := ra.SA.GetRegistration(context.Background(), &sapb.RegistrationID{Id: 1})
1643 test.AssertNotError(t, err, "GetRegistration failed")
1644 test.AssertEquals(t, dbReg.Status, string(core.StatusDeactivated))
1645 }
1646
1647
1648 type noopCAA struct{}
1649
1650 func (cr noopCAA) IsCAAValid(
1651 ctx context.Context,
1652 in *vapb.IsCAAValidRequest,
1653 opts ...grpc.CallOption,
1654 ) (*vapb.IsCAAValidResponse, error) {
1655 return &vapb.IsCAAValidResponse{}, nil
1656 }
1657
1658
1659
1660 type caaRecorder struct {
1661 sync.Mutex
1662 names map[string]bool
1663 }
1664
1665 func (cr *caaRecorder) IsCAAValid(
1666 ctx context.Context,
1667 in *vapb.IsCAAValidRequest,
1668 opts ...grpc.CallOption,
1669 ) (*vapb.IsCAAValidResponse, error) {
1670 cr.Lock()
1671 defer cr.Unlock()
1672 cr.names[in.Domain] = true
1673 return &vapb.IsCAAValidResponse{}, nil
1674 }
1675
1676
1677
1678 func TestRecheckCAADates(t *testing.T) {
1679 _, _, ra, fc, cleanUp := initAuthorities(t)
1680 defer cleanUp()
1681 recorder := &caaRecorder{names: make(map[string]bool)}
1682 ra.caa = recorder
1683 ra.authorizationLifetime = 15 * time.Hour
1684
1685 recentValidated := fc.Now().Add(-1 * time.Hour)
1686 recentExpires := fc.Now().Add(15 * time.Hour)
1687 olderValidated := fc.Now().Add(-8 * time.Hour)
1688 olderExpires := fc.Now().Add(5 * time.Hour)
1689 makeIdentifier := func(name string) identifier.ACMEIdentifier {
1690 return identifier.ACMEIdentifier{
1691 Type: identifier.DNS,
1692 Value: name,
1693 }
1694 }
1695
1696 authzs := map[string]*core.Authorization{
1697 "recent.com": {
1698 Identifier: makeIdentifier("recent.com"),
1699 Expires: &recentExpires,
1700 Challenges: []core.Challenge{
1701 {
1702 Status: core.StatusValid,
1703 Type: core.ChallengeTypeHTTP01,
1704 Token: "exampleToken",
1705 Validated: &recentValidated,
1706 },
1707 },
1708 },
1709 "older.com": {
1710 Identifier: makeIdentifier("older.com"),
1711 Expires: &olderExpires,
1712 Challenges: []core.Challenge{
1713 {
1714 Status: core.StatusValid,
1715 Type: core.ChallengeTypeHTTP01,
1716 Token: "exampleToken",
1717 Validated: &olderValidated,
1718 },
1719 },
1720 },
1721 "older2.com": {
1722 Identifier: makeIdentifier("older2.com"),
1723 Expires: &olderExpires,
1724 Challenges: []core.Challenge{
1725 {
1726 Status: core.StatusValid,
1727 Type: core.ChallengeTypeHTTP01,
1728 Token: "exampleToken",
1729 Validated: &olderValidated,
1730 },
1731 },
1732 },
1733 "wildcard.com": {
1734 Identifier: makeIdentifier("wildcard.com"),
1735 Expires: &olderExpires,
1736 Challenges: []core.Challenge{
1737 {
1738 Status: core.StatusValid,
1739 Type: core.ChallengeTypeHTTP01,
1740 Token: "exampleToken",
1741 Validated: &olderValidated,
1742 },
1743 },
1744 },
1745 "*.wildcard.com": {
1746 Identifier: makeIdentifier("*.wildcard.com"),
1747 Expires: &olderExpires,
1748 Challenges: []core.Challenge{
1749 {
1750 Status: core.StatusValid,
1751 Type: core.ChallengeTypeHTTP01,
1752 Token: "exampleToken",
1753 Validated: &olderValidated,
1754 },
1755 },
1756 },
1757 "twochallenges.com": {
1758 ID: "twochal",
1759 Identifier: makeIdentifier("twochallenges.com"),
1760 Expires: &recentExpires,
1761 Challenges: []core.Challenge{
1762 {
1763 Status: core.StatusValid,
1764 Type: core.ChallengeTypeHTTP01,
1765 Token: "exampleToken",
1766 Validated: &olderValidated,
1767 },
1768 {
1769 Status: core.StatusValid,
1770 Type: core.ChallengeTypeDNS01,
1771 Token: "exampleToken",
1772 Validated: &olderValidated,
1773 },
1774 },
1775 },
1776 "nochallenges.com": {
1777 ID: "nochal",
1778 Identifier: makeIdentifier("nochallenges.com"),
1779 Expires: &recentExpires,
1780 Challenges: []core.Challenge{},
1781 },
1782 "novalidationtime.com": {
1783 ID: "noval",
1784 Identifier: makeIdentifier("novalidationtime.com"),
1785 Expires: &recentExpires,
1786 Challenges: []core.Challenge{
1787 {
1788 Status: core.StatusValid,
1789 Type: core.ChallengeTypeHTTP01,
1790 Token: "exampleToken",
1791 Validated: nil,
1792 },
1793 },
1794 },
1795 }
1796
1797
1798
1799 names := []string{"recent.com", "older.com", "older2.com", "wildcard.com", "*.wildcard.com"}
1800 err := ra.checkAuthorizationsCAA(context.Background(), Registration.Id, names, authzs, fc.Now())
1801
1802 if err != nil {
1803 t.Errorf("expected nil err, got %s", err)
1804 }
1805
1806
1807 err = ra.checkAuthorizationsCAA(context.Background(), Registration.Id, []string{"twochallenges.com"}, authzs, fc.Now())
1808 test.AssertEquals(t, err.Error(), "authorization has incorrect number of challenges. 1 expected, 2 found for: id twochal")
1809
1810
1811 err = ra.checkAuthorizationsCAA(context.Background(), Registration.Id, []string{"nochallenges.com"}, authzs, fc.Now())
1812 test.AssertEquals(t, err.Error(), "authorization has incorrect number of challenges. 1 expected, 0 found for: id nochal")
1813
1814
1815 err = ra.checkAuthorizationsCAA(context.Background(), Registration.Id, []string{"novalidationtime.com"}, authzs, fc.Now())
1816 test.AssertEquals(t, err.Error(), "authorization's challenge has no validated timestamp for: id noval")
1817
1818
1819
1820 test.AssertMetricWithLabelsEquals(t, ra.recheckCAAUsedAuthzLifetime, prometheus.Labels{}, 0)
1821
1822
1823
1824 if _, present := recorder.names["recent.com"]; present {
1825 t.Errorf("Rechecked CAA unnecessarily for recent.com")
1826 }
1827
1828
1829 if _, present := recorder.names["older.com"]; !present {
1830 t.Errorf("Failed to recheck CAA for older.com")
1831 }
1832
1833
1834 if _, present := recorder.names["older2.com"]; !present {
1835 t.Errorf("Failed to recheck CAA for older2.com")
1836 }
1837
1838
1839 if _, present := recorder.names["wildcard.com"]; !present {
1840 t.Errorf("Failed to recheck CAA for wildcard.com")
1841 }
1842
1843
1844
1845 if _, present := recorder.names["*.wildcard.com"]; !present {
1846 t.Errorf("Failed to recheck CAA for *.wildcard.com")
1847 }
1848 }
1849
1850 type caaFailer struct{}
1851
1852 func (cf *caaFailer) IsCAAValid(
1853 ctx context.Context,
1854 in *vapb.IsCAAValidRequest,
1855 opts ...grpc.CallOption,
1856 ) (*vapb.IsCAAValidResponse, error) {
1857 cvrpb := &vapb.IsCAAValidResponse{}
1858 switch in.Domain {
1859 case "a.com":
1860 cvrpb.Problem = &corepb.ProblemDetails{
1861 Detail: "CAA invalid for a.com",
1862 }
1863 case "c.com":
1864 cvrpb.Problem = &corepb.ProblemDetails{
1865 Detail: "CAA invalid for c.com",
1866 }
1867 case "d.com":
1868 return nil, fmt.Errorf("Error checking CAA for d.com")
1869 }
1870 return cvrpb, nil
1871 }
1872
1873 func TestRecheckCAAEmpty(t *testing.T) {
1874 _, _, ra, _, cleanUp := initAuthorities(t)
1875 defer cleanUp()
1876 err := ra.recheckCAA(context.Background(), nil)
1877 test.AssertNotError(t, err, "expected nil")
1878 }
1879
1880 func makeHTTP01Authorization(domain string) *core.Authorization {
1881 return &core.Authorization{
1882 Identifier: identifier.ACMEIdentifier{Type: identifier.DNS, Value: domain},
1883 Challenges: []core.Challenge{{Status: core.StatusValid, Type: core.ChallengeTypeHTTP01}},
1884 }
1885 }
1886
1887 func TestRecheckCAASuccess(t *testing.T) {
1888 _, _, ra, _, cleanUp := initAuthorities(t)
1889 defer cleanUp()
1890 authzs := []*core.Authorization{
1891 makeHTTP01Authorization("a.com"),
1892 makeHTTP01Authorization("b.com"),
1893 makeHTTP01Authorization("c.com"),
1894 }
1895 err := ra.recheckCAA(context.Background(), authzs)
1896 test.AssertNotError(t, err, "expected nil")
1897 }
1898
1899 func TestRecheckCAAFail(t *testing.T) {
1900 _, _, ra, _, cleanUp := initAuthorities(t)
1901 defer cleanUp()
1902 ra.caa = &caaFailer{}
1903 authzs := []*core.Authorization{
1904 makeHTTP01Authorization("a.com"),
1905 makeHTTP01Authorization("b.com"),
1906 makeHTTP01Authorization("c.com"),
1907 }
1908 err := ra.recheckCAA(context.Background(), authzs)
1909
1910 test.AssertError(t, err, "expected err, got nil")
1911 var berr *berrors.BoulderError
1912 test.AssertErrorWraps(t, err, &berr)
1913 test.AssertErrorIs(t, berr, berrors.CAA)
1914 test.AssertEquals(t, len(berr.SubErrors), 2)
1915
1916
1917
1918 expectedDetailRegex := regexp.MustCompile(
1919 `Rechecking CAA for "(?:a\.com|c\.com)" and 1 more identifiers failed. Refer to sub-problems for more information`,
1920 )
1921 if !expectedDetailRegex.MatchString(berr.Detail) {
1922 t.Errorf("expected suberror detail to match expected regex, got %q", err)
1923 }
1924
1925
1926 subErrMap := make(map[string]berrors.SubBoulderError, len(berr.SubErrors))
1927 for _, subErr := range berr.SubErrors {
1928 subErrMap[subErr.Identifier.Value] = subErr
1929 }
1930 subErrA, foundA := subErrMap["a.com"]
1931 subErrB, foundB := subErrMap["c.com"]
1932 test.AssertEquals(t, foundA, true)
1933 test.AssertEquals(t, foundB, true)
1934 test.AssertEquals(t, subErrA.Type, berrors.CAA)
1935 test.AssertEquals(t, subErrB.Type, berrors.CAA)
1936
1937
1938 authzs = []*core.Authorization{
1939 makeHTTP01Authorization("a.com"),
1940 }
1941 err = ra.recheckCAA(context.Background(), authzs)
1942
1943 test.AssertError(t, err, "expected err from recheckCAA")
1944
1945 test.AssertErrorWraps(t, err, &berr)
1946
1947 test.AssertEquals(t, len(berr.SubErrors), 0)
1948 }
1949
1950 func TestRecheckCAAInternalServerError(t *testing.T) {
1951 _, _, ra, _, cleanUp := initAuthorities(t)
1952 defer cleanUp()
1953 ra.caa = &caaFailer{}
1954 authzs := []*core.Authorization{
1955 makeHTTP01Authorization("a.com"),
1956 makeHTTP01Authorization("b.com"),
1957 makeHTTP01Authorization("d.com"),
1958 }
1959 err := ra.recheckCAA(context.Background(), authzs)
1960 test.AssertError(t, err, "expected err, got nil")
1961 test.AssertErrorIs(t, err, berrors.InternalServer)
1962 }
1963
1964 func TestNewOrder(t *testing.T) {
1965 _, _, ra, fc, cleanUp := initAuthorities(t)
1966 defer cleanUp()
1967 ra.orderLifetime = time.Hour
1968
1969 now := fc.Now()
1970 orderA, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{
1971 RegistrationID: Registration.Id,
1972 Names: []string{"b.com", "a.com", "a.com", "C.COM"},
1973 })
1974 test.AssertNotError(t, err, "ra.NewOrder failed")
1975 test.AssertEquals(t, orderA.RegistrationID, int64(1))
1976 test.AssertEquals(t, orderA.ExpiresNS, now.Add(time.Hour).UnixNano())
1977 test.AssertEquals(t, orderA.Expires.AsTime(), now.Add(time.Hour))
1978 test.AssertEquals(t, len(orderA.Names), 3)
1979
1980 test.AssertDeepEquals(t, orderA.Names, []string{"a.com", "b.com", "c.com"})
1981 test.AssertEquals(t, orderA.Id, int64(1))
1982 test.AssertEquals(t, numAuthorizations(orderA), 3)
1983
1984
1985 now = fc.Now()
1986 orderB, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{
1987 RegistrationID: Registration.Id,
1988 Names: []string{"b.com", "a.com", "C.COM"},
1989 })
1990 test.AssertNotError(t, err, "ra.NewOrder failed")
1991 test.AssertEquals(t, orderB.RegistrationID, int64(1))
1992 test.AssertEquals(t, orderB.ExpiresNS, now.Add(time.Hour).UnixNano())
1993 test.AssertEquals(t, orderB.Expires.AsTime(), now.Add(time.Hour))
1994
1995 test.AssertEquals(t, orderB.Id, orderA.Id)
1996 test.AssertEquals(t, len(orderB.Names), 3)
1997 test.AssertDeepEquals(t, orderB.Names, []string{"a.com", "b.com", "c.com"})
1998 test.AssertEquals(t, numAuthorizations(orderB), 3)
1999 test.AssertDeepEquals(t, orderB.V2Authorizations, orderA.V2Authorizations)
2000
2001
2002
2003 orderA.Names = append(orderA.Names, "d.com")
2004 now = fc.Now()
2005 orderC, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{
2006 RegistrationID: Registration.Id,
2007 Names: orderA.Names,
2008 })
2009 test.AssertNotError(t, err, "ra.NewOrder failed")
2010 test.AssertEquals(t, orderC.RegistrationID, int64(1))
2011 test.AssertEquals(t, orderC.ExpiresNS, now.Add(time.Hour).UnixNano())
2012 test.AssertEquals(t, orderC.Expires.AsTime(), now.Add(time.Hour))
2013 test.AssertEquals(t, len(orderC.Names), 4)
2014 test.AssertDeepEquals(t, orderC.Names, []string{"a.com", "b.com", "c.com", "d.com"})
2015
2016
2017 test.AssertNotEquals(t, orderC.Id, orderA.Id)
2018 test.AssertEquals(t, numAuthorizations(orderC), 4)
2019
2020 existing := orderC.V2Authorizations[:3]
2021 test.AssertDeepEquals(t, existing, orderA.V2Authorizations)
2022
2023 _, err = ra.NewOrder(context.Background(), &rapb.NewOrderRequest{
2024 RegistrationID: Registration.Id,
2025 Names: []string{"a"},
2026 })
2027 test.AssertError(t, err, "NewOrder with invalid names did not error")
2028 test.AssertEquals(t, err.Error(), "Cannot issue for \"a\": Domain name needs at least one dot")
2029 }
2030
2031
2032
2033
2034 func TestNewOrderReuse(t *testing.T) {
2035 _, _, ra, fc, cleanUp := initAuthorities(t)
2036 defer cleanUp()
2037
2038 ctx := context.Background()
2039 names := []string{"zombo.com", "welcome.to.zombo.com"}
2040
2041
2042 ra.orderLifetime = time.Hour
2043
2044 doubleLifetime := ra.orderLifetime * 2
2045
2046
2047 orderReq := &rapb.NewOrderRequest{
2048 RegistrationID: Registration.Id,
2049 Names: names,
2050 }
2051
2052
2053 acctKeyB, err := AccountKeyB.MarshalJSON()
2054 test.AssertNotError(t, err, "failed to marshal account key")
2055 input := &corepb.Registration{
2056 Key: acctKeyB,
2057 InitialIP: parseAndMarshalIP(t, "42.42.42.42"),
2058 }
2059 secondReg, err := ra.NewRegistration(ctx, input)
2060 test.AssertNotError(t, err, "Error creating a second test registration")
2061
2062 firstOrder, err := ra.NewOrder(context.Background(), orderReq)
2063
2064 test.AssertNotError(t, err, "Adding an initial order for regA failed")
2065
2066 test.AssertNotNil(t, firstOrder.Id, "Initial order had a nil ID")
2067
2068 testCases := []struct {
2069 Name string
2070 OrderReq *rapb.NewOrderRequest
2071 ExpectReuse bool
2072 AdvanceClock *time.Duration
2073 }{
2074 {
2075 Name: "Duplicate order, same regID",
2076 OrderReq: orderReq,
2077
2078 ExpectReuse: true,
2079 },
2080 {
2081 Name: "Subset of order names, same regID",
2082 OrderReq: &rapb.NewOrderRequest{
2083 RegistrationID: Registration.Id,
2084 Names: []string{names[1]},
2085 },
2086
2087 ExpectReuse: false,
2088 },
2089 {
2090 Name: "Duplicate order, different regID",
2091 OrderReq: &rapb.NewOrderRequest{
2092 RegistrationID: secondReg.Id,
2093 Names: names,
2094 },
2095
2096 ExpectReuse: false,
2097 },
2098 {
2099 Name: "Duplicate order, same regID, first expired",
2100 OrderReq: orderReq,
2101 AdvanceClock: &doubleLifetime,
2102
2103 ExpectReuse: true,
2104 },
2105 }
2106
2107 for _, tc := range testCases {
2108 t.Run(tc.Name, func(t *testing.T) {
2109
2110 if tc.AdvanceClock != nil {
2111 _ = fc.Now().Add(*tc.AdvanceClock)
2112 }
2113
2114 order, err := ra.NewOrder(ctx, tc.OrderReq)
2115
2116 test.AssertNotError(t, err, "NewOrder returned an unexpected error")
2117
2118 test.AssertNotNil(t, order.Id, "NewOrder returned an order with a nil Id")
2119
2120 if tc.ExpectReuse {
2121
2122
2123 test.AssertEquals(t, firstOrder.Id, order.Id)
2124 } else {
2125
2126
2127 test.AssertNotEquals(t, firstOrder.Id, order.Id)
2128 }
2129 })
2130 }
2131 }
2132
2133 func TestNewOrderReuseInvalidAuthz(t *testing.T) {
2134 _, _, ra, _, cleanUp := initAuthorities(t)
2135 defer cleanUp()
2136
2137 ctx := context.Background()
2138 names := []string{"zombo.com"}
2139
2140
2141 orderReq := &rapb.NewOrderRequest{
2142 RegistrationID: Registration.Id,
2143 Names: names,
2144 }
2145
2146
2147 order, err := ra.NewOrder(ctx, orderReq)
2148
2149 test.AssertNotError(t, err, "Adding an initial order for regA failed")
2150
2151 test.AssertNotNil(t, order.Id, "Initial order had a nil ID")
2152
2153 test.AssertEquals(t, numAuthorizations(order), 1)
2154
2155 now := ra.clk.Now()
2156 _, err = ra.SA.FinalizeAuthorization2(ctx, &sapb.FinalizeAuthorizationRequest{
2157 Id: order.V2Authorizations[0],
2158 Status: string(core.StatusInvalid),
2159 ExpiresNS: order.ExpiresNS,
2160 Expires: order.Expires,
2161 Attempted: string(core.ChallengeTypeDNS01),
2162 AttemptedAtNS: now.UnixNano(),
2163 AttemptedAt: timestamppb.New(now),
2164 })
2165 test.AssertNotError(t, err, "FinalizeAuthorization2 failed")
2166
2167
2168 updatedOrder, err := ra.SA.GetOrder(ctx, &sapb.OrderRequest{Id: order.Id})
2169 test.AssertNotError(t, err, "Error getting order to check status")
2170 test.AssertEquals(t, updatedOrder.Status, "invalid")
2171
2172
2173 secondOrder, err := ra.NewOrder(ctx, orderReq)
2174
2175 test.AssertNotError(t, err, "Adding an initial order for regA failed")
2176
2177 test.AssertNotEquals(t, secondOrder.Id, order.Id)
2178
2179 test.AssertEquals(t, secondOrder.Status, "pending")
2180 test.AssertEquals(t, numAuthorizations(secondOrder), 1)
2181
2182 test.AssertNotEquals(t, secondOrder.V2Authorizations[0], order.V2Authorizations[0])
2183 }
2184
2185
2186
2187 type mockSACountPendingFails struct {
2188 mocks.StorageAuthority
2189 }
2190
2191 func (mock *mockSACountPendingFails) CountPendingAuthorizations2(ctx context.Context, req *sapb.RegistrationID, _ ...grpc.CallOption) (*sapb.Count, error) {
2192 return nil, errors.New("counting is slow and boring")
2193 }
2194
2195
2196
2197 func TestPendingAuthorizationsUnlimited(t *testing.T) {
2198 _, _, ra, _, cleanUp := initAuthorities(t)
2199 defer cleanUp()
2200
2201 ra.rlPolicies = &dummyRateLimitConfig{
2202 PendingAuthorizationsPerAccountPolicy: ratelimit.RateLimitPolicy{
2203 Threshold: 1,
2204 Window: config.Duration{Duration: 24 * time.Hour},
2205 RegistrationOverrides: map[int64]int64{
2206 13: -1,
2207 },
2208 },
2209 }
2210
2211 ra.SA = &mockSACountPendingFails{}
2212
2213 limit := ra.rlPolicies.PendingAuthorizationsPerAccount()
2214 err := ra.checkPendingAuthorizationLimit(context.Background(), 13, limit)
2215 test.AssertNotError(t, err, "checking pending authorization limit")
2216 }
2217
2218
2219 func TestNewOrderCheckFailedAuthorizationsFirst(t *testing.T) {
2220 _, _, ra, _, cleanUp := initAuthorities(t)
2221 defer cleanUp()
2222
2223
2224 ctx := context.Background()
2225 order, err := ra.NewOrder(ctx, &rapb.NewOrderRequest{
2226 RegistrationID: Registration.Id,
2227 Names: []string{"example.com"},
2228 })
2229 test.AssertNotError(t, err, "adding an initial order for regA")
2230 test.AssertNotNil(t, order.Id, "initial order had a nil ID")
2231 test.AssertEquals(t, numAuthorizations(order), 1)
2232
2233
2234 ra.SA = &mockInvalidPlusValidAuthzAuthority{mockInvalidAuthorizationsAuthority{domainWithFailures: "example.com"}}
2235
2236
2237 ra.rlPolicies = &dummyRateLimitConfig{
2238 InvalidAuthorizationsPerAccountPolicy: ratelimit.RateLimitPolicy{
2239 Threshold: 1,
2240 Window: config.Duration{Duration: 24 * time.Hour},
2241 },
2242 }
2243
2244
2245
2246 _, err = ra.NewOrder(ctx, &rapb.NewOrderRequest{
2247 RegistrationID: Registration.Id,
2248 Names: []string{"example.com"},
2249 })
2250
2251 test.AssertError(t, err, "expected error for domain with too many failures")
2252 test.AssertEquals(t, err.Error(), "too many failed authorizations recently: see https://letsencrypt.org/docs/failed-validation-limit/")
2253 }
2254
2255
2256
2257 type mockSAUnsafeAuthzReuse struct {
2258 mocks.StorageAuthority
2259 }
2260
2261 func authzMapToPB(m map[string]*core.Authorization) (*sapb.Authorizations, error) {
2262 resp := &sapb.Authorizations{}
2263 for k, v := range m {
2264 authzPB, err := bgrpc.AuthzToPB(*v)
2265 if err != nil {
2266 return nil, err
2267 }
2268 resp.Authz = append(resp.Authz, &sapb.Authorizations_MapElement{Domain: k, Authz: authzPB})
2269 }
2270 return resp, nil
2271 }
2272
2273
2274
2275
2276
2277 func (msa *mockSAUnsafeAuthzReuse) GetAuthorizations2(ctx context.Context, req *sapb.GetAuthorizationsRequest, _ ...grpc.CallOption) (*sapb.Authorizations, error) {
2278 expires := time.Now()
2279 authzs := map[string]*core.Authorization{
2280 "*.zombo.com": {
2281
2282 ID: "1",
2283 Identifier: identifier.DNSIdentifier("*.zombo.com"),
2284 RegistrationID: req.RegistrationID,
2285
2286 Status: "valid",
2287 Expires: &expires,
2288 Challenges: []core.Challenge{
2289
2290 {
2291 Type: core.ChallengeTypeHTTP01,
2292 Status: core.StatusValid,
2293 },
2294
2295 {
2296 Type: core.ChallengeTypeDNS01,
2297 Status: core.StatusPending,
2298 },
2299 },
2300 },
2301 "zombo.com": {
2302
2303 ID: "2",
2304 Identifier: identifier.DNSIdentifier("zombo.com"),
2305 RegistrationID: req.RegistrationID,
2306
2307 Status: "valid",
2308 Expires: &expires,
2309 Challenges: []core.Challenge{
2310
2311 {
2312 Type: core.ChallengeTypeHTTP01,
2313 Status: core.StatusValid,
2314 },
2315
2316 {
2317 Type: core.ChallengeTypeDNS01,
2318 Status: core.StatusPending,
2319 },
2320 },
2321 },
2322 }
2323 return authzMapToPB(authzs)
2324
2325 }
2326
2327 func (msa *mockSAUnsafeAuthzReuse) NewOrderAndAuthzs(ctx context.Context, req *sapb.NewOrderAndAuthzsRequest, _ ...grpc.CallOption) (*corepb.Order, error) {
2328 for range req.NewAuthzs {
2329 req.NewOrder.V2Authorizations = append(req.NewOrder.V2Authorizations, mrand.Int63())
2330 }
2331 return msa.StorageAuthority.NewOrderAndAuthzs(ctx, req)
2332 }
2333
2334
2335
2336
2337
2338
2339
2340 func TestNewOrderAuthzReuseSafety(t *testing.T) {
2341 _, _, ra, _, cleanUp := initAuthorities(t)
2342 defer cleanUp()
2343
2344 ctx := context.Background()
2345 names := []string{"*.zombo.com"}
2346
2347
2348
2349 ra.SA = &mockSAUnsafeAuthzReuse{}
2350
2351
2352 orderReq := &rapb.NewOrderRequest{
2353 RegistrationID: Registration.Id,
2354 Names: names,
2355 }
2356
2357
2358 order, err := ra.NewOrder(ctx, orderReq)
2359
2360 test.AssertNotError(t, err, "Adding an initial order for regA failed")
2361 test.AssertEquals(t, numAuthorizations(order), 1)
2362
2363 test.AssertNotEquals(t, order.V2Authorizations[0], int64(1))
2364 }
2365
2366 func TestNewOrderWildcard(t *testing.T) {
2367 _, _, ra, _, cleanUp := initAuthorities(t)
2368 defer cleanUp()
2369 ra.orderLifetime = time.Hour
2370
2371 orderNames := []string{"example.com", "*.welcome.zombo.com"}
2372 wildcardOrderRequest := &rapb.NewOrderRequest{
2373 RegistrationID: Registration.Id,
2374 Names: orderNames,
2375 }
2376
2377 order, err := ra.NewOrder(context.Background(), wildcardOrderRequest)
2378 test.AssertNotError(t, err, "NewOrder failed for a wildcard order request")
2379
2380
2381 test.AssertEquals(t, order.Status, string(core.StatusPending))
2382
2383 test.AssertEquals(t, len(order.Names), 2)
2384
2385 test.AssertDeepEquals(t,
2386 core.UniqueLowerNames(order.Names),
2387 core.UniqueLowerNames(orderNames))
2388 test.AssertEquals(t, numAuthorizations(order), 2)
2389
2390
2391 for _, authzID := range order.V2Authorizations {
2392
2393 authzID := authzID
2394 authzPB, err := ra.SA.GetAuthorization2(ctx, &sapb.AuthorizationID2{Id: authzID})
2395 test.AssertNotError(t, err, "sa.GetAuthorization2 failed")
2396 authz, err := bgrpc.PBToAuthz(authzPB)
2397 test.AssertNotError(t, err, "bgrpc.PBToAuthz failed")
2398
2399
2400 test.AssertEquals(t, authz.Status, core.StatusPending)
2401
2402 name := authz.Identifier.Value
2403 switch name {
2404 case "*.welcome.zombo.com":
2405
2406
2407 test.AssertEquals(t, len(authz.Challenges), 1)
2408 test.AssertEquals(t, authz.Challenges[0].Status, core.StatusPending)
2409 test.AssertEquals(t, authz.Challenges[0].Type, core.ChallengeTypeDNS01)
2410 case "example.com":
2411
2412 test.AssertEquals(t, len(authz.Challenges), 2)
2413 default:
2414 t.Fatalf("Received an authorization for a name not requested: %q", name)
2415 }
2416 }
2417
2418
2419
2420
2421 orderNames = []string{"zombo.com", "*.zombo.com"}
2422 wildcardOrderRequest = &rapb.NewOrderRequest{
2423 RegistrationID: Registration.Id,
2424 Names: orderNames,
2425 }
2426 order, err = ra.NewOrder(context.Background(), wildcardOrderRequest)
2427 test.AssertNotError(t, err, "NewOrder failed for a wildcard order request")
2428
2429
2430 test.AssertEquals(t, order.Status, string(core.StatusPending))
2431
2432 test.AssertEquals(t, len(order.Names), 2)
2433
2434 test.AssertDeepEquals(t,
2435 core.UniqueLowerNames(order.Names),
2436 core.UniqueLowerNames(orderNames))
2437 test.AssertEquals(t, numAuthorizations(order), 2)
2438
2439 for _, authzID := range order.V2Authorizations {
2440
2441 authzID := authzID
2442 authzPB, err := ra.SA.GetAuthorization2(ctx, &sapb.AuthorizationID2{Id: authzID})
2443 test.AssertNotError(t, err, "sa.GetAuthorization2 failed")
2444 authz, err := bgrpc.PBToAuthz(authzPB)
2445 test.AssertNotError(t, err, "bgrpc.PBToAuthz failed")
2446
2447 test.AssertEquals(t, authz.Status, core.StatusPending)
2448 switch authz.Identifier.Value {
2449 case "zombo.com":
2450
2451
2452 test.AssertEquals(t, len(authz.Challenges), 2)
2453 case "*.zombo.com":
2454
2455
2456 test.AssertEquals(t, len(authz.Challenges), 1)
2457 test.AssertEquals(t, authz.Challenges[0].Status, core.StatusPending)
2458 test.AssertEquals(t, authz.Challenges[0].Type, core.ChallengeTypeDNS01)
2459 default:
2460 t.Fatal("Unexpected authorization value returned from new-order")
2461 }
2462 }
2463
2464
2465
2466 normalOrderReq := &rapb.NewOrderRequest{
2467 RegistrationID: Registration.Id,
2468 Names: []string{"everything.is.possible.zombo.com"},
2469 }
2470 normalOrder, err := ra.NewOrder(context.Background(), normalOrderReq)
2471 test.AssertNotError(t, err, "NewOrder failed for a normal non-wildcard order")
2472
2473 test.AssertEquals(t, numAuthorizations(normalOrder), 1)
2474
2475 test.AssertEquals(t, order.Status, string(core.StatusPending))
2476 var authz core.Authorization
2477 authzPB, err := ra.SA.GetAuthorization2(ctx, &sapb.AuthorizationID2{Id: normalOrder.V2Authorizations[0]})
2478 test.AssertNotError(t, err, "sa.GetAuthorization2 failed")
2479 authz, err = bgrpc.PBToAuthz(authzPB)
2480 test.AssertNotError(t, err, "bgrpc.PBToAuthz failed")
2481
2482 test.AssertEquals(t, authz.Status, core.StatusPending)
2483
2484 test.AssertEquals(t, authz.Identifier.Value, "everything.is.possible.zombo.com")
2485
2486 test.AssertEquals(t, len(authz.Challenges), 2)
2487
2488
2489
2490
2491 orderNames = []string{"*.everything.is.possible.zombo.com"}
2492 wildcardOrderRequest = &rapb.NewOrderRequest{
2493 RegistrationID: Registration.Id,
2494 Names: orderNames,
2495 }
2496 order, err = ra.NewOrder(context.Background(), wildcardOrderRequest)
2497 test.AssertNotError(t, err, "NewOrder failed for a wildcard order request")
2498
2499 test.AssertEquals(t, order.Status, string(core.StatusPending))
2500 test.AssertEquals(t, numAuthorizations(order), 1)
2501
2502 test.AssertNotEquals(t, order.V2Authorizations[0], normalOrder.V2Authorizations[0])
2503
2504 authzPB, err = ra.SA.GetAuthorization2(ctx, &sapb.AuthorizationID2{Id: order.V2Authorizations[0]})
2505 test.AssertNotError(t, err, "sa.GetAuthorization2 failed")
2506 authz, err = bgrpc.PBToAuthz(authzPB)
2507 test.AssertNotError(t, err, "bgrpc.PBToAuthz failed")
2508
2509 test.AssertEquals(t, authz.Status, core.StatusPending)
2510
2511 test.AssertEquals(t, authz.Identifier.Value, "*.everything.is.possible.zombo.com")
2512
2513 test.AssertEquals(t, len(authz.Challenges), 1)
2514
2515 test.AssertEquals(t, authz.Challenges[0].Status, core.StatusPending)
2516
2517 test.AssertEquals(t, authz.Challenges[0].Type, core.ChallengeTypeDNS01)
2518
2519
2520 dupeOrder, err := ra.NewOrder(context.Background(), wildcardOrderRequest)
2521 test.AssertNotError(t, err, "NewOrder failed for a wildcard order request")
2522
2523 test.AssertEquals(t, dupeOrder.Status, string(core.StatusPending))
2524 test.AssertEquals(t, numAuthorizations(dupeOrder), 1)
2525
2526
2527
2528 test.AssertEquals(t, dupeOrder.V2Authorizations[0], order.V2Authorizations[0])
2529 }
2530
2531
2532
2533 type mockSANearExpiredAuthz struct {
2534 mocks.StorageAuthority
2535 expiry time.Time
2536 }
2537
2538
2539
2540 func (msa *mockSANearExpiredAuthz) GetAuthorizations2(ctx context.Context, req *sapb.GetAuthorizationsRequest, _ ...grpc.CallOption) (*sapb.Authorizations, error) {
2541 authzs := map[string]*core.Authorization{
2542 "zombo.com": {
2543
2544 ID: "1",
2545 Identifier: identifier.DNSIdentifier("zombo.com"),
2546 RegistrationID: req.RegistrationID,
2547 Expires: &msa.expiry,
2548 Status: "valid",
2549 Challenges: []core.Challenge{
2550 {
2551 Type: core.ChallengeTypeHTTP01,
2552 Status: core.StatusValid,
2553 },
2554 },
2555 },
2556 }
2557 return authzMapToPB(authzs)
2558 }
2559
2560 func TestNewOrderExpiry(t *testing.T) {
2561 _, _, ra, clk, cleanUp := initAuthorities(t)
2562 defer cleanUp()
2563
2564 ctx := context.Background()
2565 names := []string{"zombo.com"}
2566
2567
2568 ra.orderLifetime = 48 * time.Hour
2569
2570
2571
2572 fakeAuthzExpires := clk.Now().Add(35 * time.Hour)
2573
2574
2575
2576 ra.SA = &mockSANearExpiredAuthz{expiry: fakeAuthzExpires}
2577
2578
2579 orderReq := &rapb.NewOrderRequest{
2580 RegistrationID: Registration.Id,
2581 Names: names,
2582 }
2583
2584
2585 order, err := ra.NewOrder(ctx, orderReq)
2586
2587 test.AssertNotError(t, err, "Adding an order for regA failed")
2588 test.AssertEquals(t, numAuthorizations(order), 1)
2589
2590 test.AssertEquals(t, order.V2Authorizations[0], int64(1))
2591
2592
2593 test.AssertEquals(t, order.ExpiresNS, fakeAuthzExpires.UnixNano())
2594
2595
2596 ra.orderLifetime = 12 * time.Hour
2597 expectedOrderExpiry := clk.Now().Add(ra.orderLifetime).UnixNano()
2598
2599 order, err = ra.NewOrder(ctx, orderReq)
2600
2601 test.AssertNotError(t, err, "Adding an order for regA failed")
2602 test.AssertEquals(t, numAuthorizations(order), 1)
2603
2604 test.AssertEquals(t, order.V2Authorizations[0], int64(1))
2605
2606
2607 test.AssertEquals(t, order.ExpiresNS, expectedOrderExpiry)
2608 }
2609
2610 func TestFinalizeOrder(t *testing.T) {
2611 _, sa, ra, fc, cleanUp := initAuthorities(t)
2612 defer cleanUp()
2613 ra.orderLifetime = time.Hour
2614
2615
2616
2617 now := ra.clk.Now()
2618 exp := now.Add(365 * 24 * time.Hour)
2619 authzIDA := createFinalizedAuthorization(t, sa, "not-example.com", exp, core.ChallengeTypeHTTP01, ra.clk.Now())
2620 authzIDB := createFinalizedAuthorization(t, sa, "www.not-example.com", exp, core.ChallengeTypeHTTP01, ra.clk.Now())
2621
2622 testKey, err := rsa.GenerateKey(rand.Reader, 2048)
2623 test.AssertNotError(t, err, "error generating test key")
2624
2625 policyForbidCSR, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{
2626 PublicKey: testKey.PublicKey,
2627 SignatureAlgorithm: x509.SHA256WithRSA,
2628 DNSNames: []string{"example.org"},
2629 }, testKey)
2630 test.AssertNotError(t, err, "Error creating policy forbid CSR")
2631
2632 oneDomainCSR, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{
2633 PublicKey: testKey.PublicKey,
2634 SignatureAlgorithm: x509.SHA256WithRSA,
2635 DNSNames: []string{"a.com"},
2636 }, testKey)
2637 test.AssertNotError(t, err, "Error creating CSR with one DNS name")
2638
2639 twoDomainCSR, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{
2640 PublicKey: testKey.PublicKey,
2641 SignatureAlgorithm: x509.SHA256WithRSA,
2642 DNSNames: []string{"a.com", "b.com"},
2643 }, testKey)
2644 test.AssertNotError(t, err, "Error creating CSR with two DNS names")
2645
2646 validCSR, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{
2647 PublicKey: testKey.Public(),
2648 SignatureAlgorithm: x509.SHA256WithRSA,
2649 DNSNames: []string{"not-example.com", "www.not-example.com"},
2650 }, testKey)
2651 test.AssertNotError(t, err, "Error creating CSR with authorized names")
2652
2653 expectedCert := &x509.Certificate{
2654 SerialNumber: big.NewInt(0),
2655 Subject: pkix.Name{CommonName: "not-example.com"},
2656 DNSNames: []string{"not-example.com", "www.not-example.com"},
2657 PublicKey: testKey.Public(),
2658 NotBefore: fc.Now(),
2659 BasicConstraintsValid: true,
2660 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
2661 }
2662 certDER, err := x509.CreateCertificate(rand.Reader, expectedCert, expectedCert, testKey.Public(), testKey)
2663 test.AssertNotError(t, err, "failed to construct test certificate")
2664 ra.CA.(*mocks.MockCA).PEM = pem.EncodeToMemory(&pem.Block{Bytes: certDER, Type: "CERTIFICATE"})
2665
2666 fakeRegID := int64(0xB00)
2667
2668
2669
2670
2671
2672
2673
2674 fakeRegOrder, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{
2675 RegistrationID: Registration.Id,
2676 Names: []string{"001.example.com"},
2677 })
2678 test.AssertNotError(t, err, "Could not add test order for fake reg ID order ID")
2679
2680 missingAuthzOrder, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{
2681 RegistrationID: Registration.Id,
2682 Names: []string{"002.example.com"},
2683 })
2684 test.AssertNotError(t, err, "Could not add test order for missing authz order ID")
2685
2686 validatedOrder, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{
2687 NewOrder: &sapb.NewOrderRequest{
2688 RegistrationID: Registration.Id,
2689 ExpiresNS: exp.UnixNano(),
2690 Expires: timestamppb.New(exp),
2691 Names: []string{"not-example.com", "www.not-example.com"},
2692 V2Authorizations: []int64{authzIDA, authzIDB},
2693 },
2694 })
2695 test.AssertNotError(t, err, "Could not add test order with finalized authz IDs, ready status")
2696
2697 testCases := []struct {
2698 Name string
2699 OrderReq *rapb.FinalizeOrderRequest
2700 ExpectedErrMsg string
2701 ExpectIssuance bool
2702 }{
2703 {
2704 Name: "No id in order",
2705 OrderReq: &rapb.FinalizeOrderRequest{
2706 Order: &corepb.Order{},
2707 Csr: oneDomainCSR,
2708 },
2709 ExpectedErrMsg: "invalid order ID: 0",
2710 },
2711 {
2712 Name: "No account id in order",
2713 OrderReq: &rapb.FinalizeOrderRequest{
2714 Order: &corepb.Order{
2715 Id: 1,
2716 },
2717 Csr: oneDomainCSR,
2718 },
2719 ExpectedErrMsg: "invalid account ID: 0",
2720 },
2721 {
2722 Name: "No names in order",
2723 OrderReq: &rapb.FinalizeOrderRequest{
2724 Order: &corepb.Order{
2725 Id: 1,
2726 RegistrationID: 1,
2727 Status: string(core.StatusReady),
2728 Names: []string{},
2729 },
2730 Csr: oneDomainCSR,
2731 },
2732 ExpectedErrMsg: "Order has no associated names",
2733 },
2734 {
2735 Name: "Wrong order state (valid)",
2736 OrderReq: &rapb.FinalizeOrderRequest{
2737 Order: &corepb.Order{
2738 Id: 1,
2739 RegistrationID: 1,
2740 Status: string(core.StatusValid),
2741 Names: []string{"a.com"},
2742 },
2743 Csr: oneDomainCSR,
2744 },
2745 ExpectedErrMsg: `Order's status ("valid") is not acceptable for finalization`,
2746 },
2747 {
2748 Name: "Wrong order state (pending)",
2749 OrderReq: &rapb.FinalizeOrderRequest{
2750 Order: &corepb.Order{
2751 Id: 1,
2752 RegistrationID: 1,
2753 Status: string(core.StatusPending),
2754 Names: []string{"a.com"},
2755 },
2756 Csr: oneDomainCSR,
2757 },
2758 ExpectIssuance: false,
2759 ExpectedErrMsg: `Order's status ("pending") is not acceptable for finalization`,
2760 },
2761 {
2762 Name: "Invalid CSR",
2763 OrderReq: &rapb.FinalizeOrderRequest{
2764 Order: &corepb.Order{
2765 Id: 1,
2766 RegistrationID: 1,
2767 Status: string(core.StatusReady),
2768 Names: []string{"a.com"},
2769 },
2770 Csr: []byte{0xC0, 0xFF, 0xEE},
2771 },
2772 ExpectedErrMsg: "unable to parse CSR: asn1: syntax error: truncated tag or length",
2773 },
2774 {
2775 Name: "CSR and Order with diff number of names",
2776 OrderReq: &rapb.FinalizeOrderRequest{
2777 Order: &corepb.Order{
2778 Id: 1,
2779 RegistrationID: 1,
2780 Status: string(core.StatusReady),
2781 Names: []string{"a.com", "b.com"},
2782 },
2783 Csr: oneDomainCSR,
2784 },
2785 ExpectedErrMsg: "Order includes different number of names than CSR specifies",
2786 },
2787 {
2788 Name: "CSR and Order with diff number of names (other way)",
2789 OrderReq: &rapb.FinalizeOrderRequest{
2790 Order: &corepb.Order{
2791 Id: 1,
2792 RegistrationID: 1,
2793 Status: string(core.StatusReady),
2794 Names: []string{"a.com"},
2795 },
2796 Csr: twoDomainCSR,
2797 },
2798 ExpectedErrMsg: "Order includes different number of names than CSR specifies",
2799 },
2800 {
2801 Name: "CSR missing an order name",
2802 OrderReq: &rapb.FinalizeOrderRequest{
2803 Order: &corepb.Order{
2804 Id: 1,
2805 RegistrationID: 1,
2806 Status: string(core.StatusReady),
2807 Names: []string{"foobar.com"},
2808 },
2809 Csr: oneDomainCSR,
2810 },
2811 ExpectedErrMsg: "CSR is missing Order domain \"foobar.com\"",
2812 },
2813 {
2814 Name: "CSR with policy forbidden name",
2815 OrderReq: &rapb.FinalizeOrderRequest{
2816 Order: &corepb.Order{
2817 Id: 1,
2818 RegistrationID: 1,
2819 Status: string(core.StatusReady),
2820 Names: []string{"example.org"},
2821 ExpiresNS: exp.UnixNano(),
2822 Expires: timestamppb.New(exp),
2823 CertificateSerial: "",
2824 BeganProcessing: false,
2825 },
2826 Csr: policyForbidCSR,
2827 },
2828 ExpectedErrMsg: "Cannot issue for \"example.org\": The ACME server refuses to issue a certificate for this domain name, because it is forbidden by policy",
2829 },
2830 {
2831 Name: "Order with missing registration",
2832 OrderReq: &rapb.FinalizeOrderRequest{
2833 Order: &corepb.Order{
2834 Status: string(core.StatusReady),
2835 Names: []string{"a.com"},
2836 Id: fakeRegOrder.Id,
2837 RegistrationID: fakeRegID,
2838 ExpiresNS: exp.UnixNano(),
2839 Expires: timestamppb.New(exp),
2840 CertificateSerial: "",
2841 BeganProcessing: false,
2842 CreatedNS: now.UnixNano(),
2843 Created: timestamppb.New(now),
2844 },
2845 Csr: oneDomainCSR,
2846 },
2847 ExpectedErrMsg: fmt.Sprintf("registration with ID '%d' not found", fakeRegID),
2848 },
2849 {
2850 Name: "Order with missing authorizations",
2851 OrderReq: &rapb.FinalizeOrderRequest{
2852 Order: &corepb.Order{
2853 Status: string(core.StatusReady),
2854 Names: []string{"a.com", "b.com"},
2855 Id: missingAuthzOrder.Id,
2856 RegistrationID: Registration.Id,
2857 ExpiresNS: exp.UnixNano(),
2858 Expires: timestamppb.New(exp),
2859 CertificateSerial: "",
2860 BeganProcessing: false,
2861 CreatedNS: now.UnixNano(),
2862 Created: timestamppb.New(now),
2863 },
2864 Csr: twoDomainCSR,
2865 },
2866 ExpectedErrMsg: "authorizations for these names not found or expired: a.com, b.com",
2867 },
2868 {
2869 Name: "Order with correct authorizations, ready status",
2870 OrderReq: &rapb.FinalizeOrderRequest{
2871 Order: validatedOrder,
2872 Csr: validCSR,
2873 },
2874 ExpectIssuance: true,
2875 },
2876 }
2877
2878 for _, tc := range testCases {
2879 t.Run(tc.Name, func(t *testing.T) {
2880 _, result := ra.FinalizeOrder(context.Background(), tc.OrderReq)
2881
2882 if !tc.ExpectIssuance {
2883
2884 test.AssertError(t, result, "FinalizeOrder did not fail when expected to")
2885 test.AssertEquals(t, result.Error(), tc.ExpectedErrMsg)
2886 } else {
2887
2888 test.AssertNotError(t, result, fmt.Sprintf("FinalizeOrder result was %#v, expected nil", result))
2889
2890 updatedOrder, err := sa.GetOrder(
2891 context.Background(),
2892 &sapb.OrderRequest{Id: tc.OrderReq.Order.Id})
2893 test.AssertNotError(t, err, "Error getting order to check serial")
2894 test.AssertNotEquals(t, updatedOrder.CertificateSerial, "")
2895 test.AssertEquals(t, updatedOrder.Status, "valid")
2896 test.AssertEquals(t, updatedOrder.ExpiresNS, exp.UnixNano())
2897 test.AssertEquals(t, updatedOrder.Expires.AsTime(), exp)
2898 }
2899 })
2900 }
2901 }
2902
2903 func TestFinalizeOrderWithMixedSANAndCN(t *testing.T) {
2904 _, sa, ra, _, cleanUp := initAuthorities(t)
2905 defer cleanUp()
2906 ra.orderLifetime = time.Hour
2907
2908
2909 now := ra.clk.Now()
2910 exp := now.Add(365 * 24 * time.Hour)
2911
2912
2913
2914 authzIDA := createFinalizedAuthorization(t, sa, "not-example.com", exp, core.ChallengeTypeHTTP01, ra.clk.Now())
2915 authzIDB := createFinalizedAuthorization(t, sa, "www.not-example.com", exp, core.ChallengeTypeHTTP01, ra.clk.Now())
2916
2917
2918 mixedOrder, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{
2919 NewOrder: &sapb.NewOrderRequest{
2920 RegistrationID: Registration.Id,
2921 ExpiresNS: exp.UnixNano(),
2922 Expires: timestamppb.New(exp),
2923 Names: []string{"not-example.com", "www.not-example.com"},
2924 V2Authorizations: []int64{authzIDA, authzIDB},
2925 },
2926 })
2927 test.AssertNotError(t, err, "Could not add test order with finalized authz IDs")
2928 testKey, err := rsa.GenerateKey(rand.Reader, 2048)
2929 test.AssertNotError(t, err, "error generating test key")
2930 mixedCSR, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{
2931 PublicKey: testKey.PublicKey,
2932 SignatureAlgorithm: x509.SHA256WithRSA,
2933 Subject: pkix.Name{CommonName: "not-example.com"},
2934 DNSNames: []string{"www.not-example.com"},
2935 }, testKey)
2936 test.AssertNotError(t, err, "Could not create mixed CSR")
2937
2938 template := &x509.Certificate{
2939 SerialNumber: big.NewInt(12),
2940 Subject: pkix.Name{CommonName: "not-example.com"},
2941 DNSNames: []string{"www.not-example.com", "not-example.com"},
2942 NotBefore: time.Now(),
2943 BasicConstraintsValid: true,
2944 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
2945 }
2946 cert, err := x509.CreateCertificate(rand.Reader, template, template, testKey.Public(), testKey)
2947 test.AssertNotError(t, err, "Failed to create mixed cert")
2948
2949 ra.CA = &mocks.MockCA{
2950 PEM: pem.EncodeToMemory(&pem.Block{
2951 Bytes: cert,
2952 }),
2953 }
2954
2955 _, result := ra.FinalizeOrder(context.Background(), &rapb.FinalizeOrderRequest{Order: mixedOrder, Csr: mixedCSR})
2956 test.AssertNotError(t, result, "FinalizeOrder failed")
2957
2958 updatedOrder, err := sa.GetOrder(
2959 context.Background(),
2960 &sapb.OrderRequest{Id: mixedOrder.Id})
2961 test.AssertNotError(t, err, "Error getting order to check serial")
2962 test.AssertNotEquals(t, updatedOrder.CertificateSerial, "")
2963 test.AssertEquals(t, updatedOrder.Status, "valid")
2964 }
2965
2966 func TestFinalizeOrderWildcard(t *testing.T) {
2967 _, sa, ra, _, cleanUp := initAuthorities(t)
2968 defer cleanUp()
2969
2970
2971 now := ra.clk.Now()
2972 exp := now.Add(365 * 24 * time.Hour)
2973
2974 testKey, err := rsa.GenerateKey(rand.Reader, 2048)
2975 test.AssertNotError(t, err, "Error creating test RSA key")
2976 wildcardCSR, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{
2977 PublicKey: testKey.PublicKey,
2978 SignatureAlgorithm: x509.SHA256WithRSA,
2979 DNSNames: []string{"*.zombo.com"},
2980 }, testKey)
2981 test.AssertNotError(t, err, "Error creating CSR with wildcard DNS name")
2982
2983 template := &x509.Certificate{
2984 SerialNumber: big.NewInt(1337),
2985 NotBefore: time.Now(),
2986 NotAfter: time.Now().AddDate(0, 0, 1),
2987 KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
2988 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
2989 BasicConstraintsValid: true,
2990 Subject: pkix.Name{CommonName: "*.zombo.com"},
2991 DNSNames: []string{"*.zombo.com"},
2992 }
2993
2994 certBytes, err := x509.CreateCertificate(rand.Reader, template, template, testKey.Public(), testKey)
2995 test.AssertNotError(t, err, "Error creating test certificate")
2996
2997 certPEM := pem.EncodeToMemory(&pem.Block{
2998 Type: "CERTIFICATE",
2999 Bytes: certBytes,
3000 })
3001
3002
3003 ca := &mocks.MockCA{
3004 PEM: certPEM,
3005 }
3006 ra.CA = ca
3007
3008
3009 orderNames := []string{"*.zombo.com"}
3010 wildcardOrderRequest := &rapb.NewOrderRequest{
3011 RegistrationID: Registration.Id,
3012 Names: orderNames,
3013 }
3014 order, err := ra.NewOrder(context.Background(), wildcardOrderRequest)
3015 test.AssertNotError(t, err, "NewOrder failed for wildcard domain order")
3016
3017
3018 _ = createFinalizedAuthorization(t, sa, "zombo.com", exp, core.ChallengeTypeHTTP01, ra.clk.Now())
3019
3020
3021
3022
3023 finalizeReq := &rapb.FinalizeOrderRequest{
3024 Order: order,
3025 Csr: wildcardCSR,
3026 }
3027 _, err = ra.FinalizeOrder(context.Background(), finalizeReq)
3028 test.AssertError(t, err, "FinalizeOrder did not fail for unauthorized "+
3029 "wildcard order")
3030 test.AssertEquals(t, err.Error(),
3031 `Order's status ("pending") is not acceptable for finalization`)
3032
3033
3034 validOrder, err := ra.NewOrder(context.Background(), wildcardOrderRequest)
3035 test.AssertNotError(t, err, "NewOrder failed for wildcard domain order")
3036 test.AssertEquals(t, numAuthorizations(validOrder), 1)
3037
3038 _, err = sa.GetAuthorization2(ctx, &sapb.AuthorizationID2{Id: validOrder.V2Authorizations[0]})
3039 test.AssertNotError(t, err, "sa.GetAuthorization2 failed")
3040
3041
3042 expires := now.Add(time.Hour * 24 * 7)
3043 _, err = sa.FinalizeAuthorization2(ctx, &sapb.FinalizeAuthorizationRequest{
3044 Id: validOrder.V2Authorizations[0],
3045 Status: string(core.StatusValid),
3046 ExpiresNS: expires.UnixNano(),
3047 Expires: timestamppb.New(expires),
3048 Attempted: string(core.ChallengeTypeDNS01),
3049 AttemptedAtNS: now.UnixNano(),
3050 AttemptedAt: timestamppb.New(now),
3051 })
3052 test.AssertNotError(t, err, "sa.FinalizeAuthorization2 failed")
3053
3054
3055 validOrder, err = sa.GetOrder(ctx, &sapb.OrderRequest{
3056 Id: validOrder.Id,
3057 })
3058 test.AssertNotError(t, err, "Could not refresh valid order from SA")
3059
3060
3061 finalizeReq = &rapb.FinalizeOrderRequest{
3062 Order: validOrder,
3063 Csr: wildcardCSR,
3064 }
3065 _, err = ra.FinalizeOrder(context.Background(), finalizeReq)
3066 test.AssertNotError(t, err, "FinalizeOrder failed for authorized "+
3067 "wildcard order")
3068 }
3069
3070 func TestIssueCertificateAuditLog(t *testing.T) {
3071 _, sa, ra, _, cleanUp := initAuthorities(t)
3072 defer cleanUp()
3073
3074
3075 ra.orderLifetime = 24 * time.Hour
3076 exp := ra.clk.Now().Add(24 * time.Hour)
3077
3078
3079 names := []string{"not-example.com", "www.not-example.com", "still.not-example.com", "definitely.not-example.com"}
3080 challs := []core.AcmeChallenge{core.ChallengeTypeHTTP01, core.ChallengeTypeDNS01, core.ChallengeTypeHTTP01, core.ChallengeTypeDNS01}
3081 var authzIDs []int64
3082 for i, name := range names {
3083 authzIDs = append(authzIDs, createFinalizedAuthorization(t, sa, name, exp, challs[i], ra.clk.Now()))
3084 }
3085
3086
3087 order, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{
3088 NewOrder: &sapb.NewOrderRequest{
3089 RegistrationID: Registration.Id,
3090 ExpiresNS: exp.UnixNano(),
3091 Expires: timestamppb.New(exp),
3092 Names: names,
3093 V2Authorizations: authzIDs,
3094 },
3095 })
3096 test.AssertNotError(t, err, "Could not add test order with finalized authz IDs")
3097
3098
3099 testKey, err := rsa.GenerateKey(rand.Reader, 2048)
3100 test.AssertNotError(t, err, "error generating test key")
3101 csr, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{
3102 PublicKey: testKey.PublicKey,
3103 SignatureAlgorithm: x509.SHA256WithRSA,
3104 Subject: pkix.Name{CommonName: "not-example.com"},
3105 DNSNames: names,
3106 }, testKey)
3107 test.AssertNotError(t, err, "Could not create test order CSR")
3108
3109
3110 template := &x509.Certificate{
3111 SerialNumber: big.NewInt(12),
3112 Subject: pkix.Name{
3113 CommonName: "not-example.com",
3114 },
3115 DNSNames: names,
3116 NotBefore: time.Now(),
3117 NotAfter: time.Now().AddDate(0, 0, 1),
3118 BasicConstraintsValid: true,
3119 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
3120 }
3121 cert, err := x509.CreateCertificate(rand.Reader, template, template, testKey.Public(), testKey)
3122 test.AssertNotError(t, err, "Failed to create mock cert for test CA")
3123
3124
3125 ra.CA = &mocks.MockCA{
3126 PEM: pem.EncodeToMemory(&pem.Block{
3127 Bytes: cert,
3128 }),
3129 }
3130
3131
3132 parsedCerts, err := x509.ParseCertificates(cert)
3133 test.AssertNotError(t, err, "Failed to parse mock cert DER bytes")
3134 test.AssertEquals(t, len(parsedCerts), 1)
3135 parsedCert := parsedCerts[0]
3136
3137
3138
3139 mockLog := ra.log.(*blog.Mock)
3140 mockLog.Clear()
3141
3142
3143 order.Status = string(core.StatusReady)
3144 _, err = ra.FinalizeOrder(context.Background(), &rapb.FinalizeOrderRequest{
3145 Order: order,
3146 Csr: csr,
3147 })
3148 test.AssertNotError(t, err, "Error finalizing test order")
3149
3150
3151 loglines := mockLog.GetAllMatching("Certificate request - successful JSON=")
3152
3153
3154 test.AssertEquals(t, len(loglines), 1)
3155
3156 jsonContent := strings.TrimPrefix(loglines[0], "INFO: [AUDIT] Certificate request - successful JSON=")
3157
3158
3159 var event certificateRequestEvent
3160 err = json.Unmarshal([]byte(jsonContent), &event)
3161
3162 test.AssertNotError(t, err, "Error unmarshalling logged JSON issuance event")
3163
3164 test.AssertEquals(t, event.Error, "")
3165
3166 test.AssertEquals(t, event.Requester, Registration.Id)
3167
3168 test.AssertEquals(t, event.OrderID, order.Id)
3169
3170 test.AssertEquals(t, event.SerialNumber, core.SerialToString(template.SerialNumber))
3171
3172 test.AssertDeepEquals(t, event.VerifiedFields, []string{"subject.commonName", "subjectAltName"})
3173
3174 test.AssertEquals(t, event.CommonName, "not-example.com")
3175
3176 test.AssertDeepEquals(t, core.UniqueLowerNames(event.Names), core.UniqueLowerNames(order.Names))
3177
3178 test.AssertEquals(t, event.NotBefore, parsedCert.NotBefore)
3179 test.AssertEquals(t, event.NotAfter, parsedCert.NotAfter)
3180
3181
3182 test.AssertEquals(t, len(event.Authorizations), len(names))
3183
3184
3185 for i, name := range names {
3186 authzEntry := event.Authorizations[name]
3187
3188 test.AssertEquals(t, authzEntry.ID, fmt.Sprintf("%d", authzIDs[i]))
3189
3190 test.AssertEquals(t, authzEntry.ChallengeType, challs[i])
3191 }
3192 }
3193
3194 func TestIssueCertificateCAACheckLog(t *testing.T) {
3195 _, sa, ra, fc, cleanUp := initAuthorities(t)
3196 defer cleanUp()
3197
3198
3199 ra.orderLifetime = 24 * time.Hour
3200 ra.authorizationLifetime = 15 * time.Hour
3201
3202 exp := fc.Now().Add(24 * time.Hour)
3203 recent := fc.Now().Add(-1 * time.Hour)
3204 older := fc.Now().Add(-8 * time.Hour)
3205
3206
3207
3208 names := []string{"not-example.com", "www.not-example.com", "still.not-example.com", "definitely.not-example.com"}
3209 var authzIDs []int64
3210 for i, name := range names {
3211 attemptedAt := older
3212 if i%2 == 0 {
3213 attemptedAt = recent
3214 }
3215 authzIDs = append(authzIDs, createFinalizedAuthorization(t, sa, name, exp, core.ChallengeTypeHTTP01, attemptedAt))
3216 }
3217
3218
3219 order, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{
3220 NewOrder: &sapb.NewOrderRequest{
3221 RegistrationID: Registration.Id,
3222 ExpiresNS: exp.UnixNano(),
3223 Expires: timestamppb.New(exp),
3224 Names: names,
3225 V2Authorizations: authzIDs,
3226 },
3227 })
3228 test.AssertNotError(t, err, "Could not add test order with finalized authz IDs")
3229
3230
3231 testKey, err := rsa.GenerateKey(rand.Reader, 2048)
3232 test.AssertNotError(t, err, "error generating test key")
3233 csr, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{
3234 PublicKey: testKey.PublicKey,
3235 SignatureAlgorithm: x509.SHA256WithRSA,
3236 Subject: pkix.Name{CommonName: "not-example.com"},
3237 DNSNames: names,
3238 }, testKey)
3239 test.AssertNotError(t, err, "Could not create test order CSR")
3240
3241
3242 template := &x509.Certificate{
3243 SerialNumber: big.NewInt(12),
3244 Subject: pkix.Name{
3245 CommonName: "not-example.com",
3246 },
3247 DNSNames: names,
3248 NotBefore: time.Now(),
3249 NotAfter: time.Now().AddDate(0, 0, 1),
3250 BasicConstraintsValid: true,
3251 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
3252 }
3253 cert, err := x509.CreateCertificate(rand.Reader, template, template, testKey.Public(), testKey)
3254 test.AssertNotError(t, err, "Failed to create mock cert for test CA")
3255
3256
3257 ra.CA = &mocks.MockCA{
3258 PEM: pem.EncodeToMemory(&pem.Block{
3259 Bytes: cert,
3260 }),
3261 }
3262
3263
3264
3265 mockLog := ra.log.(*blog.Mock)
3266 mockLog.Clear()
3267
3268
3269 order.Status = string(core.StatusReady)
3270 _, err = ra.FinalizeOrder(context.Background(), &rapb.FinalizeOrderRequest{
3271 Order: order,
3272 Csr: csr,
3273 })
3274 test.AssertNotError(t, err, "Error finalizing test order")
3275
3276
3277 loglines := mockLog.GetAllMatching("FinalizationCaaCheck JSON=")
3278
3279 test.AssertEquals(t, len(loglines), 1)
3280
3281
3282 jsonContent := strings.TrimPrefix(loglines[0], "INFO: FinalizationCaaCheck JSON=")
3283
3284
3285 var event finalizationCAACheckEvent
3286 err = json.Unmarshal([]byte(jsonContent), &event)
3287
3288 test.AssertNotError(t, err, "Error unmarshalling logged JSON issuance event.")
3289
3290 test.AssertEquals(t, event.Requester, Registration.Id)
3291
3292 test.AssertEquals(t, event.Reused, 2)
3293
3294
3295 test.AssertEquals(t, event.Rechecked, 2)
3296 }
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306 func TestUpdateMissingAuthorization(t *testing.T) {
3307 _, sa, ra, fc, cleanUp := initAuthorities(t)
3308 defer cleanUp()
3309 ctx := context.Background()
3310
3311 authzPB := createPendingAuthorization(t, sa, Identifier, fc.Now().Add(12*time.Hour))
3312 authz, err := bgrpc.PBToAuthz(authzPB)
3313 test.AssertNotError(t, err, "failed to deserialize authz")
3314
3315
3316 authz.Status = "valid"
3317 authz.Challenges[0].Status = "valid"
3318 err = ra.recordValidation(ctx, authz.ID, authz.Expires, &authz.Challenges[0])
3319 test.AssertNotError(t, err, "ra.recordValidation failed")
3320
3321 err = ra.recordValidation(ctx, authz.ID, authz.Expires, &authz.Challenges[0])
3322 test.AssertError(t, err, "ra.recordValidation didn't fail")
3323 test.AssertErrorIs(t, err, berrors.NotFound)
3324 }
3325
3326 func TestPerformValidationBadChallengeType(t *testing.T) {
3327 _, _, ra, fc, cleanUp := initAuthorities(t)
3328 defer cleanUp()
3329 pa, err := policy.New(map[core.AcmeChallenge]bool{}, blog.NewMock())
3330 test.AssertNotError(t, err, "Couldn't create PA")
3331 ra.PA = pa
3332
3333 exp := fc.Now().Add(10 * time.Hour)
3334 authz := core.Authorization{
3335 ID: "1337",
3336 Identifier: identifier.DNSIdentifier("not-example.com"),
3337 RegistrationID: 1,
3338 Status: "valid",
3339 Challenges: []core.Challenge{
3340 {
3341 Status: core.StatusValid,
3342 Type: core.ChallengeTypeHTTP01,
3343 Token: "exampleToken",
3344 },
3345 },
3346 Expires: &exp,
3347 }
3348 authzPB, err := bgrpc.AuthzToPB(authz)
3349 test.AssertNotError(t, err, "AuthzToPB failed")
3350
3351 _, err = ra.PerformValidation(context.Background(), &rapb.PerformValidationRequest{
3352 Authz: authzPB,
3353 ChallengeIndex: 0,
3354 })
3355 test.AssertError(t, err, "ra.PerformValidation allowed a update to a authorization")
3356 test.AssertEquals(t, err.Error(), "challenge type \"http-01\" no longer allowed")
3357 }
3358
3359 type timeoutPub struct {
3360 }
3361
3362 func (mp *timeoutPub) SubmitToSingleCTWithResult(_ context.Context, _ *pubpb.Request, _ ...grpc.CallOption) (*pubpb.Result, error) {
3363 return nil, context.DeadlineExceeded
3364 }
3365
3366 func TestCTPolicyMeasurements(t *testing.T) {
3367 _, ssa, ra, _, cleanup := initAuthorities(t)
3368 defer cleanup()
3369
3370 ra.ctpolicy = ctpolicy.New(&timeoutPub{}, loglist.List{
3371 "OperA": {
3372 "LogA1": {Url: "UrlA1", Key: "KeyA1"},
3373 },
3374 "OperB": {
3375 "LogB1": {Url: "UrlB1", Key: "KeyB1"},
3376 },
3377 }, nil, nil, 0, log, metrics.NoopRegisterer)
3378
3379
3380 exp := ra.clk.Now().Add(365 * 24 * time.Hour)
3381 authzIDA := createFinalizedAuthorization(t, ssa, "not-example.com", exp, core.ChallengeTypeHTTP01, ra.clk.Now())
3382 authzIDB := createFinalizedAuthorization(t, ssa, "www.not-example.com", exp, core.ChallengeTypeHTTP01, ra.clk.Now())
3383
3384 order, err := ra.SA.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{
3385 NewOrder: &sapb.NewOrderRequest{
3386 RegistrationID: Registration.Id,
3387 ExpiresNS: exp.UnixNano(),
3388 Expires: timestamppb.New(exp),
3389 Names: []string{"not-example.com", "www.not-example.com"},
3390 V2Authorizations: []int64{authzIDA, authzIDB},
3391 },
3392 })
3393 test.AssertNotError(t, err, "error generating test order")
3394
3395 testKey, err := rsa.GenerateKey(rand.Reader, 2048)
3396 test.AssertNotError(t, err, "error generating test key")
3397
3398 csr, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{
3399 PublicKey: testKey.Public(),
3400 SignatureAlgorithm: x509.SHA256WithRSA,
3401 DNSNames: []string{"not-example.com", "www.not-example.com"},
3402 }, testKey)
3403 test.AssertNotError(t, err, "error generating test CSR")
3404
3405 _, err = ra.FinalizeOrder(context.Background(), &rapb.FinalizeOrderRequest{
3406 Order: order,
3407 Csr: csr,
3408 })
3409 test.AssertError(t, err, "FinalizeOrder should have failed when SCTs timed out")
3410 test.AssertContains(t, err.Error(), "getting SCTs")
3411 test.AssertMetricWithLabelsEquals(t, ra.ctpolicyResults, prometheus.Labels{"result": "failure"}, 1)
3412 }
3413
3414 func TestWildcardOverlap(t *testing.T) {
3415 err := wildcardOverlap([]string{
3416 "*.example.com",
3417 "*.example.net",
3418 })
3419 if err != nil {
3420 t.Errorf("Got error %q, expected none", err)
3421 }
3422 err = wildcardOverlap([]string{
3423 "*.example.com",
3424 "*.example.net",
3425 "www.example.com",
3426 })
3427 if err == nil {
3428 t.Errorf("Got no error, expected one")
3429 }
3430 test.AssertErrorIs(t, err, berrors.Malformed)
3431
3432 err = wildcardOverlap([]string{
3433 "*.foo.example.com",
3434 "*.example.net",
3435 "www.example.com",
3436 })
3437 if err != nil {
3438 t.Errorf("Got error %q, expected none", err)
3439 }
3440 }
3441
3442
3443 type mockCAFailPrecert struct {
3444 mocks.MockCA
3445 err error
3446 }
3447
3448 func (ca *mockCAFailPrecert) IssuePrecertificate(
3449 context.Context,
3450 *capb.IssueCertificateRequest,
3451 ...grpc.CallOption) (*capb.IssuePrecertificateResponse, error) {
3452 return nil, ca.err
3453 }
3454
3455
3456
3457 type mockCAFailCertForPrecert struct {
3458 mocks.MockCA
3459 err error
3460 }
3461
3462
3463 func (ca *mockCAFailCertForPrecert) IssuePrecertificate(
3464 context.Context,
3465 *capb.IssueCertificateRequest,
3466 ...grpc.CallOption) (*capb.IssuePrecertificateResponse, error) {
3467 k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
3468 if err != nil {
3469 return nil, err
3470 }
3471 tmpl := &ctx509.Certificate{
3472 SerialNumber: big.NewInt(1),
3473 ExtraExtensions: []ctpkix.Extension{
3474 {
3475 Id: ctx509.OIDExtensionCTPoison,
3476 Critical: true,
3477 Value: ctasn1.NullBytes,
3478 },
3479 },
3480 }
3481 precert, err := ctx509.CreateCertificate(rand.Reader, tmpl, tmpl, k.Public(), k)
3482 if err != nil {
3483 return nil, err
3484 }
3485 return &capb.IssuePrecertificateResponse{
3486 DER: precert,
3487 }, nil
3488 }
3489
3490 func (ca *mockCAFailCertForPrecert) IssueCertificateForPrecertificate(
3491 context.Context,
3492 *capb.IssueCertificateForPrecertificateRequest,
3493 ...grpc.CallOption) (*corepb.Certificate, error) {
3494 return &corepb.Certificate{}, ca.err
3495 }
3496
3497
3498
3499
3500 func TestIssueCertificateInnerErrs(t *testing.T) {
3501 _, sa, ra, _, cleanUp := initAuthorities(t)
3502 defer cleanUp()
3503
3504 ra.orderLifetime = 24 * time.Hour
3505 exp := ra.clk.Now().Add(24 * time.Hour)
3506
3507
3508 names := []string{"not-example.com", "www.not-example.com", "still.not-example.com", "definitely.not-example.com"}
3509 var authzIDs []int64
3510 for _, name := range names {
3511 authzIDs = append(authzIDs, createFinalizedAuthorization(t, sa, name, exp, core.ChallengeTypeHTTP01, ra.clk.Now()))
3512 }
3513
3514
3515 order, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{
3516 NewOrder: &sapb.NewOrderRequest{
3517 RegistrationID: Registration.Id,
3518 ExpiresNS: exp.UnixNano(),
3519 Expires: timestamppb.New(exp),
3520 Names: names,
3521 V2Authorizations: authzIDs,
3522 },
3523 })
3524 test.AssertNotError(t, err, "Could not add test order with finalized authz IDs")
3525
3526
3527 testKey, err := rsa.GenerateKey(rand.Reader, 2048)
3528 test.AssertNotError(t, err, "error generating test key")
3529 csr, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{
3530 PublicKey: testKey.PublicKey,
3531 SignatureAlgorithm: x509.SHA256WithRSA,
3532 Subject: pkix.Name{CommonName: "not-example.com"},
3533 DNSNames: names,
3534 }, testKey)
3535 test.AssertNotError(t, err, "Could not create test order CSR")
3536
3537 csrOb, err := x509.ParseCertificateRequest(csr)
3538 test.AssertNotError(t, err, "Error pasring generated CSR")
3539
3540 testCases := []struct {
3541 Name string
3542 Mock capb.CertificateAuthorityClient
3543 ExpectedErr error
3544 ExpectedProb *berrors.BoulderError
3545 }{
3546 {
3547 Name: "vanilla error during IssuePrecertificate",
3548 Mock: &mockCAFailPrecert{
3549 err: fmt.Errorf("bad bad not good"),
3550 },
3551 ExpectedErr: fmt.Errorf("issuing precertificate: bad bad not good"),
3552 },
3553 {
3554 Name: "malformed problem during IssuePrecertificate",
3555 Mock: &mockCAFailPrecert{
3556 err: berrors.MalformedError("detected 1x whack attack"),
3557 },
3558 ExpectedProb: &berrors.BoulderError{
3559 Detail: "issuing precertificate: detected 1x whack attack",
3560 Type: berrors.Malformed,
3561 },
3562 },
3563 {
3564 Name: "vanilla error during IssueCertificateForPrecertificate",
3565 Mock: &mockCAFailCertForPrecert{
3566 err: fmt.Errorf("aaaaaaaaaaaaaaaaaaaa!!"),
3567 },
3568 ExpectedErr: fmt.Errorf("issuing certificate for precertificate: aaaaaaaaaaaaaaaaaaaa!!"),
3569 },
3570 {
3571 Name: "malformed problem during IssueCertificateForPrecertificate",
3572 Mock: &mockCAFailCertForPrecert{
3573 err: berrors.MalformedError("provided DER is DERanged"),
3574 },
3575 ExpectedProb: &berrors.BoulderError{
3576 Detail: "issuing certificate for precertificate: provided DER is DERanged",
3577 Type: berrors.Malformed,
3578 },
3579 },
3580 }
3581
3582 for _, tc := range testCases {
3583 t.Run(tc.Name, func(t *testing.T) {
3584
3585 ra.CA = tc.Mock
3586
3587 _, err = ra.issueCertificateInner(ctx, csrOb, accountID(Registration.Id), orderID(order.Id))
3588
3589 test.AssertError(t, err, "issueCertificateInner with failing mock CA did not fail")
3590
3591 if tc.ExpectedErr != nil {
3592 test.AssertEquals(t, err.Error(), tc.ExpectedErr.Error())
3593 } else if tc.ExpectedProb != nil {
3594
3595
3596 var berr *berrors.BoulderError
3597 test.AssertErrorWraps(t, err, &berr)
3598
3599 test.AssertErrorIs(t, berr, tc.ExpectedProb.Type)
3600 test.AssertEquals(t, berr.Detail, tc.ExpectedProb.Detail)
3601 }
3602 })
3603 }
3604 }
3605
3606 func TestNewOrderMaxNames(t *testing.T) {
3607 _, _, ra, _, cleanUp := initAuthorities(t)
3608 defer cleanUp()
3609
3610 ra.maxNames = 2
3611 _, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{
3612 RegistrationID: 1,
3613 Names: []string{
3614 "a",
3615 "b",
3616 "c",
3617 },
3618 })
3619 test.AssertError(t, err, "NewOrder didn't fail with too many names in request")
3620 test.AssertEquals(t, err.Error(), "Order cannot contain more than 2 DNS names")
3621 test.AssertErrorIs(t, err, berrors.Malformed)
3622 }
3623
3624
3625
3626
3627
3628 var CSRPEM = []byte(`
3629 -----BEGIN CERTIFICATE REQUEST-----
3630 MIICrjCCAZYCAQAwJzELMAkGA1UEBhMCVVMxGDAWBgNVBAMTD25vdC1leGFtcGxl
3631 LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKT1B7UsonZuLOp7
3632 qq2pw+COo0I9ZheuhN9ltu1+bAMWBYUb8KFPNGGp8Ygt6YCLjlnWOche7Fjb5lPj
3633 hV6U2BkEt85mdaGTDg6mU3qjk2/cnZeAvJWW5ewYOBGxN/g/KHgdYZ+uhHH/PbGt
3634 Wktcv5bRJ9Dxbjxsy7l8SLQ6fd/MF/3z6sBJzIHkcDupDOFdPN/Z0KOw7BOPHAbg
3635 ghLJTmiESA1Ljxb8848bENlCz8pVizIu2Ilr4xBPtA5oUfO0FJKbT1T66JZoqwy/
3636 drfrlHA7F6c8kYlAmwiOfWHzlWCkE1YuZPJrZQrt4tJ70rrPxV1qEGJDumzgcEbU
3637 /aYYiBsCAwEAAaBCMEAGCSqGSIb3DQEJDjEzMDEwLwYDVR0RBCgwJoIPbm90LWV4
3638 YW1wbGUuY29tghN3d3cubm90LWV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IB
3639 AQBuFo5SHqN1lWmM6rKaOBXFezAdzZyGb9x8+5Zq/eh9pSxpn0MTOmq/u+sDHxsC
3640 ywcshUO3P9//9u4ALtNn/jsJmSrElsTvG3SH5owl9muNEiOgf+6/rY/X8Zcnv/e0
3641 Ar9r73BcCkjoAOFbr7xiLLYu5EaBQjSj6/m4ujwJTWS2SqobK5VfdpzmDp4wT3eB
3642 V4FPLxyxxOLuWLzcBkDdLw/zh922HtR5fqk155Y4pj3WS9NnI/NMHmclrlfY/2P4
3643 dJrBVM+qVbPTzM19QplMkiy7FxpDx6toUXDYM4KdKKV0+yX/zw/V0/Gb7K7yIjVB
3644 wqjllqgMjN4nvHjiDXFx/kPY
3645 -----END CERTIFICATE REQUEST-----
3646 `)
3647
3648 var eeCertPEM = []byte(`
3649 -----BEGIN CERTIFICATE-----
3650 MIIEfTCCAmWgAwIBAgISCr9BRk0C9OOGVke6CAa8F+AXMA0GCSqGSIb3DQEBCwUA
3651 MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKDAdUZXN0IENBMRAwDgYDVQQDDAdUZXN0
3652 IENBMB4XDTE2MDMyMDE4MTEwMFoXDTE2MDMyMDE5MTEwMFowHjEcMBoGA1UEAxMT
3653 d3d3Lm5vdC1leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
3654 ggEBAKT1B7UsonZuLOp7qq2pw+COo0I9ZheuhN9ltu1+bAMWBYUb8KFPNGGp8Ygt
3655 6YCLjlnWOche7Fjb5lPjhV6U2BkEt85mdaGTDg6mU3qjk2/cnZeAvJWW5ewYOBGx
3656 N/g/KHgdYZ+uhHH/PbGtWktcv5bRJ9Dxbjxsy7l8SLQ6fd/MF/3z6sBJzIHkcDup
3657 DOFdPN/Z0KOw7BOPHAbgghLJTmiESA1Ljxb8848bENlCz8pVizIu2Ilr4xBPtA5o
3658 UfO0FJKbT1T66JZoqwy/drfrlHA7F6c8kYlAmwiOfWHzlWCkE1YuZPJrZQrt4tJ7
3659 0rrPxV1qEGJDumzgcEbU/aYYiBsCAwEAAaOBoTCBnjAdBgNVHSUEFjAUBggrBgEF
3660 BQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUIEr9ryJ0aJuD
3661 CwBsCp7Eun8Hx4AwHwYDVR0jBBgwFoAUmiamd/N/8knrCb1QlhwB4WXCqaswLwYD
3662 VR0RBCgwJoIPbm90LWV4YW1wbGUuY29tghN3d3cubm90LWV4YW1wbGUuY29tMA0G
3663 CSqGSIb3DQEBCwUAA4ICAQBpGLrCt38Z+knbuE1ALEB3hqUQCAm1OPDW6HR+v2nO
3664 f2ERxTwL9Cad++3vONxgB68+6KQeIf5ph48OGnS5DgO13mb2cxLlmM2IJpkbSFtW
3665 VeRNFt/WxRJafpbKw2hgQNJ/sxEAsCyA+kVeh1oCxGQyPO7IIXtw5FecWfIiNNwM
3666 mVM17uchtvsM5BRePvet9xZxrKOFnn6TQRs8vC4e59Y8h52On+L2Q/ytAa7j3+fb
3667 7OYCe+yWypGeosekamZTMBjHFV3RRxsGdRATSuZkv1uewyUnEPmsy5Ow4doSYZKW
3668 QmKjti+vv1YhAhFxPArob0SG3YOiFuKzZ9rSOhUtzSg01ml/kRyOiC7rfO7NRzHq
3669 idhPUhu2QBmdJTLLOBQLvKDNDOHqDYwKdIHJ7pup2y0Fvm4T96q5bnrSdmz/QAlB
3670 XVw08HWMcjeOeHYiHST3yxYfQivTNm2PlKfUACb7vcrQ6pYhOnVdYgJZm6gkV4Xd
3671 K1HKja36snIevv/gSgsE7bGcBYLVCvf16o3IRt9K8CpDoSsWn0iAVcwUP2CyPLm4
3672 QsqA1afjTUPKQTAgDKRecDPhrT1+FjtBwdpXetpRiBK0UE5exfnI4nszZ9+BYG1l
3673 xGUhoOJp0T++nz6R3TX7Rwk7KmG6xX3vWr/MFu5A3c8fvkqj987Vti5BeBezCXfs
3674 rA==
3675 -----END CERTIFICATE-----
3676 `)
3677
3678 type mockSARevocation struct {
3679 mocks.StorageAuthority
3680
3681 known *corepb.CertificateStatus
3682 blocked []*sapb.AddBlockedKeyRequest
3683 revoked map[string]int64
3684 }
3685
3686 func newMockSARevocation(known *x509.Certificate, clk clock.Clock) *mockSARevocation {
3687 return &mockSARevocation{
3688 StorageAuthority: *mocks.NewStorageAuthority(clk),
3689 known: &corepb.CertificateStatus{
3690 Serial: core.SerialToString(known.SerialNumber),
3691 IssuerID: int64(issuance.GetIssuerNameID(known)),
3692 },
3693 blocked: make([]*sapb.AddBlockedKeyRequest, 0),
3694 revoked: make(map[string]int64),
3695 }
3696 }
3697
3698 func (msar *mockSARevocation) AddBlockedKey(_ context.Context, req *sapb.AddBlockedKeyRequest, _ ...grpc.CallOption) (*emptypb.Empty, error) {
3699 msar.blocked = append(msar.blocked, req)
3700 return &emptypb.Empty{}, nil
3701 }
3702
3703 func (msar *mockSARevocation) GetCertificateStatus(_ context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*corepb.CertificateStatus, error) {
3704 if msar.known != nil && req.Serial == msar.known.Serial {
3705 return msar.known, nil
3706 }
3707 return nil, fmt.Errorf("unknown certificate status")
3708 }
3709
3710 func (msar *mockSARevocation) RevokeCertificate(_ context.Context, req *sapb.RevokeCertificateRequest, _ ...grpc.CallOption) (*emptypb.Empty, error) {
3711 if _, present := msar.revoked[req.Serial]; present {
3712 return nil, berrors.AlreadyRevokedError("already revoked")
3713 }
3714 msar.revoked[req.Serial] = req.Reason
3715 msar.known.Status = string(core.OCSPStatusRevoked)
3716 return &emptypb.Empty{}, nil
3717 }
3718
3719 func (msar *mockSARevocation) UpdateRevokedCertificate(_ context.Context, req *sapb.RevokeCertificateRequest, _ ...grpc.CallOption) (*emptypb.Empty, error) {
3720 reason, present := msar.revoked[req.Serial]
3721 if !present {
3722 return nil, errors.New("not already revoked")
3723 }
3724 if present && reason == ocsp.KeyCompromise {
3725 return nil, berrors.AlreadyRevokedError("already revoked for keyCompromise")
3726 }
3727 msar.revoked[req.Serial] = req.Reason
3728 return &emptypb.Empty{}, nil
3729 }
3730
3731 type mockOCSPA struct {
3732 mocks.MockCA
3733 }
3734
3735 func (mcao *mockOCSPA) GenerateOCSP(context.Context, *capb.GenerateOCSPRequest, ...grpc.CallOption) (*capb.OCSPResponse, error) {
3736 return &capb.OCSPResponse{Response: []byte{1, 2, 3}}, nil
3737 }
3738
3739 type mockPurger struct{}
3740
3741 func (mp *mockPurger) Purge(context.Context, *akamaipb.PurgeRequest, ...grpc.CallOption) (*emptypb.Empty, error) {
3742 return &emptypb.Empty{}, nil
3743 }
3744
3745 type mockSAGenerateOCSP struct {
3746 mocks.StorageAuthority
3747 expiration time.Time
3748 }
3749
3750 func (msgo *mockSAGenerateOCSP) GetCertificateStatus(_ context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*corepb.CertificateStatus, error) {
3751 return &corepb.CertificateStatus{
3752 Serial: req.Serial,
3753 Status: "good",
3754 NotAfterNS: msgo.expiration.UTC().UnixNano(),
3755 NotAfter: timestamppb.New(msgo.expiration.UTC()),
3756 }, nil
3757 }
3758
3759 func TestGenerateOCSP(t *testing.T) {
3760 _, _, ra, clk, cleanUp := initAuthorities(t)
3761 defer cleanUp()
3762
3763 ra.OCSP = &mockOCSPA{}
3764 ra.SA = &mockSAGenerateOCSP{expiration: clk.Now().Add(time.Hour)}
3765
3766 req := &rapb.GenerateOCSPRequest{
3767 Serial: core.SerialToString(big.NewInt(1)),
3768 }
3769
3770 resp, err := ra.GenerateOCSP(context.Background(), req)
3771 test.AssertNotError(t, err, "generating OCSP")
3772 test.AssertByteEquals(t, resp.Response, []byte{1, 2, 3})
3773
3774 ra.SA = &mockSAGenerateOCSP{expiration: clk.Now().Add(-time.Hour)}
3775 _, err = ra.GenerateOCSP(context.Background(), req)
3776 if !errors.Is(err, berrors.NotFound) {
3777 t.Errorf("expected NotFound error, got %s", err)
3778 }
3779 }
3780
3781 func TestRevokeCertByApplicant_Subscriber(t *testing.T) {
3782 _, _, ra, clk, cleanUp := initAuthorities(t)
3783 defer cleanUp()
3784
3785 ra.OCSP = &mockOCSPA{}
3786 ra.purger = &mockPurger{}
3787
3788 _, cert := test.ThrowAwayCert(t, 1)
3789 ic, err := issuance.NewCertificate(cert)
3790 test.AssertNotError(t, err, "failed to create issuer cert")
3791 ra.issuersByNameID = map[issuance.IssuerNameID]*issuance.Certificate{
3792 ic.NameID(): ic,
3793 }
3794 ra.issuersByID = map[issuance.IssuerID]*issuance.Certificate{
3795 ic.ID(): ic,
3796 }
3797 ra.SA = newMockSARevocation(cert, clk)
3798
3799
3800 _, err = ra.RevokeCertByApplicant(context.Background(), &rapb.RevokeCertByApplicantRequest{
3801 Cert: cert.Raw,
3802 Code: ocsp.Unspecified,
3803 RegID: 0,
3804 })
3805 test.AssertError(t, err, "should have failed with no RegID")
3806 test.AssertContains(t, err.Error(), "incomplete")
3807
3808
3809 _, err = ra.RevokeCertByApplicant(context.Background(), &rapb.RevokeCertByApplicantRequest{
3810 Cert: cert.Raw,
3811 Code: ocsp.CertificateHold,
3812 RegID: 1,
3813 })
3814 test.AssertError(t, err, "should have failed with bad reasonCode")
3815 test.AssertContains(t, err.Error(), "disallowed revocation reason")
3816
3817
3818 _, err = ra.RevokeCertByApplicant(context.Background(), &rapb.RevokeCertByApplicantRequest{
3819 Cert: cert.Raw,
3820 Code: ocsp.Unspecified,
3821 RegID: 1,
3822 })
3823 test.AssertNotError(t, err, "should have succeeded")
3824
3825
3826 _, err = ra.RevokeCertByApplicant(context.Background(), &rapb.RevokeCertByApplicantRequest{
3827 Cert: cert.Raw,
3828 Code: ocsp.Unspecified,
3829 RegID: 1,
3830 })
3831 test.AssertError(t, err, "should have failed with bad reasonCode")
3832 test.AssertContains(t, err.Error(), "already revoked")
3833 }
3834
3835 func TestRevokeCertByApplicant_Controller(t *testing.T) {
3836 _, _, ra, clk, cleanUp := initAuthorities(t)
3837 defer cleanUp()
3838
3839 ra.OCSP = &mockOCSPA{}
3840 ra.purger = &mockPurger{}
3841
3842 _, cert := test.ThrowAwayCert(t, 1)
3843 ic, err := issuance.NewCertificate(cert)
3844 test.AssertNotError(t, err, "failed to create issuer cert")
3845 ra.issuersByNameID = map[issuance.IssuerNameID]*issuance.Certificate{
3846 ic.NameID(): ic,
3847 }
3848 ra.issuersByID = map[issuance.IssuerID]*issuance.Certificate{
3849 ic.ID(): ic,
3850 }
3851 mockSA := newMockSARevocation(cert, clk)
3852 ra.SA = mockSA
3853
3854
3855 _, err = ra.RevokeCertByApplicant(context.Background(), &rapb.RevokeCertByApplicantRequest{
3856 Cert: cert.Raw,
3857 Code: ocsp.Unspecified,
3858 RegID: 2,
3859 })
3860 test.AssertError(t, err, "should have failed with wrong RegID")
3861 test.AssertContains(t, err.Error(), "requester does not control all names")
3862
3863
3864
3865 _, err = ra.RevokeCertByApplicant(context.Background(), &rapb.RevokeCertByApplicantRequest{
3866 Cert: cert.Raw,
3867 Code: ocsp.Unspecified,
3868 RegID: 5,
3869 })
3870 test.AssertNotError(t, err, "should have succeeded")
3871 test.AssertEquals(t, mockSA.revoked[core.SerialToString(cert.SerialNumber)], int64(ocsp.CessationOfOperation))
3872 }
3873
3874 func TestRevokeCertByKey(t *testing.T) {
3875 _, _, ra, clk, cleanUp := initAuthorities(t)
3876 defer cleanUp()
3877
3878 ra.OCSP = &mockOCSPA{}
3879 ra.purger = &mockPurger{}
3880
3881 k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
3882 test.AssertNotError(t, err, "ecdsa.GenerateKey failed")
3883 digest, err := core.KeyDigest(k.Public())
3884 test.AssertNotError(t, err, "core.KeyDigest failed")
3885
3886 template := x509.Certificate{SerialNumber: big.NewInt(257)}
3887 der, err := x509.CreateCertificate(rand.Reader, &template, &template, k.Public(), k)
3888 test.AssertNotError(t, err, "x509.CreateCertificate failed")
3889 cert, err := x509.ParseCertificate(der)
3890 test.AssertNotError(t, err, "x509.ParseCertificate failed")
3891 ic, err := issuance.NewCertificate(cert)
3892 test.AssertNotError(t, err, "failed to create issuer cert")
3893 ra.issuersByNameID = map[issuance.IssuerNameID]*issuance.Certificate{
3894 ic.NameID(): ic,
3895 }
3896 ra.issuersByID = map[issuance.IssuerID]*issuance.Certificate{
3897 ic.ID(): ic,
3898 }
3899 mockSA := newMockSARevocation(cert, clk)
3900 ra.SA = mockSA
3901
3902
3903 _, err = ra.RevokeCertByKey(context.Background(), &rapb.RevokeCertByKeyRequest{
3904 Cert: cert.Raw,
3905 })
3906 test.AssertNotError(t, err, "should have succeeded")
3907 test.AssertEquals(t, len(mockSA.blocked), 1)
3908 test.Assert(t, bytes.Equal(digest[:], mockSA.blocked[0].KeyHash), "key hash mismatch")
3909 test.AssertEquals(t, mockSA.blocked[0].Source, "API")
3910 test.AssertEquals(t, len(mockSA.blocked[0].Comment), 0)
3911 test.AssertEquals(t, mockSA.revoked[core.SerialToString(cert.SerialNumber)], int64(ocsp.KeyCompromise))
3912
3913
3914 _, err = ra.RevokeCertByKey(context.Background(), &rapb.RevokeCertByKeyRequest{
3915 Cert: cert.Raw,
3916 })
3917 test.AssertError(t, err, "should have failed")
3918
3919
3920
3921 mockSA.revoked = make(map[string]int64)
3922 _, err = ra.RevokeCertByApplicant(context.Background(), &rapb.RevokeCertByApplicantRequest{
3923 Cert: cert.Raw,
3924 Code: ocsp.Unspecified,
3925 RegID: 1,
3926 })
3927 test.AssertNotError(t, err, "should have succeeded")
3928 _, err = ra.RevokeCertByKey(context.Background(), &rapb.RevokeCertByKeyRequest{
3929 Cert: cert.Raw,
3930 })
3931 test.AssertNotError(t, err, "should have succeeded")
3932 }
3933
3934 func TestAdministrativelyRevokeCertificate(t *testing.T) {
3935 _, _, ra, clk, cleanUp := initAuthorities(t)
3936 defer cleanUp()
3937
3938 ra.OCSP = &mockOCSPA{}
3939 ra.purger = &mockPurger{}
3940
3941 k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
3942 test.AssertNotError(t, err, "ecdsa.GenerateKey failed")
3943 digest, err := core.KeyDigest(k.Public())
3944 test.AssertNotError(t, err, "core.KeyDigest failed")
3945
3946 serial := "04eac294a0e61035d8254d5a04f61a37c802"
3947 serialInt, err := core.StringToSerial(serial)
3948 test.AssertNotError(t, err, "decoding serial number")
3949 template := x509.Certificate{SerialNumber: serialInt}
3950 der, err := x509.CreateCertificate(rand.Reader, &template, &template, k.Public(), k)
3951 test.AssertNotError(t, err, "x509.CreateCertificate failed")
3952 cert, err := x509.ParseCertificate(der)
3953 test.AssertNotError(t, err, "x509.ParseCertificate failed")
3954 ic, err := issuance.NewCertificate(cert)
3955 test.AssertNotError(t, err, "failed to create issuer cert")
3956 ra.issuersByNameID = map[issuance.IssuerNameID]*issuance.Certificate{
3957 ic.NameID(): ic,
3958 }
3959 ra.issuersByID = map[issuance.IssuerID]*issuance.Certificate{
3960 ic.ID(): ic,
3961 }
3962 mockSA := newMockSARevocation(cert, clk)
3963 ra.SA = mockSA
3964
3965
3966 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{})
3967 test.AssertError(t, err, "AdministrativelyRevokeCertificate should have failed for nil request object")
3968
3969
3970 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{
3971 Code: ocsp.Unspecified,
3972 AdminName: "root",
3973 })
3974 test.AssertError(t, err, "AdministrativelyRevokeCertificate should have failed with no cert or serial")
3975
3976
3977 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{
3978 Cert: []byte{},
3979 Code: ocsp.KeyCompromise,
3980 AdminName: "",
3981 })
3982 test.AssertError(t, err, "AdministrativelyRevokeCertificate should have failed for nil `Cert`")
3983
3984
3985 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{
3986 Cert: cert.Raw,
3987 Serial: serial,
3988 Code: ocsp.KeyCompromise,
3989 AdminName: "",
3990 })
3991 test.AssertError(t, err, "AdministrativelyRevokeCertificate should have failed with empty string for `AdminName`")
3992
3993
3994 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{
3995 Cert: cert.Raw,
3996 Serial: serial,
3997 Code: ocsp.CertificateHold,
3998 AdminName: "root",
3999 })
4000 test.AssertError(t, err, "AdministrativelyRevokeCertificate should have failed with forbidden revocation reason")
4001
4002
4003 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{
4004 Cert: cert.Raw,
4005 Serial: serial,
4006 Code: ocsp.Unspecified,
4007 AdminName: "root",
4008 })
4009 test.AssertNotError(t, err, "AdministrativelyRevokeCertificate failed")
4010 test.AssertEquals(t, len(mockSA.blocked), 0)
4011 test.AssertMetricWithLabelsEquals(
4012 t, ra.revocationReasonCounter, prometheus.Labels{"reason": "unspecified"}, 1)
4013
4014
4015 mockSA.revoked = make(map[string]int64)
4016 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{
4017 Serial: core.SerialToString(cert.SerialNumber),
4018 Code: ocsp.Unspecified,
4019 AdminName: "root",
4020 })
4021 test.AssertNotError(t, err, "AdministrativelyRevokeCertificate failed")
4022 test.AssertEquals(t, len(mockSA.blocked), 0)
4023 test.AssertMetricWithLabelsEquals(
4024 t, ra.revocationReasonCounter, prometheus.Labels{"reason": "unspecified"}, 2)
4025
4026
4027
4028 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{
4029 Serial: core.SerialToString(cert.SerialNumber),
4030 Code: ocsp.Unspecified,
4031 AdminName: "root",
4032 })
4033 test.AssertError(t, err, "Should be revoked")
4034 test.AssertContains(t, err.Error(), "already revoked")
4035 test.AssertEquals(t, len(mockSA.blocked), 0)
4036 test.AssertMetricWithLabelsEquals(
4037 t, ra.revocationReasonCounter, prometheus.Labels{"reason": "unspecified"}, 2)
4038
4039
4040 mockSA.revoked = make(map[string]int64)
4041 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{
4042 Cert: cert.Raw,
4043 Serial: serial,
4044 Code: ocsp.KeyCompromise,
4045 AdminName: "root",
4046 })
4047 test.AssertNotError(t, err, "AdministrativelyRevokeCertificate failed")
4048 test.AssertEquals(t, len(mockSA.blocked), 1)
4049 test.Assert(t, bytes.Equal(digest[:], mockSA.blocked[0].KeyHash), "key hash mismatch")
4050 test.AssertEquals(t, mockSA.blocked[0].Source, "admin-revoker")
4051 test.AssertEquals(t, mockSA.blocked[0].Comment, "revoked by root")
4052 test.AssertEquals(t, mockSA.blocked[0].AddedNS, clk.Now().UnixNano())
4053 test.AssertEquals(t, mockSA.blocked[0].Added.AsTime(), clk.Now())
4054 test.AssertMetricWithLabelsEquals(
4055 t, ra.revocationReasonCounter, prometheus.Labels{"reason": "keyCompromise"}, 1)
4056
4057
4058 mockSA.revoked = make(map[string]int64)
4059 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{
4060 Serial: core.SerialToString(cert.SerialNumber),
4061 Code: ocsp.KeyCompromise,
4062 AdminName: "root",
4063 })
4064 test.AssertError(t, err, "AdministrativelyRevokeCertificate should have failed with just serial for keyCompromise")
4065 }
4066
View as plain text