github.com/eagleql/xray-core@v1.4.4/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/eagleql/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 }