github.com/xmplusdev/xray-core@v1.8.10/common/ocsp/ocsp.go (about)

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