123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- package ocsp
- import (
- "bytes"
- "crypto/x509"
- "encoding/pem"
- "io"
- "net/http"
- "os"
- "github.com/xtls/xray-core/common/platform/filesystem"
- "golang.org/x/crypto/ocsp"
- )
- func GetOCSPForFile(path string) ([]byte, error) {
- return filesystem.ReadFile(path)
- }
- func CheckOCSPFileIsNotExist(path string) bool {
- _, err := os.Stat(path)
- if err != nil {
- return os.IsNotExist(err)
- }
- return false
- }
- func GetOCSPStapling(cert [][]byte, path string) ([]byte, error) {
- ocspData, err := GetOCSPForFile(path)
- if err != nil {
- ocspData, err = GetOCSPForCert(cert)
- if !CheckOCSPFileIsNotExist(path) {
- err = os.Remove(path)
- if err != nil {
- return nil, err
- }
- }
- newFile, err := os.Create(path)
- if err != nil {
- return nil, err
- }
- newFile.Write(ocspData)
- defer newFile.Close()
- }
- return ocspData, nil
- }
- func GetOCSPForCert(cert [][]byte) ([]byte, error) {
- bundle := new(bytes.Buffer)
- for _, derBytes := range cert {
- err := pem.Encode(bundle, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
- if err != nil {
- return nil, err
- }
- }
- pemBundle := bundle.Bytes()
- certificates, err := parsePEMBundle(pemBundle)
- if err != nil {
- return nil, err
- }
- issuedCert := certificates[0]
- if len(issuedCert.OCSPServer) == 0 {
- return nil, newError("no OCSP server specified in cert")
- }
- if len(certificates) == 1 {
- if len(issuedCert.IssuingCertificateURL) == 0 {
- return nil, newError("no issuing certificate URL")
- }
- resp, errC := http.Get(issuedCert.IssuingCertificateURL[0])
- if errC != nil {
- return nil, newError("no issuing certificate URL")
- }
- defer resp.Body.Close()
- issuerBytes, errC := io.ReadAll(resp.Body)
- if errC != nil {
- return nil, newError(errC)
- }
- issuerCert, errC := x509.ParseCertificate(issuerBytes)
- if errC != nil {
- return nil, newError(errC)
- }
- certificates = append(certificates, issuerCert)
- }
- issuerCert := certificates[1]
- ocspReq, err := ocsp.CreateRequest(issuedCert, issuerCert, nil)
- if err != nil {
- return nil, err
- }
- reader := bytes.NewReader(ocspReq)
- req, err := http.Post(issuedCert.OCSPServer[0], "application/ocsp-request", reader)
- if err != nil {
- return nil, newError(err)
- }
- defer req.Body.Close()
- ocspResBytes, err := io.ReadAll(req.Body)
- if err != nil {
- return nil, newError(err)
- }
- return ocspResBytes, nil
- }
- // parsePEMBundle parses a certificate bundle from top to bottom and returns
- // a slice of x509 certificates. This function will error if no certificates are found.
- func parsePEMBundle(bundle []byte) ([]*x509.Certificate, error) {
- var certificates []*x509.Certificate
- var certDERBlock *pem.Block
- for {
- certDERBlock, bundle = pem.Decode(bundle)
- if certDERBlock == nil {
- break
- }
- if certDERBlock.Type == "CERTIFICATE" {
- cert, err := x509.ParseCertificate(certDERBlock.Bytes)
- if err != nil {
- return nil, err
- }
- certificates = append(certificates, cert)
- }
- }
- if len(certificates) == 0 {
- return nil, newError("no certificates were found while parsing the bundle")
- }
- return certificates, nil
- }
|