revoke.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // Package revoke implements the HTTP handler for the revoke command
  2. package revoke
  3. import (
  4. "encoding/json"
  5. "io/ioutil"
  6. "net/http"
  7. "time"
  8. "github.com/cloudflare/cfssl/api"
  9. "github.com/cloudflare/cfssl/certdb"
  10. "github.com/cloudflare/cfssl/errors"
  11. "github.com/cloudflare/cfssl/helpers"
  12. "github.com/cloudflare/cfssl/ocsp"
  13. stdocsp "golang.org/x/crypto/ocsp"
  14. )
  15. // A Handler accepts requests with a serial number parameter
  16. // and revokes
  17. type Handler struct {
  18. dbAccessor certdb.Accessor
  19. Signer ocsp.Signer
  20. }
  21. // NewHandler returns a new http.Handler that handles a revoke request.
  22. func NewHandler(dbAccessor certdb.Accessor) http.Handler {
  23. return &api.HTTPHandler{
  24. Handler: &Handler{
  25. dbAccessor: dbAccessor,
  26. },
  27. Methods: []string{"POST"},
  28. }
  29. }
  30. // NewOCSPHandler returns a new http.Handler that handles a revoke
  31. // request and also generates an OCSP response
  32. func NewOCSPHandler(dbAccessor certdb.Accessor, signer ocsp.Signer) http.Handler {
  33. return &api.HTTPHandler{
  34. Handler: &Handler{
  35. dbAccessor: dbAccessor,
  36. Signer: signer,
  37. },
  38. Methods: []string{"POST"},
  39. }
  40. }
  41. // This type is meant to be unmarshalled from JSON
  42. type jsonRevokeRequest struct {
  43. Serial string `json:"serial"`
  44. AKI string `json:"authority_key_id"`
  45. Reason string `json:"reason"`
  46. }
  47. // Handle responds to revocation requests. It attempts to revoke
  48. // a certificate with a given serial number
  49. func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error {
  50. body, err := ioutil.ReadAll(r.Body)
  51. if err != nil {
  52. return err
  53. }
  54. r.Body.Close()
  55. // Default the status to good so it matches the cli
  56. var req jsonRevokeRequest
  57. err = json.Unmarshal(body, &req)
  58. if err != nil {
  59. return errors.NewBadRequestString("Unable to parse revocation request")
  60. }
  61. if len(req.Serial) == 0 {
  62. return errors.NewBadRequestString("serial number is required but not provided")
  63. }
  64. var reasonCode int
  65. reasonCode, err = ocsp.ReasonStringToCode(req.Reason)
  66. if err != nil {
  67. return errors.NewBadRequestString("Invalid reason code")
  68. }
  69. err = h.dbAccessor.RevokeCertificate(req.Serial, req.AKI, reasonCode)
  70. if err != nil {
  71. return err
  72. }
  73. // If we were given a signer, try and generate an OCSP
  74. // response indicating revocation
  75. if h.Signer != nil {
  76. // TODO: should these errors be errors?
  77. // Grab the certificate from the database
  78. cr, err := h.dbAccessor.GetCertificate(req.Serial, req.AKI)
  79. if err != nil {
  80. return err
  81. }
  82. if len(cr) != 1 {
  83. return errors.NewBadRequestString("No unique certificate found")
  84. }
  85. cert, err := helpers.ParseCertificatePEM([]byte(cr[0].PEM))
  86. if err != nil {
  87. return errors.NewBadRequestString("Unable to parse certificates from PEM data")
  88. }
  89. sr := ocsp.SignRequest{
  90. Certificate: cert,
  91. Status: "revoked",
  92. Reason: reasonCode,
  93. RevokedAt: time.Now().UTC(),
  94. }
  95. ocspResponse, err := h.Signer.Sign(sr)
  96. if err != nil {
  97. return err
  98. }
  99. // We parse the OCSP response in order to get the next
  100. // update time/expiry time
  101. ocspParsed, err := stdocsp.ParseResponse(ocspResponse, nil)
  102. if err != nil {
  103. return err
  104. }
  105. ocspRecord := certdb.OCSPRecord{
  106. Serial: req.Serial,
  107. AKI: req.AKI,
  108. Body: string(ocspResponse),
  109. Expiry: ocspParsed.NextUpdate,
  110. }
  111. if err = h.dbAccessor.InsertOCSP(ocspRecord); err != nil {
  112. return err
  113. }
  114. }
  115. result := map[string]string{}
  116. return api.SendResponse(w, result)
  117. }