496 lines
20 KiB
Go
496 lines
20 KiB
Go
package notmain
|
|
|
|
import (
|
|
"context"
|
|
"crypto"
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"encoding/pem"
|
|
"fmt"
|
|
"math/big"
|
|
"net"
|
|
"os"
|
|
"os/user"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/jmhodges/clock"
|
|
akamaipb "github.com/letsencrypt/boulder/akamai/proto"
|
|
capb "github.com/letsencrypt/boulder/ca/proto"
|
|
"github.com/letsencrypt/boulder/core"
|
|
corepb "github.com/letsencrypt/boulder/core/proto"
|
|
"github.com/letsencrypt/boulder/db"
|
|
"github.com/letsencrypt/boulder/goodkey"
|
|
"github.com/letsencrypt/boulder/issuance"
|
|
blog "github.com/letsencrypt/boulder/log"
|
|
"github.com/letsencrypt/boulder/metrics"
|
|
"github.com/letsencrypt/boulder/mocks"
|
|
"github.com/letsencrypt/boulder/ra"
|
|
"github.com/letsencrypt/boulder/sa"
|
|
sapb "github.com/letsencrypt/boulder/sa/proto"
|
|
"github.com/letsencrypt/boulder/test"
|
|
ira "github.com/letsencrypt/boulder/test/inmem/ra"
|
|
isa "github.com/letsencrypt/boulder/test/inmem/sa"
|
|
"github.com/letsencrypt/boulder/test/vars"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/protobuf/types/known/emptypb"
|
|
)
|
|
|
|
type mockOCSPA struct {
|
|
mocks.MockCA
|
|
}
|
|
|
|
func (ca *mockOCSPA) GenerateOCSP(context.Context, *capb.GenerateOCSPRequest, ...grpc.CallOption) (*capb.OCSPResponse, error) {
|
|
return &capb.OCSPResponse{Response: []byte("fakeocspbytes")}, nil
|
|
}
|
|
|
|
type mockPurger struct{}
|
|
|
|
func (mp *mockPurger) Purge(context.Context, *akamaipb.PurgeRequest, ...grpc.CallOption) (*emptypb.Empty, error) {
|
|
return &emptypb.Empty{}, nil
|
|
}
|
|
|
|
func TestRevokeSerialBatchFile(t *testing.T) {
|
|
testCtx := setup(t)
|
|
defer testCtx.cleanUp()
|
|
|
|
entries, _ := setupUniqueTestEntries(t)
|
|
testCtx.createAndRegisterEntries(t, entries)
|
|
|
|
serialFile, err := os.CreateTemp("", "serials")
|
|
test.AssertNotError(t, err, "failed to open temp file")
|
|
defer os.Remove(serialFile.Name())
|
|
|
|
for _, e := range entries {
|
|
_, err = serialFile.WriteString(fmt.Sprintf("%s\n", core.SerialToString(e.serial)))
|
|
test.AssertNotError(t, err, "failed to write serial to temp file")
|
|
}
|
|
err = testCtx.revoker.revokeSerialBatchFile(context.Background(), serialFile.Name(), 0, 2)
|
|
test.AssertNotError(t, err, "revokeBatch failed")
|
|
|
|
for _, e := range entries {
|
|
status, err := testCtx.ssa.GetCertificateStatus(context.Background(), &sapb.Serial{Serial: core.SerialToString(e.serial)})
|
|
test.AssertNotError(t, err, "failed to retrieve certificate status")
|
|
test.AssertEquals(t, core.OCSPStatus(status.Status), core.OCSPStatusRevoked)
|
|
}
|
|
}
|
|
|
|
func TestRevokeIncidentTableSerials(t *testing.T) {
|
|
testCtx := setup(t)
|
|
defer testCtx.cleanUp()
|
|
|
|
entries, _ := setupUniqueTestEntries(t)
|
|
testCtx.createAndRegisterEntries(t, entries)
|
|
|
|
testIncidentsDbMap, err := sa.NewDbMap(vars.DBConnIncidentsFullPerms, sa.DbSettings{})
|
|
test.AssertNotError(t, err, "Couldn't create test dbMap")
|
|
|
|
// Ensure that an empty incident table results in the expected log output.
|
|
err = testCtx.revoker.revokeIncidentTableSerials(context.Background(), "incident_foo", 0, 1)
|
|
test.AssertNotError(t, err, "revokeIncidentTableSerials failed")
|
|
test.Assert(t, len(testCtx.log.GetAllMatching("No serials found in incident table")) > 0, "Expected log output not found")
|
|
testCtx.log.Clear()
|
|
|
|
_, err = testIncidentsDbMap.Exec(
|
|
fmt.Sprintf("INSERT INTO incident_foo (%s) VALUES ('%s', %d, %d, '%s')",
|
|
"serial, registrationID, orderID, lastNoticeSent",
|
|
core.SerialToString(entries[0].serial),
|
|
entries[0].regId,
|
|
42,
|
|
testCtx.revoker.clk.Now().Add(-time.Hour*24*7).Format(time.DateTime),
|
|
),
|
|
)
|
|
test.AssertNotError(t, err, "while inserting row into incident table")
|
|
|
|
err = testCtx.revoker.revokeIncidentTableSerials(context.Background(), "incident_foo", 0, 1)
|
|
test.AssertNotError(t, err, "revokeIncidentTableSerials failed")
|
|
|
|
// Ensure that a populated incident table results in the expected log output.
|
|
test.AssertNotError(t, err, "revokeIncidentTableSerials failed")
|
|
test.Assert(t, len(testCtx.log.GetAllMatching("No serials found in incident table")) <= 0, "Expected log output not found")
|
|
|
|
status, err := testCtx.ssa.GetCertificateStatus(context.Background(), &sapb.Serial{Serial: core.SerialToString(entries[0].serial)})
|
|
test.AssertNotError(t, err, "failed to retrieve certificate status")
|
|
test.AssertEquals(t, core.OCSPStatus(status.Status), core.OCSPStatusRevoked)
|
|
}
|
|
|
|
func TestBlockAndRevokeByPrivateKey(t *testing.T) {
|
|
testCtx := setup(t)
|
|
defer testCtx.cleanUp()
|
|
|
|
uniqueEntries, duplicateEntry := setupUniqueTestEntries(t)
|
|
testCtx.createAndRegisterEntries(t, uniqueEntries)
|
|
testCtx.createAndRegisterEntry(t, duplicateEntry)
|
|
|
|
// Write the key contents of our duplicate entry to a temp file.
|
|
duplicateKeyFile, err := os.CreateTemp("", "key")
|
|
test.AssertNotError(t, err, "failed to create temp file")
|
|
der, err := x509.MarshalPKCS8PrivateKey(duplicateEntry.testKey)
|
|
test.AssertNotError(t, err, "failed to marshal testKey1 to DER")
|
|
err = pem.Encode(duplicateKeyFile,
|
|
&pem.Block{
|
|
Type: "PRIVATE KEY",
|
|
Bytes: der,
|
|
},
|
|
)
|
|
test.AssertNotError(t, err, "failed to PEM encode test key 1")
|
|
test.AssertNotError(t, err, "failed to write to temp file")
|
|
defer os.Remove(duplicateKeyFile.Name())
|
|
|
|
// Get the SPKI hash for the provided keypair.
|
|
spkiHash, err := getPublicKeySPKIHash(&duplicateEntry.testKey.PublicKey)
|
|
test.AssertNotError(t, err, "Failed to get SPKI hash for dupe.")
|
|
|
|
// Ensure that the SPKI hash hasn't already been added to the blockedKeys
|
|
// table.
|
|
keyExists, err := testCtx.revoker.spkiHashInBlockedKeys(spkiHash)
|
|
test.AssertNotError(t, err, "countCertsMatchingSPKIHash for dupe failed")
|
|
test.Assert(t, !keyExists, "SPKI hash should not be in blockedKeys")
|
|
|
|
// For some additional validation let's ensure that counts for all test
|
|
// entries, except our known duplicate, are 1.
|
|
for _, e := range uniqueEntries {
|
|
switch e.names[0] {
|
|
case uniqueEntries[0].names[0]:
|
|
// example-1337.com
|
|
count, err := testCtx.revoker.countCertsMatchingSPKIHash(e.spkiHash)
|
|
test.AssertNotError(t, err, "countCertsMatchingSPKIHash for entry failed")
|
|
test.AssertEquals(t, count, 2)
|
|
|
|
case uniqueEntries[1].names[0]:
|
|
// example-1338.com
|
|
count, err := testCtx.revoker.countCertsMatchingSPKIHash(e.spkiHash)
|
|
test.AssertNotError(t, err, "countCertsMatchingSPKIHash for entry failed")
|
|
test.AssertEquals(t, count, 1)
|
|
|
|
case uniqueEntries[2].names[0]:
|
|
// example-1339.com
|
|
count, err := testCtx.revoker.countCertsMatchingSPKIHash(e.spkiHash)
|
|
test.AssertNotError(t, err, "countCertsMatchingSPKIHash for entry failed")
|
|
test.AssertEquals(t, count, 1)
|
|
}
|
|
}
|
|
|
|
// Revoke one of our two duplicate certificates by serial. This is to test
|
|
// that revokeByPrivateKey will continue if one of the two matching
|
|
// certificates has already been revoked.
|
|
err = testCtx.revoker.revokeBySerial(context.Background(), core.SerialToString(duplicateEntry.serial), 1, true)
|
|
test.AssertNotError(t, err, "While attempting to revoke 1 of our matching certificates ahead of time")
|
|
|
|
// Revoke the certificates, but do not block issuance.
|
|
err = testCtx.revoker.revokeByPrivateKey(context.Background(), duplicateKeyFile.Name())
|
|
test.AssertNotError(t, err, "While attempting to revoke certificates for the provided key")
|
|
|
|
// Ensure that the key is not blocked, yet.
|
|
keyExists, err = testCtx.revoker.spkiHashInBlockedKeys(spkiHash)
|
|
test.AssertNotError(t, err, "countCertsMatchingSPKIHash for dupe failed")
|
|
test.Assert(t, !keyExists, "SPKI hash should not be in blockedKeys")
|
|
|
|
// Block issuance for the key.
|
|
err = testCtx.revoker.blockByPrivateKey(context.Background(), "", duplicateKeyFile.Name())
|
|
test.AssertNotError(t, err, "While attempting to block issuance for the provided key")
|
|
|
|
// Ensure that the key is now blocked.
|
|
keyExists, err = testCtx.revoker.spkiHashInBlockedKeys(spkiHash)
|
|
test.AssertNotError(t, err, "countCertsMatchingSPKIHash for dupe failed")
|
|
test.Assert(t, keyExists, "SPKI hash should not be in blockedKeys")
|
|
|
|
// Ensure that blocking issuance is idempotent.
|
|
err = testCtx.revoker.blockByPrivateKey(context.Background(), "", duplicateKeyFile.Name())
|
|
test.AssertNotError(t, err, "While attempting to block issuance for the provided key")
|
|
}
|
|
|
|
func TestPrivateKeyBlock(t *testing.T) {
|
|
testCtx := setup(t)
|
|
defer testCtx.cleanUp()
|
|
|
|
uniqueEntries, duplicateEntry := setupUniqueTestEntries(t)
|
|
testCtx.createAndRegisterEntries(t, uniqueEntries)
|
|
testCtx.createAndRegisterEntry(t, duplicateEntry)
|
|
|
|
// Write the key contents of our duplicate entry to a temp file.
|
|
duplicateKeyFile, err := os.CreateTemp("", "key")
|
|
test.AssertNotError(t, err, "failed to create temp file")
|
|
der, err := x509.MarshalPKCS8PrivateKey(duplicateEntry.testKey)
|
|
test.AssertNotError(t, err, "failed to marshal testKey1 to DER")
|
|
err = pem.Encode(duplicateKeyFile,
|
|
&pem.Block{
|
|
Type: "PRIVATE KEY",
|
|
Bytes: der,
|
|
},
|
|
)
|
|
test.AssertNotError(t, err, "failed to PEM encode test key")
|
|
test.AssertNotError(t, err, "failed to write to temp file")
|
|
defer os.Remove(duplicateKeyFile.Name())
|
|
|
|
// Get the SPKI hash for the provided keypair.
|
|
duplicateKeySPKI, err := getPublicKeySPKIHash(&duplicateEntry.testKey.PublicKey)
|
|
test.AssertNotError(t, err, "Failed to get SPKI hash for dupe.")
|
|
|
|
// Query the 'keyHashToSerial' table for certificates with a matching SPKI
|
|
// hash. We expect that since this key was re-used we'll find 2 matches.
|
|
count, err := testCtx.revoker.countCertsMatchingSPKIHash(duplicateKeySPKI)
|
|
test.AssertNotError(t, err, "countCertsMatchingSPKIHash for dupe failed")
|
|
test.AssertEquals(t, count, 2)
|
|
|
|
// With dryRun=true this should not block the key.
|
|
err = privateKeyBlock(&testCtx.revoker, true, "", count, duplicateKeySPKI, duplicateKeyFile.Name())
|
|
test.AssertNotError(t, err, "While attempting to block issuance for the provided key")
|
|
|
|
// Ensure that the key is not blocked, yet.
|
|
keyExists, err := testCtx.revoker.spkiHashInBlockedKeys(duplicateKeySPKI)
|
|
test.AssertNotError(t, err, "countCertsMatchingSPKIHash for dupe failed")
|
|
test.Assert(t, !keyExists, "SPKI hash should not be in blockedKeys")
|
|
|
|
// With dryRun=false this should block the key.
|
|
comment := "key blocked as part of test"
|
|
err = privateKeyBlock(&testCtx.revoker, false, comment, count, duplicateKeySPKI, duplicateKeyFile.Name())
|
|
test.AssertNotError(t, err, "While attempting to block issuance for the provided key")
|
|
|
|
// With dryRun=false this should result in an error as the key is already blocked.
|
|
err = privateKeyBlock(&testCtx.revoker, false, "", count, duplicateKeySPKI, duplicateKeyFile.Name())
|
|
test.AssertError(t, err, "Attempting to block a key which is already blocked should have failed.")
|
|
|
|
// Ensure that the key is now blocked.
|
|
keyExists, err = testCtx.revoker.spkiHashInBlockedKeys(duplicateKeySPKI)
|
|
test.AssertNotError(t, err, "countCertsMatchingSPKIHash for dupe failed")
|
|
test.Assert(t, keyExists, "SPKI hash should not be in blockedKeys")
|
|
|
|
// Ensure that the comment was set as expected
|
|
commentFromDB, err := testCtx.dbMap.SelectStr("SELECT comment from blockedKeys WHERE keyHash = ?", duplicateKeySPKI)
|
|
test.AssertNotError(t, err, "Failed to get comment from database")
|
|
u, err := user.Current()
|
|
test.AssertNotError(t, err, "Failed to get current user")
|
|
expectedDBComment := fmt.Sprintf("%s: %s", u.Username, comment)
|
|
test.AssertEquals(t, commentFromDB, expectedDBComment)
|
|
}
|
|
|
|
func TestPrivateKeyRevoke(t *testing.T) {
|
|
testCtx := setup(t)
|
|
defer testCtx.cleanUp()
|
|
|
|
uniqueEntries, duplicateEntry := setupUniqueTestEntries(t)
|
|
testCtx.createAndRegisterEntries(t, uniqueEntries)
|
|
testCtx.createAndRegisterEntry(t, duplicateEntry)
|
|
|
|
// Write the key contents of our duplicate entry to a temp file.
|
|
duplicateKeyFile, err := os.CreateTemp("", "key")
|
|
test.AssertNotError(t, err, "failed to create temp file")
|
|
der, err := x509.MarshalPKCS8PrivateKey(duplicateEntry.testKey)
|
|
test.AssertNotError(t, err, "failed to marshal testKey1 to DER")
|
|
err = pem.Encode(duplicateKeyFile,
|
|
&pem.Block{
|
|
Type: "PRIVATE KEY",
|
|
Bytes: der,
|
|
},
|
|
)
|
|
test.AssertNotError(t, err, "failed to PEM encode test key")
|
|
test.AssertNotError(t, err, "failed to write to temp file")
|
|
defer os.Remove(duplicateKeyFile.Name())
|
|
|
|
// Get the SPKI hash for the provided keypair.
|
|
duplicateKeySPKI, err := getPublicKeySPKIHash(&duplicateEntry.testKey.PublicKey)
|
|
test.AssertNotError(t, err, "Failed to get SPKI hash for dupe.")
|
|
|
|
// Query the 'keyHashToSerial' table for certificates with a matching SPKI
|
|
// hash. We expect that since this key was re-used we'll find 2 matches.
|
|
count, err := testCtx.revoker.countCertsMatchingSPKIHash(duplicateKeySPKI)
|
|
test.AssertNotError(t, err, "countCertsMatchingSPKIHash for dupe failed")
|
|
test.AssertEquals(t, count, 2)
|
|
|
|
// With dryRun=true this should not revoke certificates or block issuance.
|
|
err = privateKeyRevoke(&testCtx.revoker, true, "", count, duplicateKeyFile.Name())
|
|
test.AssertNotError(t, err, "While attempting to block issuance for the provided key")
|
|
|
|
// Ensure that the key is not blocked, yet.
|
|
keyExists, err := testCtx.revoker.spkiHashInBlockedKeys(duplicateKeySPKI)
|
|
test.AssertNotError(t, err, "spkiHashInBlockedKeys failed for key that shouldn't be blocked yet")
|
|
test.Assert(t, !keyExists, "SPKI hash should not be in blockedKeys")
|
|
|
|
// With dryRun=false this should revoke matching certificates and block the key.
|
|
comment := "key blocked as part of test"
|
|
err = privateKeyRevoke(&testCtx.revoker, false, comment, count, duplicateKeyFile.Name())
|
|
test.AssertNotError(t, err, "While attempting to block issuance for the provided key")
|
|
|
|
// Ensure that the key is now blocked.
|
|
keyExists, err = testCtx.revoker.spkiHashInBlockedKeys(duplicateKeySPKI)
|
|
test.AssertNotError(t, err, "spkiHashInBlockedKeys failed for key that should now be blocked")
|
|
test.Assert(t, keyExists, "SPKI hash should not be in blockedKeys")
|
|
|
|
// Ensure that the comment was set as expected
|
|
commentFromDB, err := testCtx.dbMap.SelectStr("SELECT comment from blockedKeys WHERE keyHash = ?", duplicateKeySPKI)
|
|
test.AssertNotError(t, err, "Failed to get comment from database")
|
|
u, err := user.Current()
|
|
test.AssertNotError(t, err, "Failed to get current user")
|
|
expectedDBComment := fmt.Sprintf("%s: %s", u.Username, comment)
|
|
test.AssertEquals(t, commentFromDB, expectedDBComment)
|
|
}
|
|
|
|
type entry struct {
|
|
jwk string
|
|
serial *big.Int
|
|
names []string
|
|
testKey *rsa.PrivateKey
|
|
regId int64
|
|
spkiHash []byte
|
|
}
|
|
|
|
func setupUniqueTestEntries(t *testing.T) ([]*entry, *entry) {
|
|
t.Helper()
|
|
|
|
// Unique keys for each of our test certificates.
|
|
key1, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
test.AssertNotError(t, err, "Generating test key 1")
|
|
key2, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
test.AssertNotError(t, err, "Generating test key 2")
|
|
key3, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
test.AssertNotError(t, err, "Generating test key 3")
|
|
|
|
// Unique JWKs so we can register each of our entries.
|
|
testJWK1 := `{"kty":"RSA","n":"yNWVhtYEKJR21y9xsHV-PD_bYwbXSeNuFal46xYxVfRL5mqha7vttvjB_vc7Xg2RvgCxHPCqoxgMPTzHrZT75LjCwIW2K_klBYN8oYvTwwmeSkAz6ut7ZxPv-nZaT5TJhGk0NT2kh_zSpdriEJ_3vW-mqxYbbBmpvHqsa1_zx9fSuHYctAZJWzxzUZXykbWMWQZpEiE0J4ajj51fInEzVn7VxV-mzfMyboQjujPh7aNJxAWSq4oQEJJDgWwSh9leyoJoPpONHxh5nEE5AjE01FkGICSxjpZsF-w8hOTI3XXohUdu29Se26k2B0PolDSuj0GIQU6-W9TdLXSjBb2SpQ","e":"AQAB"}`
|
|
testJWK2 := `{"kty":"RSA","n":"qnARLrT7Xz4gRcKyLdydmCr-ey9OuPImX4X40thk3on26FkMznR3fRjs66eLK7mmPcBZ6uOJseURU6wAaZNmemoYx1dMvqvWWIyiQleHSD7Q8vBrhR6uIoO4jAzJZR-ChzZuSDt7iHN-3xUVspu5XGwXU_MVJZshTwp4TaFx5elHIT_ObnTvTOU3Xhish07AbgZKmWsVbXh5s-CrIicU4OexJPgunWZ_YJJueOKmTvnLlTV4MzKR2oZlBKZ27S0-SfdV_QDx_ydle5oMAyKVtlAV35cyPMIsYNwgUGBCdY_2Uzi5eX0lTc7MPRwz6qR1kip-i59VcGcUQgqHV6Fyqw","e":"AQAB"}`
|
|
testJWK3 := `{"kty":"RSA","n":"uTQER6vUA1RDixS8xsfCRiKUNGRzzyIK0MhbS2biClShbb0hSx2mPP7gBvis2lizZ9r-y9hL57kNQoYCKndOBg0FYsHzrQ3O9AcoV1z2Mq-XhHZbFrVYaXI0M3oY9BJCWog0dyi3XC0x8AxC1npd1U61cToHx-3uSvgZOuQA5ffEn5L38Dz1Ti7OV3E4XahnRJvejadUmTkki7phLBUXm5MnnyFm0CPpf6ApV7zhLjN5W-nV0WL17o7v8aDgV_t9nIdi1Y26c3PlCEtiVHZcebDH5F1Deta3oLLg9-g6rWnTqPbY3knffhp4m0scLD6e33k8MtzxDX_D7vHsg0_X1w","e":"AQAB"}`
|
|
testJWK4 := `{"kty":"RSA","n":"qih-cx32M0wq8MhhN-kBi2xPE-wnw4_iIg1hWO5wtBfpt2PtWikgPuBT6jvK9oyQwAWbSfwqlVZatMPY_-3IyytMNb9R9OatNr6o5HROBoyZnDVSiC4iMRd7bRl_PWSIqj_MjhPNa9cYwBdW5iC3jM5TaOgmp0-YFm4tkLGirDcIBDkQYlnv9NKILvuwqkapZ7XBixeqdCcikUcTRXW5unqygO6bnapzw-YtPsPPlj4Ih3SvK4doyziPV96U8u5lbNYYEzYiW1mbu9n0KLvmKDikGcdOpf6-yRa_10kMZyYQatY1eclIKI0xb54kbluEl0GQDaL5FxLmiKeVnsapzw","e":"AQAB"}`
|
|
return []*entry{
|
|
{jwk: testJWK1, serial: big.NewInt(1), names: []string{"example-1337.com"}, testKey: key1},
|
|
{jwk: testJWK2, serial: big.NewInt(2), names: []string{"example-1338.com"}, testKey: key2},
|
|
{jwk: testJWK3, serial: big.NewInt(3), names: []string{"example-1339.com"}, testKey: key3},
|
|
},
|
|
&entry{jwk: testJWK4, serial: big.NewInt(4), names: []string{"example-1336.com"}, testKey: key1}
|
|
}
|
|
|
|
type testCtx struct {
|
|
revoker revoker
|
|
ssa sapb.StorageAuthorityClient
|
|
dbMap *db.WrappedMap
|
|
cleanUp func()
|
|
issuer *issuance.Certificate
|
|
signer crypto.Signer
|
|
log *blog.Mock
|
|
}
|
|
|
|
func (c testCtx) addRegistation(t *testing.T, names []string, jwk string) int64 {
|
|
t.Helper()
|
|
initialIP, err := net.ParseIP("127.0.0.1").MarshalText()
|
|
test.AssertNotError(t, err, "Failed to create initialIP")
|
|
|
|
reg := &corepb.Registration{
|
|
Id: 1,
|
|
Contact: []string{fmt.Sprintf("hello@%s", names[0])},
|
|
Key: []byte(jwk),
|
|
InitialIP: initialIP,
|
|
}
|
|
|
|
reg, err = c.ssa.NewRegistration(context.Background(), reg)
|
|
test.AssertNotError(t, err, "Failed to store test registration")
|
|
return reg.Id
|
|
}
|
|
|
|
func (c testCtx) addCertificate(t *testing.T, serial *big.Int, names []string, pubKey rsa.PublicKey, regId int64) *x509.Certificate {
|
|
t.Helper()
|
|
template := &x509.Certificate{
|
|
SerialNumber: serial,
|
|
Subject: pkix.Name{Organization: []string{"tests"}},
|
|
NotBefore: time.Now(),
|
|
NotAfter: time.Now().AddDate(0, 0, 1),
|
|
DNSNames: names,
|
|
}
|
|
|
|
rawCert, err := x509.CreateCertificate(rand.Reader, template, c.issuer.Certificate, &pubKey, c.signer)
|
|
test.AssertNotError(t, err, "Failed to generate test cert")
|
|
|
|
_, err = c.ssa.AddPrecertificate(
|
|
context.Background(), &sapb.AddCertificateRequest{
|
|
Der: rawCert,
|
|
RegID: regId,
|
|
Issued: time.Now().UnixNano(),
|
|
IssuerNameID: 1,
|
|
},
|
|
)
|
|
test.AssertNotError(t, err, "Failed to add test precert")
|
|
|
|
cert, err := x509.ParseCertificate(rawCert)
|
|
test.AssertNotError(t, err, "Failed to parse test cert")
|
|
return cert
|
|
}
|
|
|
|
func (c testCtx) createAndRegisterEntries(t *testing.T, entries []*entry) {
|
|
t.Helper()
|
|
for _, entry := range entries {
|
|
c.createAndRegisterEntry(t, entry)
|
|
}
|
|
}
|
|
|
|
func (c testCtx) createAndRegisterEntry(t *testing.T, e *entry) {
|
|
t.Helper()
|
|
e.regId = c.addRegistation(t, e.names, e.jwk)
|
|
cert := c.addCertificate(t, e.serial, e.names, e.testKey.PublicKey, e.regId)
|
|
var err error
|
|
e.spkiHash, err = getPublicKeySPKIHash(cert.PublicKey)
|
|
test.AssertNotError(t, err, "Failed to get SPKI hash")
|
|
}
|
|
|
|
func setup(t *testing.T) testCtx {
|
|
t.Helper()
|
|
log := blog.UseMock()
|
|
fc := clock.NewFake()
|
|
|
|
// Set some non-zero time for GRPC requests to be non-nil.
|
|
fc.Set(time.Now())
|
|
|
|
dbMap, err := sa.NewDbMap(vars.DBConnSA, sa.DbSettings{})
|
|
if err != nil {
|
|
t.Fatalf("Failed to create dbMap: %s", err)
|
|
}
|
|
incidentsDbMap, err := sa.NewDbMap(vars.DBConnIncidents, sa.DbSettings{})
|
|
test.AssertNotError(t, err, "Couldn't create test dbMap")
|
|
|
|
ssa, err := sa.NewSQLStorageAuthority(dbMap, dbMap, incidentsDbMap, 1, 0, fc, log, metrics.NoopRegisterer)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create SA: %s", err)
|
|
}
|
|
cleanUp := func() {
|
|
test.ResetBoulderTestDatabase(t)
|
|
test.ResetIncidentsTestDatabase(t)
|
|
}
|
|
|
|
issuer, err := issuance.LoadCertificate("../../test/hierarchy/int-r3.cert.pem")
|
|
test.AssertNotError(t, err, "Failed to load test issuer")
|
|
|
|
signer, err := test.LoadSigner("../../test/hierarchy/int-r3.key.pem")
|
|
test.AssertNotError(t, err, "Failed to load test signer")
|
|
|
|
ra := ra.NewRegistrationAuthorityImpl(
|
|
fc,
|
|
log,
|
|
metrics.NoopRegisterer,
|
|
1,
|
|
goodkey.KeyPolicy{},
|
|
100,
|
|
300*24*time.Hour,
|
|
7*24*time.Hour,
|
|
nil,
|
|
nil,
|
|
0,
|
|
0,
|
|
nil,
|
|
&mockPurger{},
|
|
[]*issuance.Certificate{issuer},
|
|
)
|
|
ra.SA = isa.SA{Impl: ssa}
|
|
ra.OCSP = &mockOCSPA{}
|
|
rac := ira.RA{Impl: ra}
|
|
|
|
return testCtx{
|
|
revoker: revoker{rac, isa.SA{Impl: ssa}, dbMap, fc, log},
|
|
ssa: isa.SA{Impl: ssa},
|
|
dbMap: dbMap,
|
|
cleanUp: cleanUp,
|
|
issuer: issuer,
|
|
signer: signer,
|
|
log: log,
|
|
}
|
|
}
|