|
package main |
|
|
|
import ( |
|
"bytes" |
|
"context" |
|
"crypto" |
|
"crypto/x509" |
|
"fmt" |
|
"io" |
|
"io/ioutil" |
|
"log" |
|
"net/http" |
|
"net/url" |
|
"os" |
|
|
|
"golang.org/x/crypto/ocsp" |
|
) |
|
|
|
func main() { |
|
// read x509 certificate from DER encoded file |
|
cert, err := readCert(os.Args[1]) |
|
if err != nil { |
|
log.Fatal(err) |
|
} |
|
|
|
// Perform OCSP Check |
|
err = CheckOCSPStatus(context.Background(), cert) |
|
if err != nil { |
|
log.Fatal(err) |
|
} |
|
|
|
log.Println("OCSP check was successful") |
|
} |
|
|
|
// CheckOCSPStatus will make an OCSP request for the provided certificate. |
|
// If the status of the certificate is not good, then an error is returned. |
|
func CheckOCSPStatus(ctx context.Context, cert *x509.Certificate) error { |
|
var ( |
|
ocspURL = cert.OCSPServer[0] |
|
issuerCertURL = cert.IssuingCertificateURL[0] |
|
) |
|
|
|
// download the issuer certificate |
|
issuer, err := getCert(ctx, issuerCertURL) |
|
if err != nil { |
|
return fmt.Errorf("getting issuer certificate: %w", err) |
|
} |
|
|
|
// Build OCSP request |
|
buffer, err := ocsp.CreateRequest(cert, issuer, &ocsp.RequestOptions{ |
|
Hash: crypto.SHA1, |
|
}) |
|
if err != nil { |
|
return fmt.Errorf("creating ocsp request body: %w", err) |
|
} |
|
|
|
req, err := http.NewRequest(http.MethodPost, ocspURL, bytes.NewBuffer(buffer)) |
|
if err != nil { |
|
return fmt.Errorf("creating http request: %w", err) |
|
} |
|
|
|
ocspUrl, err := url.Parse(ocspURL) |
|
if err != nil { |
|
return fmt.Errorf("parsing ocsp url: %w", err) |
|
} |
|
|
|
req.Header.Add("Content-Type", "application/ocsp-request") |
|
req.Header.Add("Accept", "application/ocsp-response") |
|
req.Header.Add("host", ocspUrl.Host) |
|
req = req.WithContext(ctx) |
|
|
|
// Make OCSP request |
|
httpResponse, err := http.DefaultClient.Do(req) |
|
if err != nil { |
|
return fmt.Errorf("making ocsp request: %w", err) |
|
} |
|
|
|
defer httpResponse.Body.Close() |
|
|
|
output, err := ioutil.ReadAll(httpResponse.Body) |
|
if err != nil { |
|
return fmt.Errorf("reading response body: %w", err) |
|
} |
|
|
|
// Parse response |
|
ocspResponse, err := ocsp.ParseResponse(output, issuer) |
|
if err != nil { |
|
return fmt.Errorf("parsing ocsp response: %w", err) |
|
} |
|
|
|
// check status |
|
if ocspResponse.Status != ocsp.Good { |
|
return fmt.Errorf("invalid cert status: %v", ocspResponse.Status) |
|
} |
|
|
|
return nil |
|
} |
|
|
|
func getCert(ctx context.Context, url string) (*x509.Certificate, error) { |
|
req, _ := http.NewRequest(http.MethodGet, url, nil) |
|
req = req.WithContext(ctx) |
|
|
|
resp, err := http.DefaultClient.Do(req) |
|
if err != nil { |
|
return nil, fmt.Errorf("getting cert from %s: %w", url, err) |
|
} |
|
|
|
defer resp.Body.Close() |
|
|
|
body, err := io.ReadAll(resp.Body) |
|
if err != nil { |
|
return nil, fmt.Errorf("reading response body: %w", err) |
|
} |
|
|
|
cert, err := x509.ParseCertificate(body) |
|
if err != nil { |
|
return nil, fmt.Errorf("parsing certificate: %w", err) |
|
} |
|
|
|
return cert, nil |
|
} |
|
|
|
func readCert(path string) (*x509.Certificate, error) { |
|
file, err := os.Open(path) |
|
if err != nil { |
|
return nil, fmt.Errorf("opening %s: %w", path, err) |
|
} |
|
|
|
defer file.Close() |
|
|
|
b, err := io.ReadAll(file) |
|
if err != nil { |
|
return nil, fmt.Errorf("reading %s: %w", path, err) |
|
} |
|
|
|
cert, err := x509.ParseCertificate(b) |
|
if err != nil { |
|
return nil, fmt.Errorf("parsing certificate %s: %w", path, err) |
|
} |
|
|
|
return cert, nil |
|
} |