1
2
3
4
5
6
7 package ocsp
8
9 import (
10 "bytes"
11 "context"
12 "crypto/tls"
13 "crypto/x509"
14 "crypto/x509/pkix"
15 "encoding/asn1"
16 "errors"
17 "fmt"
18 "io/ioutil"
19 "math/big"
20 "net/http"
21 "time"
22
23 "golang.org/x/crypto/ocsp"
24 "golang.org/x/sync/errgroup"
25 )
26
27 var (
28 tlsFeatureExtensionOID = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 24}
29 mustStapleFeatureValue = big.NewInt(5)
30 )
31
32
33 type Error struct {
34 wrapped error
35 }
36
37
38 func (e *Error) Error() string {
39 return fmt.Sprintf("OCSP verification failed: %v", e.wrapped)
40 }
41
42
43 func (e *Error) Unwrap() error {
44 return e.wrapped
45 }
46
47 func newOCSPError(wrapped error) error {
48 return &Error{wrapped: wrapped}
49 }
50
51
52
53 type ResponseDetails struct {
54 Status int
55 NextUpdate time.Time
56 }
57
58 func extractResponseDetails(res *ocsp.Response) *ResponseDetails {
59 return &ResponseDetails{
60 Status: res.Status,
61 NextUpdate: res.NextUpdate,
62 }
63 }
64
65
66 func Verify(ctx context.Context, connState tls.ConnectionState, opts *VerifyOptions) error {
67 if opts.Cache == nil {
68
69
70
71 return newOCSPError(errors.New("no OCSP cache provided"))
72 }
73 if len(connState.VerifiedChains) == 0 {
74 return newOCSPError(errors.New("no verified certificate chains reported after TLS handshake"))
75 }
76
77 certChain := connState.VerifiedChains[0]
78 if numCerts := len(certChain); numCerts == 0 {
79 return newOCSPError(errors.New("verified chain contained no certificates"))
80 }
81
82 ocspCfg, err := newConfig(certChain, opts)
83 if err != nil {
84 return newOCSPError(err)
85 }
86
87 res, err := getParsedResponse(ctx, ocspCfg, connState)
88 if err != nil {
89 return err
90 }
91 if res == nil {
92
93
94 return nil
95 }
96
97 if res.Status == ocsp.Revoked {
98 return newOCSPError(errors.New("certificate is revoked"))
99 }
100 return nil
101 }
102
103
104
105 func getParsedResponse(ctx context.Context, cfg config, connState tls.ConnectionState) (*ResponseDetails, error) {
106 stapledResponse, err := processStaple(cfg, connState.OCSPResponse)
107 if err != nil {
108 return nil, err
109 }
110
111 if stapledResponse != nil {
112
113
114 return cfg.cache.Update(cfg.ocspRequest, stapledResponse), nil
115 }
116 if cachedResponse := cfg.cache.Get(cfg.ocspRequest); cachedResponse != nil {
117 return cachedResponse, nil
118 }
119
120
121
122 if cfg.disableEndpointChecking {
123 return nil, nil
124 }
125 externalResponse := contactResponders(ctx, cfg)
126 if externalResponse == nil {
127
128 return nil, nil
129 }
130
131
132
133 return cfg.cache.Update(cfg.ocspRequest, externalResponse), nil
134 }
135
136
137
138
139
140
141
142
143 func processStaple(cfg config, staple []byte) (*ResponseDetails, error) {
144 mustStaple, err := isMustStapleCertificate(cfg.serverCert)
145 if err != nil {
146 return nil, err
147 }
148
149
150 if mustStaple && len(staple) == 0 {
151 return nil, errors.New("server provided a certificate with the Must-Staple extension but did not " +
152 "provide a stapled OCSP response")
153 }
154
155 if len(staple) == 0 {
156 return nil, nil
157 }
158
159 parsedResponse, err := ocsp.ParseResponseForCert(staple, cfg.serverCert, cfg.issuer)
160 if err != nil {
161
162
163
164 return nil, fmt.Errorf("error parsing stapled response: %w", err)
165 }
166 if err = verifyResponse(cfg, parsedResponse); err != nil {
167 return nil, fmt.Errorf("error validating stapled response: %w", err)
168 }
169
170 return extractResponseDetails(parsedResponse), nil
171 }
172
173
174 func isMustStapleCertificate(cert *x509.Certificate) (bool, error) {
175 var featureExtension pkix.Extension
176 var foundExtension bool
177 for _, ext := range cert.Extensions {
178 if ext.Id.Equal(tlsFeatureExtensionOID) {
179 featureExtension = ext
180 foundExtension = true
181 break
182 }
183 }
184 if !foundExtension {
185 return false, nil
186 }
187
188
189
190
191
192
193 var featureValues []*big.Int
194 if _, err := asn1.Unmarshal(featureExtension.Value, &featureValues); err != nil {
195 return false, fmt.Errorf("error unmarshalling TLS feature extension values: %w", err)
196 }
197
198 for _, value := range featureValues {
199 if value.Cmp(mustStapleFeatureValue) == 0 {
200 return true, nil
201 }
202 }
203 return false, nil
204 }
205
206
207
208
209
210 func contactResponders(ctx context.Context, cfg config) *ResponseDetails {
211 if len(cfg.serverCert.OCSPServer) == 0 {
212 return nil
213 }
214
215
216
217 ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
218 defer cancel()
219
220 group, ctx := errgroup.WithContext(ctx)
221 ocspResponses := make(chan *ocsp.Response, len(cfg.serverCert.OCSPServer))
222 defer close(ocspResponses)
223
224 for _, endpoint := range cfg.serverCert.OCSPServer {
225
226
227 endpoint := endpoint
228
229
230
231
232
233 group.Go(func() error {
234
235
236
237 request, err := http.NewRequest("POST", endpoint, bytes.NewReader(cfg.ocspRequestBytes))
238 if err != nil {
239 return nil
240 }
241 request = request.WithContext(ctx)
242
243 httpResponse, err := cfg.httpClient.Do(request)
244 if err != nil {
245 return nil
246 }
247 defer func() {
248 _ = httpResponse.Body.Close()
249 }()
250
251 if httpResponse.StatusCode != 200 {
252 return nil
253 }
254
255 httpBytes, err := ioutil.ReadAll(httpResponse.Body)
256 if err != nil {
257 return nil
258 }
259
260 ocspResponse, err := ocsp.ParseResponseForCert(httpBytes, cfg.serverCert, cfg.issuer)
261 if err != nil || verifyResponse(cfg, ocspResponse) != nil || ocspResponse.Status == ocsp.Unknown {
262
263
264 return nil
265 }
266
267
268
269 ocspResponses <- ocspResponse
270 return errors.New("done")
271 })
272 }
273
274 _ = group.Wait()
275 select {
276 case res := <-ocspResponses:
277 return extractResponseDetails(res)
278 default:
279
280
281 return nil
282 }
283 }
284
285
286 func verifyResponse(cfg config, res *ocsp.Response) error {
287 if err := verifyExtendedKeyUsage(cfg, res); err != nil {
288 return err
289 }
290
291 currTime := time.Now().UTC()
292 if res.ThisUpdate.After(currTime) {
293 return fmt.Errorf("reported thisUpdate time %s is after current time %s", res.ThisUpdate, currTime)
294 }
295 if !res.NextUpdate.IsZero() && res.NextUpdate.Before(currTime) {
296 return fmt.Errorf("reported nextUpdate time %s is before current time %s", res.NextUpdate, currTime)
297 }
298 return nil
299 }
300
301 func verifyExtendedKeyUsage(cfg config, res *ocsp.Response) error {
302 if res.Certificate == nil {
303 return nil
304 }
305
306 namesMatch := res.RawResponderName != nil && bytes.Equal(res.RawResponderName, cfg.issuer.RawSubject)
307 keyHashesMatch := res.ResponderKeyHash != nil && bytes.Equal(res.ResponderKeyHash, cfg.ocspRequest.IssuerKeyHash)
308 if namesMatch || keyHashesMatch {
309
310 return nil
311 }
312
313
314 for _, extKeyUsage := range res.Certificate.ExtKeyUsage {
315 if extKeyUsage == x509.ExtKeyUsageOCSPSigning {
316 return nil
317 }
318 }
319
320 return errors.New("delegate responder certificate is missing the OCSP signing extended key usage")
321 }
322
View as plain text