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 {
|
||||
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{
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@
|
|||
"listenAddress": "0.0.0.0:4002",
|
||||
"maxAge": "10s",
|
||||
"shutdownStopTimeout": "10s",
|
||||
"debugAddr": ":8005"
|
||||
"debugAddr": ":8005",
|
||||
"requiredSerialPrefixes": ["ff"]
|
||||
},
|
||||
|
||||
"syslog": {
|
||||
|
|
|
|||
Loading…
Reference in New Issue