Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions cli/ocspserve/ocspserve.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net/http"

"github.com/cloudflare/cfssl/cli"
"github.com/cloudflare/cfssl/helpers"
"github.com/cloudflare/cfssl/log"
"github.com/cloudflare/cfssl/ocsp"
)
Expand All @@ -26,6 +27,7 @@ var ocspServerFlags = []string{"address", "port", "responses"}
// ocspServerMain is the command line entry point to the OCSP responder.
// It sets up a new HTTP server that responds to OCSP requests.
func ocspServerMain(args []string, c cli.Config) error {
var src ocsp.Source
// serve doesn't support arguments.
if len(args) > 0 {
return errors.New("argument is provided but not defined; please refer to the usage by flag -h")
Expand All @@ -35,9 +37,33 @@ func ocspServerMain(args []string, c cli.Config) error {
return errors.New("no response file provided, please set the -responses flag")
}

src, err := ocsp.NewSourceFromFile(c.Responses)
typ, path, err := helpers.ParseConnString(c.Responses)
if err != nil {
return errors.New("unable to read response file")
return errors.New("unable to parse responses connection string")
}
switch typ {
case "file":
src, err = ocsp.NewSourceFromFile(path)
if err != nil {
return errors.New("unable to read response file")
}
case "sqlite":
src, err = ocsp.NewSourceFromConnString("sqlite", path)
if err != nil {
return errors.New("unable to read Sqlite connection string")
}
case "mysql":
src, err = ocsp.NewSourceFromConnString("mysql", path)
if err != nil {
return errors.New("unable to read MySQL connection string")
}
case "postgres":
src, err = ocsp.NewSourceFromConnString("postgres", path)
if err != nil {
return errors.New("unable to read PostgreSQL connection string")
}
default:
return errors.New("unrecognized connection string format")
}

log.Info("Registering OCSP responder handler")
Expand Down
30 changes: 26 additions & 4 deletions helpers/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,17 @@ import (
"io"
"io/ioutil"
"math/big"
"net/url"
"os"

"github.com/google/certificate-transparency/go"
"golang.org/x/crypto/ocsp"

"strings"
"time"

"github.com/cloudflare/cfssl/crypto/pkcs7"
cferr "github.com/cloudflare/cfssl/errors"
"github.com/cloudflare/cfssl/helpers/derhelpers"
"github.com/cloudflare/cfssl/log"
"github.com/google/certificate-transparency/go"
"golang.org/x/crypto/ocsp"
"golang.org/x/crypto/pkcs12"
)

Expand Down Expand Up @@ -646,3 +645,26 @@ func ReadBytes(valFile string) ([]byte, error) {
strings.Join(splitVal[:len(splitVal)-1], ", "))
}
}

// ParseConnString parses a string representing the source of OCSP responses
// which can either be a file or the path to a DB (Sqlite, MySQL or PostgreSQL).
// It returns the type of the connection string (e.g. "File" or "MySQL" etc.) as
// well as the path to the source.
func ParseConnString(conn string) (string, string, error) {
u, err := url.Parse(conn)
if err != nil {
return "", "", err
}
switch u.Scheme {
case "", "file":
return "file", u.Path, nil
case "sqlite3":
return "sqlite", u.Path, nil
case "mysql":
return "mysql", conn[8:], nil
case "postgresql":
return "postgres", "dbname=" + u.Path[1:] + " sslmode=disable", nil
default:
return "DB", u.Path, nil
}
}
23 changes: 23 additions & 0 deletions helpers/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -625,3 +625,26 @@ func TestSCTListFromOCSPResponse(t *testing.T) {
t.Fatal("SCTs don't match")
}
}

func TestParseConnString(t *testing.T) {
filePath := "/path/to/file.txt"
typ, path, err := ParseConnString(filePath)
if typ != "file" || path != "/path/to/file.txt" || err != nil {
t.Fatal("Incorrect parsing of file path")
}
sqliteStr := "sqlite3:///path/to/db/file.db"
typ, path, err = ParseConnString(sqliteStr)
if typ != "sqlite" || path != "/path/to/db/file.db" || err != nil {
t.Fatal("Incorrect parsing of sqlite connection string")
}
mysqlStr := "mysql://root@tcp(localhost:3306)/certdb_development?parseTime=true"
typ, path, err = ParseConnString(mysqlStr)
if typ != "mysql" || path != "root@tcp(localhost:3306)/certdb_development?parseTime=true" || err != nil {
t.Fatal("Incorrect parsing of MySQL connection string")
}
postgresStr := "postgresql://root@tcp(localhost:3306)/certdb_development?parseTime=true"
typ, path, err = ParseConnString(postgresStr)
if typ != "postgres" || path != "dbname=certdb_development sslmode=disable" || err != nil {
t.Fatal("Incorrect parsing of PostgreSQL connection string")
}
}
17 changes: 17 additions & 0 deletions ocsp/responder.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ import (
"time"

"github.com/cloudflare/cfssl/certdb"
"github.com/cloudflare/cfssl/certdb/sql"
"github.com/cloudflare/cfssl/log"
"github.com/jmhodges/clock"
"github.com/jmoiron/sqlx"
"golang.org/x/crypto/ocsp"
)

Expand Down Expand Up @@ -63,6 +65,21 @@ func NewDBSource(dbAccessor certdb.Accessor) Source {
}
}

// NewSourceFromConnString creates a new DBSource object with an associated
// dbAccessor. They type of the DB connection is specificied by the typ
// argument, and this function currently supports Sqlite, MySQL and PostgreSQL.
// The dbpath argument is a connection string aiding in connecting to the
// associated DB type.
func NewSourceFromConnString(typ, dbpath string) (Source, error) {
db, err := sqlx.Open(typ, dbpath)
if err != nil {
return nil, err
}
accessor := sql.NewAccessor(db)
src := NewDBSource(accessor)
return src, nil
}

// Response implements cfssl.ocsp.responder.Source, which returns the
// OCSP response in the Database for the given request with the expiration
// date furthest in the future. Response also returns a bool that is false
Expand Down
Loading