ocsp.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package ocsp
  2. import (
  3. "bytes"
  4. "crypto/x509"
  5. "encoding/pem"
  6. "io"
  7. "net/http"
  8. "os"
  9. "github.com/xtls/xray-core/common/platform/filesystem"
  10. "golang.org/x/crypto/ocsp"
  11. )
  12. func GetOCSPForFile(path string) ([]byte, error) {
  13. return filesystem.ReadFile(path)
  14. }
  15. func CheckOCSPFileIsNotExist(path string) bool {
  16. _, err := os.Stat(path)
  17. if err != nil {
  18. return os.IsNotExist(err)
  19. }
  20. return false
  21. }
  22. func GetOCSPStapling(cert [][]byte, path string) ([]byte, error) {
  23. ocspData, err := GetOCSPForFile(path)
  24. if err != nil {
  25. ocspData, err = GetOCSPForCert(cert)
  26. if err != nil {
  27. return nil, err
  28. }
  29. if !CheckOCSPFileIsNotExist(path) {
  30. err = os.Remove(path)
  31. if err != nil {
  32. return nil, err
  33. }
  34. }
  35. newFile, err := os.Create(path)
  36. if err != nil {
  37. return nil, err
  38. }
  39. newFile.Write(ocspData)
  40. defer newFile.Close()
  41. }
  42. return ocspData, nil
  43. }
  44. func GetOCSPForCert(cert [][]byte) ([]byte, error) {
  45. bundle := new(bytes.Buffer)
  46. for _, derBytes := range cert {
  47. err := pem.Encode(bundle, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
  48. if err != nil {
  49. return nil, err
  50. }
  51. }
  52. pemBundle := bundle.Bytes()
  53. certificates, err := parsePEMBundle(pemBundle)
  54. if err != nil {
  55. return nil, err
  56. }
  57. issuedCert := certificates[0]
  58. if len(issuedCert.OCSPServer) == 0 {
  59. return nil, newError("no OCSP server specified in cert")
  60. }
  61. if len(certificates) == 1 {
  62. if len(issuedCert.IssuingCertificateURL) == 0 {
  63. return nil, newError("no issuing certificate URL")
  64. }
  65. resp, errC := http.Get(issuedCert.IssuingCertificateURL[0])
  66. if errC != nil {
  67. return nil, newError("no issuing certificate URL")
  68. }
  69. defer resp.Body.Close()
  70. issuerBytes, errC := io.ReadAll(resp.Body)
  71. if errC != nil {
  72. return nil, newError(errC)
  73. }
  74. issuerCert, errC := x509.ParseCertificate(issuerBytes)
  75. if errC != nil {
  76. return nil, newError(errC)
  77. }
  78. certificates = append(certificates, issuerCert)
  79. }
  80. issuerCert := certificates[1]
  81. ocspReq, err := ocsp.CreateRequest(issuedCert, issuerCert, nil)
  82. if err != nil {
  83. return nil, err
  84. }
  85. reader := bytes.NewReader(ocspReq)
  86. req, err := http.Post(issuedCert.OCSPServer[0], "application/ocsp-request", reader)
  87. if err != nil {
  88. return nil, newError(err)
  89. }
  90. defer req.Body.Close()
  91. ocspResBytes, err := io.ReadAll(req.Body)
  92. if err != nil {
  93. return nil, newError(err)
  94. }
  95. return ocspResBytes, nil
  96. }
  97. // parsePEMBundle parses a certificate bundle from top to bottom and returns
  98. // a slice of x509 certificates. This function will error if no certificates are found.
  99. func parsePEMBundle(bundle []byte) ([]*x509.Certificate, error) {
  100. var certificates []*x509.Certificate
  101. var certDERBlock *pem.Block
  102. for {
  103. certDERBlock, bundle = pem.Decode(bundle)
  104. if certDERBlock == nil {
  105. break
  106. }
  107. if certDERBlock.Type == "CERTIFICATE" {
  108. cert, err := x509.ParseCertificate(certDERBlock.Bytes)
  109. if err != nil {
  110. return nil, err
  111. }
  112. certificates = append(certificates, cert)
  113. }
  114. }
  115. if len(certificates) == 0 {
  116. return nil, newError("no certificates were found while parsing the bundle")
  117. }
  118. return certificates, nil
  119. }