mirror of https://github.com/XTLS/Xray-core
Add OCSP Stapling for TLS & XTLS (#92)
parent
6f25191822
commit
3d7e86efba
@ -0,0 +1,9 @@
|
||||
package ocsp
|
||||
|
||||
import "github.com/xtls/xray-core/common/errors"
|
||||
|
||||
type errPathObjHolder struct{}
|
||||
|
||||
func newError(values ...interface{}) *errors.Error {
|
||||
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
package ocsp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||
"golang.org/x/crypto/ocsp"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
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 := ioutil.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 := ioutil.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
|
||||
}
|
Loading…
Reference in new issue