insert_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. package certadd
  2. import (
  3. "bytes"
  4. "crypto/rand"
  5. "crypto/rsa"
  6. "crypto/x509"
  7. "crypto/x509/pkix"
  8. "encoding/base64"
  9. "encoding/hex"
  10. "encoding/json"
  11. "encoding/pem"
  12. "io"
  13. "math/big"
  14. "net/http"
  15. "net/http/httptest"
  16. "testing"
  17. "time"
  18. "github.com/cloudflare/cfssl/certdb"
  19. "github.com/cloudflare/cfssl/certdb/sql"
  20. "github.com/cloudflare/cfssl/certdb/testdb"
  21. "github.com/cloudflare/cfssl/ocsp"
  22. stdocsp "golang.org/x/crypto/ocsp"
  23. )
  24. func prepDB() (certdb.Accessor, error) {
  25. db := testdb.SQLiteDB("../../certdb/testdb/certstore_development.db")
  26. dbAccessor := sql.NewAccessor(db)
  27. return dbAccessor, nil
  28. }
  29. func makeRequest(t *testing.T, dbAccessor certdb.Accessor, signer ocsp.Signer, req map[string]interface{}) (resp *http.Response, body []byte) {
  30. ts := httptest.NewServer(NewHandler(dbAccessor, signer))
  31. defer ts.Close()
  32. blob, err := json.Marshal(req)
  33. if err != nil {
  34. t.Fatal(err)
  35. }
  36. resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob))
  37. if err != nil {
  38. t.Fatal(err)
  39. }
  40. body, err = io.ReadAll(resp.Body)
  41. if err != nil {
  42. t.Fatal(err)
  43. }
  44. return
  45. }
  46. func makeCertificate() (serialNumber *big.Int, cert *x509.Certificate, pemBytes []byte, signer ocsp.Signer, err error) {
  47. privKey, err := rsa.GenerateKey(rand.Reader, 2048)
  48. if err != nil {
  49. return
  50. }
  51. serialNumberRange := new(big.Int).Lsh(big.NewInt(1), 128)
  52. serialNumber, err = rand.Int(rand.Reader, serialNumberRange)
  53. if err != nil {
  54. return
  55. }
  56. template := x509.Certificate{
  57. SerialNumber: serialNumber,
  58. Subject: pkix.Name{
  59. Organization: []string{"Cornell CS 5152"},
  60. },
  61. AuthorityKeyId: []byte{42, 42, 42, 42},
  62. NotAfter: time.Now(),
  63. }
  64. cert = &template
  65. issuerSerial, err := rand.Int(rand.Reader, serialNumberRange)
  66. if err != nil {
  67. return
  68. }
  69. responderSerial, err := rand.Int(rand.Reader, serialNumberRange)
  70. if err != nil {
  71. return
  72. }
  73. // Generate a CA certificate
  74. issuerTemplate := x509.Certificate{
  75. SerialNumber: issuerSerial,
  76. Subject: pkix.Name{
  77. Organization: []string{"Cornell CS 5152"},
  78. },
  79. AuthorityKeyId: []byte{42, 42, 42, 42},
  80. KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
  81. IsCA: true,
  82. BasicConstraintsValid: true,
  83. }
  84. issuerBytes, err := x509.CreateCertificate(rand.Reader, &issuerTemplate, &issuerTemplate, &privKey.PublicKey, privKey)
  85. if err != nil {
  86. return
  87. }
  88. issuer, err := x509.ParseCertificate(issuerBytes)
  89. if err != nil {
  90. return
  91. }
  92. responderTemplate := x509.Certificate{
  93. SerialNumber: responderSerial,
  94. Subject: pkix.Name{
  95. Organization: []string{"Cornell CS 5152 Responder"},
  96. },
  97. AuthorityKeyId: []byte{42, 42, 42, 43},
  98. }
  99. responderBytes, err := x509.CreateCertificate(rand.Reader, &responderTemplate, &responderTemplate, &privKey.PublicKey, privKey)
  100. if err != nil {
  101. return
  102. }
  103. responder, err := x509.ParseCertificate(responderBytes)
  104. if err != nil {
  105. return
  106. }
  107. signer, err = ocsp.NewSigner(issuer, responder, privKey, time.Hour)
  108. if err != nil {
  109. return
  110. }
  111. derBytes, err := x509.CreateCertificate(rand.Reader, &template, issuer, &privKey.PublicKey, privKey)
  112. if err != nil {
  113. return
  114. }
  115. pemBytes = pem.EncodeToMemory(&pem.Block{
  116. Type: "CERTIFICATE",
  117. Bytes: derBytes,
  118. })
  119. return
  120. }
  121. func TestInsertValidCertificate(t *testing.T) {
  122. dbAccessor, err := prepDB()
  123. if err != nil {
  124. t.Fatal(err)
  125. }
  126. serialNumber, cert, pemBytes, signer, err := makeCertificate()
  127. if err != nil {
  128. t.Fatal(err)
  129. }
  130. resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{
  131. "serial_number": serialNumber.Text(10),
  132. "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId),
  133. "status": "good",
  134. "pem": string(pemBytes),
  135. "expiry": cert.NotAfter.UTC().Format(time.RFC3339),
  136. })
  137. if resp.StatusCode != http.StatusOK {
  138. t.Fatal("Expected HTTP OK, got", resp.StatusCode, string(body))
  139. }
  140. var response map[string]interface{}
  141. if err = json.Unmarshal(body, &response); err != nil {
  142. t.Fatal("Could not parse response: ", err)
  143. }
  144. responseResult := response["result"].(map[string]interface{})
  145. encodedOcsp := responseResult["ocsp_response"].(string)
  146. rawOcsp, err := base64.StdEncoding.DecodeString(encodedOcsp)
  147. if err != nil {
  148. t.Fatal("Could not base64 decode response: ", err)
  149. }
  150. returnedOcsp, err := stdocsp.ParseResponse(rawOcsp, nil)
  151. if err != nil {
  152. t.Fatal("Could not parse returned OCSP response", err)
  153. }
  154. ocsps, err := dbAccessor.GetOCSP(serialNumber.Text(10), hex.EncodeToString(cert.AuthorityKeyId))
  155. if err != nil {
  156. t.Fatal(err)
  157. }
  158. if len(ocsps) != 1 {
  159. t.Fatal("Expected 1 OCSP record to be inserted, but found ", len(ocsps))
  160. }
  161. parsedOcsp, err := stdocsp.ParseResponse([]byte(ocsps[0].Body), nil)
  162. if err != nil {
  163. t.Fatal(err)
  164. }
  165. if parsedOcsp.SerialNumber.Cmp(returnedOcsp.SerialNumber) != 0 {
  166. t.Fatal("The returned and inserted OCSP response have different serial numbers: got ", returnedOcsp.SerialNumber, " but decoded ", parsedOcsp.SerialNumber)
  167. }
  168. if parsedOcsp.SerialNumber.Cmp(serialNumber) != 0 {
  169. t.Fatal("Got the wrong serial number: expected", serialNumber, "but got", parsedOcsp.SerialNumber)
  170. }
  171. if parsedOcsp.Status != stdocsp.Good {
  172. t.Fatal("Expected OCSP response status to be ", stdocsp.Good,
  173. " but found ", parsedOcsp.Status)
  174. }
  175. }
  176. func TestInsertMissingSerial(t *testing.T) {
  177. dbAccessor, err := prepDB()
  178. if err != nil {
  179. t.Fatal(err)
  180. }
  181. _, cert, pemBytes, signer, err := makeCertificate()
  182. if err != nil {
  183. t.Fatal(err)
  184. }
  185. resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{
  186. "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId),
  187. "status": "good",
  188. "pem": string(pemBytes),
  189. "expiry": cert.NotAfter.UTC().Format(time.RFC3339),
  190. })
  191. if resp.StatusCode != http.StatusBadRequest {
  192. t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body))
  193. }
  194. }
  195. func TestInsertMissingAKI(t *testing.T) {
  196. dbAccessor, err := prepDB()
  197. if err != nil {
  198. t.Fatal(err)
  199. }
  200. serialNumber, cert, pemBytes, signer, err := makeCertificate()
  201. if err != nil {
  202. t.Fatal(err)
  203. }
  204. resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{
  205. "serial_number": serialNumber.Text(10),
  206. "status": "good",
  207. "pem": string(pemBytes),
  208. "expiry": cert.NotAfter.UTC().Format(time.RFC3339),
  209. })
  210. if resp.StatusCode != http.StatusBadRequest {
  211. t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body))
  212. }
  213. }
  214. func TestInsertMissingExpiry(t *testing.T) {
  215. dbAccessor, err := prepDB()
  216. if err != nil {
  217. t.Fatal(err)
  218. }
  219. serialNumber, cert, pemBytes, signer, err := makeCertificate()
  220. if err != nil {
  221. t.Fatal(err)
  222. }
  223. resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{
  224. "serial_number": serialNumber.Text(10),
  225. "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId),
  226. "status": "good",
  227. "pem": string(pemBytes),
  228. })
  229. if resp.StatusCode != http.StatusBadRequest {
  230. t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body))
  231. }
  232. }
  233. func TestInsertMissingPEM(t *testing.T) {
  234. dbAccessor, err := prepDB()
  235. if err != nil {
  236. t.Fatal(err)
  237. }
  238. serialNumber, cert, _, signer, err := makeCertificate()
  239. if err != nil {
  240. t.Fatal(err)
  241. }
  242. resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{
  243. "serial_number": serialNumber.Text(10),
  244. "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId),
  245. "status": "good",
  246. "expiry": cert.NotAfter.UTC().Format(time.RFC3339),
  247. })
  248. if resp.StatusCode != http.StatusBadRequest {
  249. t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body))
  250. }
  251. }
  252. func TestInsertInvalidSerial(t *testing.T) {
  253. dbAccessor, err := prepDB()
  254. if err != nil {
  255. t.Fatal(err)
  256. }
  257. _, cert, pemBytes, signer, err := makeCertificate()
  258. if err != nil {
  259. t.Fatal(err)
  260. }
  261. resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{
  262. "serial_number": "this is not a serial number",
  263. "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId),
  264. "status": "good",
  265. "pem": string(pemBytes),
  266. "expiry": cert.NotAfter.UTC().Format(time.RFC3339),
  267. })
  268. if resp.StatusCode != http.StatusBadRequest {
  269. t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body))
  270. }
  271. }
  272. func TestInsertInvalidAKI(t *testing.T) {
  273. dbAccessor, err := prepDB()
  274. if err != nil {
  275. t.Fatal(err)
  276. }
  277. serialNumber, cert, pemBytes, signer, err := makeCertificate()
  278. if err != nil {
  279. t.Fatal(err)
  280. }
  281. resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{
  282. "serial_number": serialNumber.Text(10),
  283. "authority_key_identifier": "this is not an AKI",
  284. "status": "good",
  285. "pem": string(pemBytes),
  286. "expiry": cert.NotAfter.UTC().Format(time.RFC3339),
  287. })
  288. if resp.StatusCode != http.StatusBadRequest {
  289. t.Fatal("Expected HTTP Bad Request, got", resp.StatusCode, string(body))
  290. }
  291. }
  292. func TestInsertInvalidStatus(t *testing.T) {
  293. dbAccessor, err := prepDB()
  294. if err != nil {
  295. t.Fatal(err)
  296. }
  297. serialNumber, cert, pemBytes, signer, err := makeCertificate()
  298. if err != nil {
  299. t.Fatal(err)
  300. }
  301. resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{
  302. "serial_number": serialNumber.Text(10),
  303. "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId),
  304. "status": "invalid",
  305. "pem": string(pemBytes),
  306. "expiry": cert.NotAfter.UTC().Format(time.RFC3339),
  307. })
  308. if resp.StatusCode != http.StatusBadRequest {
  309. t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body))
  310. }
  311. }
  312. func TestInsertInvalidPEM(t *testing.T) {
  313. dbAccessor, err := prepDB()
  314. if err != nil {
  315. t.Fatal(err)
  316. }
  317. serialNumber, cert, _, signer, err := makeCertificate()
  318. if err != nil {
  319. t.Fatal(err)
  320. }
  321. resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{
  322. "serial_number": serialNumber.Text(10),
  323. "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId),
  324. "status": "good",
  325. "pem": "this is not a PEM certificate",
  326. "expiry": cert.NotAfter.UTC().Format(time.RFC3339),
  327. })
  328. if resp.StatusCode != http.StatusBadRequest {
  329. t.Fatal("Expected HTTP Bad Request, got", resp.StatusCode, string(body))
  330. }
  331. }
  332. func TestInsertInvalidExpiry(t *testing.T) {
  333. dbAccessor, err := prepDB()
  334. if err != nil {
  335. t.Fatal(err)
  336. }
  337. serialNumber, cert, pemBytes, signer, err := makeCertificate()
  338. if err != nil {
  339. t.Fatal(err)
  340. }
  341. resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{
  342. "serial_number": serialNumber.Text(10),
  343. "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId),
  344. "status": "good",
  345. "pem": string(pemBytes),
  346. "expiry": "this is not an expiry",
  347. })
  348. if resp.StatusCode != http.StatusBadRequest {
  349. t.Fatal("Expected HTTP Bad Request, got", resp.StatusCode, string(body))
  350. }
  351. }
  352. func TestInsertWrongSerial(t *testing.T) {
  353. dbAccessor, err := prepDB()
  354. if err != nil {
  355. t.Fatal(err)
  356. }
  357. _, cert, pemBytes, signer, err := makeCertificate()
  358. if err != nil {
  359. t.Fatal(err)
  360. }
  361. resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{
  362. "serial_number": big.NewInt(1).Text(10),
  363. "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId),
  364. "status": "good",
  365. "pem": string(pemBytes),
  366. "expiry": cert.NotAfter.UTC().Format(time.RFC3339),
  367. })
  368. if resp.StatusCode != http.StatusBadRequest {
  369. t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body))
  370. }
  371. }
  372. func TestInsertWrongAKI(t *testing.T) {
  373. dbAccessor, err := prepDB()
  374. if err != nil {
  375. t.Fatal(err)
  376. }
  377. serialNumber, cert, pemBytes, signer, err := makeCertificate()
  378. if err != nil {
  379. t.Fatal(err)
  380. }
  381. resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{
  382. "serial_number": serialNumber.Text(10),
  383. "authority_key_identifier": hex.EncodeToString([]byte{7, 7}),
  384. "status": "good",
  385. "pem": string(pemBytes),
  386. "expiry": cert.NotAfter.UTC().Format(time.RFC3339),
  387. })
  388. if resp.StatusCode != http.StatusBadRequest {
  389. t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body))
  390. }
  391. }
  392. func TestInsertWrongExpiry(t *testing.T) {
  393. dbAccessor, err := prepDB()
  394. if err != nil {
  395. t.Fatal(err)
  396. }
  397. serialNumber, _, pemBytes, signer, err := makeCertificate()
  398. if err != nil {
  399. t.Fatal(err)
  400. }
  401. resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{
  402. "serial_number": serialNumber.Text(10),
  403. "authority_key_identifier": hex.EncodeToString([]byte{7, 7}),
  404. "status": "good",
  405. "pem": string(pemBytes),
  406. "expiry": time.Now().UTC().Format(time.RFC3339),
  407. })
  408. if resp.StatusCode != http.StatusBadRequest {
  409. t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body))
  410. }
  411. }
  412. func TestInsertRevokedCertificate(t *testing.T) {
  413. dbAccessor, err := prepDB()
  414. if err != nil {
  415. t.Fatal(err)
  416. }
  417. serialNumber, cert, pemBytes, signer, err := makeCertificate()
  418. if err != nil {
  419. t.Fatal(err)
  420. }
  421. resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{
  422. "serial_number": serialNumber.Text(10),
  423. "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId),
  424. "status": "revoked",
  425. "pem": string(pemBytes),
  426. "revoked_at": time.Now(),
  427. "expiry": cert.NotAfter.UTC().Format(time.RFC3339),
  428. })
  429. if resp.StatusCode != http.StatusOK {
  430. t.Fatal("Expected HTTP OK", resp.StatusCode, string(body))
  431. }
  432. ocsps, err := dbAccessor.GetOCSP(serialNumber.Text(10), hex.EncodeToString(cert.AuthorityKeyId))
  433. if err != nil {
  434. t.Fatal(err)
  435. }
  436. if len(ocsps) != 1 {
  437. t.Fatal("Expected 1 OCSP record to be inserted, but found ", len(ocsps))
  438. }
  439. response, err := stdocsp.ParseResponse([]byte(ocsps[0].Body), nil)
  440. if err != nil {
  441. t.Fatal(err)
  442. }
  443. if response.Status != stdocsp.Revoked {
  444. t.Fatal("Expected OCSP response status to be ", stdocsp.Revoked,
  445. " but found ", response.Status)
  446. }
  447. }
  448. func TestInsertRevokedCertificateWithoutTime(t *testing.T) {
  449. dbAccessor, err := prepDB()
  450. if err != nil {
  451. t.Fatal(err)
  452. }
  453. serialNumber, cert, pemBytes, signer, err := makeCertificate()
  454. if err != nil {
  455. t.Fatal(err)
  456. }
  457. resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{
  458. "serial_number": serialNumber.Text(10),
  459. "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId),
  460. "status": "revoked",
  461. "pem": string(pemBytes),
  462. "expiry": cert.NotAfter.UTC().Format(time.RFC3339),
  463. // Omit RevokedAt
  464. })
  465. if resp.StatusCode != http.StatusBadRequest {
  466. t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body))
  467. }
  468. }