1// Copyright 2023 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package cert
16
17import (
18 "crypto/tls"
19 "errors"
20 "sync"
21)
22
23// defaultCertData holds all the variables pertaining to
24// the default certificate provider created by [DefaultProvider].
25//
26// A singleton model is used to allow the provider to be reused
27// by the transport layer. As mentioned in [DefaultProvider] (provider nil, nil)
28// may be returned to indicate a default provider could not be found, which
29// will skip extra tls config in the transport layer .
30type defaultCertData struct {
31 once sync.Once
32 provider Provider
33 err error
34}
35
36var (
37 defaultCert defaultCertData
38)
39
40// Provider is a function that can be passed into crypto/tls.Config.GetClientCertificate.
41type Provider func(*tls.CertificateRequestInfo) (*tls.Certificate, error)
42
43// errSourceUnavailable is a sentinel error to indicate certificate source is unavailable.
44var errSourceUnavailable = errors.New("certificate source is unavailable")
45
46// DefaultProvider returns a certificate source using the preferred EnterpriseCertificateProxySource.
47// If EnterpriseCertificateProxySource is not available, fall back to the legacy SecureConnectSource.
48//
49// If neither source is available (due to missing configurations), a nil Source and a nil Error are
50// returned to indicate that a default certificate source is unavailable.
51func DefaultProvider() (Provider, error) {
52 defaultCert.once.Do(func() {
53 defaultCert.provider, defaultCert.err = NewWorkloadX509CertProvider("")
54 if errors.Is(defaultCert.err, errSourceUnavailable) {
55 defaultCert.provider, defaultCert.err = NewEnterpriseCertificateProxyProvider("")
56 if errors.Is(defaultCert.err, errSourceUnavailable) {
57 defaultCert.provider, defaultCert.err = NewSecureConnectProvider("")
58 if errors.Is(defaultCert.err, errSourceUnavailable) {
59 defaultCert.provider, defaultCert.err = nil, nil
60 }
61 }
62 }
63 })
64 return defaultCert.provider, defaultCert.err
65}