root.mx raw

   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  )
  29  
  30  func systemRootsPool() *CertPool {
  31  	once.Do(initSystemRoots)
  32  	systemRootsMu.RLock()
  33  	defer systemRootsMu.RUnlock()
  34  	return systemRoots
  35  }
  36  
  37  func initSystemRoots() {
  38  	systemRootsMu.Lock()
  39  	defer systemRootsMu.Unlock()
  40  	systemRoots, systemRootsErr = loadSystemRoots()
  41  	if systemRootsErr != nil {
  42  		systemRoots = nil
  43  	}
  44  }
  45  
  46  var x509usefallbackroots = godebug.New("x509usefallbackroots")
  47  
  48  // SetFallbackRoots sets the roots to use during certificate verification, if no
  49  // custom roots are specified and a platform verifier or a system certificate
  50  // pool is not available (for instance in a container which does not have a root
  51  // certificate bundle). SetFallbackRoots will panic if roots is nil.
  52  //
  53  // SetFallbackRoots may only be called once, if called multiple times it will
  54  // panic.
  55  //
  56  // The fallback behavior can be forced on all platforms, even when there is a
  57  // system certificate pool, by setting GODEBUG=x509usefallbackroots=1 (note that
  58  // on Windows and macOS this will disable usage of the platform verification
  59  // APIs and cause the pure Go verifier to be used). Setting
  60  // x509usefallbackroots=1 without calling SetFallbackRoots has no effect.
  61  func SetFallbackRoots(roots *CertPool) {
  62  	if roots == nil {
  63  		panic("roots must be non-nil")
  64  	}
  65  
  66  	// trigger initSystemRoots if it hasn't already been called before we
  67  	// take the lock
  68  	_ = systemRootsPool()
  69  
  70  	systemRootsMu.Lock()
  71  	defer systemRootsMu.Unlock()
  72  
  73  	if fallbacksSet {
  74  		panic("SetFallbackRoots has already been called")
  75  	}
  76  	fallbacksSet = true
  77  
  78  	if systemRoots != nil && (systemRoots.len() > 0 || systemRoots.systemPool) {
  79  		if x509usefallbackroots.Value() != "1" {
  80  			return
  81  		}
  82  		x509usefallbackroots.IncNonDefault()
  83  	}
  84  	systemRoots, systemRootsErr = roots, nil
  85  }
  86