Allow ocsp-responder to filter requests by serial prefix (#3815)

This commit is contained in:
Roland Bracewell Shoemaker 2018-08-10 08:16:22 -07:00 committed by Daniel McCarney
parent 77c2071392
commit 3a8f0bc0be
3 changed files with 45 additions and 11 deletions

View File

@ -43,9 +43,10 @@ serialNumber field, since we will always query on it.
*/ */
type DBSource struct { type DBSource struct {
dbMap dbSelector dbMap dbSelector
caKeyHash []byte caKeyHash []byte
log blog.Logger reqSerialPrefixes []string
log blog.Logger
} }
// Since the only thing we use from gorp is the SelectOne method on the // Since the only thing we use from gorp is the SelectOne method on the
@ -58,8 +59,8 @@ type dbSelector interface {
// NewSourceFromDatabase produces a DBSource representing the binding of a // NewSourceFromDatabase produces a DBSource representing the binding of a
// given DB schema to a CA key. // given DB schema to a CA key.
func NewSourceFromDatabase(dbMap dbSelector, caKeyHash []byte, log blog.Logger) (src *DBSource, err error) { func NewSourceFromDatabase(dbMap dbSelector, caKeyHash []byte, reqSerialPrefixes []string, log blog.Logger) (src *DBSource, err error) {
src = &DBSource{dbMap: dbMap, caKeyHash: caKeyHash, log: log} src = &DBSource{dbMap: dbMap, caKeyHash: caKeyHash, reqSerialPrefixes: reqSerialPrefixes, log: log}
return return
} }
@ -77,6 +78,16 @@ func (src *DBSource) Response(req *ocsp.Request) ([]byte, http.Header, error) {
} }
serialString := core.SerialToString(req.SerialNumber) serialString := core.SerialToString(req.SerialNumber)
if len(src.reqSerialPrefixes) > 0 {
match := false
for _, prefix := range src.reqSerialPrefixes {
match = strings.HasPrefix(serialString, prefix)
}
if !match {
return nil, nil, cfocsp.ErrNotFound
}
}
src.log.Debugf("Searching for OCSP issued by us for serial %s", serialString) src.log.Debugf("Searching for OCSP issued by us for serial %s", serialString)
var response dbResponse var response dbResponse
@ -105,7 +116,7 @@ func (src *DBSource) Response(req *ocsp.Request) ([]byte, http.Header, error) {
return response.OCSPResponse, nil, nil return response.OCSPResponse, nil, nil
} }
func makeDBSource(dbMap dbSelector, issuerCert string, log blog.Logger) (*DBSource, error) { func makeDBSource(dbMap dbSelector, issuerCert string, reqSerialPrefixes []string, log blog.Logger) (*DBSource, error) {
// Load the CA's key so we can store its SubjectKey in the DB // Load the CA's key so we can store its SubjectKey in the DB
caCertDER, err := cmd.LoadCert(issuerCert) caCertDER, err := cmd.LoadCert(issuerCert)
if err != nil { if err != nil {
@ -120,7 +131,7 @@ func makeDBSource(dbMap dbSelector, issuerCert string, log blog.Logger) (*DBSour
} }
// Construct source from DB // Construct source from DB
return NewSourceFromDatabase(dbMap, caCert.SubjectKeyId, log) return NewSourceFromDatabase(dbMap, caCert.SubjectKeyId, reqSerialPrefixes, log)
} }
type config struct { type config struct {
@ -142,6 +153,8 @@ type config struct {
ShutdownStopTimeout cmd.ConfigDuration ShutdownStopTimeout cmd.ConfigDuration
RequiredSerialPrefixes []string
Features map[string]bool Features map[string]bool
} }
@ -201,7 +214,7 @@ as generated by Boulder's single-ocsp command.
cmd.FailOnError(err, "Could not connect to database") cmd.FailOnError(err, "Could not connect to database")
sa.SetSQLDebug(dbMap, logger) sa.SetSQLDebug(dbMap, logger)
go sa.ReportDbConnCount(dbMap, scope) go sa.ReportDbConnCount(dbMap, scope)
source, err = makeDBSource(dbMap, c.Common.IssuerCert, logger) source, err = makeDBSource(dbMap, c.Common.IssuerCert, c.OCSPResponder.RequiredSerialPrefixes, logger)
cmd.FailOnError(err, "Couldn't load OCSP DB") cmd.FailOnError(err, "Couldn't load OCSP DB")
// Export the MaxDBConns // Export the MaxDBConns
dbConnStat := prometheus.NewGauge(prometheus.GaugeOpts{ dbConnStat := prometheus.NewGauge(prometheus.GaugeOpts{

View File

@ -14,6 +14,7 @@ import (
"golang.org/x/crypto/ocsp" "golang.org/x/crypto/ocsp"
cfocsp "github.com/cloudflare/cfssl/ocsp" cfocsp "github.com/cloudflare/cfssl/ocsp"
"github.com/letsencrypt/boulder/core"
blog "github.com/letsencrypt/boulder/log" blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/metrics" "github.com/letsencrypt/boulder/metrics"
"github.com/letsencrypt/boulder/test" "github.com/letsencrypt/boulder/test"
@ -71,7 +72,7 @@ func TestMux(t *testing.T) {
} }
func TestDBHandler(t *testing.T) { func TestDBHandler(t *testing.T) {
src, err := makeDBSource(mockSelector{}, "./testdata/test-ca.der.pem", blog.NewMock()) src, err := makeDBSource(mockSelector{}, "./testdata/test-ca.der.pem", nil, blog.NewMock())
if err != nil { if err != nil {
t.Fatalf("makeDBSource: %s", err) t.Fatalf("makeDBSource: %s", err)
} }
@ -127,7 +128,7 @@ func (bs brokenSelector) SelectOne(_ interface{}, _ string, _ ...interface{}) er
func TestErrorLog(t *testing.T) { func TestErrorLog(t *testing.T) {
mockLog := blog.NewMock() mockLog := blog.NewMock()
src, err := makeDBSource(brokenSelector{}, "./testdata/test-ca.der.pem", mockLog) src, err := makeDBSource(brokenSelector{}, "./testdata/test-ca.der.pem", nil, mockLog)
test.AssertNotError(t, err, "Failed to create broken dbMap") test.AssertNotError(t, err, "Failed to create broken dbMap")
ocspReq, err := ocsp.ParseRequest(req) ocspReq, err := ocsp.ParseRequest(req)
@ -150,3 +151,22 @@ func mustRead(path string) []byte {
} }
return b return b
} }
func TestRequiredSerialPrefix(t *testing.T) {
mockLog := blog.NewMock()
src, err := makeDBSource(mockSelector{}, "./testdata/test-ca.der.pem", []string{"nope"}, mockLog)
test.AssertNotError(t, err, "failed to create DBSource")
ocspReq, err := ocsp.ParseRequest(req)
test.AssertNotError(t, err, "Failed to parse OCSP request")
_, _, err = src.Response(ocspReq)
test.AssertEquals(t, err, cfocsp.ErrNotFound)
fmt.Println(core.SerialToString(ocspReq.SerialNumber))
src, err = makeDBSource(mockSelector{}, "./testdata/test-ca.der.pem", []string{"00"}, mockLog)
test.AssertNotError(t, err, "failed to create DBSource")
_, _, err = src.Response(ocspReq)
test.AssertNotError(t, err, "src.Response failed with acceptable prefix")
}

View File

@ -6,7 +6,8 @@
"listenAddress": "0.0.0.0:4002", "listenAddress": "0.0.0.0:4002",
"maxAge": "10s", "maxAge": "10s",
"shutdownStopTimeout": "10s", "shutdownStopTimeout": "10s",
"debugAddr": ":8005" "debugAddr": ":8005",
"requiredSerialPrefixes": ["ff"]
}, },
"syslog": { "syslog": {