github.com/EagleQL/Xray-core@v1.4.3/common/ocsp/ocsp.go (about)

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