Allow ocsp-responder to filter requests by serial prefix (#3815)
This commit is contained in:
parent
77c2071392
commit
3a8f0bc0be
|
|
@ -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{
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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": {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue