...

Source file src/go.mongodb.org/mongo-driver/x/mongo/driver/ocsp/ocsp.go

Documentation: go.mongodb.org/mongo-driver/x/mongo/driver/ocsp

     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  			"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  		// 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: %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  // 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: %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  // 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  }
   322  

View as plain text