ocspsign_test.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. package ocsp
  2. import (
  3. "bytes"
  4. "encoding/base64"
  5. "encoding/json"
  6. "io"
  7. "net/http"
  8. "net/http/httptest"
  9. "os"
  10. "testing"
  11. "time"
  12. "github.com/cloudflare/cfssl/api"
  13. "github.com/cloudflare/cfssl/helpers"
  14. "github.com/cloudflare/cfssl/ocsp"
  15. goocsp "golang.org/x/crypto/ocsp"
  16. )
  17. const (
  18. testCaFile = "../../ocsp/testdata/ca.pem"
  19. testRespCertFile = "../../ocsp/testdata/server.crt"
  20. testKeyFile = "../../ocsp/testdata/server.key"
  21. testCertFile = "../../ocsp/testdata/cert.pem"
  22. )
  23. func newTestHandler(t *testing.T) http.Handler {
  24. // arbitrary duration
  25. dur, _ := time.ParseDuration("1ms")
  26. s, err := ocsp.NewSignerFromFile(testCaFile, testRespCertFile, testKeyFile, dur)
  27. if err != nil {
  28. t.Fatalf("Signer creation failed %v", err)
  29. }
  30. return NewHandler(s)
  31. }
  32. func TestNewHandler(t *testing.T) {
  33. newTestHandler(t)
  34. }
  35. func newSignServer(t *testing.T) *httptest.Server {
  36. ts := httptest.NewServer(newTestHandler(t))
  37. return ts
  38. }
  39. func testSignFile(t *testing.T, certFile, status string, reason int, revokedAt string, hash string) (resp *http.Response, body []byte) {
  40. ts := newSignServer(t)
  41. defer ts.Close()
  42. obj := map[string]interface{}{}
  43. if certFile != "" {
  44. c, err := os.ReadFile(certFile)
  45. if err != nil {
  46. t.Fatal(err)
  47. }
  48. obj["certificate"] = string(c)
  49. }
  50. if status != "" {
  51. obj["status"] = status
  52. }
  53. obj["reason"] = reason
  54. if revokedAt != "" {
  55. obj["revoked_at"] = revokedAt
  56. }
  57. obj["issuer_hash"] = hash
  58. blob, err := json.Marshal(obj)
  59. if err != nil {
  60. t.Fatal(err)
  61. }
  62. resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob))
  63. if err != nil {
  64. t.Fatal(err)
  65. }
  66. body, err = io.ReadAll(resp.Body)
  67. if err != nil {
  68. t.Fatal(err)
  69. }
  70. return
  71. }
  72. type signTest struct {
  73. CertificateFile string
  74. Status string
  75. Reason int
  76. RevokedAt string
  77. ExpectedHTTPStatus int
  78. ExpectedSuccess bool
  79. ExpectedErrorCode int
  80. IssuerHash string
  81. }
  82. var signTests = []signTest{
  83. {
  84. CertificateFile: testCertFile,
  85. ExpectedHTTPStatus: http.StatusOK,
  86. ExpectedSuccess: true,
  87. ExpectedErrorCode: 0,
  88. },
  89. {
  90. CertificateFile: testCertFile,
  91. Status: "revoked",
  92. Reason: 1,
  93. ExpectedHTTPStatus: http.StatusOK,
  94. ExpectedSuccess: true,
  95. ExpectedErrorCode: 0,
  96. },
  97. {
  98. CertificateFile: testCertFile,
  99. Status: "revoked",
  100. RevokedAt: "now",
  101. ExpectedHTTPStatus: http.StatusOK,
  102. ExpectedSuccess: true,
  103. ExpectedErrorCode: 0,
  104. },
  105. {
  106. CertificateFile: testCertFile,
  107. Status: "revoked",
  108. RevokedAt: "2015-08-15",
  109. ExpectedHTTPStatus: http.StatusOK,
  110. ExpectedSuccess: true,
  111. ExpectedErrorCode: 0,
  112. },
  113. {
  114. CertificateFile: testCertFile,
  115. Status: "revoked",
  116. RevokedAt: "a",
  117. ExpectedHTTPStatus: http.StatusBadRequest,
  118. ExpectedSuccess: false,
  119. ExpectedErrorCode: http.StatusBadRequest,
  120. },
  121. {
  122. CertificateFile: "",
  123. Status: "",
  124. ExpectedHTTPStatus: http.StatusBadRequest,
  125. ExpectedSuccess: false,
  126. ExpectedErrorCode: http.StatusBadRequest,
  127. },
  128. {
  129. CertificateFile: testCertFile,
  130. Status: "_",
  131. ExpectedHTTPStatus: http.StatusBadRequest,
  132. ExpectedSuccess: false,
  133. ExpectedErrorCode: 8200,
  134. },
  135. {
  136. CertificateFile: testCertFile,
  137. IssuerHash: "SHA256",
  138. ExpectedHTTPStatus: http.StatusOK,
  139. ExpectedSuccess: true,
  140. ExpectedErrorCode: 0,
  141. },
  142. {
  143. CertificateFile: testCertFile,
  144. IssuerHash: "MD4",
  145. ExpectedHTTPStatus: http.StatusBadRequest,
  146. ExpectedSuccess: false,
  147. ExpectedErrorCode: http.StatusBadRequest,
  148. },
  149. }
  150. func TestSign(t *testing.T) {
  151. for i, test := range signTests {
  152. resp, body := testSignFile(t, test.CertificateFile, test.Status, test.Reason, test.RevokedAt, test.IssuerHash)
  153. if resp.StatusCode != test.ExpectedHTTPStatus {
  154. t.Logf("Test %d: expected: %d, have %d", i, test.ExpectedHTTPStatus, resp.StatusCode)
  155. t.Fatal(resp.Status, test.ExpectedHTTPStatus, string(body))
  156. }
  157. message := new(api.Response)
  158. err := json.Unmarshal(body, message)
  159. if err != nil {
  160. t.Logf("failed to read response body: %v", err)
  161. t.Fatal(resp.Status, test.ExpectedHTTPStatus, message)
  162. }
  163. if test.ExpectedSuccess != message.Success {
  164. t.Logf("Test %d: expected: %v, have %v", i, test.ExpectedSuccess, message.Success)
  165. t.Fatal(resp.Status, test.ExpectedHTTPStatus, message)
  166. }
  167. if !test.ExpectedSuccess {
  168. if test.ExpectedErrorCode != message.Errors[0].Code {
  169. t.Fatalf("Test %d: expected: %v, have %v", i, test.ExpectedErrorCode, message.Errors[0].Code)
  170. t.Fatal(resp.Status, test.ExpectedHTTPStatus, message)
  171. }
  172. continue
  173. }
  174. result, ok := message.Result.(map[string]interface{})
  175. if !ok {
  176. t.Logf("failed to read result")
  177. t.Fatal(resp.Status, test.ExpectedHTTPStatus, string(body))
  178. }
  179. b64Resp, ok := result["ocspResponse"].(string)
  180. if !ok {
  181. t.Logf("failed to find ocspResponse")
  182. t.Fatal(resp.Status, test.ExpectedHTTPStatus, string(body))
  183. }
  184. der, err := base64.StdEncoding.DecodeString(b64Resp)
  185. if err != nil {
  186. t.Logf("failed to decode base64")
  187. t.Fatal(resp.Status, test.ExpectedHTTPStatus, b64Resp)
  188. }
  189. ocspResp, err := goocsp.ParseResponse(der, nil)
  190. if err != nil {
  191. t.Logf("failed to parse ocsp response: %v", err)
  192. t.Fatal(resp.Status, test.ExpectedHTTPStatus, b64Resp)
  193. }
  194. // should default to good
  195. if test.Status == "" {
  196. test.Status = "good"
  197. }
  198. intStatus := ocsp.StatusCode[test.Status]
  199. if ocspResp.Status != intStatus {
  200. t.Fatalf("Test %d incorrect status: expected: %v, have %v", i, intStatus, ocspResp.Status)
  201. t.Fatal(ocspResp.Status, intStatus, ocspResp)
  202. }
  203. if test.Status == "revoked" {
  204. if ocspResp.RevocationReason != test.Reason {
  205. t.Fatalf("Test %d incorrect reason: expected: %v, have %v", i, test.Reason, ocspResp.RevocationReason)
  206. t.Fatal(ocspResp.RevocationReason, test.Reason, ocspResp)
  207. }
  208. var r time.Time
  209. if test.RevokedAt == "" || test.RevokedAt == "now" {
  210. r = time.Now().UTC().Truncate(helpers.OneDay)
  211. } else {
  212. r, _ = time.Parse("2006-01-02", test.RevokedAt)
  213. }
  214. if !ocspResp.RevokedAt.Truncate(helpers.OneDay).Equal(r) {
  215. t.Fatalf("Test %d incorrect revokedAt: expected: %v, have %v", i, r, ocspResp.RevokedAt)
  216. t.Fatal(ocspResp.RevokedAt, test.RevokedAt, ocspResp)
  217. }
  218. }
  219. }
  220. }