Merge pull request #735 from letsencrypt/clock_ca

correct ca and sa revocation code and tests
This commit is contained in:
Jacob Hoffman-Andrews 2015-09-04 16:25:02 -04:00
commit 82f134dd92
10 changed files with 161 additions and 65 deletions

View File

@ -15,6 +15,7 @@ import (
"io/ioutil"
"time"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/jmhodges/clock"
"github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/core"
blog "github.com/letsencrypt/boulder/log"
@ -52,6 +53,7 @@ type CertificateAuthorityImpl struct {
SA core.StorageAuthority
PA core.PolicyAuthority
DB core.CertificateAuthorityDatabase
Clk clock.Clock // TODO(jmhodges): should be private, like log
log *blog.AuditLogger
Prefix int // Prepended to the serial number
ValidityPeriod time.Duration
@ -66,7 +68,7 @@ type CertificateAuthorityImpl struct {
// using CFSSL's authenticated signature scheme. A CA created in this way
// issues for a single profile on the remote signer, which is indicated
// by name in this constructor.
func NewCertificateAuthorityImpl(cadb core.CertificateAuthorityDatabase, config cmd.CAConfig, issuerCert string) (*CertificateAuthorityImpl, error) {
func NewCertificateAuthorityImpl(cadb core.CertificateAuthorityDatabase, config cmd.CAConfig, clk clock.Clock, issuerCert string) (*CertificateAuthorityImpl, error) {
var ca *CertificateAuthorityImpl
var err error
logger := blog.GetAuditLogger()
@ -125,6 +127,7 @@ func NewCertificateAuthorityImpl(cadb core.CertificateAuthorityDatabase, config
profile: config.Profile,
DB: cadb,
Prefix: config.SerialPrefix,
Clk: clk,
log: logger,
NotAfter: issuer.NotAfter,
}
@ -212,7 +215,7 @@ func (ca *CertificateAuthorityImpl) RevokeCertificate(serial string, reasonCode
Certificate: cert,
Status: string(core.OCSPStatusRevoked),
Reason: int(reasonCode),
RevokedAt: time.Now(),
RevokedAt: ca.Clk.Now(),
}
ocspResponse, err := ca.OCSPSigner.Sign(signRequest)
if err != nil {
@ -292,7 +295,7 @@ func (ca *CertificateAuthorityImpl) IssueCertificate(csr x509.CertificateRequest
}
}
notAfter := time.Now().Add(ca.ValidityPeriod)
notAfter := ca.Clk.Now().Add(ca.ValidityPeriod)
if ca.NotAfter.Before(notAfter) {
// AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c

View File

@ -16,6 +16,7 @@ import (
cfsslConfig "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
ocspConfig "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/ocsp/config"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/jmhodges/clock"
"github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/mocks"
"github.com/letsencrypt/boulder/policy"
@ -112,6 +113,7 @@ type testCtx struct {
caConfig cmd.CAConfig
reg core.Registration
pa core.PolicyAuthority
fc clock.FakeClock
cleanUp func()
}
@ -121,7 +123,9 @@ func setup(t *testing.T) *testCtx {
if err != nil {
t.Fatalf("Failed to create dbMap: %s", err)
}
ssa, err := sa.NewSQLStorageAuthority(dbMap)
fc := clock.NewFake()
fc.Add(1 * time.Hour)
ssa, err := sa.NewSQLStorageAuthority(dbMap, fc)
if err != nil {
t.Fatalf("Failed to create SA: %s", err)
}
@ -188,7 +192,7 @@ func setup(t *testing.T) *testCtx {
},
},
}
return &testCtx{cadb, ssa, caConfig, reg, pa, cleanUp}
return &testCtx{cadb, ssa, caConfig, reg, pa, fc, cleanUp}
}
func TestFailNoSerial(t *testing.T) {
@ -196,31 +200,33 @@ func TestFailNoSerial(t *testing.T) {
defer ctx.cleanUp()
ctx.caConfig.SerialPrefix = 0
_, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, caCertFile)
_, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, ctx.fc, caCertFile)
test.AssertError(t, err, "CA should have failed with no SerialPrefix")
}
func TestRevoke(t *testing.T) {
ctx := setup(t)
defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, caCertFile)
ca.PA = ctx.pa
ca, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, ctx.fc, caCertFile)
test.AssertNotError(t, err, "Failed to create CA")
if err != nil {
return
}
ca.PA = ctx.pa
ca.SA = ctx.sa
ca.MaxKeySize = 4096
csr, _ := x509.ParseCertificateRequest(CNandSANCSR)
certObj, err := ca.IssueCertificate(*csr, ctx.reg.ID, FarFuture)
test.AssertNotError(t, err, "Failed to sign certificate")
if err != nil {
return
}
cert, err := x509.ParseCertificate(certObj.DER)
test.AssertNotError(t, err, "Certificate failed to parse")
serialString := core.SerialToString(cert.SerialNumber)
beforeRevoke, err := ctx.sa.GetCertificateStatus(serialString)
test.AssertNotError(t, err, "Failed to get cert status")
ctx.fc.Add(1 * time.Hour)
err = ca.RevokeCertificate(serialString, 0)
test.AssertNotError(t, err, "Revocation failed")
@ -228,15 +234,22 @@ func TestRevoke(t *testing.T) {
test.AssertNotError(t, err, "Failed to get cert status")
test.AssertEquals(t, status.Status, core.OCSPStatusRevoked)
secondAgo := time.Now().Add(-time.Second)
test.Assert(t, status.OCSPLastUpdated.After(secondAgo),
fmt.Sprintf("OCSP LastUpdated was more than a second old: %v", status.OCSPLastUpdated))
if !ctx.fc.Now().Equal(status.OCSPLastUpdated) {
t.Errorf("OCSPLastUpdated, expected %s, got %s",
ctx.fc.Now(),
status.OCSPLastUpdated)
}
if !status.OCSPLastUpdated.After(beforeRevoke.OCSPLastUpdated) {
t.Errorf("OCSPLastUpdated, before revocation: %s; after: %s", beforeRevoke.OCSPLastUpdated, status.OCSPLastUpdated)
}
}
func TestIssueCertificate(t *testing.T) {
ctx := setup(t)
defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, caCertFile)
ca, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, ctx.fc, caCertFile)
test.AssertNotError(t, err, "Failed to create CA")
ca.PA = ctx.pa
ca.SA = ctx.sa
@ -313,7 +326,7 @@ func TestIssueCertificate(t *testing.T) {
func TestRejectNoName(t *testing.T) {
ctx := setup(t)
defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, caCertFile)
ca, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, ctx.fc, caCertFile)
test.AssertNotError(t, err, "Failed to create CA")
ca.PA = ctx.pa
ca.SA = ctx.sa
@ -330,7 +343,7 @@ func TestRejectNoName(t *testing.T) {
func TestRejectTooManyNames(t *testing.T) {
ctx := setup(t)
defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, caCertFile)
ca, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, ctx.fc, caCertFile)
test.AssertNotError(t, err, "Failed to create CA")
ca.PA = ctx.pa
ca.SA = ctx.sa
@ -344,7 +357,7 @@ func TestRejectTooManyNames(t *testing.T) {
func TestDeduplication(t *testing.T) {
ctx := setup(t)
defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, caCertFile)
ca, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, ctx.fc, caCertFile)
test.AssertNotError(t, err, "Failed to create CA")
ca.PA = ctx.pa
ca.SA = ctx.sa
@ -374,7 +387,7 @@ func TestDeduplication(t *testing.T) {
func TestRejectValidityTooLong(t *testing.T) {
ctx := setup(t)
defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, caCertFile)
ca, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, ctx.fc, caCertFile)
test.AssertNotError(t, err, "Failed to create CA")
ca.PA = ctx.pa
ca.SA = ctx.sa
@ -387,7 +400,7 @@ func TestRejectValidityTooLong(t *testing.T) {
// Test that the CA rejects CSRs that would expire after the intermediate cert
csr, _ = x509.ParseCertificateRequest(NoCNCSR)
ca.NotAfter = time.Now()
ca.NotAfter = ctx.fc.Now()
_, err = ca.IssueCertificate(*csr, 1, FarFuture)
test.AssertEquals(t, err.Error(), "Cannot issue a certificate that expires after the intermediate certificate.")
}
@ -395,7 +408,7 @@ func TestRejectValidityTooLong(t *testing.T) {
func TestShortKey(t *testing.T) {
ctx := setup(t)
defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, caCertFile)
ca, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, ctx.fc, caCertFile)
ca.PA = ctx.pa
ca.SA = ctx.sa
ca.MaxKeySize = 4096
@ -409,7 +422,7 @@ func TestShortKey(t *testing.T) {
func TestRejectBadAlgorithm(t *testing.T) {
ctx := setup(t)
defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, caCertFile)
ca, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, ctx.fc, caCertFile)
ca.PA = ctx.pa
ca.SA = ctx.sa
ca.MaxKeySize = 4096

View File

@ -7,6 +7,7 @@ package main
import (
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/jmhodges/clock"
"github.com/letsencrypt/boulder/ca"
"github.com/letsencrypt/boulder/cmd"
blog "github.com/letsencrypt/boulder/log"
@ -43,7 +44,7 @@ func main() {
pa, err := policy.NewPolicyAuthorityImpl(paDbMap, c.PA.EnforcePolicyWhitelist)
cmd.FailOnError(err, "Couldn't create PA")
cai, err := ca.NewCertificateAuthorityImpl(cadb, c.CA, c.Common.IssuerCert)
cai, err := ca.NewCertificateAuthorityImpl(cadb, c.CA, clock.Default(), c.Common.IssuerCert)
cmd.FailOnError(err, "Failed to create CA impl")
cai.MaxKeySize = c.Common.MaxKeySize
cai.PA = pa

View File

@ -7,7 +7,7 @@ package main
import (
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/jmhodges/clock"
"github.com/letsencrypt/boulder/cmd"
blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/rpc"
@ -34,7 +34,7 @@ func main() {
dbMap, err := sa.NewDbMap(c.SA.DBConnect)
cmd.FailOnError(err, "Couldn't connect to SA database")
sai, err := sa.NewSQLStorageAuthority(dbMap)
sai, err := sa.NewSQLStorageAuthority(dbMap, clock.Default())
cmd.FailOnError(err, "Failed to create SA impl")
sai.SetSQLDebug(c.SQL.SQLDebug)

View File

@ -74,14 +74,14 @@ type certChecker struct {
clock clock.Clock
}
func newChecker(saDbMap *gorp.DbMap, paDbMap *gorp.DbMap, enforceWhitelist bool) certChecker {
func newChecker(saDbMap *gorp.DbMap, paDbMap *gorp.DbMap, clk clock.Clock, enforceWhitelist bool) certChecker {
pa, err := policy.NewPolicyAuthorityImpl(paDbMap, enforceWhitelist)
cmd.FailOnError(err, "Failed to create PA")
c := certChecker{
pa: pa,
dbMap: saDbMap,
certs: make(chan core.Certificate, batchSize),
clock: clock.Default(),
clock: clk,
}
c.issuedReport.Entries = make(map[string]reportEntry)
return c
@ -234,7 +234,7 @@ func main() {
paDbMap, err := sa.NewDbMap(c.PA.DBConnect)
cmd.FailOnError(err, "Could not connect to policy database")
checker := newChecker(saDbMap, paDbMap, c.PA.EnforcePolicyWhitelist)
checker := newChecker(saDbMap, paDbMap, clock.Default(), c.PA.EnforcePolicyWhitelist)
auditlogger.Info("# Getting certificates issued in the last 90 days")
// Since we grab certificates in batches we don't want this to block, when it

View File

@ -49,7 +49,7 @@ func BenchmarkCheckCert(b *testing.B) {
os.Exit(1)
}()
checker := newChecker(saDbMap, paDbMap, false)
checker := newChecker(saDbMap, paDbMap, clock.Default(), false)
testKey, _ := rsa.GenerateKey(rand.Reader, 1024)
expiry := time.Now().AddDate(0, 0, 1)
serial := big.NewInt(1337)
@ -87,10 +87,10 @@ func TestCheckCert(t *testing.T) {
}()
testKey, _ := rsa.GenerateKey(rand.Reader, 1024)
checker := newChecker(saDbMap, paDbMap, false)
fc := clock.NewFake()
fc.Add(time.Hour * 24 * 90)
checker.clock = fc
checker := newChecker(saDbMap, paDbMap, fc, false)
issued := checker.clock.Now().Add(-time.Hour * 24 * 45)
goodExpiry := issued.Add(checkPeriod)
@ -146,13 +146,16 @@ func TestGetAndProcessCerts(t *testing.T) {
test.AssertNotError(t, err, "Couldn't connect to database")
paDbMap, err := sa.NewDbMap(paDbConnStr)
test.AssertNotError(t, err, "Couldn't connect to policy database")
checker := newChecker(saDbMap, paDbMap, false)
sa, err := sa.NewSQLStorageAuthority(saDbMap)
fc := clock.NewFake()
checker := newChecker(saDbMap, paDbMap, fc, false)
sa, err := sa.NewSQLStorageAuthority(saDbMap, fc)
test.AssertNotError(t, err, "Couldn't create SA to insert certificates")
saCleanUp := test.ResetTestDatabase(t, saDbMap.Db)
paCleanUp := test.ResetTestDatabase(t, paDbMap.Db)
defer func() {
saDbMap.TruncateTables()
paDbMap.TruncateTables()
test.AssertNotError(t, err, "Failed to truncate tables")
saCleanUp()
paCleanUp()
}()
testKey, _ := rsa.GenerateKey(rand.Reader, 1024)

View File

@ -456,7 +456,8 @@ func setup(t *testing.T, nagTimes []time.Duration) *testCtx {
if err != nil {
t.Fatalf("Couldn't connect the database: %s", err)
}
ssa, err := sa.NewSQLStorageAuthority(dbMap)
fc := clock.NewFake()
ssa, err := sa.NewSQLStorageAuthority(dbMap, fc)
if err != nil {
t.Fatalf("unable to create SQLStorageAuthority: %s", err)
}
@ -464,7 +465,6 @@ func setup(t *testing.T, nagTimes []time.Duration) *testCtx {
stats, _ := statsd.NewNoopClient(nil)
mc := &mockMail{}
fc := clock.NewFake()
m := &mailer{
log: blog.GetAuditLogger(),

View File

@ -20,6 +20,7 @@ import (
cfsslConfig "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/ocsp"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/jmhodges/clock"
jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose"
"github.com/letsencrypt/boulder/ca"
"github.com/letsencrypt/boulder/core"
@ -144,11 +145,13 @@ func initAuthorities(t *testing.T) (*DummyValidationAuthority, *sa.SQLStorageAut
err = json.Unmarshal(ShortKeyJSON, &ShortKey)
test.AssertNotError(t, err, "Failed to unmarshall JWK")
fc := clock.NewFake()
dbMap, err := sa.NewDbMap(saDBConnStr)
if err != nil {
t.Fatalf("Failed to create dbMap: %s", err)
}
ssa, err := sa.NewSQLStorageAuthority(dbMap)
ssa, err := sa.NewSQLStorageAuthority(dbMap, fc)
if err != nil {
t.Fatalf("Failed to create SA: %s", err)
}
@ -193,6 +196,7 @@ func initAuthorities(t *testing.T) (*DummyValidationAuthority, *sa.SQLStorageAut
ValidityPeriod: time.Hour * 2190,
NotAfter: time.Now().Add(time.Hour * 8761),
MaxKeySize: 4096,
Clk: fc,
}
cleanUp := func() {
saDBCleanUp()

View File

@ -16,6 +16,7 @@ import (
"strings"
"time"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/jmhodges/clock"
jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose"
gorp "github.com/letsencrypt/boulder/Godeps/_workspace/src/gopkg.in/gorp.v1"
"github.com/letsencrypt/boulder/core"
@ -27,6 +28,7 @@ const getChallengesQuery = "SELECT * FROM challenges WHERE authorizationID = :au
// SQLStorageAuthority defines a Storage Authority
type SQLStorageAuthority struct {
dbMap *gorp.DbMap
clk clock.Clock
log *blog.AuditLogger
}
@ -49,13 +51,14 @@ type authzModel struct {
// NewSQLStorageAuthority provides persistence using a SQL backend for
// Boulder. It will modify the given gorp.DbMap by adding relevent tables.
func NewSQLStorageAuthority(dbMap *gorp.DbMap) (*SQLStorageAuthority, error) {
func NewSQLStorageAuthority(dbMap *gorp.DbMap, clk clock.Clock) (*SQLStorageAuthority, error) {
logger := blog.GetAuditLogger()
logger.Notice("Storage Authority Starting")
ssa := &SQLStorageAuthority{
dbMap: dbMap,
clk: clk,
log: logger,
}
@ -287,7 +290,6 @@ func (ssa *SQLStorageAuthority) GetCertificateStatus(serial string) (status core
if err != nil {
return
}
status = *certificateStats.(*core.CertificateStatus)
return
}
@ -318,7 +320,7 @@ func (ssa *SQLStorageAuthority) UpdateOCSP(serial string, ocspResponse []byte) (
return
}
timeStamp := time.Now()
timeStamp := ssa.clk.Now()
// Record the response.
ocspResp := &core.OCSPResponse{Serial: serial, CreatedAt: timeStamp, Response: ocspResponse}
@ -358,7 +360,8 @@ func (ssa *SQLStorageAuthority) MarkCertificateRevoked(serial string, ocspRespon
return
}
ocspResp := &core.OCSPResponse{Serial: serial, CreatedAt: time.Now(), Response: ocspResponse}
ocspResp := &core.OCSPResponse{Serial: serial, CreatedAt: ssa.clk.Now(), Response: ocspResponse}
err = tx.Insert(ocspResp)
if err != nil {
tx.Rollback()
@ -375,18 +378,25 @@ func (ssa *SQLStorageAuthority) MarkCertificateRevoked(serial string, ocspRespon
tx.Rollback()
return
}
now := ssa.clk.Now()
status := statusObj.(*core.CertificateStatus)
status.Status = core.OCSPStatusRevoked
status.RevokedDate = time.Now()
status.RevokedDate = now
status.RevokedReason = reasonCode
status.OCSPLastUpdated = now
_, err = tx.Update(status)
n, err := tx.Update(status)
if err != nil {
tx.Rollback()
return
}
if n == 0 {
tx.Rollback()
err = errors.New("No certificate updated. Maybe the lock column was off?")
return
}
err = tx.Commit()
return
}
@ -561,7 +571,7 @@ func (ssa *SQLStorageAuthority) AddCertificate(certDER []byte, regID int64) (dig
Serial: serial,
Digest: digest,
DER: certDER,
Issued: time.Now(),
Issued: ssa.clk.Now(),
Expires: parsedCertificate.NotAfter,
}
certStatus := &core.CertificateStatus{

View File

@ -16,6 +16,7 @@ import (
"testing"
"time"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/jmhodges/clock"
jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose"
"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/mocks"
@ -29,18 +30,21 @@ var log = mocks.UseMockLog()
// initSA constructs a SQLStorageAuthority and a clean up function
// that should be defer'ed to the end of the test.
func initSA(t *testing.T) (*SQLStorageAuthority, func()) {
func initSA(t *testing.T) (*SQLStorageAuthority, clock.FakeClock, func()) {
dbMap, err := NewDbMap(dbConnStr)
if err != nil {
t.Fatalf("Failed to create dbMap: %s", err)
}
sa, err := NewSQLStorageAuthority(dbMap)
fc := clock.NewFake()
fc.Add(1 * time.Hour)
sa, err := NewSQLStorageAuthority(dbMap, fc)
if err != nil {
t.Fatalf("Failed to create SA: %s", err)
}
cleanUp := test.ResetTestDatabase(t, dbMap.Db)
return sa, cleanUp
return sa, fc, cleanUp
}
var (
@ -52,7 +56,7 @@ var (
)
func TestAddRegistration(t *testing.T) {
sa, cleanUp := initSA(t)
sa, _, cleanUp := initSA(t)
defer cleanUp()
jwk := satest.GoodJWK()
@ -104,7 +108,7 @@ func TestAddRegistration(t *testing.T) {
}
func TestNoSuchRegistrationErrors(t *testing.T) {
sa, cleanUp := initSA(t)
sa, _, cleanUp := initSA(t)
defer cleanUp()
_, err := sa.GetRegistration(100)
@ -125,7 +129,7 @@ func TestNoSuchRegistrationErrors(t *testing.T) {
}
func TestAddAuthorization(t *testing.T) {
sa, cleanUp := initSA(t)
sa, _, cleanUp := initSA(t)
defer cleanUp()
reg := satest.CreateWorkingRegistration(t, sa)
@ -196,7 +200,7 @@ func CreateDomainAuthWithRegId(t *testing.T, domainName string, sa *SQLStorageAu
// Ensure we get only valid authorization with correct RegID
func TestGetLatestValidAuthorizationBasic(t *testing.T) {
sa, cleanUp := initSA(t)
sa, _, cleanUp := initSA(t)
defer cleanUp()
// attempt to get unauthorized domain
@ -228,7 +232,7 @@ func TestGetLatestValidAuthorizationBasic(t *testing.T) {
// Ensure we get the latest valid authorization for an ident
func TestGetLatestValidAuthorizationMultiple(t *testing.T) {
sa, cleanUp := initSA(t)
sa, _, cleanUp := initSA(t)
defer cleanUp()
domain := "example.org"
@ -283,7 +287,7 @@ func TestGetLatestValidAuthorizationMultiple(t *testing.T) {
}
func TestAddCertificate(t *testing.T) {
sa, cleanUp := initSA(t)
sa, _, cleanUp := initSA(t)
defer cleanUp()
reg := satest.CreateWorkingRegistration(t, sa)
@ -338,7 +342,7 @@ func TestAddCertificate(t *testing.T) {
// TestGetCertificateByShortSerial tests some failure conditions for GetCertificate.
// Success conditions are tested above in TestAddCertificate.
func TestGetCertificateByShortSerial(t *testing.T) {
sa, cleanUp := initSA(t)
sa, _, cleanUp := initSA(t)
defer cleanUp()
_, err := sa.GetCertificateByShortSerial("")
@ -357,7 +361,7 @@ func TestDeniedCSR(t *testing.T) {
csrBytes, _ := x509.CreateCertificateRequest(rand.Reader, template, key)
csr, _ := x509.ParseCertificateRequest(csrBytes)
sa, cleanUp := initSA(t)
sa, _, cleanUp := initSA(t)
defer cleanUp()
exists, err := sa.AlreadyDeniedCSR(append(csr.DNSNames, csr.Subject.CommonName))
@ -366,7 +370,7 @@ func TestDeniedCSR(t *testing.T) {
}
func TestUpdateOCSP(t *testing.T) {
sa, cleanUp := initSA(t)
sa, fc, cleanUp := initSA(t)
defer cleanUp()
reg := satest.CreateWorkingRegistration(t, sa)
@ -378,15 +382,21 @@ func TestUpdateOCSP(t *testing.T) {
serial := "00000000000000000000000000021bd4"
const ocspResponse = "this is a fake OCSP response"
certificateStatusObj, err := sa.dbMap.Get(core.CertificateStatus{}, serial)
beforeUpdate := certificateStatusObj.(*core.CertificateStatus)
fc.Add(1 * time.Hour)
err = sa.UpdateOCSP(serial, []byte(ocspResponse))
test.AssertNotError(t, err, "UpdateOCSP failed")
certificateStatusObj, err := sa.dbMap.Get(core.CertificateStatus{}, serial)
certificateStatusObj, err = sa.dbMap.Get(core.CertificateStatus{}, serial)
certificateStatus := certificateStatusObj.(*core.CertificateStatus)
test.AssertNotError(t, err, "Failed to fetch certificate status")
test.Assert(t,
certificateStatus.OCSPLastUpdated.After(time.Now().Add(-time.Second)),
"OCSP last updated too old.")
certificateStatus.OCSPLastUpdated.After(beforeUpdate.OCSPLastUpdated),
fmt.Sprintf("UpdateOCSP did not take. before: %s; after: %s", beforeUpdate.OCSPLastUpdated, certificateStatus.OCSPLastUpdated))
var fetchedOcspResponse core.OCSPResponse
err = sa.dbMap.SelectOne(&fetchedOcspResponse,
@ -395,3 +405,55 @@ func TestUpdateOCSP(t *testing.T) {
test.AssertNotError(t, err, "Failed to fetch OCSP response")
test.AssertEquals(t, ocspResponse, string(fetchedOcspResponse.Response))
}
func TestMarkCertificateRevoked(t *testing.T) {
sa, fc, cleanUp := initSA(t)
defer cleanUp()
reg := satest.CreateWorkingRegistration(t, sa)
// Add a cert to the DB to test with.
certDER, err := ioutil.ReadFile("www.eff.org.der")
test.AssertNotError(t, err, "Couldn't read example cert DER")
_, err = sa.AddCertificate(certDER, reg.ID)
test.AssertNotError(t, err, "Couldn't add www.eff.org.der")
serial := "00000000000000000000000000021bd4"
const ocspResponse = "this is a fake OCSP response"
certificateStatusObj, err := sa.dbMap.Get(core.CertificateStatus{}, serial)
beforeStatus := certificateStatusObj.(*core.CertificateStatus)
test.AssertEquals(t, beforeStatus.Status, core.OCSPStatusGood)
fc.Add(1 * time.Hour)
code := core.RevocationCode(1)
err = sa.MarkCertificateRevoked(serial, []byte(ocspResponse), code)
test.AssertNotError(t, err, "MarkCertificateRevoked failed")
certificateStatusObj, err = sa.dbMap.Get(core.CertificateStatus{}, serial)
afterStatus := certificateStatusObj.(*core.CertificateStatus)
test.AssertNotError(t, err, "Failed to fetch certificate status")
if code != afterStatus.RevokedReason {
t.Errorf("RevokedReasons, expected %s, got %s", code, afterStatus.RevokedReason)
}
if !fc.Now().Equal(afterStatus.RevokedDate) {
t.Errorf("RevokedData, expected %s, got %s", fc.Now(), afterStatus.RevokedDate)
}
if !fc.Now().Equal(afterStatus.OCSPLastUpdated) {
t.Errorf("OCSPLastUpdated, expected %s, got %s", fc.Now(), afterStatus.OCSPLastUpdated)
}
if !afterStatus.OCSPLastUpdated.After(beforeStatus.OCSPLastUpdated) {
t.Errorf("OCSPLastUpdated did not update correctly. before: %s; after: %s",
beforeStatus.OCSPLastUpdated, afterStatus.OCSPLastUpdated)
}
var fetched core.OCSPResponse
err = sa.dbMap.SelectOne(&fetched,
`SELECT * from ocspResponses where serial = ? order by createdAt DESC limit 1;`,
serial)
test.AssertNotError(t, err, "Failed to fetch OCSP response")
if ocspResponse != string(fetched.Response) {
t.Errorf("OCSPResponse response, expected %#v, got %#v", ocspResponse, string(fetched.Response))
}
}