package sa import ( "bytes" "crypto/sha256" "fmt" "testing" "time" "github.com/letsencrypt/boulder/db" berrors "github.com/letsencrypt/boulder/errors" sapb "github.com/letsencrypt/boulder/sa/proto" "github.com/letsencrypt/boulder/sa/satest" "github.com/letsencrypt/boulder/test" ) // findIssuedName is a small helper test function to directly query the // issuedNames table for a given name to find a serial (or return an err). func findIssuedName(dbMap db.OneSelector, name string) (string, error) { var issuedNamesSerial string err := dbMap.SelectOne( &issuedNamesSerial, `SELECT serial FROM issuedNames WHERE reversedName = ? ORDER BY notBefore DESC LIMIT 1`, ReverseName(name)) return issuedNamesSerial, err } func TestAddPrecertificate(t *testing.T) { sa, clk, cleanUp := initSA(t) defer cleanUp() reg := satest.CreateWorkingRegistration(t, sa) addPrecert := func(expectIssuedNamesUpdate bool) { // Create a throw-away self signed certificate with a random name and // serial number serial, testCert := test.ThrowAwayCert(t, 1) // Add the cert as a precertificate ocspResp := []byte{0, 0, 1} regID := reg.ID issuedTime := time.Date(2018, 4, 1, 7, 0, 0, 0, time.UTC) issuedTimeNano := issuedTime.UnixNano() _, err := sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{ Der: testCert.Raw, RegID: ®ID, Ocsp: ocspResp, Issued: &issuedTimeNano, }) test.AssertNotError(t, err, "Couldn't add test cert") // It should have the expected certificate status certStatus, err := sa.GetCertificateStatus(ctx, serial) test.AssertNotError(t, err, "Couldn't get status for test cert") test.Assert( t, bytes.Compare(certStatus.OCSPResponse, ocspResp) == 0, fmt.Sprintf("OCSP responses don't match, expected: %x, got %x", certStatus.OCSPResponse, ocspResp), ) test.Assert( t, clk.Now().Equal(certStatus.OCSPLastUpdated), fmt.Sprintf("OCSPLastUpdated doesn't match, expected %s, got %s", clk.Now(), certStatus.OCSPLastUpdated), ) issuedNamesSerial, err := findIssuedName(sa.dbMap, testCert.DNSNames[0]) if expectIssuedNamesUpdate { // If we expectIssuedNamesUpdate then there should be no err and the // expected serial test.AssertNotError(t, err, "expected no err querying issuedNames for precert") test.AssertEquals(t, issuedNamesSerial, serial) // We should also be able to call AddCertificate with the same cert // without it being an error. The duplicate err on inserting to // issuedNames should be ignored. _, err := sa.AddCertificate(ctx, testCert.Raw, regID, nil, &issuedTime) test.AssertNotError(t, err, "unexpected err adding final cert after precert") } else { // Otherwise we expect an ErrDatabaseOp that indicates NoRows because // AddCertificate not AddPrecertificate will be updating this table. test.AssertEquals(t, db.IsNoRows(err), true) } // Adding the same certificate with the same serial should result in an // error _, err = sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{ Der: testCert.Raw, RegID: ®ID, Ocsp: ocspResp, Issued: &issuedTimeNano, }) if err == nil { t.Fatalf("Expected error inserting duplicate precertificate, got none") } if !berrors.Is(err, berrors.Duplicate) { t.Fatalf("Expected berrors.Duplicate inserting duplicate precertificate, got %#v", err) } } addPrecert(true) } func TestAddPrecertificateKeyHash(t *testing.T) { sa, _, cleanUp := initSA(t) defer cleanUp() reg := satest.CreateWorkingRegistration(t, sa) serial, testCert := test.ThrowAwayCert(t, 1) issued := testCert.NotBefore.UnixNano() _, err := sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{ Der: testCert.Raw, RegID: ®.ID, Ocsp: []byte{1, 2, 3}, Issued: &issued, }) test.AssertNotError(t, err, "failed to add precert") var keyHashes []keyHashModel _, err = sa.dbMap.Select(&keyHashes, "SELECT * FROM keyHashToSerial") test.AssertNotError(t, err, "failed to retrieve rows from keyHashToSerial") test.AssertEquals(t, len(keyHashes), 1) test.AssertEquals(t, keyHashes[0].CertSerial, serial) test.AssertEquals(t, keyHashes[0].CertNotAfter, testCert.NotAfter) spkiHash := sha256.Sum256(testCert.RawSubjectPublicKeyInfo) test.Assert(t, bytes.Compare(keyHashes[0].KeyHash, spkiHash[:]) == 0, "spki hash mismatch") }