aboutsummaryrefslogtreecommitdiff
path: root/crypto/tls/ocsp.go
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/tls/ocsp.go')
-rw-r--r--crypto/tls/ocsp.go94
1 files changed, 94 insertions, 0 deletions
diff --git a/crypto/tls/ocsp.go b/crypto/tls/ocsp.go
new file mode 100644
index 0000000..9ae9828
--- /dev/null
+++ b/crypto/tls/ocsp.go
@@ -0,0 +1,94 @@
1package tls
2
3import (
4 "bytes"
5 "crypto/tls"
6 "crypto/x509"
7 "fmt"
8 "io"
9 "net/http"
10
11 "golang.org/x/crypto/ocsp"
12)
13
14func GetOcspResponse(chain *tls.Certificate) ([]byte, *ocsp.Response, error) {
15 var certs []*x509.Certificate
16 for _, c := range chain.Certificate {
17 cert, err := x509.ParseCertificate(c)
18 if err != nil {
19 return nil, nil, err
20 }
21 certs = append(certs, cert)
22 }
23 if len(certs) == 0 {
24 return nil, nil, fmt.Errorf("no certificates found in bundle")
25 }
26
27 // We expect the certificate slice to be ordered downwards the chain.
28 // SRV CRT -> CA. We need to pull the leaf and issuer certs out of it,
29 // which should always be the first two certificates. If there's no
30 // OCSP server listed in the leaf cert, there's nothing to do. And if
31 // we have only one certificate so far, we need to get the issuer cert.
32 leaf := certs[0]
33 if len(leaf.OCSPServer) == 0 {
34 return nil, nil, fmt.Errorf("no OCSP server specified in certificate")
35 }
36
37 if len(certs) == 1 {
38 if len(leaf.IssuingCertificateURL) == 0 {
39 return nil, nil, fmt.Errorf("no URL to issuing certificate")
40 }
41
42 resp, err := http.Get(leaf.IssuingCertificateURL[0])
43 if err != nil {
44 return nil, nil, fmt.Errorf("getting issuer certificate: %w", err)
45 }
46 defer resp.Body.Close()
47
48 issuerBytes, err := io.ReadAll(io.LimitReader(resp.Body, 1024*1024))
49 if err != nil {
50 return nil, nil, fmt.Errorf("reading issuer certificate: %w", err)
51 }
52
53 issuer, err := x509.ParseCertificate(issuerBytes)
54 if err != nil {
55 return nil, nil, fmt.Errorf("parsing issuer certificate: %w", err)
56 }
57
58 certs = append(certs, issuer)
59 }
60
61 issuer := certs[1]
62
63 req, err := ocsp.CreateRequest(leaf, issuer, nil)
64 if err != nil {
65 return nil, nil, fmt.Errorf("creating OCSP request: %w", err)
66 }
67
68 httpRes, err := http.Post(leaf.OCSPServer[0], "application/ocsp-request", bytes.NewReader(req))
69 if err != nil {
70 return nil, nil, fmt.Errorf("making OCSP request: %w", err)
71 }
72 defer httpRes.Body.Close()
73
74 rawRes, err := io.ReadAll(io.LimitReader(httpRes.Body, 1024*1024))
75 if err != nil {
76 return nil, nil, fmt.Errorf("reading OCSP response: %w", err)
77 }
78
79 res, err := ocsp.ParseResponse(rawRes, issuer)
80 if err != nil {
81 return nil, nil, fmt.Errorf("parsing OCSP response: %w", err)
82 }
83
84 if res.Status != ocsp.Good {
85 return nil, nil, fmt.Errorf("invalid: OCSP response was not of Good status")
86 }
87
88 // This is invalid, the response expires after the certificate
89 if res.NextUpdate.After(leaf.NotAfter) {
90 return nil, nil, fmt.Errorf("invalid: OCSP response valid after certificate expiration")
91 }
92
93 return rawRes, res, nil
94}