113 lines
3.1 KiB
Go
113 lines
3.1 KiB
Go
// Package ocsprefresh implements the ocsprefresh command.
|
|
package ocsprefresh
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/cloudflare/cfssl/certdb/dbconf"
|
|
"github.com/cloudflare/cfssl/certdb/sql"
|
|
"github.com/cloudflare/cfssl/cli"
|
|
"github.com/cloudflare/cfssl/helpers"
|
|
"github.com/cloudflare/cfssl/log"
|
|
"github.com/cloudflare/cfssl/ocsp"
|
|
)
|
|
|
|
// Usage text of 'cfssl ocsprefresh'
|
|
var ocsprefreshUsageText = `cfssl ocsprefresh -- refreshes the ocsp_responses table
|
|
with new OCSP responses for all known unexpired certificates
|
|
|
|
Usage of ocsprefresh:
|
|
cfssl ocsprefresh -db-config db-config -ca cert -responder cert -responder-key key [-interval 96h]
|
|
|
|
Flags:
|
|
`
|
|
|
|
// Flags of 'cfssl ocsprefresh'
|
|
var ocsprefreshFlags = []string{"ca", "responder", "responder-key", "db-config", "interval"}
|
|
|
|
// ocsprefreshMain is the main CLI of OCSP refresh functionality.
|
|
func ocsprefreshMain(args []string, c cli.Config) error {
|
|
if c.DBConfigFile == "" {
|
|
return errors.New("need DB config file (provide with -db-config)")
|
|
}
|
|
|
|
if c.ResponderFile == "" {
|
|
return errors.New("need responder certificate (provide with -responder)")
|
|
}
|
|
|
|
if c.ResponderKeyFile == "" {
|
|
return errors.New("need responder key (provide with -responder-key)")
|
|
}
|
|
|
|
if c.CAFile == "" {
|
|
return errors.New("need CA certificate (provide with -ca)")
|
|
}
|
|
|
|
s, err := SignerFromConfig(c)
|
|
if err != nil {
|
|
log.Critical("Unable to create OCSP signer: ", err)
|
|
return err
|
|
}
|
|
|
|
db, err := dbconf.DBFromConfig(c.DBConfigFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
dbAccessor := sql.NewAccessor(db)
|
|
certs, err := dbAccessor.GetUnexpiredCertificates()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Set an expiry timestamp for all certificates refreshed in this batch
|
|
ocspExpiry := time.Now().Add(c.Interval)
|
|
for _, certRecord := range certs {
|
|
cert, err := helpers.ParseCertificatePEM([]byte(certRecord.PEM))
|
|
if err != nil {
|
|
log.Critical("Unable to parse certificate: ", err)
|
|
return err
|
|
}
|
|
|
|
req := ocsp.SignRequest{
|
|
Certificate: cert,
|
|
Status: certRecord.Status,
|
|
}
|
|
|
|
if certRecord.Status == "revoked" {
|
|
req.Reason = int(certRecord.Reason)
|
|
req.RevokedAt = certRecord.RevokedAt
|
|
}
|
|
|
|
resp, err := s.Sign(req)
|
|
if err != nil {
|
|
log.Critical("Unable to sign OCSP response: ", err)
|
|
return err
|
|
}
|
|
|
|
err = dbAccessor.UpsertOCSP(cert.SerialNumber.String(), hex.EncodeToString(cert.AuthorityKeyId), string(resp), ocspExpiry)
|
|
if err != nil {
|
|
log.Critical("Unable to save OCSP response: ", err)
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// SignerFromConfig creates a signer from a cli.Config as a helper for cli and serve
|
|
func SignerFromConfig(c cli.Config) (ocsp.Signer, error) {
|
|
//if this is called from serve then we need to use the specific responder key file
|
|
//fallback to key for backwards-compatibility
|
|
k := c.ResponderKeyFile
|
|
if k == "" {
|
|
k = c.KeyFile
|
|
}
|
|
return ocsp.NewSignerFromFile(c.CAFile, c.ResponderFile, k, time.Duration(c.Interval))
|
|
}
|
|
|
|
// Command assembles the definition of Command 'ocsprefresh'
|
|
var Command = &cli.Command{UsageText: ocsprefreshUsageText, Flags: ocsprefreshFlags, Main: ocsprefreshMain}
|