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