certificate.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. package acme
  2. import (
  3. "crypto"
  4. "crypto/x509"
  5. "encoding/base64"
  6. "encoding/pem"
  7. "fmt"
  8. "net/http"
  9. )
  10. func (c Client) decodeCertificateChain(body []byte, resp *http.Response, account Account) ([]*x509.Certificate, error) {
  11. var certs []*x509.Certificate
  12. for {
  13. var p *pem.Block
  14. p, body = pem.Decode(body)
  15. if p == nil {
  16. break
  17. }
  18. cert, err := x509.ParseCertificate(p.Bytes)
  19. if err != nil {
  20. return certs, fmt.Errorf("acme: error parsing certificate: %v", err)
  21. }
  22. certs = append(certs, cert)
  23. }
  24. up := fetchLink(resp, "up")
  25. if up != "" {
  26. upCerts, err := c.FetchCertificates(account, up)
  27. if err != nil {
  28. return certs, fmt.Errorf("acme: error fetching up cert: %v", err)
  29. }
  30. if len(upCerts) != 0 {
  31. certs = append(certs, upCerts...)
  32. }
  33. }
  34. return certs, nil
  35. }
  36. // FetchCertificates downloads a certificate chain from a url given in an order certificate.
  37. func (c Client) FetchCertificates(account Account, certificateURL string) ([]*x509.Certificate, error) {
  38. resp, body, err := c.postRaw(0, certificateURL, account.URL, account.PrivateKey, "", []int{http.StatusOK})
  39. if err != nil {
  40. return nil, err
  41. }
  42. return c.decodeCertificateChain(body, resp, account)
  43. }
  44. // FetchAllCertificates downloads a certificate chain from a url given in an order certificate, as well as any alternate certificates if provided.
  45. // Returns a mapping of certificate urls to the certificate chain.
  46. func (c Client) FetchAllCertificates(account Account, certificateURL string) (map[string][]*x509.Certificate, error) {
  47. resp, body, err := c.postRaw(0, certificateURL, account.URL, account.PrivateKey, "", []int{http.StatusOK})
  48. if err != nil {
  49. return nil, err
  50. }
  51. certChain, err := c.decodeCertificateChain(body, resp, account)
  52. if err != nil {
  53. return nil, err
  54. }
  55. certs := map[string][]*x509.Certificate{
  56. certificateURL: certChain,
  57. }
  58. alternates := fetchLinks(resp, "alternate")
  59. for _, altURL := range alternates {
  60. altResp, altBody, err := c.postRaw(0, altURL, account.URL, account.PrivateKey, "", []int{http.StatusOK})
  61. if err != nil {
  62. return certs, fmt.Errorf("acme: error fetching alt cert chain at %q - %v", altURL, err)
  63. }
  64. altCertChain, err := c.decodeCertificateChain(altBody, altResp, account)
  65. if err != nil {
  66. return certs, fmt.Errorf("acme: error decoding alt cert chain at %q - %v", altURL, err)
  67. }
  68. certs[altURL] = altCertChain
  69. }
  70. return certs, nil
  71. }
  72. // RevokeCertificate revokes a given certificate given the certificate key or account key, and a reason.
  73. func (c Client) RevokeCertificate(account Account, cert *x509.Certificate, key crypto.Signer, reason int) error {
  74. revokeReq := struct {
  75. Certificate string `json:"certificate"`
  76. Reason int `json:"reason"`
  77. }{
  78. Certificate: base64.RawURLEncoding.EncodeToString(cert.Raw),
  79. Reason: reason,
  80. }
  81. kid := ""
  82. if key == account.PrivateKey {
  83. kid = account.URL
  84. }
  85. if _, err := c.post(c.dir.RevokeCert, kid, key, revokeReq, nil, http.StatusOK); err != nil {
  86. return err
  87. }
  88. return nil
  89. }