github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/go.mongodb.org/mongo-driver/x/mongo/driver/ocsp/ocsp.go (about) 1 // Copyright (C) MongoDB, Inc. 2017-present. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 // not use this file except in compliance with the License. You may obtain 5 // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 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 // Error represents an OCSP verification error 33 type Error struct { 34 wrapped error 35 } 36 37 // Error implements the error interface 38 func (e *Error) Error() string { 39 return fmt.Sprintf("OCSP verification failed: %v", e.wrapped) 40 } 41 42 // Unwrap returns the underlying error. 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 // ResponseDetails contains a subset of the details needed from an OCSP response after the original response has been 52 // validated. 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 // Verify performs OCSP verification for the provided ConnectionState instance. 66 func Verify(ctx context.Context, connState tls.ConnectionState, opts *VerifyOptions) error { 67 if opts.Cache == nil { 68 // There should always be an OCSP cache. Even if the user has specified the URI option to disable communication 69 // with OCSP responders, the driver will cache any stapled responses. Requiring that the cache is non-nil 70 // allows us to confirm that the cache is correctly being passed down from a higher level. 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 // If no response was parsed from the staple and responders, the status of the certificate is unknown, so don't 93 // error. 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 // getParsedResponse attempts to parse a response from the stapled OCSP data or by contacting OCSP responders if no 104 // staple is present. 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 // If there is a staple, attempt to cache it. The cache.Update call will resolve conflicts with an existing 113 // cache enry if necessary. 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 // If there is no stapled or cached response, fall back to querying the responders if that functionality has not 121 // been disabled. 122 if cfg.disableEndpointChecking { 123 return nil, nil 124 } 125 externalResponse := contactResponders(ctx, cfg) 126 if externalResponse == nil { 127 // None of the responders were available. 128 return nil, nil 129 } 130 131 // Similar to the stapled response case above, unconditionally call Update and it will either cache the response 132 // or resolve conflicts if a different connection has cached a response since the previous call to Get. 133 return cfg.cache.Update(cfg.ocspRequest, externalResponse), nil 134 } 135 136 // processStaple returns the OCSP response from the provided staple. An error will be returned if any of the following 137 // are true: 138 // 139 // 1. cfg.serverCert has the Must-Staple extension but the staple is empty. 140 // 2. The staple is malformed. 141 // 3. The staple does not cover cfg.serverCert. 142 // 4. The OCSP response has an error status. 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 // If the server has a Must-Staple certificate and the server does not present a stapled OCSP response, error. 150 if mustStaple && len(staple) == 0 { 151 return nil, errors.New("server provided a certificate with the Must-Staple extension but did not " + 152 "provde 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 // If the stapled response could not be parsed correctly, error. This can happen if the response is malformed, 162 // the response does not cover the certificate presented by the server, or if the response contains an error 163 // status. 164 return nil, fmt.Errorf("error parsing stapled response: %v", err) 165 } 166 if err = verifyResponse(cfg, parsedResponse); err != nil { 167 return nil, fmt.Errorf("error validating stapled response: %v", err) 168 } 169 170 return extractResponseDetails(parsedResponse), nil 171 } 172 173 // isMustStapleCertificate determines whether or not an X509 certificate is a must-staple certificate. 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 // The value for the TLS feature extension is a sequence of integers. Per the asn1.Unmarshal documentation, an 189 // integer can be unmarshalled into an int, int32, int64, or *big.Int and unmarshalling will error if the integer 190 // cannot be encoded into the target type. 191 // 192 // Use []*big.Int to ensure that all values in the sequence can be successfully unmarshalled. 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: %v", 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 // contactResponders will send a request to all OCSP responders reported by cfg.serverCert. The 207 // first response that conclusively identifies cfg.serverCert as good or revoked will be returned. 208 // If all responders are unavailable or no responder returns a conclusive status, it returns nil. 209 // contactResponders will wait for up to 5 seconds to get a certificate status response. 210 func contactResponders(ctx context.Context, cfg config) *ResponseDetails { 211 if len(cfg.serverCert.OCSPServer) == 0 { 212 return nil 213 } 214 215 // Limit all OCSP responder calls to a maximum of 5 seconds or when the passed-in context expires, 216 // whichever happens first. 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 // Re-assign endpoint so it gets re-scoped rather than using the iteration variable in the goroutine. See 226 // https://golang.org/doc/faq#closures_and_goroutines. 227 endpoint := endpoint 228 229 // Start a group of goroutines that each attempt to request the certificate status from one 230 // of the OCSP endpoints listed in the server certificate. We want to "soft fail" on all 231 // errors, so this function never returns actual errors. Only a "done" error is returned 232 // when a response is received so the errgroup cancels any other in-progress requests. 233 group.Go(func() error { 234 // Use bytes.NewReader instead of bytes.NewBuffer because a bytes.Buffer is an owning representation and the 235 // docs recommend not using the underlying []byte after creating the buffer, so a new copy of the request 236 // bytes would be needed for each request. 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 // If there was an error parsing/validating the response or the response was 263 // inconclusive, suppress the error because we want to ignore this responder. 264 return nil 265 } 266 267 // Send the conclusive response on the response channel and return a "done" error that 268 // will cause the errgroup to cancel all other in-progress requests. 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 // If there is no OCSP response on the response channel, all OCSP calls either failed or 280 // were inconclusive. Return nil. 281 return nil 282 } 283 } 284 285 // verifyResponse checks that the provided OCSP response is valid. 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 // The responder certificate is the same as the issuer certificate. 310 return nil 311 } 312 313 // There is a delegate. 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 }