ocspsign_test.go 6.2 KB

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