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 }