mirror of
https://github.com/crowdsecurity/crowdsec.git
synced 2025-05-11 12:25:53 +02:00
100 lines
2.7 KiB
Go
100 lines
2.7 KiB
Go
package v1
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto"
|
|
"crypto/x509"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
"golang.org/x/crypto/ocsp"
|
|
)
|
|
|
|
type OCSPChecker struct {
|
|
logger *log.Entry
|
|
}
|
|
|
|
func NewOCSPChecker(logger *log.Entry) *OCSPChecker {
|
|
return &OCSPChecker{
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
func (oc *OCSPChecker) query(server string, cert *x509.Certificate, issuer *x509.Certificate) (*ocsp.Response, error) {
|
|
req, err := ocsp.CreateRequest(cert, issuer, &ocsp.RequestOptions{Hash: crypto.SHA256})
|
|
if err != nil {
|
|
oc.logger.Errorf("TLSAuth: error creating OCSP request: %s", err)
|
|
return nil, err
|
|
}
|
|
|
|
httpRequest, err := http.NewRequest(http.MethodPost, server, bytes.NewBuffer(req))
|
|
if err != nil {
|
|
oc.logger.Error("TLSAuth: cannot create HTTP request for OCSP")
|
|
return nil, err
|
|
}
|
|
|
|
ocspURL, err := url.Parse(server)
|
|
if err != nil {
|
|
oc.logger.Error("TLSAuth: cannot parse OCSP URL")
|
|
return nil, err
|
|
}
|
|
|
|
httpRequest.Header.Add("Content-Type", "application/ocsp-request")
|
|
httpRequest.Header.Add("Accept", "application/ocsp-response")
|
|
httpRequest.Header.Add("Host", ocspURL.Host)
|
|
|
|
httpClient := &http.Client{}
|
|
|
|
// XXX: timeout, context?
|
|
httpResponse, err := httpClient.Do(httpRequest)
|
|
if err != nil {
|
|
oc.logger.Error("TLSAuth: cannot send HTTP request to OCSP")
|
|
return nil, err
|
|
}
|
|
defer httpResponse.Body.Close()
|
|
|
|
output, err := io.ReadAll(httpResponse.Body)
|
|
if err != nil {
|
|
oc.logger.Error("TLSAuth: cannot read HTTP response from OCSP")
|
|
return nil, err
|
|
}
|
|
|
|
ocspResponse, err := ocsp.ParseResponseForCert(output, cert, issuer)
|
|
|
|
return ocspResponse, err
|
|
}
|
|
|
|
// isRevokedBy checks if the client certificate is revoked by the issuer via any of the OCSP servers present in the certificate.
|
|
// It returns a boolean indicating if the certificate is revoked and a boolean indicating
|
|
// if the OCSP check was successful and could be cached.
|
|
func (oc *OCSPChecker) isRevokedBy(cert *x509.Certificate, issuer *x509.Certificate) (bool, bool) {
|
|
if cert.OCSPServer == nil || len(cert.OCSPServer) == 0 {
|
|
oc.logger.Infof("TLSAuth: no OCSP Server present in client certificate, skipping OCSP verification")
|
|
return false, true
|
|
}
|
|
|
|
for _, server := range cert.OCSPServer {
|
|
ocspResponse, err := oc.query(server, cert, issuer)
|
|
if err != nil {
|
|
oc.logger.Errorf("TLSAuth: error querying OCSP server %s: %s", server, err)
|
|
continue
|
|
}
|
|
|
|
switch ocspResponse.Status {
|
|
case ocsp.Good:
|
|
return false, true
|
|
case ocsp.Revoked:
|
|
oc.logger.Errorf("TLSAuth: client certificate is revoked by server %s", server)
|
|
return true, true
|
|
case ocsp.Unknown:
|
|
log.Debugf("unknown OCSP status for server %s", server)
|
|
continue
|
|
}
|
|
}
|
|
|
|
log.Infof("Could not get any valid OCSP response, assuming the cert is revoked")
|
|
|
|
return true, false
|
|
}
|