...

Source file src/github.com/letsencrypt/boulder/sa/sa_test.go

Documentation: github.com/letsencrypt/boulder/sa

     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  // initSA constructs a SQLStorageAuthority and a clean up function that should
    67  // be defer'ed to the end of the test.
    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  // CreateWorkingTestRegistration inserts a new, correct Registration into the
    99  // given SA.
   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, // dnsName
   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  	// First, set the lagFactor to 0. Neither selecting a real registration nor
   274  	// selecting a nonexistent registration should cause the clock to advance.
   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  	// With lagFactor disabled, we should never enter the retry codepath, as a
   287  	// result the metric should not increment.
   288  	test.AssertMetricWithLabelsEquals(t, sa.lagFactorCounter, prometheus.Labels{"method": "GetRegistration", "result": "notfound"}, 0)
   289  
   290  	// Now, set the lagFactor to 1. Trying to select a nonexistent registration
   291  	// should cause the clock to advance when GetRegistration sleeps and retries.
   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  	// lagFactor is enabled, but the registration exists.
   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  	// With lagFactor enabled, we should enter the retry codepath and as a result
   305  	// the metric should increment.
   306  	test.AssertMetricWithLabelsEquals(t, sa.lagFactorCounter, prometheus.Labels{"method": "GetRegistration", "result": "notfound"}, 1)
   307  }
   308  
   309  // findIssuedName is a small helper test function to directly query the
   310  // issuedNames table for a given name to find a serial (or return an err).
   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  	// Create a throw-away self signed certificate with a random name and
   417  	// serial number
   418  	serial, testCert := test.ThrowAwayCert(t, 1)
   419  
   420  	// Add the cert as a precertificate
   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  	// It should have the expected certificate status
   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  	// It should show up in the issued names table
   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  	// We should also be able to call AddCertificate with the same cert
   446  	// without it being an error. The duplicate err on inserting to
   447  	// issuedNames should be ignored.
   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  	// Create a throw-away self signed certificate with a random name and
   510  	// serial number
   511  	_, testCert := test.ThrowAwayCert(t, 1)
   512  
   513  	// Add the cert as a precertificate
   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  		// Leaving out IssuerNameID
   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  	// An example cert taken from EFF's website
   560  	certDER, err := os.ReadFile("www.eff.org.der")
   561  	test.AssertNotError(t, err, "Couldn't read example cert DER")
   562  
   563  	// Calling AddCertificate with a non-nil issued should succeed
   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  	// Because nil was provided as the Issued time we expect the cert was stored
   577  	// with an issued time equal to now
   578  	test.AssertEquals(t, retrievedCert.IssuedNS, issuedTime.UnixNano())
   579  	test.AssertEquals(t, retrievedCert.Issued.AsTime(), issuedTime)
   580  
   581  	// Test cert generated locally by Boulder, with names [example.com,
   582  	// www.example.com, admin.example.com]
   583  	certDER2, err := os.ReadFile("test-cert.der")
   584  	test.AssertNotError(t, err, "Couldn't read example cert DER")
   585  	serial := "ffdd9b8a82126d96f61d378d5ba99a0474f0"
   586  
   587  	// Add the certificate with a specific issued time instead of nil
   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  	// The cert should have been added with the specific issued time we provided
   601  	// as the issued field.
   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  	// Test cert generated locally by Boulder, with names [example.com,
   638  	// www.example.com, admin.example.com]
   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  	// Set the test clock's time to the time from the test certificate, plus an
   646  	// hour to account for rounding.
   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  	// Count for a name that doesn't have any certs
   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  	// Add the test cert and query for its names.
   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  	// Time range including now should find the cert.
   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  	// Time range between two days ago and yesterday should not find the cert.
   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  	// Time range between now and tomorrow also should not (time ranges are
   696  	// inclusive at the tail end, but not the beginning end).
   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  	// Add a second test cert (for example.co.bn) and query for multiple names.
   707  	names := []string{"example.com", "foo.com", "example.co.bn"}
   708  
   709  	// Override countCertificatesByName with an implementation of certCountFunc
   710  	// that will block forever if it's called in serial, but will succeed if
   711  	// called in parallel.
   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  	// Create one IPv4 registration
   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  	// Create two IPv6 registrations, both within the same /48
   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  	// There should be 0 registrations for an IPv4 address we didn't add
   799  	// a registration for
   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  	// There should be 1 registration for the IPv4 address we did add
   804  	// a registration for.
   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  	// There should be 1 registration for the first IPv6 address we added
   810  	// a registration for
   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  	// There should be 1 registration for the second IPv6 address we added
   816  	// a registration for as well
   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  	// There should be 0 registrations for an IPv6 address in the same /48 as the
   822  	// two IPv6 addresses with registrations
   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  	// Create one IPv4 registration
   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  	// Create two IPv6 registrations, both within the same /48
   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  	// There should be 0 registrations in the range for an IPv4 address we didn't
   875  	// add a registration for
   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  	// There should be 1 registration in the range for the IPv4 address we did
   881  	// add a registration for
   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  	// There should be 2 registrations in the range for the first IPv6 address we added
   887  	// a registration for because it's in the same /48
   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  	// There should be 2 registrations in the range for the second IPv6 address
   893  	// we added a registration for as well, because it too is in the same /48
   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  	// There should also be 2 registrations in the range for an arbitrary IPv6 address in
   899  	// the same /48 as the registrations we added
   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  	// only one valid
   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  	// check hash isn't affected by changing name order/casing
   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  	// add another valid set
   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  	// only two valid
   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  	// add an expired set
   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  	// only two valid
   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  	// Ensure zero issuance has occurred for names.
   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  	// Add an issuance for names inside the window.
   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  	// Ensure there's 1 issuance timestamp for names inside the window.
  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  	// Ensure that the hash isn't affected by changing name order/casing.
  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  	// Add another issuance for names inside the window.
  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  	// Ensure there are two issuance timestamps for names inside the window.
  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  	// Add another issuance for names but just outside the window.
  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  	// Ensure there are still only two issuance timestamps in the window.
  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  	// An example cert taken from EFF's website
  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  	// deactivate a pending authorization
  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  	// deactivate a valid authorization"
  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  	// Create a test registration to reference
  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  	// Insert two pre-existing authorizations to reference
  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  		// Insert an order for four names, two of which already have authzs
  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  		// And add new authorizations for the other two names.
  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  // TestNewOrderAndAuthzs_NonNilInnerOrder verifies that a nil
  1347  // sapb.NewOrderAndAuthzsRequest NewOrder object returns an error.
  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  	// Create a test registration to reference.
  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  	// Create an authz that does not yet exist in the database with some invalid
  1393  	// data smuggled in.
  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  	// Safely get the authz for the order we created above.
  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  	// To access the data stored in obj at compile time, we type assert obj
  1424  	// into a pointer to an authzModel.
  1425  	am, ok := obj.(*authzModel)
  1426  	test.Assert(t, ok, "Could not type assert obj into authzModel")
  1427  
  1428  	// If we're making a brand new authz, it should have the pending status
  1429  	// regardless of what incorrect status value was passed in during construction.
  1430  	test.AssertEquals(t, am.Status, statusUint(core.StatusPending))
  1431  
  1432  	// Testing for the existence of these boxed nils is a definite break from
  1433  	// our paradigm of avoiding passing around boxed nils whenever possible.
  1434  	// However, the existence of these boxed nils in relation to this test is
  1435  	// actually expected. If these tests fail, then a possible SA refactor or RA
  1436  	// bug placed incorrect data into brand new authz input fields.
  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  	// Create a test registration to reference
  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  	// Add one valid authz
  1457  	expires := fc.Now().Add(time.Hour)
  1458  	attemptedAt := fc.Now()
  1459  	authzID := createFinalizedAuthorization(t, sa, "example.com", expires, "valid", attemptedAt)
  1460  
  1461  	// Add a new order in pending status with no certificate serial
  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  	// Set the order to be processing
  1475  	_, err = sa.SetOrderProcessing(context.Background(), &sapb.OrderRequest{Id: order.Id})
  1476  	test.AssertNotError(t, err, "SetOrderProcessing failed")
  1477  
  1478  	// Read the order by ID from the DB to check the status was correctly updated
  1479  	// to processing
  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  	// Try to set the same order to be processing again. We should get an error.
  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  	// Create a test registration to reference
  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  	// Add one valid authz
  1507  	expires := fc.Now().Add(time.Hour)
  1508  	attemptedAt := fc.Now()
  1509  	authzID := createFinalizedAuthorization(t, sa, "example.com", expires, "valid", attemptedAt)
  1510  
  1511  	// Add a new order in pending status with no certificate serial
  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  	// Set the order to processing so it can be finalized
  1525  	_, err = sa.SetOrderProcessing(ctx, &sapb.OrderRequest{Id: order.Id})
  1526  	test.AssertNotError(t, err, "SetOrderProcessing failed")
  1527  
  1528  	// Finalize the order with a certificate serial
  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  	// Read the order by ID from the DB to check the certificate serial and status
  1534  	// was correctly updated
  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  	// Create a test registration to reference
  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  	// Set the order to expire in two hours
  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  	// Create the order
  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  	// The Order from GetOrder should match the following expected order
  1583  	created := sa.clk.Now()
  1584  	expectedOrder := &corepb.Order{
  1585  		// The registration ID, authorizations, expiry, and names should match the
  1586  		// input to NewOrderAndAuthzs
  1587  		RegistrationID:   inputOrder.RegistrationID,
  1588  		V2Authorizations: inputOrder.V2Authorizations,
  1589  		Names:            inputOrder.Names,
  1590  		ExpiresNS:        inputOrder.ExpiresNS,
  1591  		Expires:          inputOrder.Expires,
  1592  		// The ID should have been set to 1 by the SA
  1593  		Id: 1,
  1594  		// The status should be pending
  1595  		Status: string(core.StatusPending),
  1596  		// The serial should be empty since this is a pending order
  1597  		CertificateSerial: "",
  1598  		// We should not be processing it
  1599  		BeganProcessing: false,
  1600  		// The created timestamp should have been set to the current time
  1601  		CreatedNS: created.UnixNano(),
  1602  		Created:   timestamppb.New(created),
  1603  	}
  1604  
  1605  	// Fetch the order by its ID and make sure it matches the expected
  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  // TestGetAuthorization2NoRows ensures that the GetAuthorization2 function returns
  1612  // the correct error when there are no results for the provided ID.
  1613  func TestGetAuthorization2NoRows(t *testing.T) {
  1614  	sa, _, cleanUp := initSA(t)
  1615  	defer cleanUp()
  1616  
  1617  	// An empty authz ID should result in a not found berror.
  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  	// Associate authorizations with an order so that GetAuthorizations2 thinks
  1644  	// they are WFE2 authorizations.
  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  	// Set an expiry cut off of 1 day in the future similar to `RA.NewOrderAndAuthzs`. This
  1662  	// should exclude pending authorization C based on its nearbyExpires expiry
  1663  	// value.
  1664  	expiryCutoff := fc.Now().AddDate(0, 0, 1)
  1665  	// Get authorizations for the names used above.
  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  	// It should not fail
  1673  	test.AssertNotError(t, err, "sa.GetAuthorizations2 failed")
  1674  	// We should get back two authorizations since one of the three authorizations
  1675  	// created above expires too soon.
  1676  	test.AssertEquals(t, len(authz.Authz), 2)
  1677  
  1678  	// Get authorizations for the names used above, and one name that doesn't exist
  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  	// It should not fail
  1686  	test.AssertNotError(t, err, "sa.GetAuthorizations2 failed")
  1687  	// It should still return only two authorizations
  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  	// Counting new orders for a reg ID that doesn't exist should return 0
  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  	// Add a pending authorization
  1715  	authzID := createPendingAuthorization(t, sa, "example.com", expires)
  1716  
  1717  	// Add one pending order
  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  	// Counting new orders for the reg ID should now yield 1
  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  	// Moving the count window to after the order was created should return the
  1736  	// count to 0
  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  	// Give the order we create a short lifetime
  1796  	orderLifetime := time.Hour
  1797  	expires := fc.Now().Add(orderLifetime)
  1798  
  1799  	// Create two test registrations to associate with orders
  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  	// Add one pending authz for the first name for regA and one
  1809  	// pending authz for the second name for regA
  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  	// Call GetOrderForNames for a set of names we haven't created an order for
  1818  	// yet
  1819  	result, err := sa.GetOrderForNames(ctx, &sapb.GetOrderForNamesRequest{
  1820  		AcctID: regA.Id,
  1821  		Names:  names,
  1822  	})
  1823  	// We expect the result to return an error
  1824  	test.AssertError(t, err, "sa.GetOrderForNames did not return an error for an empty result")
  1825  	// The error should be a notfound error
  1826  	test.AssertErrorIs(t, err, berrors.NotFound)
  1827  	// The result should be nil
  1828  	test.Assert(t, result == nil, "sa.GetOrderForNames for non-existent order returned non-nil result")
  1829  
  1830  	// Add a new order for a set of names
  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  	// It shouldn't error
  1841  	test.AssertNotError(t, err, "sa.NewOrderAndAuthzs failed")
  1842  	// The order ID shouldn't be nil
  1843  	test.AssertNotNil(t, order.Id, "NewOrderAndAuthzs returned with a nil Id")
  1844  
  1845  	// Call GetOrderForNames with the same account ID and set of names as the
  1846  	// above NewOrderAndAuthzs call
  1847  	result, err = sa.GetOrderForNames(ctx, &sapb.GetOrderForNamesRequest{
  1848  		AcctID: regA.Id,
  1849  		Names:  names,
  1850  	})
  1851  	// It shouldn't error
  1852  	test.AssertNotError(t, err, "sa.GetOrderForNames failed")
  1853  	// The order returned should have the same ID as the order we created above
  1854  	test.AssertNotNil(t, result, "Returned order was nil")
  1855  	test.AssertEquals(t, result.Id, order.Id)
  1856  
  1857  	// Call GetOrderForNames with a different account ID from the NewOrderAndAuthzs call
  1858  	regB := int64(1337)
  1859  	result, err = sa.GetOrderForNames(ctx, &sapb.GetOrderForNamesRequest{
  1860  		AcctID: regB,
  1861  		Names:  names,
  1862  	})
  1863  	// It should error
  1864  	test.AssertError(t, err, "sa.GetOrderForNames did not return an error for an empty result")
  1865  	// The error should be a notfound error
  1866  	test.AssertErrorIs(t, err, berrors.NotFound)
  1867  	// The result should be nil
  1868  	test.Assert(t, result == nil, "sa.GetOrderForNames for diff AcctID returned non-nil result")
  1869  
  1870  	// Advance the clock beyond the initial order's lifetime
  1871  	fc.Add(2 * orderLifetime)
  1872  
  1873  	// Call GetOrderForNames again with the same account ID and set of names as
  1874  	// the initial NewOrderAndAuthzs call
  1875  	result, err = sa.GetOrderForNames(ctx, &sapb.GetOrderForNamesRequest{
  1876  		AcctID: regA.Id,
  1877  		Names:  names,
  1878  	})
  1879  	// It should error since there is no result
  1880  	test.AssertError(t, err, "sa.GetOrderForNames did not return an error for an empty result")
  1881  	// The error should be a notfound error
  1882  	test.AssertErrorIs(t, err, berrors.NotFound)
  1883  	// The result should be nil because the initial order expired & we don't want
  1884  	// to return expired orders
  1885  	test.Assert(t, result == nil, "sa.GetOrderForNames returned non-nil result for expired order case")
  1886  
  1887  	// Create two valid authorizations
  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  	// Add a fresh order that uses the authorizations created above
  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  	// It shouldn't error
  1906  	test.AssertNotError(t, err, "sa.NewOrderAndAuthzs failed")
  1907  	// The order ID shouldn't be nil
  1908  	test.AssertNotNil(t, order.Id, "NewOrderAndAuthzs returned with a nil Id")
  1909  
  1910  	// Call GetOrderForNames with the same account ID and set of names as
  1911  	// the earlier NewOrderAndAuthzs call
  1912  	result, err = sa.GetOrderForNames(ctx, &sapb.GetOrderForNamesRequest{
  1913  		AcctID: regA.Id,
  1914  		Names:  names,
  1915  	})
  1916  	// It should not error since a ready order can be reused.
  1917  	test.AssertNotError(t, err, "sa.GetOrderForNames returned an unexpected error for ready order reuse")
  1918  	// The order returned should have the same ID as the order we created above
  1919  	test.AssertNotNil(t, result, "sa.GetOrderForNames returned nil result")
  1920  	test.AssertEquals(t, result.Id, order.Id)
  1921  
  1922  	// Set the order processing so it can be finalized
  1923  	_, err = sa.SetOrderProcessing(ctx, &sapb.OrderRequest{Id: order.Id})
  1924  	test.AssertNotError(t, err, "sa.SetOrderProcessing failed")
  1925  
  1926  	// Finalize the order
  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  	// Call GetOrderForNames with the same account ID and set of names as
  1932  	// the earlier NewOrderAndAuthzs call
  1933  	result, err = sa.GetOrderForNames(ctx, &sapb.GetOrderForNamesRequest{
  1934  		AcctID: regA.Id,
  1935  		Names:  names,
  1936  	})
  1937  	// It should error since a valid order should not be reused.
  1938  	test.AssertError(t, err, "sa.GetOrderForNames did not return an error for an empty result")
  1939  	// The error should be a notfound error
  1940  	test.AssertErrorIs(t, err, berrors.NotFound)
  1941  	// The result should be nil because the one matching order has been finalized
  1942  	// already
  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  	// Create a registration to work with
  1956  	reg := createWorkingRegistration(t, sa)
  1957  
  1958  	// Create a pending authz, an expired authz, an invalid authz, a deactivated authz,
  1959  	// and a valid authz
  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  			// If the testcase doesn't specify an order expiry use a default timestamp
  2041  			// in the near future.
  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  			// If requested, set the order to processing
  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  			// If requested, finalize the order
  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  			// Fetch the order by ID to get its calculated status
  2073  			storedOrder, err := sa.GetOrder(ctx, &sapb.OrderRequest{Id: newOrder.Id})
  2074  			test.AssertNotError(t, err, "GetOrder failed")
  2075  			// The status shouldn't be nil
  2076  			test.AssertNotNil(t, storedOrder.Status, "Order status was nil")
  2077  			// The status should match expected
  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  	// Create a valid authz
  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  	// Add a cert to the DB to test with.
  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  	// Add a cert to the DB to test with.
  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  	// Add a cert to the DB to test with.
  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  	// Try to update it before its been revoked
  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  	// Now revoke it, so we can update it.
  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  	// Double check that setup worked.
  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  	// Try to update its revocation info with no backdate
  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  	// Try to update its revocation info for a reason other than keyCompromise
  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  	// Try to update the revocation info of the wrong certificate
  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  	// Try to update its revocation info with the wrong backdate
  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  	// Try to update its revocation info correctly
  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  	// Add a cert to the DB to test with.
  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  	// Now revoke it with a shardIdx, so that it gets updated in both the
  2382  	// certificateStatus table and the revokedCertificates table.
  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  	// Updating revocation should succeed, with the revokedCertificates row being
  2396  	// updated.
  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  	// Add a cert to the DB to test with.
  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  	// Now revoke it *without* a shardIdx, so that it only gets updated in the
  2448  	// certificateStatus table, and not the revokedCertificates table.
  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  	// Confirm that setup worked as expected.
  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  	// Updating revocation should succeed, with a new row being written into the
  2472  	// revokedCertificates table.
  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  	// An example cert taken from EFF's website
  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  	// Add a FQDN set for the names so that it will be considered a renewal
  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  	// Add the certificate with the same names.
  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  	// All of the names should have a issuedNames row marking it as a renewal.
  2550  	for _, name := range names {
  2551  		assertIsRenewal(t, name, true)
  2552  	}
  2553  
  2554  	// Add a certificate with different names.
  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  	// None of the names should have a issuedNames row marking it as a renewal.
  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  	// Create a test registration
  2588  	reg := createWorkingRegistration(t, sa)
  2589  
  2590  	// Create a small throw away key for the test certificates.
  2591  	testKey, err := rsa.GenerateKey(rand.Reader, 512)
  2592  	test.AssertNotError(t, err, "error generating test key")
  2593  
  2594  	// Create an initial test certificate for a set of domain names, issued an
  2595  	// hour ago.
  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  	// Update the template with a new serial number and a not before of now and
  2608  	// create a second test cert for the same names. This will be a renewal.
  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  	// Update the template with a third serial number and a partially overlapping
  2616  	// set of names. This will not be a renewal but will help test the exact name
  2617  	// counts.
  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  	// Add the first certificate - it won't be considered a renewal.
  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  	// The count for the base domain should be 1 - just certA has been added.
  2656  	test.AssertEquals(t, countName(t, "not-example.com"), int64(1))
  2657  
  2658  	// Add the second certificate - it should be considered a renewal
  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  	// The count for the base domain should still be 1, just certA. CertB should
  2669  	// be ignored.
  2670  	test.AssertEquals(t, countName(t, "not-example.com"), int64(1))
  2671  
  2672  	// Add the third certificate - it should not be considered a renewal
  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  	// The count for the base domain should be 2 now: certA and certC.
  2682  	// CertB should be ignored.
  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  	// Implicit good port with good scheme
  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  	// Explicit good port with good scheme
  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  	// Explicit bad port with good scheme
  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  	// Explicit bad port with bad scheme
  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  	// Missing URL field
  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  	// Registration has two new style pending authorizations
  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  	// Registration has two new style pending authorizations, one of which has expired
  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  	// Registration with no authorizations should be 0
  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  	// Create two new valid authorizations
  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  	// Getting the order authorizations for an order that doesn't exist should return nothing
  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  	// Getting the order authorizations for an order that does exist, but for the
  3081  	// wrong acct ID should return nothing
  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  	// Create two authorizations, one pending, one invalid
  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  	// Create a valid authorization
  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  	// Add a disabled incident.
  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  	// No incidents are enabled, so this should return in error.
  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  	// Add an enabled incident.
  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  	// Add a row to the incident table with serial '1338'.
  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  	// The incident table should not contain a row with serial '1337'.
  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  	// Add a row to the incident table with serial '1337'.
  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  	// The incident table should now contain a row with serial '1337'.
  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  	// Request serials from a malformed incident table name.
  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  	// Request serials from another malformed incident table name.
  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  	// Request serials for an incident table which doesn't exists.
  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  	// Assert that the error is a MySQL error so we can inspect the error code.
  3408  	var mysqlErr *mysql.MySQLError
  3409  	if errors.As(err, &mysqlErr) {
  3410  		// We expect the error code to be 1146 (ER_NO_SUCH_TABLE):
  3411  		// https://mariadb.com/kb/en/mariadb-error-codes/
  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  	// Request serials from table 'incident_foo', which we expect to exist but
  3418  	// be empty.
  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) // Let our main test thread continue.
  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  	// Add 4 rows of incident serials to 'incident_foo'.
  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  	// Request all 4 serials from the incident table we just added entries to.
  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  	// Add a cert to the DB to test with. We use AddPrecertificate because it sets
  3500  	// up the certificateStatus row we need. This particular cert has a notAfter
  3501  	// date of Mar 6 2023, and we lie about its IssuerNameID to make things easy.
  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  	// Check that it worked.
  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  	// Here's a little helper func we'll use to call GetRevokedCerts and count
  3530  	// how many results it returned.
  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  	// Asking for revoked certs now should return no results.
  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  	// Revoke the certificate.
  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  	// Asking for revoked certs now should return one result.
  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  	// Asking for revoked certs with an old RevokedBefore should return no results.
  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  	// Asking for revoked certs in a time period that does not cover this cert's
  3604  	// notAfter timestamp should return zero results.
  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  	// Asking for revoked certs from a different issuer should return zero results.
  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  	// Add a cert to the DB to test with. We use AddPrecertificate because it sets
  3640  	// up the certificateStatus row we need. This particular cert has a notAfter
  3641  	// date of Mar 6 2023, and we lie about its IssuerNameID to make things easy.
  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  	// Check that it worked.
  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  	// Here's a little helper func we'll use to call GetRevokedCerts and count
  3670  	// how many results it returned.
  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  	// Asking for revoked certs now should return no results.
  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  	// Revoke the certificate, providing the ShardIdx so it gets written into
  3701  	// both the certificateStatus and revokedCertificates tables.
  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  	// Check that it worked in the most basic way.
  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  	// Asking for revoked certs now should return one result.
  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  	// Asking for revoked certs from a different issuer should return zero results.
  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  	// Asking for revoked certs from a different shard should return zero reults.
  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  	// Asking for revoked certs with an old RevokedBefore should return no results.
  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  	// Add a cert to the DB to test with. We use AddPrecertificate because it sets
  3783  	// up the certificateStatus row we need. This particular cert has a notAfter
  3784  	// date of Mar 6 2023, and we lie about its IssuerNameID to make things easy.
  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  	// Create 8 shards: 4 for each of 2 issuers. For each issuer, one shard is
  3808  	// currently leased, three are available, and one of those failed to update.
  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  	// Leasing from a fully-leased subset should fail.
  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  	// Leasing any known shard should return the never-before-leased one (3).
  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  	// Leasing any known shard *again* should now return the oldest one (1).
  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  	// Leasing from a superset of known shards should succeed and return one of
  3896  	// the previously-unknown shards.
  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  	// Create 8 shards: 4 for each of 2 issuers. For each issuer, one shard is
  3927  	// currently leased, three are available, and one of those failed to update.
  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  	// Leasing an unleased shard should work.
  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  	// Leasing a never-before-leased shard should work.
  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  	// Leasing a previously-unknown specific shard should work (to ease the
  4003  	// transition into using leasing).
  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  	// Leasing a leased shard should fail.
  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  	// Leasing more than one shard should fail.
  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  	// Create 8 shards: 4 for each of 2 issuers. For each issuer, one shard is
  4055  	// currently leased, three are available, and one of those failed to update.
  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  	// Updating a leased shard should work.
  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  	// Updating an unleased shard should work.
  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  	// Updating without supplying a NextUpdate should work.
  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  	// Updating a shard to an earlier time should fail.
  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  	// Updating an unknown shard should fail.
  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