1
0

ocsp.go 3.1 KB

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