ocsprefresh.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. // Package ocsprefresh implements the ocsprefresh command.
  2. package ocsprefresh
  3. import (
  4. "encoding/hex"
  5. "errors"
  6. "time"
  7. "github.com/cloudflare/cfssl/certdb/dbconf"
  8. "github.com/cloudflare/cfssl/certdb/sql"
  9. "github.com/cloudflare/cfssl/cli"
  10. "github.com/cloudflare/cfssl/helpers"
  11. "github.com/cloudflare/cfssl/log"
  12. "github.com/cloudflare/cfssl/ocsp"
  13. )
  14. // Usage text of 'cfssl ocsprefresh'
  15. var ocsprefreshUsageText = `cfssl ocsprefresh -- refreshes the ocsp_responses table
  16. with new OCSP responses for all known unexpired certificates
  17. Usage of ocsprefresh:
  18. cfssl ocsprefresh -db-config db-config -ca cert -responder cert -responder-key key [-interval 96h]
  19. Flags:
  20. `
  21. // Flags of 'cfssl ocsprefresh'
  22. var ocsprefreshFlags = []string{"ca", "responder", "responder-key", "db-config", "interval"}
  23. // ocsprefreshMain is the main CLI of OCSP refresh functionality.
  24. func ocsprefreshMain(args []string, c cli.Config) error {
  25. if c.DBConfigFile == "" {
  26. return errors.New("need DB config file (provide with -db-config)")
  27. }
  28. if c.ResponderFile == "" {
  29. return errors.New("need responder certificate (provide with -responder)")
  30. }
  31. if c.ResponderKeyFile == "" {
  32. return errors.New("need responder key (provide with -responder-key)")
  33. }
  34. if c.CAFile == "" {
  35. return errors.New("need CA certificate (provide with -ca)")
  36. }
  37. s, err := SignerFromConfig(c)
  38. if err != nil {
  39. log.Critical("Unable to create OCSP signer: ", err)
  40. return err
  41. }
  42. db, err := dbconf.DBFromConfig(c.DBConfigFile)
  43. if err != nil {
  44. return err
  45. }
  46. dbAccessor := sql.NewAccessor(db)
  47. certs, err := dbAccessor.GetUnexpiredCertificates()
  48. if err != nil {
  49. return err
  50. }
  51. // Set an expiry timestamp for all certificates refreshed in this batch
  52. ocspExpiry := time.Now().Add(c.Interval)
  53. for _, certRecord := range certs {
  54. cert, err := helpers.ParseCertificatePEM([]byte(certRecord.PEM))
  55. if err != nil {
  56. log.Critical("Unable to parse certificate: ", err)
  57. return err
  58. }
  59. req := ocsp.SignRequest{
  60. Certificate: cert,
  61. Status: certRecord.Status,
  62. }
  63. if certRecord.Status == "revoked" {
  64. req.Reason = int(certRecord.Reason)
  65. req.RevokedAt = certRecord.RevokedAt
  66. }
  67. resp, err := s.Sign(req)
  68. if err != nil {
  69. log.Critical("Unable to sign OCSP response: ", err)
  70. return err
  71. }
  72. err = dbAccessor.UpsertOCSP(cert.SerialNumber.String(), hex.EncodeToString(cert.AuthorityKeyId), string(resp), ocspExpiry)
  73. if err != nil {
  74. log.Critical("Unable to save OCSP response: ", err)
  75. return err
  76. }
  77. }
  78. return nil
  79. }
  80. // SignerFromConfig creates a signer from a cli.Config as a helper for cli and serve
  81. func SignerFromConfig(c cli.Config) (ocsp.Signer, error) {
  82. //if this is called from serve then we need to use the specific responder key file
  83. //fallback to key for backwards-compatibility
  84. k := c.ResponderKeyFile
  85. if k == "" {
  86. k = c.KeyFile
  87. }
  88. return ocsp.NewSignerFromFile(c.CAFile, c.ResponderFile, k, time.Duration(c.Interval))
  89. }
  90. // Command assembles the definition of Command 'ocsprefresh'
  91. var Command = &cli.Command{UsageText: ocsprefreshUsageText, Flags: ocsprefreshFlags, Main: ocsprefreshMain}