1 package sa
2
3 import (
4 "bytes"
5 "context"
6 "crypto/rand"
7 "crypto/rsa"
8 "crypto/sha256"
9 "crypto/x509"
10 "database/sql"
11 "encoding/base64"
12 "encoding/json"
13 "errors"
14 "fmt"
15 "math/big"
16 "math/bits"
17 mrand "math/rand"
18 "net"
19 "os"
20 "reflect"
21 "strings"
22 "sync"
23 "testing"
24 "time"
25
26 "github.com/go-sql-driver/mysql"
27 "github.com/jmhodges/clock"
28 "github.com/letsencrypt/boulder/core"
29 corepb "github.com/letsencrypt/boulder/core/proto"
30 "github.com/letsencrypt/boulder/db"
31 berrors "github.com/letsencrypt/boulder/errors"
32 "github.com/letsencrypt/boulder/features"
33 bgrpc "github.com/letsencrypt/boulder/grpc"
34 blog "github.com/letsencrypt/boulder/log"
35 "github.com/letsencrypt/boulder/metrics"
36 "github.com/letsencrypt/boulder/probs"
37 "github.com/letsencrypt/boulder/revocation"
38 sapb "github.com/letsencrypt/boulder/sa/proto"
39 "github.com/letsencrypt/boulder/test"
40 "github.com/letsencrypt/boulder/test/vars"
41 "github.com/prometheus/client_golang/prometheus"
42 "golang.org/x/crypto/ocsp"
43 "google.golang.org/grpc"
44 "google.golang.org/protobuf/types/known/durationpb"
45 "google.golang.org/protobuf/types/known/emptypb"
46 "google.golang.org/protobuf/types/known/timestamppb"
47 "gopkg.in/go-jose/go-jose.v2"
48 )
49
50 var log = blog.UseMock()
51 var ctx = context.Background()
52
53 var (
54 theKey = `{
55 "kty": "RSA",
56 "n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw",
57 "e": "AQAB"
58 }`
59 )
60
61 func TestImplementation(t *testing.T) {
62 test.AssertImplementsGRPCServer(t, &SQLStorageAuthority{}, sapb.UnimplementedStorageAuthorityServer{})
63 test.AssertImplementsGRPCServer(t, &SQLStorageAuthorityRO{}, sapb.UnimplementedStorageAuthorityReadOnlyServer{})
64 }
65
66
67
68 func initSA(t *testing.T) (*SQLStorageAuthority, clock.FakeClock, func()) {
69 t.Helper()
70 features.Reset()
71
72 dbMap, err := DBMapForTest(vars.DBConnSA)
73 if err != nil {
74 t.Fatalf("Failed to create dbMap: %s", err)
75 }
76
77 dbIncidentsMap, err := DBMapForTest(vars.DBConnIncidents)
78 if err != nil {
79 t.Fatalf("Failed to create dbMap: %s", err)
80 }
81
82 fc := clock.NewFake()
83 fc.Set(time.Date(2015, 3, 4, 5, 0, 0, 0, time.UTC))
84
85 saro, err := NewSQLStorageAuthorityRO(dbMap, dbIncidentsMap, metrics.NoopRegisterer, 1, 0, fc, log)
86 if err != nil {
87 t.Fatalf("Failed to create SA: %s", err)
88 }
89
90 sa, err := NewSQLStorageAuthorityWrapping(saro, dbMap, metrics.NoopRegisterer)
91 if err != nil {
92 t.Fatalf("Failed to create SA: %s", err)
93 }
94
95 return sa, fc, test.ResetBoulderTestDatabase(t)
96 }
97
98
99
100 func createWorkingRegistration(t *testing.T, sa *SQLStorageAuthority) *corepb.Registration {
101 initialIP, _ := net.ParseIP("88.77.66.11").MarshalText()
102 created := time.Date(2003, 5, 10, 0, 0, 0, 0, time.UTC)
103 reg, err := sa.NewRegistration(context.Background(), &corepb.Registration{
104 Key: []byte(theKey),
105 Contact: []string{"mailto:foo@example.com"},
106 InitialIP: initialIP,
107 CreatedAtNS: created.UnixNano(),
108 CreatedAt: timestamppb.New(created),
109 Status: string(core.StatusValid),
110 })
111 if err != nil {
112 t.Fatalf("Unable to create new registration: %s", err)
113 }
114 return reg
115 }
116
117 func createPendingAuthorization(t *testing.T, sa *SQLStorageAuthority, domain string, exp time.Time) int64 {
118 t.Helper()
119
120 tokenStr := core.NewToken()
121 token, err := base64.RawURLEncoding.DecodeString(tokenStr)
122 test.AssertNotError(t, err, "computing test authorization challenge token")
123
124 am := authzModel{
125 IdentifierType: 0,
126 IdentifierValue: domain,
127 RegistrationID: 1,
128 Status: statusToUint[core.StatusPending],
129 Expires: exp,
130 Challenges: 1 << challTypeToUint[string(core.ChallengeTypeHTTP01)],
131 Token: token,
132 }
133
134 err = sa.dbMap.Insert(context.Background(), &am)
135 test.AssertNotError(t, err, "creating test authorization")
136
137 return am.ID
138 }
139
140 func createFinalizedAuthorization(t *testing.T, sa *SQLStorageAuthority, domain string, exp time.Time,
141 status string, attemptedAt time.Time) int64 {
142 t.Helper()
143 pendingID := createPendingAuthorization(t, sa, domain, exp)
144 attempted := string(core.ChallengeTypeHTTP01)
145 _, err := sa.FinalizeAuthorization2(context.Background(), &sapb.FinalizeAuthorizationRequest{
146 Id: pendingID,
147 Status: status,
148 ExpiresNS: exp.UnixNano(),
149 Expires: timestamppb.New(exp),
150 Attempted: attempted,
151 AttemptedAtNS: attemptedAt.UnixNano(),
152 AttemptedAt: timestamppb.New(attemptedAt),
153 })
154 test.AssertNotError(t, err, "sa.FinalizeAuthorizations2 failed")
155 return pendingID
156 }
157
158 func goodTestJWK() *jose.JSONWebKey {
159 var jwk jose.JSONWebKey
160 err := json.Unmarshal([]byte(theKey), &jwk)
161 if err != nil {
162 panic("known-good theKey is no longer known-good")
163 }
164 return &jwk
165 }
166
167 func TestAddRegistration(t *testing.T) {
168 sa, clk, cleanUp := initSA(t)
169 defer cleanUp()
170
171 jwk := goodTestJWK()
172 jwkJSON, _ := jwk.MarshalJSON()
173
174 contacts := []string{"mailto:foo@example.com"}
175 initialIP, _ := net.ParseIP("43.34.43.34").MarshalText()
176 reg, err := sa.NewRegistration(ctx, &corepb.Registration{
177 Key: jwkJSON,
178 Contact: contacts,
179 InitialIP: initialIP,
180 })
181 if err != nil {
182 t.Fatalf("Couldn't create new registration: %s", err)
183 }
184 test.Assert(t, reg.Id != 0, "ID shouldn't be 0")
185 test.AssertDeepEquals(t, reg.Contact, contacts)
186
187 _, err = sa.GetRegistration(ctx, &sapb.RegistrationID{Id: 0})
188 test.AssertError(t, err, "Registration object for ID 0 was returned")
189
190 dbReg, err := sa.GetRegistration(ctx, &sapb.RegistrationID{Id: reg.Id})
191 test.AssertNotError(t, err, fmt.Sprintf("Couldn't get registration with ID %v", reg.Id))
192
193 createdAt := clk.Now()
194 test.AssertEquals(t, dbReg.Id, reg.Id)
195 test.AssertByteEquals(t, dbReg.Key, jwkJSON)
196 test.AssertDeepEquals(t, dbReg.CreatedAtNS, createdAt.UnixNano())
197
198 initialIP, _ = net.ParseIP("72.72.72.72").MarshalText()
199 newReg := &corepb.Registration{
200 Id: reg.Id,
201 Key: jwkJSON,
202 Contact: []string{"test.com"},
203 InitialIP: initialIP,
204 Agreement: "yes",
205 }
206 _, err = sa.UpdateRegistration(ctx, newReg)
207 test.AssertNotError(t, err, fmt.Sprintf("Couldn't get registration with ID %v", reg.Id))
208 dbReg, err = sa.GetRegistrationByKey(ctx, &sapb.JSONWebKey{Jwk: jwkJSON})
209 test.AssertNotError(t, err, "Couldn't get registration by key")
210
211 test.AssertEquals(t, dbReg.Id, newReg.Id)
212 test.AssertEquals(t, dbReg.Agreement, newReg.Agreement)
213
214 anotherKey := `{
215 "kty":"RSA",
216 "n": "vd7rZIoTLEe-z1_8G1FcXSw9CQFEJgV4g9V277sER7yx5Qjz_Pkf2YVth6wwwFJEmzc0hoKY-MMYFNwBE4hQHw",
217 "e":"AQAB"
218 }`
219
220 _, err = sa.GetRegistrationByKey(ctx, &sapb.JSONWebKey{Jwk: []byte(anotherKey)})
221 test.AssertError(t, err, "Registration object for invalid key was returned")
222 }
223
224 func TestNoSuchRegistrationErrors(t *testing.T) {
225 sa, _, cleanUp := initSA(t)
226 defer cleanUp()
227
228 _, err := sa.GetRegistration(ctx, &sapb.RegistrationID{Id: 100})
229 test.AssertErrorIs(t, err, berrors.NotFound)
230
231 jwk := goodTestJWK()
232 jwkJSON, _ := jwk.MarshalJSON()
233
234 _, err = sa.GetRegistrationByKey(ctx, &sapb.JSONWebKey{Jwk: jwkJSON})
235 test.AssertErrorIs(t, err, berrors.NotFound)
236
237 _, err = sa.UpdateRegistration(ctx, &corepb.Registration{Id: 100, Key: jwkJSON, InitialIP: []byte("foo")})
238 test.AssertErrorIs(t, err, berrors.NotFound)
239 }
240
241 func TestSelectRegistration(t *testing.T) {
242 sa, _, cleanUp := initSA(t)
243 defer cleanUp()
244 var ctx = context.Background()
245 jwk := goodTestJWK()
246 jwkJSON, _ := jwk.MarshalJSON()
247 sha, err := core.KeyDigestB64(jwk.Key)
248 test.AssertNotError(t, err, "couldn't parse jwk.Key")
249
250 initialIP, _ := net.ParseIP("43.34.43.34").MarshalText()
251 reg, err := sa.NewRegistration(ctx, &corepb.Registration{
252 Key: jwkJSON,
253 Contact: []string{"mailto:foo@example.com"},
254 InitialIP: initialIP,
255 })
256 test.AssertNotError(t, err, fmt.Sprintf("couldn't create new registration: %s", err))
257 test.Assert(t, reg.Id != 0, "ID shouldn't be 0")
258
259 _, err = selectRegistration(ctx, sa.dbMap, "id", reg.Id)
260 test.AssertNotError(t, err, "selecting by id should work")
261 _, err = selectRegistration(ctx, sa.dbMap, "jwk_sha256", sha)
262 test.AssertNotError(t, err, "selecting by jwk_sha256 should work")
263 _, err = selectRegistration(ctx, sa.dbMap, "initialIP", reg.Id)
264 test.AssertError(t, err, "selecting by any other column should not work")
265 }
266
267 func TestReplicationLagRetries(t *testing.T) {
268 sa, clk, cleanUp := initSA(t)
269 defer cleanUp()
270
271 reg := createWorkingRegistration(t, sa)
272
273
274
275 sa.lagFactor = 0
276 start := clk.Now()
277
278 _, err := sa.GetRegistration(ctx, &sapb.RegistrationID{Id: reg.Id})
279 test.AssertNotError(t, err, "selecting extant registration")
280 test.AssertEquals(t, clk.Now(), start)
281 test.AssertMetricWithLabelsEquals(t, sa.lagFactorCounter, prometheus.Labels{"method": "GetRegistration", "result": "notfound"}, 0)
282
283 _, err = sa.GetRegistration(ctx, &sapb.RegistrationID{Id: reg.Id + 1})
284 test.AssertError(t, err, "selecting nonexistent registration")
285 test.AssertEquals(t, clk.Now(), start)
286
287
288 test.AssertMetricWithLabelsEquals(t, sa.lagFactorCounter, prometheus.Labels{"method": "GetRegistration", "result": "notfound"}, 0)
289
290
291
292 sa.lagFactor = 1
293 start = clk.Now()
294
295 _, err = sa.GetRegistration(ctx, &sapb.RegistrationID{Id: reg.Id})
296 test.AssertNotError(t, err, "selecting extant registration")
297 test.AssertEquals(t, clk.Now(), start)
298
299 test.AssertMetricWithLabelsEquals(t, sa.lagFactorCounter, prometheus.Labels{"method": "GetRegistration", "result": "notfound"}, 0)
300
301 _, err = sa.GetRegistration(ctx, &sapb.RegistrationID{Id: reg.Id + 1})
302 test.AssertError(t, err, "selecting nonexistent registration")
303 test.AssertEquals(t, clk.Now(), start.Add(1))
304
305
306 test.AssertMetricWithLabelsEquals(t, sa.lagFactorCounter, prometheus.Labels{"method": "GetRegistration", "result": "notfound"}, 1)
307 }
308
309
310
311 func findIssuedName(ctx context.Context, dbMap db.OneSelector, name string) (string, error) {
312 var issuedNamesSerial string
313 err := dbMap.SelectOne(
314 ctx,
315 &issuedNamesSerial,
316 `SELECT serial FROM issuedNames
317 WHERE reversedName = ?
318 ORDER BY notBefore DESC
319 LIMIT 1`,
320 ReverseName(name))
321 return issuedNamesSerial, err
322 }
323
324 func TestAddSerial(t *testing.T) {
325 sa, _, cleanUp := initSA(t)
326 defer cleanUp()
327
328 reg := createWorkingRegistration(t, sa)
329 serial, testCert := test.ThrowAwayCert(t, 1)
330
331 _, err := sa.AddSerial(context.Background(), &sapb.AddSerialRequest{
332 RegID: reg.Id,
333 CreatedNS: testCert.NotBefore.UnixNano(),
334 Created: timestamppb.New(testCert.NotBefore),
335 ExpiresNS: testCert.NotAfter.UnixNano(),
336 Expires: timestamppb.New(testCert.NotAfter),
337 })
338 test.AssertError(t, err, "adding without serial should fail")
339
340 _, err = sa.AddSerial(context.Background(), &sapb.AddSerialRequest{
341 Serial: serial,
342 CreatedNS: testCert.NotBefore.UnixNano(),
343 Created: timestamppb.New(testCert.NotBefore),
344 ExpiresNS: testCert.NotAfter.UnixNano(),
345 Expires: timestamppb.New(testCert.NotAfter),
346 })
347 test.AssertError(t, err, "adding without regid should fail")
348
349 _, err = sa.AddSerial(context.Background(), &sapb.AddSerialRequest{
350 Serial: serial,
351 RegID: reg.Id,
352 ExpiresNS: testCert.NotAfter.UnixNano(),
353 Expires: timestamppb.New(testCert.NotAfter),
354 })
355 test.AssertError(t, err, "adding without created should fail")
356
357 _, err = sa.AddSerial(context.Background(), &sapb.AddSerialRequest{
358 Serial: serial,
359 RegID: reg.Id,
360 CreatedNS: testCert.NotBefore.UnixNano(),
361 Created: timestamppb.New(testCert.NotBefore),
362 })
363 test.AssertError(t, err, "adding without expires should fail")
364
365 _, err = sa.AddSerial(context.Background(), &sapb.AddSerialRequest{
366 Serial: serial,
367 RegID: reg.Id,
368 CreatedNS: testCert.NotBefore.UnixNano(),
369 Created: timestamppb.New(testCert.NotBefore),
370 ExpiresNS: testCert.NotAfter.UnixNano(),
371 Expires: timestamppb.New(testCert.NotAfter),
372 })
373 test.AssertNotError(t, err, "adding serial should have succeeded")
374 }
375
376 func TestGetSerialMetadata(t *testing.T) {
377 sa, clk, cleanUp := initSA(t)
378 defer cleanUp()
379
380 reg := createWorkingRegistration(t, sa)
381 serial, _ := test.ThrowAwayCert(t, 1)
382
383 _, err := sa.GetSerialMetadata(context.Background(), &sapb.Serial{Serial: serial})
384 test.AssertError(t, err, "getting nonexistent serial should have failed")
385
386 now := clk.Now()
387 hourLater := now.Add(time.Hour)
388 _, err = sa.AddSerial(context.Background(), &sapb.AddSerialRequest{
389 Serial: serial,
390 RegID: reg.Id,
391 CreatedNS: now.UnixNano(),
392 Created: timestamppb.New(now),
393 ExpiresNS: hourLater.UnixNano(),
394 Expires: timestamppb.New(hourLater),
395 })
396 test.AssertNotError(t, err, "failed to add test serial")
397
398 m, err := sa.GetSerialMetadata(context.Background(), &sapb.Serial{Serial: serial})
399
400 test.AssertNotError(t, err, "getting serial should have succeeded")
401 test.AssertEquals(t, m.Serial, serial)
402 test.AssertEquals(t, m.RegistrationID, reg.Id)
403 test.AssertEquals(t, time.Unix(0, m.CreatedNS).UTC(), now)
404 test.AssertEquals(t, now, timestamppb.New(now).AsTime())
405 test.AssertEquals(t, time.Unix(0, m.ExpiresNS).UTC(), hourLater)
406 test.AssertEquals(t, m.Expires.AsTime(), timestamppb.New(hourLater).AsTime())
407 }
408
409 func TestAddPrecertificate(t *testing.T) {
410 ctx := context.Background()
411 sa, clk, cleanUp := initSA(t)
412 defer cleanUp()
413
414 reg := createWorkingRegistration(t, sa)
415
416
417
418 serial, testCert := test.ThrowAwayCert(t, 1)
419
420
421 regID := reg.Id
422 issuedTime := time.Date(2018, 4, 1, 7, 0, 0, 0, time.UTC)
423 _, err := sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
424 Der: testCert.Raw,
425 RegID: regID,
426 IssuedNS: issuedTime.UnixNano(),
427 Issued: timestamppb.New(issuedTime),
428 IssuerNameID: 1,
429 })
430 test.AssertNotError(t, err, "Couldn't add test cert")
431
432
433 certStatus, err := sa.GetCertificateStatus(ctx, &sapb.Serial{Serial: serial})
434 test.AssertNotError(t, err, "Couldn't get status for test cert")
435 test.AssertEquals(t, certStatus.Status, string(core.OCSPStatusGood))
436 now := clk.Now()
437 test.AssertEquals(t, now.UnixNano(), certStatus.OcspLastUpdatedNS)
438 test.AssertEquals(t, now, certStatus.OcspLastUpdated.AsTime())
439
440
441 issuedNamesSerial, err := findIssuedName(ctx, sa.dbMap, testCert.DNSNames[0])
442 test.AssertNotError(t, err, "expected no err querying issuedNames for precert")
443 test.AssertEquals(t, issuedNamesSerial, serial)
444
445
446
447
448 _, err = sa.AddCertificate(ctx, &sapb.AddCertificateRequest{
449 Der: testCert.Raw,
450 RegID: regID,
451 IssuedNS: issuedTime.UnixNano(),
452 Issued: timestamppb.New(issuedTime),
453 })
454 test.AssertNotError(t, err, "unexpected err adding final cert after precert")
455 }
456
457 func TestAddPrecertificateNoOCSP(t *testing.T) {
458 sa, _, cleanUp := initSA(t)
459 defer cleanUp()
460
461 reg := createWorkingRegistration(t, sa)
462 _, testCert := test.ThrowAwayCert(t, 1)
463
464 regID := reg.Id
465 issuedTime := time.Date(2018, 4, 1, 7, 0, 0, 0, time.UTC)
466 _, err := sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
467 Der: testCert.Raw,
468 RegID: regID,
469 IssuedNS: issuedTime.UnixNano(),
470 Issued: timestamppb.New(issuedTime),
471 IssuerNameID: 1,
472 })
473 test.AssertNotError(t, err, "Couldn't add test cert")
474 }
475
476 func TestAddPreCertificateDuplicate(t *testing.T) {
477 sa, clk, cleanUp := initSA(t)
478 defer cleanUp()
479
480 reg := createWorkingRegistration(t, sa)
481
482 _, testCert := test.ThrowAwayCert(t, 1)
483 issuedTime := clk.Now()
484 _, err := sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
485 Der: testCert.Raw,
486 IssuedNS: issuedTime.UnixNano(),
487 Issued: timestamppb.New(issuedTime),
488 RegID: reg.Id,
489 IssuerNameID: 1,
490 })
491 test.AssertNotError(t, err, "Couldn't add test certificate")
492
493 _, err = sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
494 Der: testCert.Raw,
495 IssuedNS: issuedTime.UnixNano(),
496 Issued: timestamppb.New(issuedTime),
497 RegID: reg.Id,
498 IssuerNameID: 1,
499 })
500 test.AssertDeepEquals(t, err, berrors.DuplicateError("cannot add a duplicate cert"))
501 }
502
503 func TestAddPrecertificateIncomplete(t *testing.T) {
504 sa, _, cleanUp := initSA(t)
505 defer cleanUp()
506
507 reg := createWorkingRegistration(t, sa)
508
509
510
511 _, testCert := test.ThrowAwayCert(t, 1)
512
513
514 regID := reg.Id
515 issuedTime := time.Date(2018, 4, 1, 7, 0, 0, 0, time.UTC)
516 _, err := sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
517 Der: testCert.Raw,
518 RegID: regID,
519 IssuedNS: issuedTime.UnixNano(),
520 Issued: timestamppb.New(issuedTime),
521
522 })
523
524 test.AssertError(t, err, "Adding precert with no issuer did not fail")
525 }
526
527 func TestAddPrecertificateKeyHash(t *testing.T) {
528 sa, _, cleanUp := initSA(t)
529 defer cleanUp()
530 reg := createWorkingRegistration(t, sa)
531
532 serial, testCert := test.ThrowAwayCert(t, 1)
533 _, err := sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
534 Der: testCert.Raw,
535 RegID: reg.Id,
536 IssuedNS: testCert.NotBefore.UnixNano(),
537 Issued: timestamppb.New(testCert.NotBefore),
538 IssuerNameID: 1,
539 })
540 test.AssertNotError(t, err, "failed to add precert")
541
542 var keyHashes []keyHashModel
543 _, err = sa.dbMap.Select(context.Background(), &keyHashes, "SELECT * FROM keyHashToSerial")
544 test.AssertNotError(t, err, "failed to retrieve rows from keyHashToSerial")
545 test.AssertEquals(t, len(keyHashes), 1)
546 test.AssertEquals(t, keyHashes[0].CertSerial, serial)
547 test.AssertEquals(t, keyHashes[0].CertNotAfter, testCert.NotAfter)
548 test.AssertEquals(t, keyHashes[0].CertNotAfter, timestamppb.New(testCert.NotAfter).AsTime())
549 spkiHash := sha256.Sum256(testCert.RawSubjectPublicKeyInfo)
550 test.Assert(t, bytes.Equal(keyHashes[0].KeyHash, spkiHash[:]), "spki hash mismatch")
551 }
552
553 func TestAddCertificate(t *testing.T) {
554 sa, _, cleanUp := initSA(t)
555 defer cleanUp()
556
557 reg := createWorkingRegistration(t, sa)
558
559
560 certDER, err := os.ReadFile("www.eff.org.der")
561 test.AssertNotError(t, err, "Couldn't read example cert DER")
562
563
564 issuedTime := sa.clk.Now()
565 _, err = sa.AddCertificate(ctx, &sapb.AddCertificateRequest{
566 Der: certDER,
567 RegID: reg.Id,
568 IssuedNS: issuedTime.UnixNano(),
569 Issued: timestamppb.New(issuedTime),
570 })
571 test.AssertNotError(t, err, "Couldn't add www.eff.org.der")
572
573 retrievedCert, err := sa.GetCertificate(ctx, &sapb.Serial{Serial: "000000000000000000000000000000021bd4"})
574 test.AssertNotError(t, err, "Couldn't get www.eff.org.der by full serial")
575 test.AssertByteEquals(t, certDER, retrievedCert.Der)
576
577
578 test.AssertEquals(t, retrievedCert.IssuedNS, issuedTime.UnixNano())
579 test.AssertEquals(t, retrievedCert.Issued.AsTime(), issuedTime)
580
581
582
583 certDER2, err := os.ReadFile("test-cert.der")
584 test.AssertNotError(t, err, "Couldn't read example cert DER")
585 serial := "ffdd9b8a82126d96f61d378d5ba99a0474f0"
586
587
588 issuedTime = time.Date(2018, 4, 1, 7, 0, 0, 0, time.UTC)
589 _, err = sa.AddCertificate(ctx, &sapb.AddCertificateRequest{
590 Der: certDER2,
591 RegID: reg.Id,
592 IssuedNS: issuedTime.UnixNano(),
593 Issued: timestamppb.New(issuedTime),
594 })
595 test.AssertNotError(t, err, "Couldn't add test-cert.der")
596
597 retrievedCert2, err := sa.GetCertificate(ctx, &sapb.Serial{Serial: serial})
598 test.AssertNotError(t, err, "Couldn't get test-cert.der")
599 test.AssertByteEquals(t, certDER2, retrievedCert2.Der)
600
601
602 test.AssertEquals(t, retrievedCert2.IssuedNS, issuedTime.UnixNano())
603 test.AssertEquals(t, retrievedCert2.Issued.AsTime(), issuedTime)
604 }
605
606 func TestAddCertificateDuplicate(t *testing.T) {
607 sa, clk, cleanUp := initSA(t)
608 defer cleanUp()
609
610 reg := createWorkingRegistration(t, sa)
611
612 _, testCert := test.ThrowAwayCert(t, 1)
613
614 issuedTime := clk.Now()
615 _, err := sa.AddCertificate(ctx, &sapb.AddCertificateRequest{
616 Der: testCert.Raw,
617 RegID: reg.Id,
618 IssuedNS: issuedTime.UnixNano(),
619 Issued: timestamppb.New(issuedTime),
620 })
621 test.AssertNotError(t, err, "Couldn't add test certificate")
622
623 _, err = sa.AddCertificate(ctx, &sapb.AddCertificateRequest{
624 Der: testCert.Raw,
625 RegID: reg.Id,
626 IssuedNS: issuedTime.UnixNano(),
627 Issued: timestamppb.New(issuedTime),
628 })
629 test.AssertDeepEquals(t, err, berrors.DuplicateError("cannot add a duplicate cert"))
630
631 }
632
633 func TestCountCertificatesByNames(t *testing.T) {
634 sa, clk, cleanUp := initSA(t)
635 defer cleanUp()
636
637
638
639 certDER, err := os.ReadFile("test-cert.der")
640 test.AssertNotError(t, err, "Couldn't read example cert DER")
641
642 cert, err := x509.ParseCertificate(certDER)
643 test.AssertNotError(t, err, "Couldn't parse example cert DER")
644
645
646
647 clk.Add(time.Hour - clk.Now().Sub(cert.NotBefore))
648 now := clk.Now()
649 yesterday := clk.Now().Add(-24 * time.Hour)
650 twoDaysAgo := clk.Now().Add(-48 * time.Hour)
651 tomorrow := clk.Now().Add(24 * time.Hour)
652
653
654 req := &sapb.CountCertificatesByNamesRequest{
655 Names: []string{"example.com"},
656 Range: &sapb.Range{
657 EarliestNS: yesterday.UnixNano(),
658 Earliest: timestamppb.New(yesterday),
659 LatestNS: now.UnixNano(),
660 Latest: timestamppb.New(now),
661 },
662 }
663 counts, err := sa.CountCertificatesByNames(ctx, req)
664 test.AssertNotError(t, err, "Error counting certs.")
665 test.AssertEquals(t, len(counts.Counts), 1)
666 test.AssertEquals(t, counts.Counts["example.com"], int64(0))
667
668
669 reg := createWorkingRegistration(t, sa)
670 issued := sa.clk.Now()
671 _, err = sa.AddCertificate(ctx, &sapb.AddCertificateRequest{
672 Der: certDER,
673 RegID: reg.Id,
674 IssuedNS: issued.UnixNano(),
675 Issued: timestamppb.New(issued),
676 })
677 test.AssertNotError(t, err, "Couldn't add test-cert.der")
678
679
680 counts, err = sa.CountCertificatesByNames(ctx, req)
681 test.AssertNotError(t, err, "sa.CountCertificatesByName failed")
682 test.AssertEquals(t, len(counts.Counts), 1)
683 test.AssertEquals(t, counts.Counts["example.com"], int64(1))
684
685
686 req.Range.EarliestNS = twoDaysAgo.UnixNano()
687 req.Range.Earliest = timestamppb.New(twoDaysAgo)
688 req.Range.LatestNS = yesterday.UnixNano()
689 req.Range.Latest = timestamppb.New(yesterday)
690 counts, err = sa.CountCertificatesByNames(ctx, req)
691 test.AssertNotError(t, err, "Error counting certs.")
692 test.AssertEquals(t, len(counts.Counts), 1)
693 test.AssertEquals(t, counts.Counts["example.com"], int64(0))
694
695
696
697 req.Range.EarliestNS = now.UnixNano()
698 req.Range.Earliest = timestamppb.New(now)
699 req.Range.LatestNS = tomorrow.UnixNano()
700 req.Range.Latest = timestamppb.New(tomorrow)
701 counts, err = sa.CountCertificatesByNames(ctx, req)
702 test.AssertNotError(t, err, "Error counting certs.")
703 test.AssertEquals(t, len(counts.Counts), 1)
704 test.AssertEquals(t, counts.Counts["example.com"], int64(0))
705
706
707 names := []string{"example.com", "foo.com", "example.co.bn"}
708
709
710
711
712 var interlocker sync.WaitGroup
713 interlocker.Add(len(names))
714 sa.parallelismPerRPC = len(names)
715 oldCertCountFunc := sa.countCertificatesByName
716 sa.countCertificatesByName = func(ctx context.Context, sel db.Selector, domain string, timeRange *sapb.Range) (int64, time.Time, error) {
717 interlocker.Done()
718 interlocker.Wait()
719 return oldCertCountFunc(ctx, sel, domain, timeRange)
720 }
721
722 certDER2, err := os.ReadFile("test-cert2.der")
723 test.AssertNotError(t, err, "Couldn't read test-cert2.der")
724 _, err = sa.AddCertificate(ctx, &sapb.AddCertificateRequest{
725 Der: certDER2,
726 RegID: reg.Id,
727 IssuedNS: issued.UnixNano(),
728 Issued: timestamppb.New(issued),
729 })
730 test.AssertNotError(t, err, "Couldn't add test-cert2.der")
731 req.Names = names
732 req.Range.EarliestNS = yesterday.UnixNano()
733 req.Range.Earliest = timestamppb.New(yesterday)
734 req.Range.LatestNS = now.Add(10000 * time.Hour).UnixNano()
735 req.Range.Latest = timestamppb.New(now.Add(10000 * time.Hour))
736 counts, err = sa.CountCertificatesByNames(ctx, req)
737 test.AssertNotError(t, err, "Error counting certs.")
738 test.AssertEquals(t, len(counts.Counts), 3)
739
740 expected := map[string]int64{
741 "example.co.bn": 1,
742 "foo.com": 0,
743 "example.com": 1,
744 }
745 for name, count := range counts.Counts {
746 domain := name
747 actualCount := count
748 expectedCount := expected[domain]
749 test.AssertEquals(t, actualCount, expectedCount)
750 }
751 }
752
753 func TestCountRegistrationsByIP(t *testing.T) {
754 sa, fc, cleanUp := initSA(t)
755 defer cleanUp()
756
757 contact := []string{"mailto:foo@example.com"}
758
759
760 key, _ := jose.JSONWebKey{Key: &rsa.PublicKey{N: big.NewInt(1), E: 1}}.MarshalJSON()
761 initialIP, _ := net.ParseIP("43.34.43.34").MarshalText()
762 _, err := sa.NewRegistration(ctx, &corepb.Registration{
763 Key: key,
764 InitialIP: initialIP,
765 Contact: contact,
766 })
767
768 key, _ = jose.JSONWebKey{Key: &rsa.PublicKey{N: big.NewInt(2), E: 1}}.MarshalJSON()
769 initialIP, _ = net.ParseIP("2001:cdba:1234:5678:9101:1121:3257:9652").MarshalText()
770 test.AssertNotError(t, err, "Couldn't insert registration")
771 _, err = sa.NewRegistration(ctx, &corepb.Registration{
772 Key: key,
773 InitialIP: initialIP,
774 Contact: contact,
775 })
776 test.AssertNotError(t, err, "Couldn't insert registration")
777 key, _ = jose.JSONWebKey{Key: &rsa.PublicKey{N: big.NewInt(3), E: 1}}.MarshalJSON()
778 initialIP, _ = net.ParseIP("2001:cdba:1234:5678:9101:1121:3257:9653").MarshalText()
779 _, err = sa.NewRegistration(ctx, &corepb.Registration{
780 Key: key,
781 InitialIP: initialIP,
782 Contact: contact,
783 })
784 test.AssertNotError(t, err, "Couldn't insert registration")
785
786 latest := fc.Now()
787 earliest := latest.Add(-time.Hour * 24)
788 req := &sapb.CountRegistrationsByIPRequest{
789 Ip: net.ParseIP("1.1.1.1"),
790 Range: &sapb.Range{
791 EarliestNS: earliest.UnixNano(),
792 Earliest: timestamppb.New(earliest),
793 LatestNS: latest.UnixNano(),
794 Latest: timestamppb.New(latest),
795 },
796 }
797
798
799
800 count, err := sa.CountRegistrationsByIP(ctx, req)
801 test.AssertNotError(t, err, "Failed to count registrations")
802 test.AssertEquals(t, count.Count, int64(0))
803
804
805 req.Ip = net.ParseIP("43.34.43.34")
806 count, err = sa.CountRegistrationsByIP(ctx, req)
807 test.AssertNotError(t, err, "Failed to count registrations")
808 test.AssertEquals(t, count.Count, int64(1))
809
810
811 req.Ip = net.ParseIP("2001:cdba:1234:5678:9101:1121:3257:9652")
812 count, err = sa.CountRegistrationsByIP(ctx, req)
813 test.AssertNotError(t, err, "Failed to count registrations")
814 test.AssertEquals(t, count.Count, int64(1))
815
816
817 req.Ip = net.ParseIP("2001:cdba:1234:5678:9101:1121:3257:9653")
818 count, err = sa.CountRegistrationsByIP(ctx, req)
819 test.AssertNotError(t, err, "Failed to count registrations")
820 test.AssertEquals(t, count.Count, int64(1))
821
822
823 req.Ip = net.ParseIP("2001:cdba:1234:0000:0000:0000:0000:0000")
824 count, err = sa.CountRegistrationsByIP(ctx, req)
825 test.AssertNotError(t, err, "Failed to count registrations")
826 test.AssertEquals(t, count.Count, int64(0))
827 }
828
829 func TestCountRegistrationsByIPRange(t *testing.T) {
830 sa, fc, cleanUp := initSA(t)
831 defer cleanUp()
832
833 contact := []string{"mailto:foo@example.com"}
834
835
836 key, _ := jose.JSONWebKey{Key: &rsa.PublicKey{N: big.NewInt(1), E: 1}}.MarshalJSON()
837 initialIP, _ := net.ParseIP("43.34.43.34").MarshalText()
838 _, err := sa.NewRegistration(ctx, &corepb.Registration{
839 Key: key,
840 InitialIP: initialIP,
841 Contact: contact,
842 })
843
844 key, _ = jose.JSONWebKey{Key: &rsa.PublicKey{N: big.NewInt(2), E: 1}}.MarshalJSON()
845 initialIP, _ = net.ParseIP("2001:cdba:1234:5678:9101:1121:3257:9652").MarshalText()
846 test.AssertNotError(t, err, "Couldn't insert registration")
847 _, err = sa.NewRegistration(ctx, &corepb.Registration{
848 Key: key,
849 InitialIP: initialIP,
850 Contact: contact,
851 })
852 test.AssertNotError(t, err, "Couldn't insert registration")
853 key, _ = jose.JSONWebKey{Key: &rsa.PublicKey{N: big.NewInt(3), E: 1}}.MarshalJSON()
854 initialIP, _ = net.ParseIP("2001:cdba:1234:5678:9101:1121:3257:9653").MarshalText()
855 _, err = sa.NewRegistration(ctx, &corepb.Registration{
856 Key: key,
857 InitialIP: initialIP,
858 Contact: contact,
859 })
860 test.AssertNotError(t, err, "Couldn't insert registration")
861
862 latest := fc.Now()
863 earliest := latest.Add(-time.Hour * 24)
864 req := &sapb.CountRegistrationsByIPRequest{
865 Ip: net.ParseIP("1.1.1.1"),
866 Range: &sapb.Range{
867 EarliestNS: earliest.UnixNano(),
868 Earliest: timestamppb.New(earliest),
869 LatestNS: latest.UnixNano(),
870 Latest: timestamppb.New(latest),
871 },
872 }
873
874
875
876 req.Ip = net.ParseIP("1.1.1.1")
877 count, err := sa.CountRegistrationsByIPRange(ctx, req)
878 test.AssertNotError(t, err, "Failed to count registrations")
879 test.AssertEquals(t, count.Count, int64(0))
880
881
882 req.Ip = net.ParseIP("43.34.43.34")
883 count, err = sa.CountRegistrationsByIPRange(ctx, req)
884 test.AssertNotError(t, err, "Failed to count registrations")
885 test.AssertEquals(t, count.Count, int64(1))
886
887
888 req.Ip = net.ParseIP("2001:cdba:1234:5678:9101:1121:3257:9652")
889 count, err = sa.CountRegistrationsByIPRange(ctx, req)
890 test.AssertNotError(t, err, "Failed to count registrations")
891 test.AssertEquals(t, count.Count, int64(2))
892
893
894 req.Ip = net.ParseIP("2001:cdba:1234:5678:9101:1121:3257:9653")
895 count, err = sa.CountRegistrationsByIPRange(ctx, req)
896 test.AssertNotError(t, err, "Failed to count registrations")
897 test.AssertEquals(t, count.Count, int64(2))
898
899
900 req.Ip = net.ParseIP("2001:cdba:1234:0000:0000:0000:0000:0000")
901 count, err = sa.CountRegistrationsByIPRange(ctx, req)
902 test.AssertNotError(t, err, "Failed to count registrations")
903 test.AssertEquals(t, count.Count, int64(2))
904 }
905
906 func TestFQDNSets(t *testing.T) {
907 ctx := context.Background()
908 sa, fc, cleanUp := initSA(t)
909 defer cleanUp()
910
911 tx, err := sa.dbMap.BeginTx(ctx)
912 test.AssertNotError(t, err, "Failed to open transaction")
913 names := []string{"a.example.com", "B.example.com"}
914 expires := fc.Now().Add(time.Hour * 2).UTC()
915 issued := fc.Now()
916 err = addFQDNSet(ctx, tx, names, "serial", issued, expires)
917 test.AssertNotError(t, err, "Failed to add name set")
918 test.AssertNotError(t, tx.Commit(), "Failed to commit transaction")
919
920 threeHours := time.Hour * 3
921 req := &sapb.CountFQDNSetsRequest{
922 Domains: names,
923 WindowNS: threeHours.Nanoseconds(),
924 Window: durationpb.New(threeHours),
925 }
926 test.AssertEquals(t, time.Duration(req.WindowNS), req.Window.AsDuration())
927
928 count, err := sa.CountFQDNSets(ctx, req)
929 test.AssertNotError(t, err, "Failed to count name sets")
930 test.AssertEquals(t, count.Count, int64(1))
931
932
933 req.Domains = []string{"b.example.com", "A.example.COM"}
934 count, err = sa.CountFQDNSets(ctx, req)
935 test.AssertNotError(t, err, "Failed to count name sets")
936 test.AssertEquals(t, count.Count, int64(1))
937
938
939 tx, err = sa.dbMap.BeginTx(ctx)
940 test.AssertNotError(t, err, "Failed to open transaction")
941 err = addFQDNSet(ctx, tx, names, "anotherSerial", issued, expires)
942 test.AssertNotError(t, err, "Failed to add name set")
943 test.AssertNotError(t, tx.Commit(), "Failed to commit transaction")
944
945
946 req.Domains = names
947 count, err = sa.CountFQDNSets(ctx, req)
948 test.AssertNotError(t, err, "Failed to count name sets")
949 test.AssertEquals(t, count.Count, int64(2))
950
951
952 tx, err = sa.dbMap.BeginTx(ctx)
953 test.AssertNotError(t, err, "Failed to open transaction")
954 err = addFQDNSet(
955 ctx,
956 tx,
957 names,
958 "yetAnotherSerial",
959 issued.Add(-threeHours),
960 expires.Add(-threeHours),
961 )
962 test.AssertNotError(t, err, "Failed to add name set")
963 test.AssertNotError(t, tx.Commit(), "Failed to commit transaction")
964
965
966 count, err = sa.CountFQDNSets(ctx, req)
967 test.AssertNotError(t, err, "Failed to count name sets")
968 test.AssertEquals(t, count.Count, int64(2))
969 }
970
971 func TestFQDNSetTimestampsForWindow(t *testing.T) {
972 sa, fc, cleanUp := initSA(t)
973 defer cleanUp()
974
975 tx, err := sa.dbMap.BeginTx(ctx)
976 test.AssertNotError(t, err, "Failed to open transaction")
977
978 names := []string{"a.example.com", "B.example.com"}
979 window := time.Hour * 3
980 req := &sapb.CountFQDNSetsRequest{
981 Domains: names,
982 WindowNS: window.Nanoseconds(),
983 Window: durationpb.New(window),
984 }
985 test.AssertEquals(t, time.Duration(req.WindowNS), req.Window.AsDuration())
986
987
988 resp, err := sa.FQDNSetTimestampsForWindow(ctx, req)
989 test.AssertNotError(t, err, "Failed to count name sets")
990 test.AssertEquals(t, len(resp.TimestampsNS), 0)
991
992
993 expires := fc.Now().Add(time.Hour * 2).UTC()
994 firstIssued := fc.Now()
995 err = addFQDNSet(ctx, tx, names, "serial", firstIssued, expires)
996 test.AssertNotError(t, err, "Failed to add name set")
997 test.AssertNotError(t, tx.Commit(), "Failed to commit transaction")
998
999
1000 resp, err = sa.FQDNSetTimestampsForWindow(ctx, req)
1001 test.AssertNotError(t, err, "Failed to count name sets")
1002 test.AssertEquals(t, len(resp.TimestampsNS), 1)
1003 test.AssertEquals(t, firstIssued, time.Unix(0, resp.TimestampsNS[len(resp.TimestampsNS)-1]).UTC())
1004
1005
1006 req.Domains = []string{"b.example.com", "A.example.COM"}
1007 resp, err = sa.FQDNSetTimestampsForWindow(ctx, req)
1008 test.AssertNotError(t, err, "Failed to count name sets")
1009 test.AssertEquals(t, len(resp.TimestampsNS), 1)
1010 test.AssertEquals(t, firstIssued, time.Unix(0, resp.TimestampsNS[len(resp.TimestampsNS)-1]).UTC())
1011
1012
1013 tx, err = sa.dbMap.BeginTx(ctx)
1014 test.AssertNotError(t, err, "Failed to open transaction")
1015 err = addFQDNSet(ctx, tx, names, "anotherSerial", firstIssued, expires)
1016 test.AssertNotError(t, err, "Failed to add name set")
1017 test.AssertNotError(t, tx.Commit(), "Failed to commit transaction")
1018
1019
1020 req.Domains = names
1021 resp, err = sa.FQDNSetTimestampsForWindow(ctx, req)
1022 test.AssertNotError(t, err, "Failed to count name sets")
1023 test.AssertEquals(t, len(resp.TimestampsNS), 2)
1024 test.AssertEquals(t, firstIssued, time.Unix(0, resp.TimestampsNS[len(resp.TimestampsNS)-1]).UTC())
1025
1026
1027 tx, err = sa.dbMap.BeginTx(ctx)
1028 test.AssertNotError(t, err, "Failed to open transaction")
1029 err = addFQDNSet(ctx, tx, names, "yetAnotherSerial", firstIssued.Add(-window), expires)
1030 test.AssertNotError(t, err, "Failed to add name set")
1031 test.AssertNotError(t, tx.Commit(), "Failed to commit transaction")
1032
1033
1034 resp, err = sa.FQDNSetTimestampsForWindow(ctx, req)
1035 test.AssertNotError(t, err, "Failed to count name sets")
1036 test.AssertEquals(t, len(resp.TimestampsNS), 2)
1037 test.AssertEquals(t, firstIssued, time.Unix(0, resp.TimestampsNS[len(resp.TimestampsNS)-1]).UTC())
1038 }
1039
1040 func TestFQDNSetsExists(t *testing.T) {
1041 sa, fc, cleanUp := initSA(t)
1042 defer cleanUp()
1043
1044 names := []string{"a.example.com", "B.example.com"}
1045 exists, err := sa.FQDNSetExists(ctx, &sapb.FQDNSetExistsRequest{Domains: names})
1046 test.AssertNotError(t, err, "Failed to check FQDN set existence")
1047 test.Assert(t, !exists.Exists, "FQDN set shouldn't exist")
1048
1049 tx, err := sa.dbMap.BeginTx(ctx)
1050 test.AssertNotError(t, err, "Failed to open transaction")
1051 expires := fc.Now().Add(time.Hour * 2).UTC()
1052 issued := fc.Now()
1053 err = addFQDNSet(ctx, tx, names, "serial", issued, expires)
1054 test.AssertNotError(t, err, "Failed to add name set")
1055 test.AssertNotError(t, tx.Commit(), "Failed to commit transaction")
1056
1057 exists, err = sa.FQDNSetExists(ctx, &sapb.FQDNSetExistsRequest{Domains: names})
1058 test.AssertNotError(t, err, "Failed to check FQDN set existence")
1059 test.Assert(t, exists.Exists, "FQDN set does exist")
1060 }
1061
1062 type queryRecorder struct {
1063 query string
1064 args []interface{}
1065 }
1066
1067 func (e *queryRecorder) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
1068 e.query = query
1069 e.args = args
1070 return nil, nil
1071 }
1072
1073 func TestAddIssuedNames(t *testing.T) {
1074 serial := big.NewInt(1)
1075 expectedSerial := "000000000000000000000000000000000001"
1076 notBefore := time.Date(2018, 2, 14, 12, 0, 0, 0, time.UTC)
1077 placeholdersPerName := "(?,?,?,?)"
1078 baseQuery := "INSERT INTO issuedNames (reversedName,serial,notBefore,renewal) VALUES"
1079
1080 testCases := []struct {
1081 Name string
1082 IssuedNames []string
1083 SerialNumber *big.Int
1084 NotBefore time.Time
1085 Renewal bool
1086 ExpectedArgs []interface{}
1087 }{
1088 {
1089 Name: "One domain, not a renewal",
1090 IssuedNames: []string{"example.co.uk"},
1091 SerialNumber: serial,
1092 NotBefore: notBefore,
1093 Renewal: false,
1094 ExpectedArgs: []interface{}{
1095 "uk.co.example",
1096 expectedSerial,
1097 notBefore,
1098 false,
1099 },
1100 },
1101 {
1102 Name: "Two domains, not a renewal",
1103 IssuedNames: []string{"example.co.uk", "example.xyz"},
1104 SerialNumber: serial,
1105 NotBefore: notBefore,
1106 Renewal: false,
1107 ExpectedArgs: []interface{}{
1108 "uk.co.example",
1109 expectedSerial,
1110 notBefore,
1111 false,
1112 "xyz.example",
1113 expectedSerial,
1114 notBefore,
1115 false,
1116 },
1117 },
1118 {
1119 Name: "One domain, renewal",
1120 IssuedNames: []string{"example.co.uk"},
1121 SerialNumber: serial,
1122 NotBefore: notBefore,
1123 Renewal: true,
1124 ExpectedArgs: []interface{}{
1125 "uk.co.example",
1126 expectedSerial,
1127 notBefore,
1128 true,
1129 },
1130 },
1131 {
1132 Name: "Two domains, renewal",
1133 IssuedNames: []string{"example.co.uk", "example.xyz"},
1134 SerialNumber: serial,
1135 NotBefore: notBefore,
1136 Renewal: true,
1137 ExpectedArgs: []interface{}{
1138 "uk.co.example",
1139 expectedSerial,
1140 notBefore,
1141 true,
1142 "xyz.example",
1143 expectedSerial,
1144 notBefore,
1145 true,
1146 },
1147 },
1148 }
1149
1150 for _, tc := range testCases {
1151 t.Run(tc.Name, func(t *testing.T) {
1152 var e queryRecorder
1153 err := addIssuedNames(
1154 ctx,
1155 &e,
1156 &x509.Certificate{
1157 DNSNames: tc.IssuedNames,
1158 SerialNumber: tc.SerialNumber,
1159 NotBefore: tc.NotBefore,
1160 },
1161 tc.Renewal)
1162 test.AssertNotError(t, err, "addIssuedNames failed")
1163 expectedPlaceholders := placeholdersPerName
1164 for i := 0; i < len(tc.IssuedNames)-1; i++ {
1165 expectedPlaceholders = fmt.Sprintf("%s,%s", expectedPlaceholders, placeholdersPerName)
1166 }
1167 expectedQuery := fmt.Sprintf("%s %s", baseQuery, expectedPlaceholders)
1168 test.AssertEquals(t, e.query, expectedQuery)
1169 if !reflect.DeepEqual(e.args, tc.ExpectedArgs) {
1170 t.Errorf("Wrong args: got\n%#v, expected\n%#v", e.args, tc.ExpectedArgs)
1171 }
1172 })
1173 }
1174 }
1175
1176 func TestPreviousCertificateExists(t *testing.T) {
1177 sa, _, cleanUp := initSA(t)
1178 defer cleanUp()
1179
1180 reg := createWorkingRegistration(t, sa)
1181
1182
1183 certDER, err := os.ReadFile("www.eff.org.der")
1184 test.AssertNotError(t, err, "reading cert DER")
1185
1186 issued := sa.clk.Now()
1187 _, err = sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
1188 Der: certDER,
1189 IssuedNS: issued.UnixNano(),
1190 Issued: timestamppb.New(issued),
1191 RegID: reg.Id,
1192 IssuerNameID: 1,
1193 })
1194 test.AssertNotError(t, err, "Failed to add precertificate")
1195 _, err = sa.AddCertificate(ctx, &sapb.AddCertificateRequest{
1196 Der: certDER,
1197 RegID: reg.Id,
1198 IssuedNS: issued.UnixNano(),
1199 Issued: timestamppb.New(issued),
1200 })
1201 test.AssertNotError(t, err, "calling AddCertificate")
1202
1203 cases := []struct {
1204 name string
1205 domain string
1206 regID int64
1207 expected bool
1208 }{
1209 {"matches", "www.eff.org", reg.Id, true},
1210 {"wrongDomain", "wwoof.org", reg.Id, false},
1211 {"wrongAccount", "www.eff.org", 3333, false},
1212 }
1213
1214 for _, testCase := range cases {
1215 t.Run(testCase.name, func(t *testing.T) {
1216 exists, err := sa.PreviousCertificateExists(context.Background(),
1217 &sapb.PreviousCertificateExistsRequest{
1218 Domain: testCase.domain,
1219 RegID: testCase.regID,
1220 })
1221 test.AssertNotError(t, err, "calling PreviousCertificateExists")
1222 if exists.Exists != testCase.expected {
1223 t.Errorf("wanted %v got %v", testCase.expected, exists.Exists)
1224 }
1225 })
1226 }
1227 }
1228
1229 func TestDeactivateAuthorization2(t *testing.T) {
1230 sa, fc, cleanUp := initSA(t)
1231 defer cleanUp()
1232
1233
1234 expires := fc.Now().Add(time.Hour).UTC()
1235 attemptedAt := fc.Now()
1236 authzID := createPendingAuthorization(t, sa, "example.com", expires)
1237 _, err := sa.DeactivateAuthorization2(context.Background(), &sapb.AuthorizationID2{Id: authzID})
1238 test.AssertNotError(t, err, "sa.DeactivateAuthorization2 failed")
1239
1240
1241 authzID = createFinalizedAuthorization(t, sa, "example.com", expires, "valid", attemptedAt)
1242 _, err = sa.DeactivateAuthorization2(context.Background(), &sapb.AuthorizationID2{Id: authzID})
1243 test.AssertNotError(t, err, "sa.DeactivateAuthorization2 failed")
1244 }
1245
1246 func TestDeactivateAccount(t *testing.T) {
1247 sa, _, cleanUp := initSA(t)
1248 defer cleanUp()
1249
1250 reg := createWorkingRegistration(t, sa)
1251
1252 _, err := sa.DeactivateRegistration(context.Background(), &sapb.RegistrationID{Id: reg.Id})
1253 test.AssertNotError(t, err, "DeactivateRegistration failed")
1254
1255 dbReg, err := sa.GetRegistration(context.Background(), &sapb.RegistrationID{Id: reg.Id})
1256 test.AssertNotError(t, err, "GetRegistration failed")
1257 test.AssertEquals(t, core.AcmeStatus(dbReg.Status), core.StatusDeactivated)
1258 }
1259
1260 func TestReverseName(t *testing.T) {
1261 testCases := []struct {
1262 inputDomain string
1263 inputReversed string
1264 }{
1265 {"", ""},
1266 {"...", "..."},
1267 {"com", "com"},
1268 {"example.com", "com.example"},
1269 {"www.example.com", "com.example.www"},
1270 {"world.wide.web.example.com", "com.example.web.wide.world"},
1271 }
1272
1273 for _, tc := range testCases {
1274 output := ReverseName(tc.inputDomain)
1275 test.AssertEquals(t, output, tc.inputReversed)
1276 }
1277 }
1278
1279 func TestNewOrderAndAuthzs(t *testing.T) {
1280 sa, _, cleanup := initSA(t)
1281 defer cleanup()
1282
1283
1284 key, _ := jose.JSONWebKey{Key: &rsa.PublicKey{N: big.NewInt(1), E: 1}}.MarshalJSON()
1285 initialIP, _ := net.ParseIP("42.42.42.42").MarshalText()
1286 reg, err := sa.NewRegistration(ctx, &corepb.Registration{
1287 Key: key,
1288 InitialIP: initialIP,
1289 })
1290 test.AssertNotError(t, err, "Couldn't create test registration")
1291
1292
1293 idA := createPendingAuthorization(t, sa, "a.com", sa.clk.Now().Add(time.Hour))
1294 idB := createPendingAuthorization(t, sa, "b.com", sa.clk.Now().Add(time.Hour))
1295 test.AssertEquals(t, idA, int64(1))
1296 test.AssertEquals(t, idB, int64(2))
1297
1298 nowC := sa.clk.Now().Add(time.Hour)
1299 nowD := sa.clk.Now().Add(time.Hour)
1300 expires := sa.clk.Now().Add(2 * time.Hour)
1301 order, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{
1302
1303 NewOrder: &sapb.NewOrderRequest{
1304 RegistrationID: reg.Id,
1305 ExpiresNS: expires.UnixNano(),
1306 Expires: timestamppb.New(expires),
1307 Names: []string{"a.com", "b.com", "c.com", "d.com"},
1308 V2Authorizations: []int64{1, 2},
1309 },
1310
1311 NewAuthzs: []*corepb.Authorization{
1312 {
1313 Identifier: "c.com",
1314 RegistrationID: reg.Id,
1315 ExpiresNS: nowC.UnixNano(),
1316 Expires: timestamppb.New(nowC),
1317 Status: "pending",
1318 Challenges: []*corepb.Challenge{{Token: core.NewToken()}},
1319 },
1320 {
1321 Identifier: "d.com",
1322 RegistrationID: reg.Id,
1323 ExpiresNS: nowD.UnixNano(),
1324 Expires: timestamppb.New(nowD),
1325 Status: "pending",
1326 Challenges: []*corepb.Challenge{{Token: core.NewToken()}},
1327 },
1328 },
1329 })
1330 test.AssertNotError(t, err, "sa.NewOrderAndAuthzs failed")
1331 test.AssertEquals(t, order.Id, int64(1))
1332 test.AssertDeepEquals(t, order.V2Authorizations, []int64{1, 2, 3, 4})
1333
1334 var authzIDs []int64
1335 _, err = sa.dbMap.Select(ctx, &authzIDs, "SELECT authzID FROM orderToAuthz2 WHERE orderID = ?;", order.Id)
1336 test.AssertNotError(t, err, "Failed to count orderToAuthz entries")
1337 test.AssertEquals(t, len(authzIDs), 4)
1338 test.AssertDeepEquals(t, authzIDs, []int64{1, 2, 3, 4})
1339
1340 names, err := namesForOrder(ctx, sa.dbReadOnlyMap, order.Id)
1341 test.AssertNotError(t, err, "namesForOrder errored")
1342 test.AssertEquals(t, len(names), 4)
1343 test.AssertDeepEquals(t, names, []string{"com.a", "com.b", "com.c", "com.d"})
1344 }
1345
1346
1347
1348 func TestNewOrderAndAuthzs_NonNilInnerOrder(t *testing.T) {
1349 sa, fc, cleanup := initSA(t)
1350 defer cleanup()
1351
1352 key, _ := jose.JSONWebKey{Key: &rsa.PublicKey{N: big.NewInt(1), E: 1}}.MarshalJSON()
1353 initialIP, _ := net.ParseIP("17.17.17.17").MarshalText()
1354 reg, err := sa.NewRegistration(ctx, &corepb.Registration{
1355 Key: key,
1356 InitialIP: initialIP,
1357 })
1358 test.AssertNotError(t, err, "Couldn't create test registration")
1359
1360 expires := fc.Now().Add(2 * time.Hour)
1361 _, err = sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{
1362 NewAuthzs: []*corepb.Authorization{
1363 {
1364 Identifier: "a.com",
1365 RegistrationID: reg.Id,
1366 ExpiresNS: expires.UnixNano(),
1367 Expires: timestamppb.New(expires),
1368 Status: "pending",
1369 Challenges: []*corepb.Challenge{{Token: core.NewToken()}},
1370 },
1371 },
1372 })
1373 test.AssertErrorIs(t, err, errIncompleteRequest)
1374 }
1375
1376 func TestNewOrderAndAuthzs_NewAuthzExpectedFields(t *testing.T) {
1377 sa, fc, cleanup := initSA(t)
1378 defer cleanup()
1379
1380
1381 key, _ := jose.JSONWebKey{Key: &rsa.PublicKey{N: big.NewInt(1), E: 1}}.MarshalJSON()
1382 initialIP, _ := net.ParseIP("17.17.17.17").MarshalText()
1383 reg, err := sa.NewRegistration(ctx, &corepb.Registration{
1384 Key: key,
1385 InitialIP: initialIP,
1386 })
1387 test.AssertNotError(t, err, "Couldn't create test registration")
1388
1389 expires := fc.Now().Add(time.Hour)
1390 domain := "a.com"
1391
1392
1393
1394 order, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{
1395 NewAuthzs: []*corepb.Authorization{
1396 {
1397 Identifier: domain,
1398 RegistrationID: reg.Id,
1399 ExpiresNS: expires.UnixNano(),
1400 Expires: timestamppb.New(expires),
1401 Status: string(core.StatusPending),
1402 Challenges: []*corepb.Challenge{
1403 {
1404 Status: "real fake garbage data",
1405 Token: core.NewToken(),
1406 },
1407 },
1408 },
1409 },
1410 NewOrder: &sapb.NewOrderRequest{
1411 RegistrationID: reg.Id,
1412 ExpiresNS: expires.UnixNano(),
1413 Expires: timestamppb.New(expires),
1414 Names: []string{domain},
1415 },
1416 })
1417 test.AssertNotError(t, err, "sa.NewOrderAndAuthzs failed")
1418
1419
1420 obj, err := sa.dbReadOnlyMap.Get(ctx, authzModel{}, order.V2Authorizations[0])
1421 test.AssertNotError(t, err, fmt.Sprintf("authorization %d not found", order.V2Authorizations[0]))
1422
1423
1424
1425 am, ok := obj.(*authzModel)
1426 test.Assert(t, ok, "Could not type assert obj into authzModel")
1427
1428
1429
1430 test.AssertEquals(t, am.Status, statusUint(core.StatusPending))
1431
1432
1433
1434
1435
1436
1437 test.AssertBoxedNil(t, am.Attempted, "am.Attempted should be nil")
1438 test.AssertBoxedNil(t, am.AttemptedAt, "am.AttemptedAt should be nil")
1439 test.AssertBoxedNil(t, am.ValidationError, "am.ValidationError should be nil")
1440 test.AssertBoxedNil(t, am.ValidationRecord, "am.ValidationRecord should be nil")
1441 }
1442
1443 func TestSetOrderProcessing(t *testing.T) {
1444 sa, fc, cleanup := initSA(t)
1445 defer cleanup()
1446
1447
1448 key, _ := jose.JSONWebKey{Key: &rsa.PublicKey{N: big.NewInt(1), E: 1}}.MarshalJSON()
1449 initialIP, _ := net.ParseIP("42.42.42.42").MarshalText()
1450 reg, err := sa.NewRegistration(ctx, &corepb.Registration{
1451 Key: key,
1452 InitialIP: initialIP,
1453 })
1454 test.AssertNotError(t, err, "Couldn't create test registration")
1455
1456
1457 expires := fc.Now().Add(time.Hour)
1458 attemptedAt := fc.Now()
1459 authzID := createFinalizedAuthorization(t, sa, "example.com", expires, "valid", attemptedAt)
1460
1461
1462 expires1Year := sa.clk.Now().Add(365 * 24 * time.Hour)
1463 order, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{
1464 NewOrder: &sapb.NewOrderRequest{
1465 RegistrationID: reg.Id,
1466 ExpiresNS: expires1Year.UnixNano(),
1467 Expires: timestamppb.New(expires1Year),
1468 Names: []string{"example.com"},
1469 V2Authorizations: []int64{authzID},
1470 },
1471 })
1472 test.AssertNotError(t, err, "NewOrderAndAuthzs failed")
1473
1474
1475 _, err = sa.SetOrderProcessing(context.Background(), &sapb.OrderRequest{Id: order.Id})
1476 test.AssertNotError(t, err, "SetOrderProcessing failed")
1477
1478
1479
1480 updatedOrder, err := sa.GetOrder(
1481 context.Background(),
1482 &sapb.OrderRequest{Id: order.Id})
1483 test.AssertNotError(t, err, "GetOrder failed")
1484 test.AssertEquals(t, updatedOrder.Status, string(core.StatusProcessing))
1485 test.AssertEquals(t, updatedOrder.BeganProcessing, true)
1486
1487
1488 _, err = sa.SetOrderProcessing(context.Background(), &sapb.OrderRequest{Id: order.Id})
1489 test.AssertError(t, err, "Set the same order processing twice. This should have been an error.")
1490 test.AssertErrorIs(t, err, berrors.OrderNotReady)
1491 }
1492
1493 func TestFinalizeOrder(t *testing.T) {
1494 sa, fc, cleanup := initSA(t)
1495 defer cleanup()
1496
1497
1498 key, _ := jose.JSONWebKey{Key: &rsa.PublicKey{N: big.NewInt(1), E: 1}}.MarshalJSON()
1499 initialIP, _ := net.ParseIP("42.42.42.42").MarshalText()
1500 reg, err := sa.NewRegistration(ctx, &corepb.Registration{
1501 Key: key,
1502 InitialIP: initialIP,
1503 })
1504 test.AssertNotError(t, err, "Couldn't create test registration")
1505
1506
1507 expires := fc.Now().Add(time.Hour)
1508 attemptedAt := fc.Now()
1509 authzID := createFinalizedAuthorization(t, sa, "example.com", expires, "valid", attemptedAt)
1510
1511
1512 expires1Year := sa.clk.Now().Add(365 * 24 * time.Hour)
1513 order, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{
1514 NewOrder: &sapb.NewOrderRequest{
1515 RegistrationID: reg.Id,
1516 ExpiresNS: expires1Year.UnixNano(),
1517 Expires: timestamppb.New(expires1Year),
1518 Names: []string{"example.com"},
1519 V2Authorizations: []int64{authzID},
1520 },
1521 })
1522 test.AssertNotError(t, err, "NewOrderAndAuthzs failed")
1523
1524
1525 _, err = sa.SetOrderProcessing(ctx, &sapb.OrderRequest{Id: order.Id})
1526 test.AssertNotError(t, err, "SetOrderProcessing failed")
1527
1528
1529 order.CertificateSerial = "eat.serial.for.breakfast"
1530 _, err = sa.FinalizeOrder(context.Background(), &sapb.FinalizeOrderRequest{Id: order.Id, CertificateSerial: order.CertificateSerial})
1531 test.AssertNotError(t, err, "FinalizeOrder failed")
1532
1533
1534
1535 updatedOrder, err := sa.GetOrder(
1536 context.Background(),
1537 &sapb.OrderRequest{Id: order.Id})
1538 test.AssertNotError(t, err, "GetOrder failed")
1539 test.AssertEquals(t, updatedOrder.CertificateSerial, "eat.serial.for.breakfast")
1540 test.AssertEquals(t, updatedOrder.Status, string(core.StatusValid))
1541 }
1542
1543 func TestOrder(t *testing.T) {
1544 sa, fc, cleanup := initSA(t)
1545 defer cleanup()
1546
1547
1548 key, _ := jose.JSONWebKey{Key: &rsa.PublicKey{N: big.NewInt(1), E: 1}}.MarshalJSON()
1549 initialIP, _ := net.ParseIP("42.42.42.42").MarshalText()
1550 reg, err := sa.NewRegistration(ctx, &corepb.Registration{
1551 Key: key,
1552 InitialIP: initialIP,
1553 })
1554 test.AssertNotError(t, err, "Couldn't create test registration")
1555
1556 authzExpires := fc.Now().Add(time.Hour)
1557 authzID := createPendingAuthorization(t, sa, "example.com", authzExpires)
1558
1559
1560 expires := fc.Now().Add(2 * time.Hour)
1561
1562 inputOrder := &corepb.Order{
1563 RegistrationID: reg.Id,
1564 ExpiresNS: expires.UnixNano(),
1565 Expires: timestamppb.New(expires),
1566 Names: []string{"example.com"},
1567 V2Authorizations: []int64{authzID},
1568 }
1569
1570
1571 order, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{
1572 NewOrder: &sapb.NewOrderRequest{
1573 RegistrationID: inputOrder.RegistrationID,
1574 ExpiresNS: inputOrder.ExpiresNS,
1575 Expires: inputOrder.Expires,
1576 Names: inputOrder.Names,
1577 V2Authorizations: inputOrder.V2Authorizations,
1578 },
1579 })
1580 test.AssertNotError(t, err, "sa.NewOrderAndAuthzs failed")
1581
1582
1583 created := sa.clk.Now()
1584 expectedOrder := &corepb.Order{
1585
1586
1587 RegistrationID: inputOrder.RegistrationID,
1588 V2Authorizations: inputOrder.V2Authorizations,
1589 Names: inputOrder.Names,
1590 ExpiresNS: inputOrder.ExpiresNS,
1591 Expires: inputOrder.Expires,
1592
1593 Id: 1,
1594
1595 Status: string(core.StatusPending),
1596
1597 CertificateSerial: "",
1598
1599 BeganProcessing: false,
1600
1601 CreatedNS: created.UnixNano(),
1602 Created: timestamppb.New(created),
1603 }
1604
1605
1606 storedOrder, err := sa.GetOrder(context.Background(), &sapb.OrderRequest{Id: order.Id})
1607 test.AssertNotError(t, err, "sa.GetOrder failed")
1608 test.AssertDeepEquals(t, storedOrder, expectedOrder)
1609 }
1610
1611
1612
1613 func TestGetAuthorization2NoRows(t *testing.T) {
1614 sa, _, cleanUp := initSA(t)
1615 defer cleanUp()
1616
1617
1618 id := int64(123)
1619 _, err := sa.GetAuthorization2(ctx, &sapb.AuthorizationID2{Id: id})
1620 test.AssertError(t, err, "Didn't get an error looking up non-existent authz ID")
1621 test.AssertErrorIs(t, err, berrors.NotFound)
1622 }
1623
1624 func TestGetAuthorizations2(t *testing.T) {
1625 sa, fc, cleanup := initSA(t)
1626 defer cleanup()
1627
1628 reg := createWorkingRegistration(t, sa)
1629 exp := fc.Now().AddDate(0, 0, 10).UTC()
1630 attemptedAt := fc.Now()
1631
1632 identA := "aaa"
1633 identB := "bbb"
1634 identC := "ccc"
1635 identD := "ddd"
1636 idents := []string{identA, identB, identC}
1637
1638 authzIDA := createFinalizedAuthorization(t, sa, "aaa", exp, "valid", attemptedAt)
1639 authzIDB := createPendingAuthorization(t, sa, "bbb", exp)
1640 nearbyExpires := fc.Now().UTC().Add(time.Hour)
1641 authzIDC := createPendingAuthorization(t, sa, "ccc", nearbyExpires)
1642
1643
1644
1645 err := sa.dbMap.Insert(ctx, &orderToAuthzModel{
1646 OrderID: 1,
1647 AuthzID: authzIDA,
1648 })
1649 test.AssertNotError(t, err, "sa.dbMap.Insert failed")
1650 err = sa.dbMap.Insert(ctx, &orderToAuthzModel{
1651 OrderID: 1,
1652 AuthzID: authzIDB,
1653 })
1654 test.AssertNotError(t, err, "sa.dbMap.Insert failed")
1655 err = sa.dbMap.Insert(ctx, &orderToAuthzModel{
1656 OrderID: 1,
1657 AuthzID: authzIDC,
1658 })
1659 test.AssertNotError(t, err, "sa.dbMap.Insert failed")
1660
1661
1662
1663
1664 expiryCutoff := fc.Now().AddDate(0, 0, 1)
1665
1666 authz, err := sa.GetAuthorizations2(context.Background(), &sapb.GetAuthorizationsRequest{
1667 RegistrationID: reg.Id,
1668 Domains: idents,
1669 NowNS: expiryCutoff.UnixNano(),
1670 Now: timestamppb.New(expiryCutoff),
1671 })
1672
1673 test.AssertNotError(t, err, "sa.GetAuthorizations2 failed")
1674
1675
1676 test.AssertEquals(t, len(authz.Authz), 2)
1677
1678
1679 authz, err = sa.GetAuthorizations2(context.Background(), &sapb.GetAuthorizationsRequest{
1680 RegistrationID: reg.Id,
1681 Domains: append(idents, identD),
1682 NowNS: expiryCutoff.UnixNano(),
1683 Now: timestamppb.New(expiryCutoff),
1684 })
1685
1686 test.AssertNotError(t, err, "sa.GetAuthorizations2 failed")
1687
1688 test.AssertEquals(t, len(authz.Authz), 2)
1689 }
1690
1691 func TestCountOrders(t *testing.T) {
1692 sa, _, cleanUp := initSA(t)
1693 defer cleanUp()
1694
1695 reg := createWorkingRegistration(t, sa)
1696 now := sa.clk.Now()
1697 expires := now.Add(24 * time.Hour)
1698
1699 req := &sapb.CountOrdersRequest{
1700 AccountID: 12345,
1701 Range: &sapb.Range{
1702 EarliestNS: now.Add(-time.Hour).UnixNano(),
1703 Earliest: timestamppb.New(now.Add(-time.Hour)),
1704 LatestNS: now.Add(time.Second).UnixNano(),
1705 Latest: timestamppb.New(now.Add(time.Second)),
1706 },
1707 }
1708
1709
1710 count, err := sa.CountOrders(ctx, req)
1711 test.AssertNotError(t, err, "Couldn't count new orders for fake reg ID")
1712 test.AssertEquals(t, count.Count, int64(0))
1713
1714
1715 authzID := createPendingAuthorization(t, sa, "example.com", expires)
1716
1717
1718 order, err := sa.NewOrderAndAuthzs(ctx, &sapb.NewOrderAndAuthzsRequest{
1719 NewOrder: &sapb.NewOrderRequest{
1720 RegistrationID: reg.Id,
1721 ExpiresNS: expires.UnixNano(),
1722 Expires: timestamppb.New(expires),
1723 Names: []string{"example.com"},
1724 V2Authorizations: []int64{authzID},
1725 },
1726 })
1727 test.AssertNotError(t, err, "Couldn't create new pending order")
1728
1729
1730 req.AccountID = reg.Id
1731 count, err = sa.CountOrders(ctx, req)
1732 test.AssertNotError(t, err, "Couldn't count new orders for reg ID")
1733 test.AssertEquals(t, count.Count, int64(1))
1734
1735
1736
1737 earliest := time.Unix(0, order.CreatedNS).Add(time.Minute)
1738 req.Range.EarliestNS = earliest.UnixNano()
1739 req.Range.LatestNS = earliest.Add(time.Hour).UnixNano()
1740 count, err = sa.CountOrders(ctx, req)
1741 test.AssertNotError(t, err, "Couldn't count new orders for reg ID")
1742 test.AssertEquals(t, count.Count, int64(0))
1743 }
1744
1745 func TestFasterGetOrderForNames(t *testing.T) {
1746 sa, fc, cleanUp := initSA(t)
1747 defer cleanUp()
1748
1749 domain := "example.com"
1750 expires := fc.Now().Add(time.Hour)
1751
1752 key, _ := goodTestJWK().MarshalJSON()
1753 initialIP, _ := net.ParseIP("42.42.42.42").MarshalText()
1754 reg, err := sa.NewRegistration(ctx, &corepb.Registration{
1755 Key: key,
1756 InitialIP: initialIP,
1757 })
1758 test.AssertNotError(t, err, "Couldn't create test registration")
1759
1760 authzIDs := createPendingAuthorization(t, sa, domain, expires)
1761
1762 _, err = sa.NewOrderAndAuthzs(ctx, &sapb.NewOrderAndAuthzsRequest{
1763 NewOrder: &sapb.NewOrderRequest{
1764 RegistrationID: reg.Id,
1765 ExpiresNS: expires.UnixNano(),
1766 Expires: timestamppb.New(expires),
1767 V2Authorizations: []int64{authzIDs},
1768 Names: []string{domain},
1769 },
1770 })
1771 test.AssertNotError(t, err, "sa.NewOrderAndAuthzs failed")
1772
1773 _, err = sa.NewOrderAndAuthzs(ctx, &sapb.NewOrderAndAuthzsRequest{
1774 NewOrder: &sapb.NewOrderRequest{
1775 RegistrationID: reg.Id,
1776 ExpiresNS: expires.UnixNano(),
1777 Expires: timestamppb.New(expires),
1778 V2Authorizations: []int64{authzIDs},
1779 Names: []string{domain},
1780 },
1781 })
1782 test.AssertNotError(t, err, "sa.NewOrderAndAuthzs failed")
1783
1784 _, err = sa.GetOrderForNames(ctx, &sapb.GetOrderForNamesRequest{
1785 AcctID: reg.Id,
1786 Names: []string{domain},
1787 })
1788 test.AssertNotError(t, err, "sa.GetOrderForNames failed")
1789 }
1790
1791 func TestGetOrderForNames(t *testing.T) {
1792 sa, fc, cleanUp := initSA(t)
1793 defer cleanUp()
1794
1795
1796 orderLifetime := time.Hour
1797 expires := fc.Now().Add(orderLifetime)
1798
1799
1800 key, _ := goodTestJWK().MarshalJSON()
1801 initialIP, _ := net.ParseIP("42.42.42.42").MarshalText()
1802 regA, err := sa.NewRegistration(ctx, &corepb.Registration{
1803 Key: key,
1804 InitialIP: initialIP,
1805 })
1806 test.AssertNotError(t, err, "Couldn't create test registration")
1807
1808
1809
1810 authzExpires := fc.Now().Add(time.Hour)
1811 authzIDA := createPendingAuthorization(t, sa, "example.com", authzExpires)
1812 authzIDB := createPendingAuthorization(t, sa, "just.another.example.com", authzExpires)
1813
1814 ctx := context.Background()
1815 names := []string{"example.com", "just.another.example.com"}
1816
1817
1818
1819 result, err := sa.GetOrderForNames(ctx, &sapb.GetOrderForNamesRequest{
1820 AcctID: regA.Id,
1821 Names: names,
1822 })
1823
1824 test.AssertError(t, err, "sa.GetOrderForNames did not return an error for an empty result")
1825
1826 test.AssertErrorIs(t, err, berrors.NotFound)
1827
1828 test.Assert(t, result == nil, "sa.GetOrderForNames for non-existent order returned non-nil result")
1829
1830
1831 order, err := sa.NewOrderAndAuthzs(ctx, &sapb.NewOrderAndAuthzsRequest{
1832 NewOrder: &sapb.NewOrderRequest{
1833 RegistrationID: regA.Id,
1834 ExpiresNS: expires.UnixNano(),
1835 Expires: timestamppb.New(expires),
1836 V2Authorizations: []int64{authzIDA, authzIDB},
1837 Names: names,
1838 },
1839 })
1840
1841 test.AssertNotError(t, err, "sa.NewOrderAndAuthzs failed")
1842
1843 test.AssertNotNil(t, order.Id, "NewOrderAndAuthzs returned with a nil Id")
1844
1845
1846
1847 result, err = sa.GetOrderForNames(ctx, &sapb.GetOrderForNamesRequest{
1848 AcctID: regA.Id,
1849 Names: names,
1850 })
1851
1852 test.AssertNotError(t, err, "sa.GetOrderForNames failed")
1853
1854 test.AssertNotNil(t, result, "Returned order was nil")
1855 test.AssertEquals(t, result.Id, order.Id)
1856
1857
1858 regB := int64(1337)
1859 result, err = sa.GetOrderForNames(ctx, &sapb.GetOrderForNamesRequest{
1860 AcctID: regB,
1861 Names: names,
1862 })
1863
1864 test.AssertError(t, err, "sa.GetOrderForNames did not return an error for an empty result")
1865
1866 test.AssertErrorIs(t, err, berrors.NotFound)
1867
1868 test.Assert(t, result == nil, "sa.GetOrderForNames for diff AcctID returned non-nil result")
1869
1870
1871 fc.Add(2 * orderLifetime)
1872
1873
1874
1875 result, err = sa.GetOrderForNames(ctx, &sapb.GetOrderForNamesRequest{
1876 AcctID: regA.Id,
1877 Names: names,
1878 })
1879
1880 test.AssertError(t, err, "sa.GetOrderForNames did not return an error for an empty result")
1881
1882 test.AssertErrorIs(t, err, berrors.NotFound)
1883
1884
1885 test.Assert(t, result == nil, "sa.GetOrderForNames returned non-nil result for expired order case")
1886
1887
1888 authzExpires = fc.Now().Add(time.Hour)
1889 attemptedAt := fc.Now()
1890 authzIDC := createFinalizedAuthorization(t, sa, "zombo.com", authzExpires, "valid", attemptedAt)
1891 authzIDD := createFinalizedAuthorization(t, sa, "welcome.to.zombo.com", authzExpires, "valid", attemptedAt)
1892
1893
1894 names = []string{"zombo.com", "welcome.to.zombo.com"}
1895 expires = fc.Now().Add(orderLifetime)
1896 order, err = sa.NewOrderAndAuthzs(ctx, &sapb.NewOrderAndAuthzsRequest{
1897 NewOrder: &sapb.NewOrderRequest{
1898 RegistrationID: regA.Id,
1899 ExpiresNS: expires.UnixNano(),
1900 Expires: timestamppb.New(expires),
1901 V2Authorizations: []int64{authzIDC, authzIDD},
1902 Names: names,
1903 },
1904 })
1905
1906 test.AssertNotError(t, err, "sa.NewOrderAndAuthzs failed")
1907
1908 test.AssertNotNil(t, order.Id, "NewOrderAndAuthzs returned with a nil Id")
1909
1910
1911
1912 result, err = sa.GetOrderForNames(ctx, &sapb.GetOrderForNamesRequest{
1913 AcctID: regA.Id,
1914 Names: names,
1915 })
1916
1917 test.AssertNotError(t, err, "sa.GetOrderForNames returned an unexpected error for ready order reuse")
1918
1919 test.AssertNotNil(t, result, "sa.GetOrderForNames returned nil result")
1920 test.AssertEquals(t, result.Id, order.Id)
1921
1922
1923 _, err = sa.SetOrderProcessing(ctx, &sapb.OrderRequest{Id: order.Id})
1924 test.AssertNotError(t, err, "sa.SetOrderProcessing failed")
1925
1926
1927 order.CertificateSerial = "cinnamon toast crunch"
1928 _, err = sa.FinalizeOrder(ctx, &sapb.FinalizeOrderRequest{Id: order.Id, CertificateSerial: order.CertificateSerial})
1929 test.AssertNotError(t, err, "sa.FinalizeOrder failed")
1930
1931
1932
1933 result, err = sa.GetOrderForNames(ctx, &sapb.GetOrderForNamesRequest{
1934 AcctID: regA.Id,
1935 Names: names,
1936 })
1937
1938 test.AssertError(t, err, "sa.GetOrderForNames did not return an error for an empty result")
1939
1940 test.AssertErrorIs(t, err, berrors.NotFound)
1941
1942
1943 test.Assert(t, result == nil, "sa.GetOrderForNames returned non-nil result for finalized order case")
1944 }
1945
1946 func TestStatusForOrder(t *testing.T) {
1947 sa, fc, cleanUp := initSA(t)
1948 defer cleanUp()
1949
1950 ctx := context.Background()
1951 expires := fc.Now().Add(time.Hour)
1952 alreadyExpired := expires.Add(-2 * time.Hour)
1953 attemptedAt := fc.Now()
1954
1955
1956 reg := createWorkingRegistration(t, sa)
1957
1958
1959
1960 pendingID := createPendingAuthorization(t, sa, "pending.your.order.is.up", expires)
1961 expiredID := createPendingAuthorization(t, sa, "expired.your.order.is.up", alreadyExpired)
1962 invalidID := createFinalizedAuthorization(t, sa, "invalid.your.order.is.up", expires, "invalid", attemptedAt)
1963 validID := createFinalizedAuthorization(t, sa, "valid.your.order.is.up", expires, "valid", attemptedAt)
1964 deactivatedID := createPendingAuthorization(t, sa, "deactivated.your.order.is.up", expires)
1965 _, err := sa.DeactivateAuthorization2(context.Background(), &sapb.AuthorizationID2{Id: deactivatedID})
1966 test.AssertNotError(t, err, "sa.DeactivateAuthorization2 failed")
1967
1968 testCases := []struct {
1969 Name string
1970 AuthorizationIDs []int64
1971 OrderNames []string
1972 OrderExpiresNS int64
1973 OrderExpires *timestamppb.Timestamp
1974 ExpectedStatus string
1975 SetProcessing bool
1976 Finalize bool
1977 }{
1978 {
1979 Name: "Order with an invalid authz",
1980 OrderNames: []string{"pending.your.order.is.up", "invalid.your.order.is.up", "deactivated.your.order.is.up", "valid.your.order.is.up"},
1981 AuthorizationIDs: []int64{pendingID, invalidID, deactivatedID, validID},
1982 ExpectedStatus: string(core.StatusInvalid),
1983 },
1984 {
1985 Name: "Order with an expired authz",
1986 OrderNames: []string{"pending.your.order.is.up", "expired.your.order.is.up", "deactivated.your.order.is.up", "valid.your.order.is.up"},
1987 AuthorizationIDs: []int64{pendingID, expiredID, deactivatedID, validID},
1988 ExpectedStatus: string(core.StatusInvalid),
1989 },
1990 {
1991 Name: "Order with a deactivated authz",
1992 OrderNames: []string{"pending.your.order.is.up", "deactivated.your.order.is.up", "valid.your.order.is.up"},
1993 AuthorizationIDs: []int64{pendingID, deactivatedID, validID},
1994 ExpectedStatus: string(core.StatusInvalid),
1995 },
1996 {
1997 Name: "Order with a pending authz",
1998 OrderNames: []string{"valid.your.order.is.up", "pending.your.order.is.up"},
1999 AuthorizationIDs: []int64{validID, pendingID},
2000 ExpectedStatus: string(core.StatusPending),
2001 },
2002 {
2003 Name: "Order with only valid authzs, not yet processed or finalized",
2004 OrderNames: []string{"valid.your.order.is.up"},
2005 AuthorizationIDs: []int64{validID},
2006 ExpectedStatus: string(core.StatusReady),
2007 },
2008 {
2009 Name: "Order with only valid authzs, set processing",
2010 OrderNames: []string{"valid.your.order.is.up"},
2011 AuthorizationIDs: []int64{validID},
2012 SetProcessing: true,
2013 ExpectedStatus: string(core.StatusProcessing),
2014 },
2015 {
2016 Name: "Order with only valid authzs, not yet processed or finalized, OrderReadyStatus feature flag",
2017 OrderNames: []string{"valid.your.order.is.up"},
2018 AuthorizationIDs: []int64{validID},
2019 ExpectedStatus: string(core.StatusReady),
2020 },
2021 {
2022 Name: "Order with only valid authzs, set processing",
2023 OrderNames: []string{"valid.your.order.is.up"},
2024 AuthorizationIDs: []int64{validID},
2025 SetProcessing: true,
2026 ExpectedStatus: string(core.StatusProcessing),
2027 },
2028 {
2029 Name: "Order with only valid authzs, set processing and finalized",
2030 OrderNames: []string{"valid.your.order.is.up"},
2031 AuthorizationIDs: []int64{validID},
2032 SetProcessing: true,
2033 Finalize: true,
2034 ExpectedStatus: string(core.StatusValid),
2035 },
2036 }
2037
2038 for _, tc := range testCases {
2039 t.Run(tc.Name, func(t *testing.T) {
2040
2041
2042 orderExpiryNS := tc.OrderExpiresNS
2043 if orderExpiryNS == 0 {
2044 orderExpiryNS = expires.UnixNano()
2045 }
2046 orderExpiry := tc.OrderExpires
2047 if !orderExpiry.IsValid() {
2048 orderExpiry = timestamppb.New(expires)
2049 }
2050
2051 newOrder, err := sa.NewOrderAndAuthzs(ctx, &sapb.NewOrderAndAuthzsRequest{
2052 NewOrder: &sapb.NewOrderRequest{
2053 RegistrationID: reg.Id,
2054 ExpiresNS: orderExpiryNS,
2055 Expires: orderExpiry,
2056 V2Authorizations: tc.AuthorizationIDs,
2057 Names: tc.OrderNames,
2058 },
2059 })
2060 test.AssertNotError(t, err, "NewOrderAndAuthzs errored unexpectedly")
2061
2062 if tc.SetProcessing {
2063 _, err := sa.SetOrderProcessing(ctx, &sapb.OrderRequest{Id: newOrder.Id})
2064 test.AssertNotError(t, err, "Error setting order to processing status")
2065 }
2066
2067 if tc.Finalize {
2068 newOrder.CertificateSerial = "lucky charms"
2069 _, err = sa.FinalizeOrder(ctx, &sapb.FinalizeOrderRequest{Id: newOrder.Id, CertificateSerial: newOrder.CertificateSerial})
2070 test.AssertNotError(t, err, "Error finalizing order")
2071 }
2072
2073 storedOrder, err := sa.GetOrder(ctx, &sapb.OrderRequest{Id: newOrder.Id})
2074 test.AssertNotError(t, err, "GetOrder failed")
2075
2076 test.AssertNotNil(t, storedOrder.Status, "Order status was nil")
2077
2078 test.AssertEquals(t, storedOrder.Status, tc.ExpectedStatus)
2079 })
2080 }
2081
2082 }
2083
2084 func TestUpdateChallengesDeleteUnused(t *testing.T) {
2085 sa, fc, cleanUp := initSA(t)
2086 defer cleanUp()
2087
2088 expires := fc.Now().Add(time.Hour)
2089 ctx := context.Background()
2090 attemptedAt := fc.Now()
2091
2092
2093 authzID := createFinalizedAuthorization(t, sa, "example.com", expires, "valid", attemptedAt)
2094
2095 result, err := sa.GetAuthorization2(ctx, &sapb.AuthorizationID2{Id: authzID})
2096 test.AssertNotError(t, err, "sa.GetAuthorization2 failed")
2097
2098 if len(result.Challenges) != 1 {
2099 t.Fatalf("expected 1 challenge left after finalization, got %d", len(result.Challenges))
2100 }
2101 if result.Challenges[0].Status != string(core.StatusValid) {
2102 t.Errorf("expected challenge status %q, got %q", core.StatusValid, result.Challenges[0].Status)
2103 }
2104 if result.Challenges[0].Type != "http-01" {
2105 t.Errorf("expected challenge type %q, got %q", "http-01", result.Challenges[0].Type)
2106 }
2107 }
2108
2109 func TestRevokeCertificate(t *testing.T) {
2110 sa, fc, cleanUp := initSA(t)
2111 defer cleanUp()
2112
2113 reg := createWorkingRegistration(t, sa)
2114
2115 certDER, err := os.ReadFile("www.eff.org.der")
2116 test.AssertNotError(t, err, "Couldn't read example cert DER")
2117 issuedTime := sa.clk.Now()
2118 _, err = sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
2119 Der: certDER,
2120 RegID: reg.Id,
2121 IssuedNS: issuedTime.UnixNano(),
2122 Issued: timestamppb.New(issuedTime),
2123 IssuerNameID: 1,
2124 })
2125 test.AssertNotError(t, err, "Couldn't add www.eff.org.der")
2126
2127 serial := "000000000000000000000000000000021bd4"
2128
2129 status, err := sa.GetCertificateStatus(ctx, &sapb.Serial{Serial: serial})
2130 test.AssertNotError(t, err, "GetCertificateStatus failed")
2131 test.AssertEquals(t, core.OCSPStatus(status.Status), core.OCSPStatusGood)
2132
2133 fc.Add(1 * time.Hour)
2134
2135 now := fc.Now()
2136 reason := int64(1)
2137
2138 _, err = sa.RevokeCertificate(context.Background(), &sapb.RevokeCertificateRequest{
2139 IssuerID: 1,
2140 Serial: serial,
2141 DateNS: now.UnixNano(),
2142 Date: timestamppb.New(now),
2143 Reason: reason,
2144 })
2145 test.AssertNotError(t, err, "RevokeCertificate with no OCSP response should succeed")
2146
2147 status, err = sa.GetCertificateStatus(ctx, &sapb.Serial{Serial: serial})
2148 test.AssertNotError(t, err, "GetCertificateStatus failed")
2149 test.AssertEquals(t, core.OCSPStatus(status.Status), core.OCSPStatusRevoked)
2150 test.AssertEquals(t, status.RevokedReason, reason)
2151 test.AssertEquals(t, status.RevokedDateNS, now.UnixNano())
2152 test.AssertEquals(t, status.OcspLastUpdated.AsTime(), now)
2153 test.AssertEquals(t, status.OcspLastUpdatedNS, now.UnixNano())
2154
2155 _, err = sa.RevokeCertificate(context.Background(), &sapb.RevokeCertificateRequest{
2156 IssuerID: 1,
2157 Serial: serial,
2158 DateNS: now.UnixNano(),
2159 Date: timestamppb.New(now),
2160 Reason: reason,
2161 })
2162 test.AssertError(t, err, "RevokeCertificate should've failed when certificate already revoked")
2163 }
2164
2165 func TestRevokeCertificateWithShard(t *testing.T) {
2166 if os.Getenv("BOULDER_CONFIG_DIR") != "test/config-next" {
2167 t.Skip("Test requires revokedCertificates database table")
2168 }
2169
2170 sa, fc, cleanUp := initSA(t)
2171 defer cleanUp()
2172
2173
2174 reg := createWorkingRegistration(t, sa)
2175 eeCert, err := core.LoadCert("../test/hierarchy/ee-e1.cert.pem")
2176 test.AssertNotError(t, err, "failed to load test cert")
2177 _, err = sa.AddSerial(ctx, &sapb.AddSerialRequest{
2178 RegID: reg.Id,
2179 Serial: core.SerialToString(eeCert.SerialNumber),
2180 CreatedNS: eeCert.NotBefore.UnixNano(),
2181 Created: timestamppb.New(eeCert.NotBefore),
2182 ExpiresNS: eeCert.NotAfter.UnixNano(),
2183 Expires: timestamppb.New(eeCert.NotAfter),
2184 })
2185 test.AssertNotError(t, err, "failed to add test serial")
2186 _, err = sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
2187 Der: eeCert.Raw,
2188 RegID: reg.Id,
2189 IssuedNS: eeCert.NotBefore.UnixNano(),
2190 Issued: timestamppb.New(eeCert.NotBefore),
2191 IssuerNameID: 1,
2192 })
2193 test.AssertNotError(t, err, "failed to add test cert")
2194
2195 serial := core.SerialToString(eeCert.SerialNumber)
2196 fc.Add(1 * time.Hour)
2197 now := fc.Now()
2198 reason := int64(1)
2199
2200 _, err = sa.RevokeCertificate(context.Background(), &sapb.RevokeCertificateRequest{
2201 IssuerID: 1,
2202 ShardIdx: 9,
2203 Serial: serial,
2204 DateNS: now.UnixNano(),
2205 Date: timestamppb.New(now),
2206 Reason: reason,
2207 })
2208 test.AssertNotError(t, err, "RevokeCertificate with no OCSP response should succeed")
2209
2210 status, err := sa.GetCertificateStatus(ctx, &sapb.Serial{Serial: serial})
2211 test.AssertNotError(t, err, "GetCertificateStatus failed")
2212 test.AssertEquals(t, core.OCSPStatus(status.Status), core.OCSPStatusRevoked)
2213 test.AssertEquals(t, status.RevokedReason, reason)
2214 test.AssertEquals(t, status.RevokedDateNS, now.UnixNano())
2215 test.AssertEquals(t, status.RevokedDate.AsTime(), now)
2216 test.AssertEquals(t, status.OcspLastUpdatedNS, now.UnixNano())
2217 test.AssertEquals(t, status.OcspLastUpdated.AsTime(), now)
2218 test.AssertEquals(t, status.NotAfterNS, eeCert.NotAfter.UnixNano())
2219 test.AssertEquals(t, status.NotAfter.AsTime(), eeCert.NotAfter)
2220
2221 var result revokedCertModel
2222 err = sa.dbMap.SelectOne(
2223 ctx, &result, `SELECT * FROM revokedCertificates WHERE serial = ?`, core.SerialToString(eeCert.SerialNumber))
2224 test.AssertNotError(t, err, "should be exactly one row in revokedCertificates")
2225 test.AssertEquals(t, result.ShardIdx, int64(9))
2226 test.AssertEquals(t, result.RevokedReason, revocation.Reason(ocsp.KeyCompromise))
2227 }
2228
2229 func TestUpdateRevokedCertificate(t *testing.T) {
2230 sa, fc, cleanUp := initSA(t)
2231 defer cleanUp()
2232
2233
2234 reg := createWorkingRegistration(t, sa)
2235 certDER, err := os.ReadFile("www.eff.org.der")
2236 serial := "000000000000000000000000000000021bd4"
2237 issuedTime := fc.Now()
2238 test.AssertNotError(t, err, "Couldn't read example cert DER")
2239 _, err = sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
2240 Der: certDER,
2241 RegID: reg.Id,
2242 IssuedNS: issuedTime.UnixNano(),
2243 Issued: timestamppb.New(issuedTime),
2244 IssuerNameID: 1,
2245 })
2246 test.AssertNotError(t, err, "Couldn't add www.eff.org.der")
2247 fc.Add(1 * time.Hour)
2248
2249
2250 now := fc.Now()
2251 _, err = sa.UpdateRevokedCertificate(context.Background(), &sapb.RevokeCertificateRequest{
2252 IssuerID: 1,
2253 Serial: serial,
2254 DateNS: now.UnixNano(),
2255 Date: timestamppb.New(now),
2256 BackdateNS: now.UnixNano(),
2257 Backdate: timestamppb.New(now),
2258 Reason: ocsp.KeyCompromise,
2259 Response: []byte{4, 5, 6},
2260 })
2261 test.AssertError(t, err, "UpdateRevokedCertificate should have failed")
2262 test.AssertContains(t, err.Error(), "no certificate with serial")
2263
2264
2265 revokedTime := fc.Now()
2266 _, err = sa.RevokeCertificate(context.Background(), &sapb.RevokeCertificateRequest{
2267 IssuerID: 1,
2268 Serial: serial,
2269 DateNS: revokedTime.UnixNano(),
2270 Date: timestamppb.New(revokedTime),
2271 Reason: ocsp.CessationOfOperation,
2272 Response: []byte{1, 2, 3},
2273 })
2274 test.AssertNotError(t, err, "RevokeCertificate failed")
2275
2276
2277 status, err := sa.GetCertificateStatus(ctx, &sapb.Serial{Serial: serial})
2278 test.AssertNotError(t, err, "GetCertificateStatus failed")
2279 test.AssertEquals(t, core.OCSPStatus(status.Status), core.OCSPStatusRevoked)
2280 test.AssertEquals(t, int(status.RevokedReason), ocsp.CessationOfOperation)
2281 fc.Add(1 * time.Hour)
2282
2283
2284 now = fc.Now()
2285 _, err = sa.UpdateRevokedCertificate(context.Background(), &sapb.RevokeCertificateRequest{
2286 IssuerID: 1,
2287 Serial: serial,
2288 DateNS: now.UnixNano(),
2289 Date: timestamppb.New(now),
2290 Reason: ocsp.KeyCompromise,
2291 Response: []byte{4, 5, 6},
2292 })
2293 test.AssertError(t, err, "UpdateRevokedCertificate should have failed")
2294 test.AssertContains(t, err.Error(), "incomplete")
2295
2296
2297 _, err = sa.UpdateRevokedCertificate(context.Background(), &sapb.RevokeCertificateRequest{
2298 IssuerID: 1,
2299 Serial: serial,
2300 DateNS: now.UnixNano(),
2301 Date: timestamppb.New(now),
2302 BackdateNS: revokedTime.UnixNano(),
2303 Backdate: timestamppb.New(revokedTime),
2304 Reason: ocsp.Unspecified,
2305 Response: []byte{4, 5, 6},
2306 })
2307 test.AssertError(t, err, "UpdateRevokedCertificate should have failed")
2308 test.AssertContains(t, err.Error(), "cannot update revocation for any reason other than keyCompromise")
2309
2310
2311 _, err = sa.UpdateRevokedCertificate(context.Background(), &sapb.RevokeCertificateRequest{
2312 IssuerID: 1,
2313 Serial: "000000000000000000000000000000021bd5",
2314 DateNS: now.UnixNano(),
2315 Date: timestamppb.New(now),
2316 BackdateNS: revokedTime.UnixNano(),
2317 Backdate: timestamppb.New(revokedTime),
2318 Reason: ocsp.KeyCompromise,
2319 Response: []byte{4, 5, 6},
2320 })
2321 test.AssertError(t, err, "UpdateRevokedCertificate should have failed")
2322 test.AssertContains(t, err.Error(), "no certificate with serial")
2323
2324
2325 _, err = sa.UpdateRevokedCertificate(context.Background(), &sapb.RevokeCertificateRequest{
2326 IssuerID: 1,
2327 Serial: serial,
2328 DateNS: now.UnixNano(),
2329 Date: timestamppb.New(now),
2330 BackdateNS: now.UnixNano(),
2331 Backdate: timestamppb.New(now),
2332 Reason: ocsp.KeyCompromise,
2333 Response: []byte{4, 5, 6},
2334 })
2335 test.AssertError(t, err, "UpdateRevokedCertificate should have failed")
2336 test.AssertContains(t, err.Error(), "no certificate with serial")
2337
2338
2339 _, err = sa.UpdateRevokedCertificate(context.Background(), &sapb.RevokeCertificateRequest{
2340 IssuerID: 1,
2341 Serial: serial,
2342 DateNS: now.UnixNano(),
2343 Date: timestamppb.New(now),
2344 BackdateNS: revokedTime.UnixNano(),
2345 Backdate: timestamppb.New(revokedTime),
2346 Reason: ocsp.KeyCompromise,
2347 Response: []byte{4, 5, 6},
2348 })
2349 test.AssertNotError(t, err, "UpdateRevokedCertificate failed")
2350 }
2351
2352 func TestUpdateRevokedCertificateWithShard(t *testing.T) {
2353 if os.Getenv("BOULDER_CONFIG_DIR") != "test/config-next" {
2354 t.Skip("Test requires revokedCertificates database table")
2355 }
2356
2357 sa, fc, cleanUp := initSA(t)
2358 defer cleanUp()
2359
2360
2361 reg := createWorkingRegistration(t, sa)
2362 eeCert, err := core.LoadCert("../test/hierarchy/ee-e1.cert.pem")
2363 test.AssertNotError(t, err, "failed to load test cert")
2364 _, err = sa.AddSerial(ctx, &sapb.AddSerialRequest{
2365 RegID: reg.Id,
2366 Serial: core.SerialToString(eeCert.SerialNumber),
2367 CreatedNS: eeCert.NotBefore.UnixNano(),
2368 ExpiresNS: eeCert.NotAfter.UnixNano(),
2369 })
2370 test.AssertNotError(t, err, "failed to add test serial")
2371 _, err = sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
2372 Der: eeCert.Raw,
2373 RegID: reg.Id,
2374 IssuedNS: eeCert.NotBefore.UnixNano(),
2375 Issued: timestamppb.New(eeCert.NotBefore),
2376 IssuerNameID: 1,
2377 })
2378 test.AssertNotError(t, err, "Couldn't add www.eff.org.der")
2379 fc.Add(1 * time.Hour)
2380
2381
2382
2383 revokedTime := fc.Now()
2384 _, err = sa.RevokeCertificate(context.Background(), &sapb.RevokeCertificateRequest{
2385 IssuerID: 1,
2386 ShardIdx: 9,
2387 Serial: core.SerialToString(eeCert.SerialNumber),
2388 DateNS: revokedTime.UnixNano(),
2389 Date: timestamppb.New(revokedTime),
2390 Reason: ocsp.CessationOfOperation,
2391 Response: []byte{1, 2, 3},
2392 })
2393 test.AssertNotError(t, err, "RevokeCertificate failed")
2394
2395
2396
2397 _, err = sa.UpdateRevokedCertificate(context.Background(), &sapb.RevokeCertificateRequest{
2398 IssuerID: 1,
2399 ShardIdx: 9,
2400 Serial: core.SerialToString(eeCert.SerialNumber),
2401 DateNS: fc.Now().UnixNano(),
2402 Date: timestamppb.New(fc.Now()),
2403 BackdateNS: revokedTime.UnixNano(),
2404 Backdate: timestamppb.New(revokedTime),
2405 Reason: ocsp.KeyCompromise,
2406 Response: []byte{4, 5, 6},
2407 })
2408 test.AssertNotError(t, err, "UpdateRevokedCertificate failed")
2409
2410 var result revokedCertModel
2411 err = sa.dbMap.SelectOne(
2412 ctx, &result, `SELECT * FROM revokedCertificates WHERE serial = ?`, core.SerialToString(eeCert.SerialNumber))
2413 test.AssertNotError(t, err, "should be exactly one row in revokedCertificates")
2414 test.AssertEquals(t, result.ShardIdx, int64(9))
2415 test.AssertEquals(t, result.RevokedReason, revocation.Reason(ocsp.KeyCompromise))
2416 }
2417
2418 func TestUpdateRevokedCertificateWithShardInterim(t *testing.T) {
2419 if os.Getenv("BOULDER_CONFIG_DIR") != "test/config-next" {
2420 t.Skip("Test requires revokedCertificates database table")
2421 }
2422
2423 sa, fc, cleanUp := initSA(t)
2424 defer cleanUp()
2425
2426
2427 reg := createWorkingRegistration(t, sa)
2428 eeCert, err := core.LoadCert("../test/hierarchy/ee-e1.cert.pem")
2429 test.AssertNotError(t, err, "failed to load test cert")
2430 _, err = sa.AddSerial(ctx, &sapb.AddSerialRequest{
2431 RegID: reg.Id,
2432 Serial: core.SerialToString(eeCert.SerialNumber),
2433 CreatedNS: eeCert.NotBefore.UnixNano(),
2434 ExpiresNS: eeCert.NotAfter.UnixNano(),
2435 })
2436 test.AssertNotError(t, err, "failed to add test serial")
2437 _, err = sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
2438 Der: eeCert.Raw,
2439 RegID: reg.Id,
2440 IssuedNS: eeCert.NotBefore.UnixNano(),
2441 Issued: timestamppb.New(eeCert.NotBefore),
2442 IssuerNameID: 1,
2443 })
2444 test.AssertNotError(t, err, "Couldn't add www.eff.org.der")
2445 fc.Add(1 * time.Hour)
2446
2447
2448
2449 revokedTime := fc.Now().UnixNano()
2450 _, err = sa.RevokeCertificate(context.Background(), &sapb.RevokeCertificateRequest{
2451 IssuerID: 1,
2452 Serial: core.SerialToString(eeCert.SerialNumber),
2453 DateNS: revokedTime,
2454 Reason: ocsp.CessationOfOperation,
2455 Response: []byte{1, 2, 3},
2456 })
2457 test.AssertNotError(t, err, "RevokeCertificate failed")
2458
2459
2460 status, err := sa.GetCertificateStatus(
2461 ctx, &sapb.Serial{Serial: core.SerialToString(eeCert.SerialNumber)})
2462 test.AssertNotError(t, err, "GetCertificateStatus failed")
2463 test.AssertEquals(t, core.OCSPStatus(status.Status), core.OCSPStatusRevoked)
2464
2465 c, err := sa.dbMap.SelectNullInt(
2466 ctx, "SELECT count(*) FROM revokedCertificates")
2467 test.AssertNotError(t, err, "SELECT from revokedCertificates failed")
2468 test.Assert(t, c.Valid, "SELECT from revokedCertificates got no result")
2469 test.AssertEquals(t, c.Int64, int64(0))
2470
2471
2472
2473 _, err = sa.UpdateRevokedCertificate(context.Background(), &sapb.RevokeCertificateRequest{
2474 IssuerID: 1,
2475 ShardIdx: 9,
2476 Serial: core.SerialToString(eeCert.SerialNumber),
2477 DateNS: fc.Now().UnixNano(),
2478 BackdateNS: revokedTime,
2479 Reason: ocsp.KeyCompromise,
2480 Response: []byte{4, 5, 6},
2481 })
2482 test.AssertNotError(t, err, "UpdateRevokedCertificate failed")
2483
2484 var result revokedCertModel
2485 err = sa.dbMap.SelectOne(
2486 ctx, &result, `SELECT * FROM revokedCertificates WHERE serial = ?`, core.SerialToString(eeCert.SerialNumber))
2487 test.AssertNotError(t, err, "should be exactly one row in revokedCertificates")
2488 test.AssertEquals(t, result.ShardIdx, int64(9))
2489 test.AssertEquals(t, result.RevokedReason, revocation.Reason(ocsp.KeyCompromise))
2490 }
2491
2492 func TestAddCertificateRenewalBit(t *testing.T) {
2493 sa, fc, cleanUp := initSA(t)
2494 defer cleanUp()
2495
2496 reg := createWorkingRegistration(t, sa)
2497
2498
2499 certDER, err := os.ReadFile("www.eff.org.der")
2500 test.AssertNotError(t, err, "Unexpected error reading www.eff.org.der test file")
2501 cert, err := x509.ParseCertificate(certDER)
2502 test.AssertNotError(t, err, "Unexpected error parsing www.eff.org.der test file")
2503 names := cert.DNSNames
2504
2505 expires := fc.Now().Add(time.Hour * 2).UTC()
2506 issued := fc.Now()
2507 serial := "thrilla"
2508
2509
2510 tx, err := sa.dbMap.BeginTx(ctx)
2511 test.AssertNotError(t, err, "Failed to open transaction")
2512 err = addFQDNSet(ctx, tx, names, serial, issued, expires)
2513 test.AssertNotError(t, err, "Failed to add name set")
2514 test.AssertNotError(t, tx.Commit(), "Failed to commit transaction")
2515
2516
2517 _, err = sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
2518 Der: certDER,
2519 IssuedNS: issued.UnixNano(),
2520 Issued: timestamppb.New(issued),
2521 RegID: reg.Id,
2522 IssuerNameID: 1,
2523 })
2524 test.AssertNotError(t, err, "Failed to add precertificate")
2525 _, err = sa.AddCertificate(ctx, &sapb.AddCertificateRequest{
2526 Der: certDER,
2527 RegID: reg.Id,
2528 IssuedNS: issued.UnixNano(),
2529 Issued: timestamppb.New(issued),
2530 })
2531 test.AssertNotError(t, err, "Failed to add certificate")
2532
2533 assertIsRenewal := func(t *testing.T, name string, expected bool) {
2534 t.Helper()
2535 var count int
2536 err := sa.dbMap.SelectOne(
2537 ctx,
2538 &count,
2539 `SELECT COUNT(*) FROM issuedNames
2540 WHERE reversedName = ?
2541 AND renewal = ?`,
2542 ReverseName(name),
2543 expected,
2544 )
2545 test.AssertNotError(t, err, "Unexpected error from SelectOne on issuedNames")
2546 test.AssertEquals(t, count, 1)
2547 }
2548
2549
2550 for _, name := range names {
2551 assertIsRenewal(t, name, true)
2552 }
2553
2554
2555 certDER, err = os.ReadFile("test-cert.der")
2556 test.AssertNotError(t, err, "Unexpected error reading test-cert.der test file")
2557 cert, err = x509.ParseCertificate(certDER)
2558 test.AssertNotError(t, err, "Unexpected error parsing test-cert.der test file")
2559 names = cert.DNSNames
2560
2561 _, err = sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
2562 Der: certDER,
2563 IssuedNS: issued.UnixNano(),
2564 Issued: timestamppb.New(issued),
2565 RegID: reg.Id,
2566 IssuerNameID: 1,
2567 })
2568 test.AssertNotError(t, err, "Failed to add precertificate")
2569 _, err = sa.AddCertificate(ctx, &sapb.AddCertificateRequest{
2570 Der: certDER,
2571 RegID: reg.Id,
2572 IssuedNS: issued.UnixNano(),
2573 Issued: timestamppb.New(issued),
2574 })
2575 test.AssertNotError(t, err, "Failed to add certificate")
2576
2577
2578 for _, name := range names {
2579 assertIsRenewal(t, name, false)
2580 }
2581 }
2582
2583 func TestCountCertificatesRenewalBit(t *testing.T) {
2584 sa, fc, cleanUp := initSA(t)
2585 defer cleanUp()
2586
2587
2588 reg := createWorkingRegistration(t, sa)
2589
2590
2591 testKey, err := rsa.GenerateKey(rand.Reader, 512)
2592 test.AssertNotError(t, err, "error generating test key")
2593
2594
2595
2596 template := &x509.Certificate{
2597 SerialNumber: big.NewInt(1337),
2598 DNSNames: []string{"www.not-example.com", "not-example.com", "admin.not-example.com"},
2599 NotBefore: fc.Now().Add(-time.Hour),
2600 BasicConstraintsValid: true,
2601 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
2602 }
2603 certADER, err := x509.CreateCertificate(rand.Reader, template, template, testKey.Public(), testKey)
2604 test.AssertNotError(t, err, "Failed to create test cert A")
2605 certA, _ := x509.ParseCertificate(certADER)
2606
2607
2608
2609 template.SerialNumber = big.NewInt(7331)
2610 template.NotBefore = fc.Now()
2611 certBDER, err := x509.CreateCertificate(rand.Reader, template, template, testKey.Public(), testKey)
2612 test.AssertNotError(t, err, "Failed to create test cert B")
2613 certB, _ := x509.ParseCertificate(certBDER)
2614
2615
2616
2617
2618 template.SerialNumber = big.NewInt(0xC0FFEE)
2619 template.DNSNames = []string{"www.not-example.com"}
2620 certCDER, err := x509.CreateCertificate(rand.Reader, template, template, testKey.Public(), testKey)
2621 test.AssertNotError(t, err, "Failed to create test cert C")
2622
2623 countName := func(t *testing.T, expectedName string) int64 {
2624 earliest := fc.Now().Add(-5 * time.Hour)
2625 latest := fc.Now().Add(5 * time.Hour)
2626 req := &sapb.CountCertificatesByNamesRequest{
2627 Names: []string{expectedName},
2628 Range: &sapb.Range{
2629 EarliestNS: earliest.UnixNano(),
2630 Earliest: timestamppb.New(earliest),
2631 LatestNS: latest.UnixNano(),
2632 Latest: timestamppb.New(latest),
2633 },
2634 }
2635 counts, err := sa.CountCertificatesByNames(context.Background(), req)
2636 test.AssertNotError(t, err, "Unexpected err from CountCertificatesByNames")
2637 for name, count := range counts.Counts {
2638 if name == expectedName {
2639 return count
2640 }
2641 }
2642 return 0
2643 }
2644
2645
2646 issued := certA.NotBefore
2647 _, err = sa.AddCertificate(ctx, &sapb.AddCertificateRequest{
2648 Der: certADER,
2649 RegID: reg.Id,
2650 IssuedNS: issued.UnixNano(),
2651 Issued: timestamppb.New(issued),
2652 })
2653 test.AssertNotError(t, err, "Failed to add CertA test certificate")
2654
2655
2656 test.AssertEquals(t, countName(t, "not-example.com"), int64(1))
2657
2658
2659 issued = certB.NotBefore
2660 _, err = sa.AddCertificate(ctx, &sapb.AddCertificateRequest{
2661 Der: certBDER,
2662 RegID: reg.Id,
2663 IssuedNS: issued.UnixNano(),
2664 Issued: timestamppb.New(issued),
2665 })
2666 test.AssertNotError(t, err, "Failed to add CertB test certificate")
2667
2668
2669
2670 test.AssertEquals(t, countName(t, "not-example.com"), int64(1))
2671
2672
2673 _, err = sa.AddCertificate(ctx, &sapb.AddCertificateRequest{
2674 Der: certCDER,
2675 RegID: reg.Id,
2676 IssuedNS: issued.UnixNano(),
2677 Issued: timestamppb.New(issued),
2678 })
2679 test.AssertNotError(t, err, "Failed to add CertC test certificate")
2680
2681
2682
2683 test.AssertEquals(t, countName(t, "not-example.com"), int64(2))
2684 }
2685
2686 func TestFinalizeAuthorization2(t *testing.T) {
2687 sa, fc, cleanUp := initSA(t)
2688 defer cleanUp()
2689
2690 fc.Set(time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC))
2691
2692 authzID := createPendingAuthorization(t, sa, "aaa", fc.Now().Add(time.Hour))
2693 expires := fc.Now().Add(time.Hour * 2).UTC()
2694 attemptedAt := fc.Now()
2695 ip, _ := net.ParseIP("1.1.1.1").MarshalText()
2696
2697 _, err := sa.FinalizeAuthorization2(context.Background(), &sapb.FinalizeAuthorizationRequest{
2698 Id: authzID,
2699 ValidationRecords: []*corepb.ValidationRecord{
2700 {
2701 Hostname: "example.com",
2702 Port: "80",
2703 Url: "http://example.com",
2704 AddressUsed: ip,
2705 },
2706 },
2707 Status: string(core.StatusValid),
2708 ExpiresNS: expires.UnixNano(),
2709 Expires: timestamppb.New(expires),
2710 Attempted: string(core.ChallengeTypeHTTP01),
2711 AttemptedAtNS: attemptedAt.UnixNano(),
2712 AttemptedAt: timestamppb.New(attemptedAt),
2713 })
2714 test.AssertNotError(t, err, "sa.FinalizeAuthorization2 failed")
2715
2716 dbVer, err := sa.GetAuthorization2(context.Background(), &sapb.AuthorizationID2{Id: authzID})
2717 test.AssertNotError(t, err, "sa.GetAuthorization2 failed")
2718 test.AssertEquals(t, dbVer.Status, string(core.StatusValid))
2719 test.AssertEquals(t, dbVer.ExpiresNS, expires.UnixNano())
2720 test.AssertEquals(t, dbVer.Expires.AsTime(), expires)
2721 test.AssertEquals(t, dbVer.Challenges[0].Status, string(core.StatusValid))
2722 test.AssertEquals(t, len(dbVer.Challenges[0].Validationrecords), 1)
2723 test.AssertEquals(t, dbVer.Challenges[0].Validationrecords[0].Hostname, "example.com")
2724 test.AssertEquals(t, dbVer.Challenges[0].Validationrecords[0].Port, "80")
2725 test.AssertEquals(t, dbVer.Challenges[0].ValidatedNS, attemptedAt.UnixNano())
2726 test.AssertEquals(t, dbVer.Challenges[0].Validated.AsTime(), attemptedAt)
2727
2728 authzID = createPendingAuthorization(t, sa, "aaa", fc.Now().Add(time.Hour))
2729 prob, _ := bgrpc.ProblemDetailsToPB(probs.Connection("it went bad captain"))
2730
2731 _, err = sa.FinalizeAuthorization2(context.Background(), &sapb.FinalizeAuthorizationRequest{
2732 Id: authzID,
2733 ValidationRecords: []*corepb.ValidationRecord{
2734 {
2735 Hostname: "example.com",
2736 Port: "80",
2737 Url: "http://example.com",
2738 AddressUsed: ip,
2739 },
2740 },
2741 ValidationError: prob,
2742 Status: string(core.StatusInvalid),
2743 Attempted: string(core.ChallengeTypeHTTP01),
2744 ExpiresNS: expires.UnixNano(),
2745 Expires: timestamppb.New(expires),
2746 })
2747 test.AssertNotError(t, err, "sa.FinalizeAuthorization2 failed")
2748
2749 dbVer, err = sa.GetAuthorization2(context.Background(), &sapb.AuthorizationID2{Id: authzID})
2750 test.AssertNotError(t, err, "sa.GetAuthorization2 failed")
2751 test.AssertEquals(t, dbVer.Status, string(core.StatusInvalid))
2752 test.AssertEquals(t, dbVer.Challenges[0].Status, string(core.StatusInvalid))
2753 test.AssertEquals(t, len(dbVer.Challenges[0].Validationrecords), 1)
2754 test.AssertEquals(t, dbVer.Challenges[0].Validationrecords[0].Hostname, "example.com")
2755 test.AssertEquals(t, dbVer.Challenges[0].Validationrecords[0].Port, "80")
2756 test.AssertDeepEquals(t, dbVer.Challenges[0].Error, prob)
2757 }
2758
2759 func TestRehydrateHostPort(t *testing.T) {
2760 sa, fc, cleanUp := initSA(t)
2761 defer cleanUp()
2762
2763 fc.Set(time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC))
2764
2765 expires := fc.Now().Add(time.Hour * 2).UTC()
2766 attemptedAt := fc.Now()
2767 ip, _ := net.ParseIP("1.1.1.1").MarshalText()
2768
2769
2770 authzID := createPendingAuthorization(t, sa, "aaa", fc.Now().Add(time.Hour))
2771 _, err := sa.FinalizeAuthorization2(context.Background(), &sapb.FinalizeAuthorizationRequest{
2772 Id: authzID,
2773 ValidationRecords: []*corepb.ValidationRecord{
2774 {
2775 Hostname: "example.com",
2776 Port: "80",
2777 Url: "http://example.com",
2778 AddressUsed: ip,
2779 },
2780 },
2781 Status: string(core.StatusValid),
2782 ExpiresNS: expires.UnixNano(),
2783 Expires: timestamppb.New(expires),
2784 Attempted: string(core.ChallengeTypeHTTP01),
2785 AttemptedAtNS: attemptedAt.UnixNano(),
2786 AttemptedAt: timestamppb.New(attemptedAt),
2787 })
2788 test.AssertNotError(t, err, "sa.FinalizeAuthorization2 failed")
2789 _, err = sa.GetAuthorization2(context.Background(), &sapb.AuthorizationID2{Id: authzID})
2790 test.AssertNotError(t, err, "rehydration failed in some fun and interesting way")
2791
2792
2793 authzID = createPendingAuthorization(t, sa, "aaa", fc.Now().Add(time.Hour))
2794 _, err = sa.FinalizeAuthorization2(context.Background(), &sapb.FinalizeAuthorizationRequest{
2795 Id: authzID,
2796 ValidationRecords: []*corepb.ValidationRecord{
2797 {
2798 Hostname: "example.com",
2799 Port: "80",
2800 Url: "http://example.com:80",
2801 AddressUsed: ip,
2802 },
2803 },
2804 Status: string(core.StatusValid),
2805 ExpiresNS: expires.UnixNano(),
2806 Expires: timestamppb.New(expires),
2807 Attempted: string(core.ChallengeTypeHTTP01),
2808 AttemptedAtNS: attemptedAt.UnixNano(),
2809 AttemptedAt: timestamppb.New(attemptedAt),
2810 })
2811 test.AssertNotError(t, err, "sa.FinalizeAuthorization2 failed")
2812 _, err = sa.GetAuthorization2(context.Background(), &sapb.AuthorizationID2{Id: authzID})
2813 test.AssertNotError(t, err, "rehydration failed in some fun and interesting way")
2814
2815
2816 authzID = createPendingAuthorization(t, sa, "aaa", fc.Now().Add(time.Hour))
2817 _, err = sa.FinalizeAuthorization2(context.Background(), &sapb.FinalizeAuthorizationRequest{
2818 Id: authzID,
2819 ValidationRecords: []*corepb.ValidationRecord{
2820 {
2821 Hostname: "example.com",
2822 Port: "444",
2823 Url: "http://example.com:444",
2824 AddressUsed: ip,
2825 },
2826 },
2827 Status: string(core.StatusValid),
2828 ExpiresNS: expires.UnixNano(),
2829 Expires: timestamppb.New(expires),
2830 Attempted: string(core.ChallengeTypeHTTP01),
2831 AttemptedAtNS: attemptedAt.UnixNano(),
2832 AttemptedAt: timestamppb.New(attemptedAt),
2833 })
2834 test.AssertNotError(t, err, "sa.FinalizeAuthorization2 failed")
2835 _, err = sa.GetAuthorization2(context.Background(), &sapb.AuthorizationID2{Id: authzID})
2836 test.AssertError(t, err, "only ports 80/tcp and 443/tcp are allowed in URL \"http://example.com:444\"")
2837
2838
2839 authzID = createPendingAuthorization(t, sa, "aaa", fc.Now().Add(time.Hour))
2840 _, err = sa.FinalizeAuthorization2(context.Background(), &sapb.FinalizeAuthorizationRequest{
2841 Id: authzID,
2842 ValidationRecords: []*corepb.ValidationRecord{
2843 {
2844 Hostname: "example.com",
2845 Port: "80",
2846 Url: "httpx://example.com",
2847 AddressUsed: ip,
2848 },
2849 },
2850 Status: string(core.StatusValid),
2851 ExpiresNS: expires.UnixNano(),
2852 Expires: timestamppb.New(expires),
2853 Attempted: string(core.ChallengeTypeHTTP01),
2854 AttemptedAtNS: attemptedAt.UnixNano(),
2855 AttemptedAt: timestamppb.New(attemptedAt),
2856 })
2857 test.AssertNotError(t, err, "sa.FinalizeAuthorization2 failed")
2858 _, err = sa.GetAuthorization2(context.Background(), &sapb.AuthorizationID2{Id: authzID})
2859 test.AssertError(t, err, "unknown scheme \"httpx\" in URL \"httpx://example.com\"")
2860
2861
2862 authzID = createPendingAuthorization(t, sa, "aaa", fc.Now().Add(time.Hour))
2863 _, err = sa.FinalizeAuthorization2(context.Background(), &sapb.FinalizeAuthorizationRequest{
2864 Id: authzID,
2865 ValidationRecords: []*corepb.ValidationRecord{
2866 {
2867 Hostname: "example.com",
2868 Port: "80",
2869 AddressUsed: ip,
2870 },
2871 },
2872 Status: string(core.StatusValid),
2873 ExpiresNS: expires.UnixNano(),
2874 Expires: timestamppb.New(expires),
2875 Attempted: string(core.ChallengeTypeHTTP01),
2876 AttemptedAtNS: attemptedAt.UnixNano(),
2877 AttemptedAt: timestamppb.New(attemptedAt),
2878 })
2879 test.AssertNotError(t, err, "sa.FinalizeAuthorization2 failed")
2880 _, err = sa.GetAuthorization2(context.Background(), &sapb.AuthorizationID2{Id: authzID})
2881 test.AssertError(t, err, "URL field cannot be empty")
2882 }
2883
2884 func TestGetPendingAuthorization2(t *testing.T) {
2885 sa, fc, cleanUp := initSA(t)
2886 defer cleanUp()
2887
2888 domain := "example.com"
2889 expiresA := fc.Now().Add(time.Hour).UTC()
2890 expiresB := fc.Now().Add(time.Hour * 3).UTC()
2891 authzIDA := createPendingAuthorization(t, sa, domain, expiresA)
2892 authzIDB := createPendingAuthorization(t, sa, domain, expiresB)
2893
2894 regID := int64(1)
2895 validUntil := fc.Now().Add(time.Hour * 2).UTC()
2896 dbVer, err := sa.GetPendingAuthorization2(context.Background(), &sapb.GetPendingAuthorizationRequest{
2897 RegistrationID: regID,
2898 IdentifierValue: domain,
2899 ValidUntilNS: validUntil.UnixNano(),
2900 ValidUntil: timestamppb.New(validUntil),
2901 })
2902 test.AssertNotError(t, err, "sa.GetPendingAuthorization2 failed")
2903 test.AssertEquals(t, fmt.Sprintf("%d", authzIDB), dbVer.Id)
2904
2905 validUntil = fc.Now().UTC()
2906 dbVer, err = sa.GetPendingAuthorization2(context.Background(), &sapb.GetPendingAuthorizationRequest{
2907 RegistrationID: regID,
2908 IdentifierValue: domain,
2909 ValidUntilNS: validUntil.UnixNano(),
2910 ValidUntil: timestamppb.New(validUntil),
2911 })
2912 test.AssertNotError(t, err, "sa.GetPendingAuthorization2 failed")
2913 test.AssertEquals(t, fmt.Sprintf("%d", authzIDA), dbVer.Id)
2914 }
2915
2916 func TestCountPendingAuthorizations2(t *testing.T) {
2917 sa, fc, cleanUp := initSA(t)
2918 defer cleanUp()
2919
2920 expiresA := fc.Now().Add(time.Hour).UTC()
2921 expiresB := fc.Now().Add(time.Hour * 3).UTC()
2922 _ = createPendingAuthorization(t, sa, "example.com", expiresA)
2923 _ = createPendingAuthorization(t, sa, "example.com", expiresB)
2924
2925
2926 regID := int64(1)
2927 count, err := sa.CountPendingAuthorizations2(context.Background(), &sapb.RegistrationID{
2928 Id: regID,
2929 })
2930 test.AssertNotError(t, err, "sa.CountPendingAuthorizations2 failed")
2931 test.AssertEquals(t, count.Count, int64(2))
2932
2933
2934 fc.Add(time.Hour * 2)
2935 count, err = sa.CountPendingAuthorizations2(context.Background(), &sapb.RegistrationID{
2936 Id: regID,
2937 })
2938 test.AssertNotError(t, err, "sa.CountPendingAuthorizations2 failed")
2939 test.AssertEquals(t, count.Count, int64(1))
2940
2941
2942 noReg := int64(20)
2943 count, err = sa.CountPendingAuthorizations2(context.Background(), &sapb.RegistrationID{
2944 Id: noReg,
2945 })
2946 test.AssertNotError(t, err, "sa.CountPendingAuthorizations2 failed")
2947 test.AssertEquals(t, count.Count, int64(0))
2948 }
2949
2950 func TestAuthzModelMapToPB(t *testing.T) {
2951 baseExpires := time.Now()
2952 input := map[string]authzModel{
2953 "example.com": {
2954 ID: 123,
2955 IdentifierType: 0,
2956 IdentifierValue: "example.com",
2957 RegistrationID: 77,
2958 Status: 1,
2959 Expires: baseExpires,
2960 Challenges: 4,
2961 },
2962 "www.example.com": {
2963 ID: 124,
2964 IdentifierType: 0,
2965 IdentifierValue: "www.example.com",
2966 RegistrationID: 77,
2967 Status: 1,
2968 Expires: baseExpires,
2969 Challenges: 1,
2970 },
2971 "other.example.net": {
2972 ID: 125,
2973 IdentifierType: 0,
2974 IdentifierValue: "other.example.net",
2975 RegistrationID: 77,
2976 Status: 1,
2977 Expires: baseExpires,
2978 Challenges: 3,
2979 },
2980 }
2981
2982 out, err := authzModelMapToPB(input)
2983 if err != nil {
2984 t.Fatal(err)
2985 }
2986
2987 for _, el := range out.Authz {
2988 model, ok := input[el.Domain]
2989 if !ok {
2990 t.Errorf("output had element for %q, a hostname not present in input", el.Domain)
2991 }
2992 authzPB := el.Authz
2993 test.AssertEquals(t, authzPB.Id, fmt.Sprintf("%d", model.ID))
2994 test.AssertEquals(t, authzPB.Identifier, model.IdentifierValue)
2995 test.AssertEquals(t, authzPB.RegistrationID, model.RegistrationID)
2996 test.AssertEquals(t, authzPB.Status, string(uintToStatus[model.Status]))
2997 gotTime := time.Unix(0, authzPB.ExpiresNS).UTC()
2998 if !model.Expires.Equal(gotTime) {
2999 t.Errorf("Times didn't match. Got %s, expected %s (%d)", gotTime, model.Expires, authzPB.ExpiresNS)
3000 }
3001 if len(el.Authz.Challenges) != bits.OnesCount(uint(model.Challenges)) {
3002 t.Errorf("wrong number of challenges for %q: got %d, expected %d", el.Domain,
3003 len(el.Authz.Challenges), bits.OnesCount(uint(model.Challenges)))
3004 }
3005 switch model.Challenges {
3006 case 1:
3007 test.AssertEquals(t, el.Authz.Challenges[0].Type, "http-01")
3008 case 3:
3009 test.AssertEquals(t, el.Authz.Challenges[0].Type, "http-01")
3010 test.AssertEquals(t, el.Authz.Challenges[1].Type, "dns-01")
3011 case 4:
3012 test.AssertEquals(t, el.Authz.Challenges[0].Type, "tls-alpn-01")
3013 }
3014
3015 delete(input, el.Domain)
3016 }
3017
3018 for k := range input {
3019 t.Errorf("hostname %q was not present in output", k)
3020 }
3021 }
3022
3023 func TestGetValidOrderAuthorizations2(t *testing.T) {
3024 sa, fc, cleanup := initSA(t)
3025 defer cleanup()
3026
3027
3028 reg := createWorkingRegistration(t, sa)
3029 identA := "a.example.com"
3030 identB := "b.example.com"
3031 expires := fc.Now().Add(time.Hour * 24 * 7).UTC()
3032 attemptedAt := fc.Now()
3033
3034 authzIDA := createFinalizedAuthorization(t, sa, identA, expires, "valid", attemptedAt)
3035 authzIDB := createFinalizedAuthorization(t, sa, identB, expires, "valid", attemptedAt)
3036
3037 orderExpr := fc.Now().Truncate(time.Second)
3038 order, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{
3039 NewOrder: &sapb.NewOrderRequest{
3040 RegistrationID: reg.Id,
3041 ExpiresNS: orderExpr.UnixNano(),
3042 Expires: timestamppb.New(orderExpr),
3043 Names: []string{"a.example.com", "b.example.com"},
3044 V2Authorizations: []int64{authzIDA, authzIDB},
3045 },
3046 })
3047 test.AssertNotError(t, err, "AddOrder failed")
3048
3049 authzMap, err := sa.GetValidOrderAuthorizations2(
3050 context.Background(),
3051 &sapb.GetValidOrderAuthorizationsRequest{
3052 Id: order.Id,
3053 AcctID: reg.Id,
3054 })
3055 test.AssertNotError(t, err, "sa.GetValidOrderAuthorizations failed")
3056 test.AssertNotNil(t, authzMap, "sa.GetValidOrderAuthorizations result was nil")
3057 test.AssertEquals(t, len(authzMap.Authz), 2)
3058
3059 namesToCheck := map[string]int64{"a.example.com": authzIDA, "b.example.com": authzIDB}
3060 for _, a := range authzMap.Authz {
3061 if fmt.Sprintf("%d", namesToCheck[a.Authz.Identifier]) != a.Authz.Id {
3062 t.Fatalf("incorrect identifier %q with id %s", a.Authz.Identifier, a.Authz.Id)
3063 }
3064 test.AssertEquals(t, a.Authz.ExpiresNS, expires.UnixNano())
3065 test.AssertEquals(t, a.Authz.Expires.AsTime(), expires)
3066 delete(namesToCheck, a.Authz.Identifier)
3067 }
3068
3069
3070 missingID := int64(0xC0FFEEEEEEE)
3071 authzMap, err = sa.GetValidOrderAuthorizations2(
3072 context.Background(),
3073 &sapb.GetValidOrderAuthorizationsRequest{
3074 Id: missingID,
3075 AcctID: reg.Id,
3076 })
3077 test.AssertNotError(t, err, "sa.GetValidOrderAuthorizations failed")
3078 test.AssertEquals(t, len(authzMap.Authz), 0)
3079
3080
3081
3082 wrongAcctID := int64(0xDEADDA7ABA5E)
3083 authzMap, err = sa.GetValidOrderAuthorizations2(
3084 context.Background(),
3085 &sapb.GetValidOrderAuthorizationsRequest{
3086 Id: order.Id,
3087 AcctID: wrongAcctID,
3088 })
3089 test.AssertNotError(t, err, "sa.GetValidOrderAuthorizations failed")
3090 test.AssertEquals(t, len(authzMap.Authz), 0)
3091 }
3092
3093 func TestCountInvalidAuthorizations2(t *testing.T) {
3094 sa, fc, cleanUp := initSA(t)
3095 defer cleanUp()
3096
3097
3098 fc.Add(time.Hour)
3099 reg := createWorkingRegistration(t, sa)
3100 ident := "aaa"
3101 expiresA := fc.Now().Add(time.Hour).UTC()
3102 expiresB := fc.Now().Add(time.Hour * 3).UTC()
3103 attemptedAt := fc.Now()
3104 _ = createFinalizedAuthorization(t, sa, ident, expiresA, "invalid", attemptedAt)
3105 _ = createPendingAuthorization(t, sa, ident, expiresB)
3106
3107 earliest := fc.Now().Add(-time.Hour).UTC()
3108 latest := fc.Now().Add(time.Hour * 5).UTC()
3109 count, err := sa.CountInvalidAuthorizations2(context.Background(), &sapb.CountInvalidAuthorizationsRequest{
3110 RegistrationID: reg.Id,
3111 Hostname: ident,
3112 Range: &sapb.Range{
3113 EarliestNS: earliest.UnixNano(),
3114 Earliest: timestamppb.New(earliest),
3115 LatestNS: latest.UnixNano(),
3116 Latest: timestamppb.New(latest),
3117 },
3118 })
3119 test.AssertNotError(t, err, "sa.CountInvalidAuthorizations2 failed")
3120 test.AssertEquals(t, count.Count, int64(1))
3121 }
3122
3123 func TestGetValidAuthorizations2(t *testing.T) {
3124 sa, fc, cleanUp := initSA(t)
3125 defer cleanUp()
3126
3127
3128 ident := "aaa"
3129 expires := fc.Now().Add(time.Hour).UTC()
3130 attemptedAt := fc.Now()
3131 authzID := createFinalizedAuthorization(t, sa, ident, expires, "valid", attemptedAt)
3132
3133 now := fc.Now().UTC()
3134 regID := int64(1)
3135 authzs, err := sa.GetValidAuthorizations2(context.Background(), &sapb.GetValidAuthorizationsRequest{
3136 Domains: []string{
3137 "aaa",
3138 "bbb",
3139 },
3140 RegistrationID: regID,
3141 NowNS: now.UnixNano(),
3142 Now: timestamppb.New(now),
3143 })
3144 test.AssertNotError(t, err, "sa.GetValidAuthorizations2 failed")
3145 test.AssertEquals(t, len(authzs.Authz), 1)
3146 test.AssertEquals(t, authzs.Authz[0].Domain, ident)
3147 test.AssertEquals(t, authzs.Authz[0].Authz.Id, fmt.Sprintf("%d", authzID))
3148 }
3149
3150 func TestGetOrderExpired(t *testing.T) {
3151 sa, fc, cleanUp := initSA(t)
3152 defer cleanUp()
3153 fc.Add(time.Hour * 5)
3154 now := fc.Now()
3155 reg := createWorkingRegistration(t, sa)
3156 order, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{
3157 NewOrder: &sapb.NewOrderRequest{
3158 RegistrationID: reg.Id,
3159 ExpiresNS: now.Add(-time.Hour).UnixNano(),
3160 Expires: timestamppb.New(now.Add(-time.Hour)),
3161 Names: []string{"example.com"},
3162 V2Authorizations: []int64{666},
3163 },
3164 })
3165 test.AssertNotError(t, err, "NewOrderAndAuthzs failed")
3166 _, err = sa.GetOrder(context.Background(), &sapb.OrderRequest{
3167 Id: order.Id,
3168 })
3169 test.AssertError(t, err, "GetOrder didn't fail for an expired order")
3170 test.AssertErrorIs(t, err, berrors.NotFound)
3171 }
3172
3173 func TestBlockedKey(t *testing.T) {
3174 sa, _, cleanUp := initSA(t)
3175 defer cleanUp()
3176
3177 hashA := make([]byte, 32)
3178 hashA[0] = 1
3179 hashB := make([]byte, 32)
3180 hashB[0] = 2
3181
3182 added := time.Now()
3183 source := "API"
3184 _, err := sa.AddBlockedKey(context.Background(), &sapb.AddBlockedKeyRequest{
3185 KeyHash: hashA,
3186 AddedNS: added.UnixNano(),
3187 Added: timestamppb.New(added),
3188 Source: source,
3189 })
3190 test.AssertNotError(t, err, "AddBlockedKey failed")
3191 _, err = sa.AddBlockedKey(context.Background(), &sapb.AddBlockedKeyRequest{
3192 KeyHash: hashA,
3193 AddedNS: added.UnixNano(),
3194 Added: timestamppb.New(added),
3195 Source: source,
3196 })
3197 test.AssertNotError(t, err, "AddBlockedKey failed with duplicate insert")
3198
3199 comment := "testing comments"
3200 _, err = sa.AddBlockedKey(context.Background(), &sapb.AddBlockedKeyRequest{
3201 KeyHash: hashB,
3202 AddedNS: added.UnixNano(),
3203 Added: timestamppb.New(added),
3204 Source: source,
3205 Comment: comment,
3206 })
3207 test.AssertNotError(t, err, "AddBlockedKey failed")
3208
3209 exists, err := sa.KeyBlocked(context.Background(), &sapb.KeyBlockedRequest{
3210 KeyHash: hashA,
3211 })
3212 test.AssertNotError(t, err, "KeyBlocked failed")
3213 test.Assert(t, exists != nil, "*sapb.Exists is nil")
3214 test.Assert(t, exists.Exists, "KeyBlocked returned false for blocked key")
3215 exists, err = sa.KeyBlocked(context.Background(), &sapb.KeyBlockedRequest{
3216 KeyHash: hashB,
3217 })
3218 test.AssertNotError(t, err, "KeyBlocked failed")
3219 test.Assert(t, exists != nil, "*sapb.Exists is nil")
3220 test.Assert(t, exists.Exists, "KeyBlocked returned false for blocked key")
3221 exists, err = sa.KeyBlocked(context.Background(), &sapb.KeyBlockedRequest{
3222 KeyHash: []byte{5},
3223 })
3224 test.AssertNotError(t, err, "KeyBlocked failed")
3225 test.Assert(t, exists != nil, "*sapb.Exists is nil")
3226 test.Assert(t, !exists.Exists, "KeyBlocked returned true for non-blocked key")
3227 }
3228
3229 func TestAddBlockedKeyUnknownSource(t *testing.T) {
3230 sa, fc, cleanUp := initSA(t)
3231 defer cleanUp()
3232
3233 now := fc.Now()
3234 _, err := sa.AddBlockedKey(context.Background(), &sapb.AddBlockedKeyRequest{
3235 KeyHash: []byte{1, 2, 3},
3236 AddedNS: now.UnixNano(),
3237 Added: timestamppb.New(now),
3238 Source: "heyo",
3239 })
3240 test.AssertError(t, err, "AddBlockedKey didn't fail with unknown source")
3241 test.AssertEquals(t, err.Error(), "unknown source")
3242 }
3243
3244 func TestBlockedKeyRevokedBy(t *testing.T) {
3245 sa, fc, cleanUp := initSA(t)
3246 defer cleanUp()
3247
3248 now := fc.Now()
3249 _, err := sa.AddBlockedKey(context.Background(), &sapb.AddBlockedKeyRequest{
3250 KeyHash: []byte{1},
3251 AddedNS: now.UnixNano(),
3252 Added: timestamppb.New(now),
3253 Source: "API",
3254 })
3255 test.AssertNotError(t, err, "AddBlockedKey failed")
3256
3257 _, err = sa.AddBlockedKey(context.Background(), &sapb.AddBlockedKeyRequest{
3258 KeyHash: []byte{2},
3259 AddedNS: now.UnixNano(),
3260 Added: timestamppb.New(now),
3261 Source: "API",
3262 RevokedBy: 1,
3263 })
3264 test.AssertNotError(t, err, "AddBlockedKey failed")
3265 }
3266
3267 func TestIncidentsForSerial(t *testing.T) {
3268 sa, _, cleanUp := initSA(t)
3269 defer cleanUp()
3270
3271 testSADbMap, err := DBMapForTest(vars.DBConnSAFullPerms)
3272 test.AssertNotError(t, err, "Couldn't create test dbMap")
3273
3274 testIncidentsDbMap, err := DBMapForTest(vars.DBConnIncidentsFullPerms)
3275 test.AssertNotError(t, err, "Couldn't create test dbMap")
3276 defer test.ResetIncidentsTestDatabase(t)
3277
3278 weekAgo := sa.clk.Now().Add(-time.Hour * 24 * 7)
3279
3280
3281 err = testSADbMap.Insert(ctx, &incidentModel{
3282 SerialTable: "incident_foo",
3283 URL: "https://example.com/foo-incident",
3284 RenewBy: sa.clk.Now().Add(time.Hour * 24 * 7),
3285 Enabled: false,
3286 })
3287 test.AssertNotError(t, err, "Failed to insert disabled incident")
3288
3289
3290 result, err := sa.IncidentsForSerial(context.Background(), &sapb.Serial{Serial: "1337"})
3291 test.AssertNotError(t, err, "fetching from no incidents")
3292 test.AssertEquals(t, len(result.Incidents), 0)
3293
3294
3295 err = testSADbMap.Insert(ctx, &incidentModel{
3296 SerialTable: "incident_bar",
3297 URL: "https://example.com/test-incident",
3298 RenewBy: sa.clk.Now().Add(time.Hour * 24 * 7),
3299 Enabled: true,
3300 })
3301 test.AssertNotError(t, err, "Failed to insert enabled incident")
3302
3303
3304 one := int64(1)
3305 affectedCertA := incidentSerialModel{
3306 Serial: "1338",
3307 RegistrationID: &one,
3308 OrderID: &one,
3309 LastNoticeSent: &weekAgo,
3310 }
3311 _, err = testIncidentsDbMap.ExecContext(ctx,
3312 fmt.Sprintf("INSERT INTO incident_bar (%s) VALUES ('%s', %d, %d, '%s')",
3313 "serial, registrationID, orderID, lastNoticeSent",
3314 affectedCertA.Serial,
3315 affectedCertA.RegistrationID,
3316 affectedCertA.OrderID,
3317 affectedCertA.LastNoticeSent.Format(time.DateTime),
3318 ),
3319 )
3320 test.AssertNotError(t, err, "Error while inserting row for '1338' into incident table")
3321
3322
3323 result, err = sa.IncidentsForSerial(context.Background(), &sapb.Serial{Serial: "1337"})
3324 test.AssertNotError(t, err, "fetching from one incident")
3325 test.AssertEquals(t, len(result.Incidents), 0)
3326
3327
3328 two := int64(2)
3329 affectedCertB := incidentSerialModel{
3330 Serial: "1337",
3331 RegistrationID: &two,
3332 OrderID: &two,
3333 LastNoticeSent: &weekAgo,
3334 }
3335 _, err = testIncidentsDbMap.ExecContext(ctx,
3336 fmt.Sprintf("INSERT INTO incident_bar (%s) VALUES ('%s', %d, %d, '%s')",
3337 "serial, registrationID, orderID, lastNoticeSent",
3338 affectedCertB.Serial,
3339 affectedCertB.RegistrationID,
3340 affectedCertB.OrderID,
3341 affectedCertB.LastNoticeSent.Format(time.DateTime),
3342 ),
3343 )
3344 test.AssertNotError(t, err, "Error while inserting row for '1337' into incident table")
3345
3346
3347 result, err = sa.IncidentsForSerial(context.Background(), &sapb.Serial{Serial: "1337"})
3348 test.AssertNotError(t, err, "Failed to retrieve incidents for serial")
3349 test.AssertEquals(t, len(result.Incidents), 1)
3350 }
3351
3352 type mockSerialsForIncidentServerStream struct {
3353 grpc.ServerStream
3354 output chan<- *sapb.IncidentSerial
3355 }
3356
3357 func (s mockSerialsForIncidentServerStream) Send(serial *sapb.IncidentSerial) error {
3358 s.output <- serial
3359 return nil
3360 }
3361
3362 func (s mockSerialsForIncidentServerStream) Context() context.Context {
3363 return context.Background()
3364 }
3365
3366 func TestSerialsForIncident(t *testing.T) {
3367 sa, _, cleanUp := initSA(t)
3368 defer cleanUp()
3369
3370 testIncidentsDbMap, err := DBMapForTest(vars.DBConnIncidentsFullPerms)
3371 test.AssertNotError(t, err, "Couldn't create test dbMap")
3372 defer test.ResetIncidentsTestDatabase(t)
3373
3374
3375 mockServerStream := mockSerialsForIncidentServerStream{}
3376 err = sa.SerialsForIncident(
3377 &sapb.SerialsForIncidentRequest{
3378 IncidentTable: "incidesnt_Baz",
3379 },
3380 mockServerStream,
3381 )
3382 test.AssertError(t, err, "Expected error for malformed table name")
3383 test.AssertContains(t, err.Error(), "malformed table name \"incidesnt_Baz\"")
3384
3385
3386 mockServerStream = mockSerialsForIncidentServerStream{}
3387 longTableName := "incident_l" + strings.Repeat("o", 1000) + "ng"
3388 err = sa.SerialsForIncident(
3389 &sapb.SerialsForIncidentRequest{
3390 IncidentTable: longTableName,
3391 },
3392 mockServerStream,
3393 )
3394 test.AssertError(t, err, "Expected error for long table name")
3395 test.AssertContains(t, err.Error(), fmt.Sprintf("malformed table name %q", longTableName))
3396
3397
3398 mockServerStream = mockSerialsForIncidentServerStream{}
3399 err = sa.SerialsForIncident(
3400 &sapb.SerialsForIncidentRequest{
3401 IncidentTable: "incident_baz",
3402 },
3403 mockServerStream,
3404 )
3405 test.AssertError(t, err, "Expected error for nonexistent table name")
3406
3407
3408 var mysqlErr *mysql.MySQLError
3409 if errors.As(err, &mysqlErr) {
3410
3411
3412 test.AssertEquals(t, mysqlErr.Number, uint16(1146))
3413 } else {
3414 t.Fatalf("Expected MySQL Error 1146 (ER_NO_SUCH_TABLE) from Recv(), got %q", err)
3415 }
3416
3417
3418
3419 stream := make(chan *sapb.IncidentSerial)
3420 mockServerStream = mockSerialsForIncidentServerStream{output: stream}
3421 go func() {
3422 err = sa.SerialsForIncident(
3423 &sapb.SerialsForIncidentRequest{
3424 IncidentTable: "incident_foo",
3425 },
3426 mockServerStream,
3427 )
3428 close(stream)
3429 }()
3430 for range stream {
3431 t.Fatal("No serials should have been written to this stream")
3432 }
3433 test.AssertNotError(t, err, "Error calling SerialsForIncident on empty table")
3434
3435
3436 expectedSerials := map[string]bool{
3437 "1335": true, "1336": true, "1337": true, "1338": true,
3438 }
3439 for i := range expectedSerials {
3440 randInt := func() int64 { return mrand.Int63() }
3441 _, err := testIncidentsDbMap.ExecContext(ctx,
3442 fmt.Sprintf("INSERT INTO incident_foo (%s) VALUES ('%s', %d, %d, '%s')",
3443 "serial, registrationID, orderID, lastNoticeSent",
3444 i,
3445 randInt(),
3446 randInt(),
3447 sa.clk.Now().Add(time.Hour*24*7).Format(time.DateTime),
3448 ),
3449 )
3450 test.AssertNotError(t, err, fmt.Sprintf("Error while inserting row for '%s' into incident table", i))
3451 }
3452
3453
3454 stream = make(chan *sapb.IncidentSerial)
3455 mockServerStream = mockSerialsForIncidentServerStream{output: stream}
3456 go func() {
3457 err = sa.SerialsForIncident(
3458 &sapb.SerialsForIncidentRequest{
3459 IncidentTable: "incident_foo",
3460 },
3461 mockServerStream,
3462 )
3463 close(stream)
3464 }()
3465 receivedSerials := make(map[string]bool)
3466 for serial := range stream {
3467 if len(receivedSerials) > 4 {
3468 t.Fatal("Received too many serials")
3469 }
3470 if _, ok := receivedSerials[serial.Serial]; ok {
3471 t.Fatalf("Received serial %q more than once", serial.Serial)
3472 }
3473 receivedSerials[serial.Serial] = true
3474 }
3475 test.AssertDeepEquals(t, receivedSerials, map[string]bool{
3476 "1335": true, "1336": true, "1337": true, "1338": true,
3477 })
3478 test.AssertNotError(t, err, "Error getting serials for incident")
3479 }
3480
3481 type mockGetRevokedCertsServerStream struct {
3482 grpc.ServerStream
3483 output chan<- *corepb.CRLEntry
3484 }
3485
3486 func (s mockGetRevokedCertsServerStream) Send(entry *corepb.CRLEntry) error {
3487 s.output <- entry
3488 return nil
3489 }
3490
3491 func (s mockGetRevokedCertsServerStream) Context() context.Context {
3492 return context.Background()
3493 }
3494
3495 func TestGetRevokedCerts(t *testing.T) {
3496 sa, _, cleanUp := initSA(t)
3497 defer cleanUp()
3498
3499
3500
3501
3502 reg := createWorkingRegistration(t, sa)
3503 eeCert, err := core.LoadCert("../test/hierarchy/ee-e1.cert.pem")
3504 test.AssertNotError(t, err, "failed to load test cert")
3505 _, err = sa.AddSerial(ctx, &sapb.AddSerialRequest{
3506 RegID: reg.Id,
3507 Serial: core.SerialToString(eeCert.SerialNumber),
3508 CreatedNS: eeCert.NotBefore.UnixNano(),
3509 Created: timestamppb.New(eeCert.NotBefore),
3510 ExpiresNS: eeCert.NotAfter.UnixNano(),
3511 Expires: timestamppb.New(eeCert.NotAfter),
3512 })
3513 test.AssertNotError(t, err, "failed to add test serial")
3514 _, err = sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
3515 Der: eeCert.Raw,
3516 RegID: reg.Id,
3517 IssuedNS: eeCert.NotBefore.UnixNano(),
3518 Issued: timestamppb.New(eeCert.NotBefore),
3519 IssuerNameID: 1,
3520 })
3521 test.AssertNotError(t, err, "failed to add test cert")
3522
3523
3524 status, err := sa.GetCertificateStatus(
3525 ctx, &sapb.Serial{Serial: core.SerialToString(eeCert.SerialNumber)})
3526 test.AssertNotError(t, err, "GetCertificateStatus failed")
3527 test.AssertEquals(t, core.OCSPStatus(status.Status), core.OCSPStatusGood)
3528
3529
3530
3531 countRevokedCerts := func(req *sapb.GetRevokedCertsRequest) (int, error) {
3532 stream := make(chan *corepb.CRLEntry)
3533 mockServerStream := mockGetRevokedCertsServerStream{output: stream}
3534 var err error
3535 go func() {
3536 err = sa.GetRevokedCerts(req, mockServerStream)
3537 close(stream)
3538 }()
3539 entriesReceived := 0
3540 for range stream {
3541 entriesReceived++
3542 }
3543 return entriesReceived, err
3544 }
3545
3546
3547 expiresAfter := time.Date(2023, time.March, 1, 0, 0, 0, 0, time.UTC)
3548 expiresBefore := time.Date(2023, time.April, 1, 0, 0, 0, 0, time.UTC)
3549 revokedBefore := time.Date(2023, time.April, 1, 0, 0, 0, 0, time.UTC)
3550 count, err := countRevokedCerts(&sapb.GetRevokedCertsRequest{
3551 IssuerNameID: 1,
3552 ExpiresAfterNS: expiresAfter.UnixNano(),
3553 ExpiresAfter: timestamppb.New(expiresAfter),
3554 ExpiresBeforeNS: expiresBefore.UnixNano(),
3555 ExpiresBefore: timestamppb.New(expiresBefore),
3556 RevokedBeforeNS: revokedBefore.UnixNano(),
3557 RevokedBefore: timestamppb.New(revokedBefore),
3558 })
3559 test.AssertNotError(t, err, "zero rows shouldn't result in error")
3560 test.AssertEquals(t, count, 0)
3561
3562
3563 date := time.Date(2023, time.January, 1, 0, 0, 0, 0, time.UTC)
3564 _, err = sa.RevokeCertificate(context.Background(), &sapb.RevokeCertificateRequest{
3565 IssuerID: 1,
3566 Serial: core.SerialToString(eeCert.SerialNumber),
3567 DateNS: date.UnixNano(),
3568 Date: timestamppb.New(date),
3569 Reason: 1,
3570 Response: []byte{1, 2, 3},
3571 })
3572 test.AssertNotError(t, err, "failed to revoke test cert")
3573
3574
3575 count, err = countRevokedCerts(&sapb.GetRevokedCertsRequest{
3576 IssuerNameID: 1,
3577 ExpiresAfterNS: expiresAfter.UnixNano(),
3578 ExpiresAfter: timestamppb.New(expiresAfter),
3579 ExpiresBeforeNS: expiresBefore.UnixNano(),
3580 ExpiresBefore: timestamppb.New(expiresBefore),
3581 RevokedBeforeNS: revokedBefore.UnixNano(),
3582 RevokedBefore: timestamppb.New(revokedBefore),
3583 })
3584 test.AssertNotError(t, err, "normal usage shouldn't result in error")
3585 test.AssertEquals(t, count, 1)
3586
3587
3588 expiresAfter = time.Date(2023, time.March, 1, 0, 0, 0, 0, time.UTC)
3589 expiresBefore = time.Date(2023, time.April, 1, 0, 0, 0, 0, time.UTC)
3590 revokedBefore = time.Date(2020, time.March, 1, 0, 0, 0, 0, time.UTC)
3591 count, err = countRevokedCerts(&sapb.GetRevokedCertsRequest{
3592 IssuerNameID: 1,
3593 ExpiresAfterNS: expiresAfter.UnixNano(),
3594 ExpiresAfter: timestamppb.New(expiresAfter),
3595 ExpiresBeforeNS: expiresBefore.UnixNano(),
3596 ExpiresBefore: timestamppb.New(expiresBefore),
3597 RevokedBeforeNS: revokedBefore.UnixNano(),
3598 RevokedBefore: timestamppb.New(revokedBefore),
3599 })
3600 test.AssertNotError(t, err, "zero rows shouldn't result in error")
3601 test.AssertEquals(t, count, 0)
3602
3603
3604
3605 expiresAfter = time.Date(2022, time.March, 1, 0, 0, 0, 0, time.UTC)
3606 expiresBefore = time.Date(2022, time.April, 1, 0, 0, 0, 0, time.UTC)
3607 revokedBefore = time.Date(2023, time.April, 1, 0, 0, 0, 0, time.UTC)
3608 count, err = countRevokedCerts(&sapb.GetRevokedCertsRequest{
3609 IssuerNameID: 1,
3610 ExpiresAfterNS: expiresAfter.UnixNano(),
3611 ExpiresAfter: timestamppb.New(expiresAfter),
3612 ExpiresBeforeNS: expiresBefore.UnixNano(),
3613 ExpiresBefore: timestamppb.New(expiresBefore),
3614 RevokedBeforeNS: revokedBefore.UnixNano(),
3615 RevokedBefore: timestamppb.New(revokedBefore),
3616 })
3617 test.AssertNotError(t, err, "zero rows shouldn't result in error")
3618 test.AssertEquals(t, count, 0)
3619
3620
3621 count, err = countRevokedCerts(&sapb.GetRevokedCertsRequest{
3622 IssuerNameID: 1,
3623 ExpiresAfterNS: time.Date(2022, time.March, 1, 0, 0, 0, 0, time.UTC).UnixNano(),
3624 ExpiresBeforeNS: time.Date(2022, time.April, 1, 0, 0, 0, 0, time.UTC).UnixNano(),
3625 RevokedBeforeNS: time.Date(2023, time.April, 1, 0, 0, 0, 0, time.UTC).UnixNano(),
3626 })
3627 test.AssertNotError(t, err, "zero rows shouldn't result in error")
3628 test.AssertEquals(t, count, 0)
3629 }
3630
3631 func TestGetRevokedCertsByShard(t *testing.T) {
3632 if os.Getenv("BOULDER_CONFIG_DIR") != "test/config-next" {
3633 t.Skip("Test requires revokedCertificates database table")
3634 }
3635
3636 sa, _, cleanUp := initSA(t)
3637 defer cleanUp()
3638
3639
3640
3641
3642 reg := createWorkingRegistration(t, sa)
3643 eeCert, err := core.LoadCert("../test/hierarchy/ee-e1.cert.pem")
3644 test.AssertNotError(t, err, "failed to load test cert")
3645 _, err = sa.AddSerial(ctx, &sapb.AddSerialRequest{
3646 RegID: reg.Id,
3647 Serial: core.SerialToString(eeCert.SerialNumber),
3648 CreatedNS: eeCert.NotBefore.UnixNano(),
3649 Created: timestamppb.New(eeCert.NotBefore),
3650 ExpiresNS: eeCert.NotAfter.UnixNano(),
3651 Expires: timestamppb.New(eeCert.NotAfter),
3652 })
3653 test.AssertNotError(t, err, "failed to add test serial")
3654 _, err = sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
3655 Der: eeCert.Raw,
3656 RegID: reg.Id,
3657 IssuedNS: eeCert.NotBefore.UnixNano(),
3658 Issued: timestamppb.New(eeCert.NotBefore),
3659 IssuerNameID: 1,
3660 })
3661 test.AssertNotError(t, err, "failed to add test cert")
3662
3663
3664 status, err := sa.GetCertificateStatus(
3665 ctx, &sapb.Serial{Serial: core.SerialToString(eeCert.SerialNumber)})
3666 test.AssertNotError(t, err, "GetCertificateStatus failed")
3667 test.AssertEquals(t, core.OCSPStatus(status.Status), core.OCSPStatusGood)
3668
3669
3670
3671 countRevokedCerts := func(req *sapb.GetRevokedCertsRequest) (int, error) {
3672 stream := make(chan *corepb.CRLEntry)
3673 mockServerStream := mockGetRevokedCertsServerStream{output: stream}
3674 var err error
3675 go func() {
3676 err = sa.GetRevokedCerts(req, mockServerStream)
3677 close(stream)
3678 }()
3679 entriesReceived := 0
3680 for range stream {
3681 entriesReceived++
3682 }
3683 return entriesReceived, err
3684 }
3685
3686
3687 expiresAfter := time.Date(2023, time.March, 1, 0, 0, 0, 0, time.UTC)
3688 revokedBefore := time.Date(2023, time.April, 1, 0, 0, 0, 0, time.UTC)
3689 count, err := countRevokedCerts(&sapb.GetRevokedCertsRequest{
3690 IssuerNameID: 1,
3691 ShardIdx: 9,
3692 ExpiresAfterNS: expiresAfter.UnixNano(),
3693 ExpiresAfter: timestamppb.New(expiresAfter),
3694 RevokedBeforeNS: revokedBefore.UnixNano(),
3695 RevokedBefore: timestamppb.New(revokedBefore),
3696 })
3697 test.AssertNotError(t, err, "zero rows shouldn't result in error")
3698 test.AssertEquals(t, count, 0)
3699
3700
3701
3702 date := time.Date(2023, time.January, 1, 0, 0, 0, 0, time.UTC)
3703 _, err = sa.RevokeCertificate(context.Background(), &sapb.RevokeCertificateRequest{
3704 IssuerID: 1,
3705 Serial: core.SerialToString(eeCert.SerialNumber),
3706 DateNS: date.UnixNano(),
3707 Date: timestamppb.New(date),
3708 Reason: 1,
3709 Response: []byte{1, 2, 3},
3710 ShardIdx: 9,
3711 })
3712 test.AssertNotError(t, err, "failed to revoke test cert")
3713
3714
3715 c, err := sa.dbMap.SelectNullInt(
3716 ctx, "SELECT count(*) FROM revokedCertificates")
3717 test.AssertNotError(t, err, "SELECT from revokedCertificates failed")
3718 test.Assert(t, c.Valid, "SELECT from revokedCertificates got no result")
3719 test.AssertEquals(t, c.Int64, int64(1))
3720
3721
3722 expiresAfter = time.Date(2023, time.March, 1, 0, 0, 0, 0, time.UTC)
3723 revokedBefore = time.Date(2023, time.April, 1, 0, 0, 0, 0, time.UTC)
3724 count, err = countRevokedCerts(&sapb.GetRevokedCertsRequest{
3725 IssuerNameID: 1,
3726 ShardIdx: 9,
3727 ExpiresAfterNS: expiresAfter.UnixNano(),
3728 ExpiresAfter: timestamppb.New(expiresAfter),
3729 RevokedBeforeNS: revokedBefore.UnixNano(),
3730 RevokedBefore: timestamppb.New(revokedBefore),
3731 })
3732 test.AssertNotError(t, err, "normal usage shouldn't result in error")
3733 test.AssertEquals(t, count, 1)
3734
3735
3736 expiresAfter = time.Date(2023, time.March, 1, 0, 0, 0, 0, time.UTC)
3737 revokedBefore = time.Date(2023, time.April, 1, 0, 0, 0, 0, time.UTC)
3738 count, err = countRevokedCerts(&sapb.GetRevokedCertsRequest{
3739 IssuerNameID: 2,
3740 ShardIdx: 9,
3741 ExpiresAfterNS: expiresAfter.UnixNano(),
3742 ExpiresAfter: timestamppb.New(expiresAfter),
3743 RevokedBeforeNS: revokedBefore.UnixNano(),
3744 RevokedBefore: timestamppb.New(revokedBefore),
3745 })
3746 test.AssertNotError(t, err, "zero rows shouldn't result in error")
3747 test.AssertEquals(t, count, 0)
3748
3749
3750 expiresAfter = time.Date(2023, time.March, 1, 0, 0, 0, 0, time.UTC)
3751 revokedBefore = time.Date(2023, time.April, 1, 0, 0, 0, 0, time.UTC)
3752 count, err = countRevokedCerts(&sapb.GetRevokedCertsRequest{
3753 IssuerNameID: 1,
3754 ShardIdx: 8,
3755 ExpiresAfterNS: expiresAfter.UnixNano(),
3756 ExpiresAfter: timestamppb.New(expiresAfter),
3757 RevokedBeforeNS: revokedBefore.UnixNano(),
3758 RevokedBefore: timestamppb.New(revokedBefore),
3759 })
3760 test.AssertNotError(t, err, "zero rows shouldn't result in error")
3761 test.AssertEquals(t, count, 0)
3762
3763
3764 expiresAfter = time.Date(2023, time.March, 1, 0, 0, 0, 0, time.UTC)
3765 revokedBefore = time.Date(2020, time.March, 1, 0, 0, 0, 0, time.UTC)
3766 count, err = countRevokedCerts(&sapb.GetRevokedCertsRequest{
3767 IssuerNameID: 1,
3768 ShardIdx: 9,
3769 ExpiresAfterNS: expiresAfter.UnixNano(),
3770 ExpiresAfter: timestamppb.New(expiresAfter),
3771 RevokedBeforeNS: revokedBefore.UnixNano(),
3772 RevokedBefore: timestamppb.New(revokedBefore),
3773 })
3774 test.AssertNotError(t, err, "zero rows shouldn't result in error")
3775 test.AssertEquals(t, count, 0)
3776 }
3777
3778 func TestGetMaxExpiration(t *testing.T) {
3779 sa, _, cleanUp := initSA(t)
3780 defer cleanUp()
3781
3782
3783
3784
3785 reg := createWorkingRegistration(t, sa)
3786 eeCert, err := core.LoadCert("../test/hierarchy/ee-e1.cert.pem")
3787 test.AssertNotError(t, err, "failed to load test cert")
3788 _, err = sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
3789 Der: eeCert.Raw,
3790 RegID: reg.Id,
3791 IssuedNS: eeCert.NotBefore.UnixNano(),
3792 Issued: timestamppb.New(eeCert.NotBefore),
3793 IssuerNameID: 1,
3794 })
3795 test.AssertNotError(t, err, "failed to add test cert")
3796
3797 lastExpiry, err := sa.GetMaxExpiration(context.Background(), &emptypb.Empty{})
3798 test.AssertNotError(t, err, "getting last expriy should succeed")
3799 test.Assert(t, lastExpiry.AsTime().Equal(eeCert.NotAfter), "times should be equal")
3800 test.AssertEquals(t, timestamppb.New(eeCert.NotBefore).AsTime(), eeCert.NotBefore)
3801 }
3802
3803 func TestLeaseOldestCRLShard(t *testing.T) {
3804 sa, clk, cleanUp := initSA(t)
3805 defer cleanUp()
3806
3807
3808
3809 _, err := sa.dbMap.ExecContext(ctx,
3810 `INSERT INTO crlShards (issuerID, idx, thisUpdate, nextUpdate, leasedUntil) VALUES
3811 (1, 0, ?, ?, ?),
3812 (1, 1, ?, ?, ?),
3813 (1, 2, ?, ?, ?),
3814 (1, 3, NULL, NULL, ?),
3815 (2, 0, ?, ?, ?),
3816 (2, 1, ?, ?, ?),
3817 (2, 2, ?, ?, ?),
3818 (2, 3, NULL, NULL, ?);`,
3819 clk.Now().Add(-7*24*time.Hour), clk.Now().Add(3*24*time.Hour), clk.Now().Add(time.Hour),
3820 clk.Now().Add(-6*24*time.Hour), clk.Now().Add(4*24*time.Hour), clk.Now().Add(-6*24*time.Hour),
3821 clk.Now().Add(-5*24*time.Hour), clk.Now().Add(5*24*time.Hour), clk.Now().Add(-5*24*time.Hour),
3822 clk.Now().Add(-4*24*time.Hour),
3823 clk.Now().Add(-7*24*time.Hour), clk.Now().Add(3*24*time.Hour), clk.Now().Add(time.Hour),
3824 clk.Now().Add(-6*24*time.Hour), clk.Now().Add(4*24*time.Hour), clk.Now().Add(-6*24*time.Hour),
3825 clk.Now().Add(-5*24*time.Hour), clk.Now().Add(5*24*time.Hour), clk.Now().Add(-5*24*time.Hour),
3826 clk.Now().Add(-4*24*time.Hour),
3827 )
3828 test.AssertNotError(t, err, "setting up test shards")
3829
3830 until := clk.Now().Add(time.Hour).Truncate(time.Second).UTC()
3831 var untilModel struct {
3832 LeasedUntil time.Time `db:"leasedUntil"`
3833 }
3834
3835
3836 _, err = sa.leaseOldestCRLShard(
3837 context.Background(),
3838 &sapb.LeaseCRLShardRequest{
3839 IssuerNameID: 1,
3840 MinShardIdx: 0,
3841 MaxShardIdx: 0,
3842 Until: timestamppb.New(until),
3843 },
3844 )
3845 test.AssertError(t, err, "leasing when all shards are leased")
3846
3847
3848 res, err := sa.leaseOldestCRLShard(
3849 context.Background(),
3850 &sapb.LeaseCRLShardRequest{
3851 IssuerNameID: 1,
3852 MinShardIdx: 0,
3853 MaxShardIdx: 3,
3854 Until: timestamppb.New(until),
3855 },
3856 )
3857 test.AssertNotError(t, err, "leasing available shard")
3858 test.AssertEquals(t, res.IssuerNameID, int64(1))
3859 test.AssertEquals(t, res.ShardIdx, int64(3))
3860
3861 err = sa.dbMap.SelectOne(
3862 ctx,
3863 &untilModel,
3864 `SELECT leasedUntil FROM crlShards WHERE issuerID = ? AND idx = ? LIMIT 1`,
3865 res.IssuerNameID,
3866 res.ShardIdx,
3867 )
3868 test.AssertNotError(t, err, "getting updated lease timestamp")
3869 test.Assert(t, untilModel.LeasedUntil.Equal(until), "checking updated lease timestamp")
3870
3871
3872 res, err = sa.leaseOldestCRLShard(
3873 context.Background(),
3874 &sapb.LeaseCRLShardRequest{
3875 IssuerNameID: 1,
3876 MinShardIdx: 0,
3877 MaxShardIdx: 3,
3878 Until: timestamppb.New(until),
3879 },
3880 )
3881 test.AssertNotError(t, err, "leasing available shard")
3882 test.AssertEquals(t, res.IssuerNameID, int64(1))
3883 test.AssertEquals(t, res.ShardIdx, int64(1))
3884
3885 err = sa.dbMap.SelectOne(
3886 ctx,
3887 &untilModel,
3888 `SELECT leasedUntil FROM crlShards WHERE issuerID = ? AND idx = ? LIMIT 1`,
3889 res.IssuerNameID,
3890 res.ShardIdx,
3891 )
3892 test.AssertNotError(t, err, "getting updated lease timestamp")
3893 test.Assert(t, untilModel.LeasedUntil.Equal(until), "checking updated lease timestamp")
3894
3895
3896
3897 res, err = sa.leaseOldestCRLShard(
3898 context.Background(),
3899 &sapb.LeaseCRLShardRequest{
3900 IssuerNameID: 2,
3901 MinShardIdx: 0,
3902 MaxShardIdx: 7,
3903 Until: timestamppb.New(until),
3904 },
3905 )
3906 test.AssertNotError(t, err, "leasing available shard")
3907 test.AssertEquals(t, res.IssuerNameID, int64(2))
3908 test.Assert(t, res.ShardIdx >= 4, "checking leased index")
3909 test.Assert(t, res.ShardIdx <= 7, "checking leased index")
3910
3911 err = sa.dbMap.SelectOne(
3912 ctx,
3913 &untilModel,
3914 `SELECT leasedUntil FROM crlShards WHERE issuerID = ? AND idx = ? LIMIT 1`,
3915 res.IssuerNameID,
3916 res.ShardIdx,
3917 )
3918 test.AssertNotError(t, err, "getting updated lease timestamp")
3919 test.Assert(t, untilModel.LeasedUntil.Equal(until), "checking updated lease timestamp")
3920 }
3921
3922 func TestLeaseSpecificCRLShard(t *testing.T) {
3923 sa, clk, cleanUp := initSA(t)
3924 defer cleanUp()
3925
3926
3927
3928 _, err := sa.dbMap.ExecContext(ctx,
3929 `INSERT INTO crlShards (issuerID, idx, thisUpdate, nextUpdate, leasedUntil) VALUES
3930 (1, 0, ?, ?, ?),
3931 (1, 1, ?, ?, ?),
3932 (1, 2, ?, ?, ?),
3933 (1, 3, NULL, NULL, ?),
3934 (2, 0, ?, ?, ?),
3935 (2, 1, ?, ?, ?),
3936 (2, 2, ?, ?, ?),
3937 (2, 3, NULL, NULL, ?);`,
3938 clk.Now().Add(-7*24*time.Hour), clk.Now().Add(3*24*time.Hour), clk.Now().Add(time.Hour),
3939 clk.Now().Add(-6*24*time.Hour), clk.Now().Add(4*24*time.Hour), clk.Now().Add(-6*24*time.Hour),
3940 clk.Now().Add(-5*24*time.Hour), clk.Now().Add(5*24*time.Hour), clk.Now().Add(-5*24*time.Hour),
3941 clk.Now().Add(-4*24*time.Hour),
3942 clk.Now().Add(-7*24*time.Hour), clk.Now().Add(3*24*time.Hour), clk.Now().Add(time.Hour),
3943 clk.Now().Add(-6*24*time.Hour), clk.Now().Add(4*24*time.Hour), clk.Now().Add(-6*24*time.Hour),
3944 clk.Now().Add(-5*24*time.Hour), clk.Now().Add(5*24*time.Hour), clk.Now().Add(-5*24*time.Hour),
3945 clk.Now().Add(-4*24*time.Hour),
3946 )
3947 test.AssertNotError(t, err, "setting up test shards")
3948
3949 until := clk.Now().Add(time.Hour).Truncate(time.Second).UTC()
3950 var untilModel struct {
3951 LeasedUntil time.Time `db:"leasedUntil"`
3952 }
3953
3954
3955 res, err := sa.leaseSpecificCRLShard(
3956 context.Background(),
3957 &sapb.LeaseCRLShardRequest{
3958 IssuerNameID: 1,
3959 MinShardIdx: 1,
3960 MaxShardIdx: 1,
3961 Until: timestamppb.New(until),
3962 },
3963 )
3964 test.AssertNotError(t, err, "leasing available shard")
3965 test.AssertEquals(t, res.IssuerNameID, int64(1))
3966 test.AssertEquals(t, res.ShardIdx, int64(1))
3967
3968 err = sa.dbMap.SelectOne(
3969 ctx,
3970 &untilModel,
3971 `SELECT leasedUntil FROM crlShards WHERE issuerID = ? AND idx = ? LIMIT 1`,
3972 res.IssuerNameID,
3973 res.ShardIdx,
3974 )
3975 test.AssertNotError(t, err, "getting updated lease timestamp")
3976 test.Assert(t, untilModel.LeasedUntil.Equal(until), "checking updated lease timestamp")
3977
3978
3979 res, err = sa.leaseSpecificCRLShard(
3980 context.Background(),
3981 &sapb.LeaseCRLShardRequest{
3982 IssuerNameID: 2,
3983 MinShardIdx: 3,
3984 MaxShardIdx: 3,
3985 Until: timestamppb.New(until),
3986 },
3987 )
3988 test.AssertNotError(t, err, "leasing available shard")
3989 test.AssertEquals(t, res.IssuerNameID, int64(2))
3990 test.AssertEquals(t, res.ShardIdx, int64(3))
3991
3992 err = sa.dbMap.SelectOne(
3993 ctx,
3994 &untilModel,
3995 `SELECT leasedUntil FROM crlShards WHERE issuerID = ? AND idx = ? LIMIT 1`,
3996 res.IssuerNameID,
3997 res.ShardIdx,
3998 )
3999 test.AssertNotError(t, err, "getting updated lease timestamp")
4000 test.Assert(t, untilModel.LeasedUntil.Equal(until), "checking updated lease timestamp")
4001
4002
4003
4004 res, err = sa.leaseSpecificCRLShard(
4005 context.Background(),
4006 &sapb.LeaseCRLShardRequest{
4007 IssuerNameID: 1,
4008 MinShardIdx: 9,
4009 MaxShardIdx: 9,
4010 Until: timestamppb.New(until),
4011 },
4012 )
4013 test.AssertNotError(t, err, "leasing unknown shard")
4014
4015 err = sa.dbMap.SelectOne(
4016 ctx,
4017 &untilModel,
4018 `SELECT leasedUntil FROM crlShards WHERE issuerID = ? AND idx = ? LIMIT 1`,
4019 res.IssuerNameID,
4020 res.ShardIdx,
4021 )
4022 test.AssertNotError(t, err, "getting updated lease timestamp")
4023 test.Assert(t, untilModel.LeasedUntil.Equal(until), "checking updated lease timestamp")
4024
4025
4026 _, err = sa.leaseSpecificCRLShard(
4027 context.Background(),
4028 &sapb.LeaseCRLShardRequest{
4029 IssuerNameID: 1,
4030 MinShardIdx: 0,
4031 MaxShardIdx: 0,
4032 Until: timestamppb.New(until),
4033 },
4034 )
4035 test.AssertError(t, err, "leasing unavailable shard")
4036
4037
4038 _, err = sa.leaseSpecificCRLShard(
4039 context.Background(),
4040 &sapb.LeaseCRLShardRequest{
4041 IssuerNameID: 1,
4042 MinShardIdx: 1,
4043 MaxShardIdx: 2,
4044 Until: timestamppb.New(until),
4045 },
4046 )
4047 test.AssertError(t, err, "did not lease one specific shard")
4048 }
4049
4050 func TestUpdateCRLShard(t *testing.T) {
4051 sa, clk, cleanUp := initSA(t)
4052 defer cleanUp()
4053
4054
4055
4056 _, err := sa.dbMap.ExecContext(ctx,
4057 `INSERT INTO crlShards (issuerID, idx, thisUpdate, nextUpdate, leasedUntil) VALUES
4058 (1, 0, ?, ?, ?),
4059 (1, 1, ?, ?, ?),
4060 (1, 2, ?, ?, ?),
4061 (1, 3, NULL, NULL, ?),
4062 (2, 0, ?, ?, ?),
4063 (2, 1, ?, ?, ?),
4064 (2, 2, ?, ?, ?),
4065 (2, 3, NULL, NULL, ?);`,
4066 clk.Now().Add(-7*24*time.Hour), clk.Now().Add(3*24*time.Hour), clk.Now().Add(time.Hour),
4067 clk.Now().Add(-6*24*time.Hour), clk.Now().Add(4*24*time.Hour), clk.Now().Add(-6*24*time.Hour),
4068 clk.Now().Add(-5*24*time.Hour), clk.Now().Add(5*24*time.Hour), clk.Now().Add(-5*24*time.Hour),
4069 clk.Now().Add(-4*24*time.Hour),
4070 clk.Now().Add(-7*24*time.Hour), clk.Now().Add(3*24*time.Hour), clk.Now().Add(time.Hour),
4071 clk.Now().Add(-6*24*time.Hour), clk.Now().Add(4*24*time.Hour), clk.Now().Add(-6*24*time.Hour),
4072 clk.Now().Add(-5*24*time.Hour), clk.Now().Add(5*24*time.Hour), clk.Now().Add(-5*24*time.Hour),
4073 clk.Now().Add(-4*24*time.Hour),
4074 )
4075 test.AssertNotError(t, err, "setting up test shards")
4076
4077 thisUpdate := clk.Now().Truncate(time.Second).UTC()
4078 var crlModel struct {
4079 ThisUpdate *time.Time
4080 NextUpdate *time.Time
4081 }
4082
4083
4084 _, err = sa.UpdateCRLShard(
4085 context.Background(),
4086 &sapb.UpdateCRLShardRequest{
4087 IssuerNameID: 1,
4088 ShardIdx: 0,
4089 ThisUpdate: timestamppb.New(thisUpdate),
4090 NextUpdate: timestamppb.New(thisUpdate.Add(10 * 24 * time.Hour)),
4091 },
4092 )
4093 test.AssertNotError(t, err, "updating leased shard")
4094
4095 err = sa.dbMap.SelectOne(
4096 ctx,
4097 &crlModel,
4098 `SELECT thisUpdate FROM crlShards WHERE issuerID = 1 AND idx = 0 LIMIT 1`,
4099 )
4100 test.AssertNotError(t, err, "getting updated thisUpdate timestamp")
4101 test.Assert(t, crlModel.ThisUpdate.Equal(thisUpdate), "checking updated thisUpdate timestamp")
4102
4103
4104 _, err = sa.UpdateCRLShard(
4105 context.Background(),
4106 &sapb.UpdateCRLShardRequest{
4107 IssuerNameID: 1,
4108 ShardIdx: 1,
4109 ThisUpdate: timestamppb.New(thisUpdate),
4110 NextUpdate: timestamppb.New(thisUpdate.Add(10 * 24 * time.Hour)),
4111 },
4112 )
4113 test.AssertNotError(t, err, "updating unleased shard")
4114
4115 err = sa.dbMap.SelectOne(
4116 ctx,
4117 &crlModel,
4118 `SELECT thisUpdate FROM crlShards WHERE issuerID = 1 AND idx = 1 LIMIT 1`,
4119 )
4120 test.AssertNotError(t, err, "getting updated thisUpdate timestamp")
4121 test.Assert(t, crlModel.ThisUpdate.Equal(thisUpdate), "checking updated thisUpdate timestamp")
4122
4123
4124 _, err = sa.UpdateCRLShard(
4125 context.Background(),
4126 &sapb.UpdateCRLShardRequest{
4127 IssuerNameID: 1,
4128 ShardIdx: 3,
4129 ThisUpdate: timestamppb.New(thisUpdate.Add(time.Second)),
4130 },
4131 )
4132 test.AssertNotError(t, err, "updating shard without NextUpdate")
4133
4134 err = sa.dbMap.SelectOne(
4135 ctx,
4136 &crlModel,
4137 `SELECT nextUpdate FROM crlShards WHERE issuerID = 1 AND idx = 3 LIMIT 1`,
4138 )
4139 test.AssertNotError(t, err, "getting updated nextUpdate timestamp")
4140 test.AssertBoxedNil(t, crlModel.NextUpdate, "checking updated nextUpdate timestamp")
4141
4142
4143 _, err = sa.UpdateCRLShard(
4144 context.Background(),
4145 &sapb.UpdateCRLShardRequest{
4146 IssuerNameID: 1,
4147 ShardIdx: 1,
4148 ThisUpdate: timestamppb.New(thisUpdate.Add(-24 * time.Hour)),
4149 NextUpdate: timestamppb.New(thisUpdate.Add(9 * 24 * time.Hour)),
4150 },
4151 )
4152 test.AssertError(t, err, "updating shard to an earlier time")
4153
4154
4155 _, err = sa.UpdateCRLShard(
4156 context.Background(),
4157 &sapb.UpdateCRLShardRequest{
4158 IssuerNameID: 1,
4159 ShardIdx: 4,
4160 ThisUpdate: timestamppb.New(thisUpdate),
4161 NextUpdate: timestamppb.New(thisUpdate.Add(10 * 24 * time.Hour)),
4162 },
4163 )
4164 test.AssertError(t, err, "updating an unknown shard")
4165 }
4166
View as plain text