default_cert.go raw

   1  // Copyright 2020 Google LLC.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  // Package cert contains certificate tools for Google API clients.
   6  // This package is intended to be used with crypto/tls.Config.GetClientCertificate.
   7  //
   8  // The certificates can be used to satisfy Google's Endpoint Validation.
   9  // See https://cloud.google.com/endpoint-verification/docs/overview
  10  //
  11  // This package is not intended for use by end developers. Use the
  12  // google.golang.org/api/option package to configure API clients.
  13  package cert
  14  
  15  import (
  16  	"crypto/tls"
  17  	"errors"
  18  	"sync"
  19  )
  20  
  21  // defaultCertData holds all the variables pertaining to
  22  // the default certficate source created by DefaultSource.
  23  //
  24  // A singleton model is used to allow the source to be reused
  25  // by the transport layer.
  26  type defaultCertData struct {
  27  	once   sync.Once
  28  	source Source
  29  	err    error
  30  }
  31  
  32  var (
  33  	defaultCert defaultCertData
  34  )
  35  
  36  // Source is a function that can be passed into crypto/tls.Config.GetClientCertificate.
  37  type Source func(*tls.CertificateRequestInfo) (*tls.Certificate, error)
  38  
  39  // errSourceUnavailable is a sentinel error to indicate certificate source is unavailable.
  40  var errSourceUnavailable = errors.New("certificate source is unavailable")
  41  
  42  // DefaultSource returns a certificate source using the preferred EnterpriseCertificateProxySource.
  43  // If EnterpriseCertificateProxySource is not available, fall back to the legacy SecureConnectSource.
  44  //
  45  // If neither source is available (due to missing configurations), a nil Source and a nil Error are
  46  // returned to indicate that a default certificate source is unavailable.
  47  func DefaultSource() (Source, error) {
  48  	defaultCert.once.Do(func() {
  49  		defaultCert.source, defaultCert.err = NewEnterpriseCertificateProxySource("")
  50  		if errors.Is(defaultCert.err, errSourceUnavailable) {
  51  			defaultCert.source, defaultCert.err = NewSecureConnectSource("")
  52  			if errors.Is(defaultCert.err, errSourceUnavailable) {
  53  				defaultCert.source, defaultCert.err = nil, nil
  54  			}
  55  		}
  56  	})
  57  	return defaultCert.source, defaultCert.err
  58  }
  59