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 {
dbMap dbSelector
caKeyHash []byte
log blog.Logger
dbMap dbSelector
caKeyHash []byte
reqSerialPrefixes []string
log blog.Logger
}
// 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
// given DB schema to a CA key.
func NewSourceFromDatabase(dbMap dbSelector, caKeyHash []byte, log blog.Logger) (src *DBSource, err error) {
src = &DBSource{dbMap: dbMap, caKeyHash: caKeyHash, log: log}
func NewSourceFromDatabase(dbMap dbSelector, caKeyHash []byte, reqSerialPrefixes []string, log blog.Logger) (src *DBSource, err error) {
src = &DBSource{dbMap: dbMap, caKeyHash: caKeyHash, reqSerialPrefixes: reqSerialPrefixes, log: log}
return
}
@ -77,6 +78,16 @@ func (src *DBSource) Response(req *ocsp.Request) ([]byte, http.Header, error) {
}
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)
var response dbResponse
@ -105,7 +116,7 @@ func (src *DBSource) Response(req *ocsp.Request) ([]byte, http.Header, error) {
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
caCertDER, err := cmd.LoadCert(issuerCert)
if err != nil {
@ -120,7 +131,7 @@ func makeDBSource(dbMap dbSelector, issuerCert string, log blog.Logger) (*DBSour
}
// Construct source from DB
return NewSourceFromDatabase(dbMap, caCert.SubjectKeyId, log)
return NewSourceFromDatabase(dbMap, caCert.SubjectKeyId, reqSerialPrefixes, log)
}
type config struct {
@ -142,6 +153,8 @@ type config struct {
ShutdownStopTimeout cmd.ConfigDuration
RequiredSerialPrefixes []string
Features map[string]bool
}
@ -201,7 +214,7 @@ as generated by Boulder's single-ocsp command.
cmd.FailOnError(err, "Could not connect to database")
sa.SetSQLDebug(dbMap, logger)
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")
// Export the MaxDBConns
dbConnStat := prometheus.NewGauge(prometheus.GaugeOpts{

View File

@ -14,6 +14,7 @@ import (
"golang.org/x/crypto/ocsp"
cfocsp "github.com/cloudflare/cfssl/ocsp"
"github.com/letsencrypt/boulder/core"
blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/metrics"
"github.com/letsencrypt/boulder/test"
@ -71,7 +72,7 @@ func TestMux(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 {
t.Fatalf("makeDBSource: %s", err)
}
@ -127,7 +128,7 @@ func (bs brokenSelector) SelectOne(_ interface{}, _ string, _ ...interface{}) er
func TestErrorLog(t *testing.T) {
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")
ocspReq, err := ocsp.ParseRequest(req)
@ -150,3 +151,22 @@ func mustRead(path string) []byte {
}
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",
"maxAge": "10s",
"shutdownStopTimeout": "10s",
"debugAddr": ":8005"
"debugAddr": ":8005",
"requiredSerialPrefixes": ["ff"]
},
"syslog": {