1package rootcerts 2 3import ( 4 "crypto/tls" 5 "crypto/x509" 6 "fmt" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10) 11 12// Config determines where LoadCACerts will load certificates from. When both 13// CAFile and CAPath are blank, this library's functions will either load 14// system roots explicitly and return them, or set the CertPool to nil to allow 15// Go's standard library to load system certs. 16type Config struct { 17 // CAFile is a path to a PEM-encoded certificate file or bundle. Takes 18 // precedence over CAPath. 19 CAFile string 20 21 // CAPath is a path to a directory populated with PEM-encoded certificates. 22 CAPath string 23} 24 25// ConfigureTLS sets up the RootCAs on the provided tls.Config based on the 26// Config specified. 27func ConfigureTLS(t *tls.Config, c *Config) error { 28 if t == nil { 29 return nil 30 } 31 pool, err := LoadCACerts(c) 32 if err != nil { 33 return err 34 } 35 t.RootCAs = pool 36 return nil 37} 38 39// LoadCACerts loads a CertPool based on the Config specified. 40func LoadCACerts(c *Config) (*x509.CertPool, error) { 41 if c == nil { 42 c = &Config{} 43 } 44 if c.CAFile != "" { 45 return LoadCAFile(c.CAFile) 46 } 47 if c.CAPath != "" { 48 return LoadCAPath(c.CAPath) 49 } 50 51 return LoadSystemCAs() 52} 53 54// LoadCAFile loads a single PEM-encoded file from the path specified. 55func LoadCAFile(caFile string) (*x509.CertPool, error) { 56 pool := x509.NewCertPool() 57 58 pem, err := ioutil.ReadFile(caFile) 59 if err != nil { 60 return nil, fmt.Errorf("Error loading CA File: %s", err) 61 } 62 63 ok := pool.AppendCertsFromPEM(pem) 64 if !ok { 65 return nil, fmt.Errorf("Error loading CA File: Couldn't parse PEM in: %s", caFile) 66 } 67 68 return pool, nil 69} 70 71// LoadCAPath walks the provided path and loads all certificates encounted into 72// a pool. 73func LoadCAPath(caPath string) (*x509.CertPool, error) { 74 pool := x509.NewCertPool() 75 walkFn := func(path string, info os.FileInfo, err error) error { 76 if err != nil { 77 return err 78 } 79 80 if info.IsDir() { 81 return nil 82 } 83 84 pem, err := ioutil.ReadFile(path) 85 if err != nil { 86 return fmt.Errorf("Error loading file from CAPath: %s", err) 87 } 88 89 ok := pool.AppendCertsFromPEM(pem) 90 if !ok { 91 return fmt.Errorf("Error loading CA Path: Couldn't parse PEM in: %s", path) 92 } 93 94 return nil 95 } 96 97 err := filepath.Walk(caPath, walkFn) 98 if err != nil { 99 return nil, err 100 } 101 102 return pool, nil 103} 104