blob: aeb30ece3240919754f7ce88876c74d80181fdfe [file] [log] [blame]
divyadesai81bb7ba2020-03-11 11:45:23 +00001package 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}