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