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 ) 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