Source file src/crypto/x509/root.go

     1  // Copyright 2012 The Go Authors. All rights reserved.
     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 x509
     6  
     7  import (
     8  	"internal/godebug"
     9  	"sync"
    10  	_ "unsafe" // for linkname
    11  )
    12  
    13  // systemRoots should be an internal detail,
    14  // but widely used packages access it using linkname.
    15  // Notable members of the hall of shame include:
    16  //   - github.com/breml/rootcerts
    17  //
    18  // Do not remove or change the type signature.
    19  // See go.dev/issue/67401.
    20  //
    21  //go:linkname systemRoots
    22  var (
    23  	once             sync.Once
    24  	systemRootsMu    sync.RWMutex
    25  	systemRoots      *CertPool
    26  	systemRootsErr   error
    27  	fallbacksSet     bool
    28  	useFallbackRoots bool
    29  )
    30  
    31  func systemRootsPool() *CertPool {
    32  	once.Do(initSystemRoots)
    33  	systemRootsMu.RLock()
    34  	defer systemRootsMu.RUnlock()
    35  	return systemRoots
    36  }
    37  
    38  func initSystemRoots() {
    39  	systemRootsMu.Lock()
    40  	defer systemRootsMu.Unlock()
    41  
    42  	fallbackRoots := systemRoots
    43  	systemRoots, systemRootsErr = loadSystemRoots()
    44  	if systemRootsErr != nil {
    45  		systemRoots = nil
    46  	}
    47  
    48  	if fallbackRoots == nil {
    49  		return // no fallbacks to try
    50  	}
    51  
    52  	systemCertsAvail := systemRoots != nil && (systemRoots.len() > 0 || systemRoots.systemPool)
    53  
    54  	if !useFallbackRoots && systemCertsAvail {
    55  		return
    56  	}
    57  
    58  	if useFallbackRoots && systemCertsAvail {
    59  		x509usefallbackroots.IncNonDefault() // overriding system certs with fallback certs.
    60  	}
    61  
    62  	systemRoots, systemRootsErr = fallbackRoots, nil
    63  }
    64  
    65  var x509usefallbackroots = godebug.New("x509usefallbackroots")
    66  
    67  // SetFallbackRoots sets the roots to use during certificate verification, if no
    68  // custom roots are specified and a platform verifier or a system certificate
    69  // pool is not available (for instance in a container which does not have a root
    70  // certificate bundle). SetFallbackRoots will panic if roots is nil.
    71  //
    72  // SetFallbackRoots may only be called once, if called multiple times it will
    73  // panic.
    74  //
    75  // The fallback behavior can be forced on all platforms, even when there is a
    76  // system certificate pool, by setting GODEBUG=x509usefallbackroots=1 (note that
    77  // on Windows and macOS this will disable usage of the platform verification
    78  // APIs and cause the pure Go verifier to be used). Setting
    79  // x509usefallbackroots=1 without calling SetFallbackRoots has no effect.
    80  func SetFallbackRoots(roots *CertPool) {
    81  	if roots == nil {
    82  		panic("roots must be non-nil")
    83  	}
    84  
    85  	systemRootsMu.Lock()
    86  	defer systemRootsMu.Unlock()
    87  
    88  	if fallbacksSet {
    89  		panic("SetFallbackRoots has already been called")
    90  	}
    91  	fallbacksSet = true
    92  
    93  	// Handle case when initSystemRoots was not yet executed.
    94  	// We handle that specially instead of calling loadSystemRoots, to avoid
    95  	// spending excessive amount of cpu here, since the SetFallbackRoots in most cases
    96  	// is going to be called at program startup.
    97  	if systemRoots == nil && systemRootsErr == nil {
    98  		systemRoots = roots
    99  		useFallbackRoots = x509usefallbackroots.Value() == "1"
   100  		return
   101  	}
   102  
   103  	once.Do(func() { panic("unreachable") }) // asserts that system roots were indeed loaded before.
   104  
   105  	forceFallbackRoots := x509usefallbackroots.Value() == "1"
   106  	systemCertsAvail := systemRoots != nil && (systemRoots.len() > 0 || systemRoots.systemPool)
   107  
   108  	if !forceFallbackRoots && systemCertsAvail {
   109  		return
   110  	}
   111  
   112  	if forceFallbackRoots && systemCertsAvail {
   113  		x509usefallbackroots.IncNonDefault() // overriding system certs with fallback certs.
   114  	}
   115  
   116  	systemRoots, systemRootsErr = roots, nil
   117  }
   118  

View as plain text