github.com/infraboard/keyauth@v0.8.1/common/tls/tls.go (about) 1 package tls 2 3 import ( 4 "crypto/tls" 5 "crypto/x509" 6 "fmt" 7 "io/ioutil" 8 ) 9 10 // Config configures the options for TLS connections. 11 type Config struct { 12 CAFile string // The CA cert to use for the targets. 13 CertFile string // The client cert file for the targets. 14 KeyFile string // The client key file for the targets. 15 ServerName string // Used to verify the hostname for the targets. 16 InsecureSkipVerify bool // Disable target certificate validation. 17 } 18 19 // NewTLSConfig creates a new tls.Config from the given 20 func (c *Config) NewTLSConfig() (*tls.Config, error) { 21 tlsConfig := &tls.Config{InsecureSkipVerify: c.InsecureSkipVerify} 22 23 // If a CA cert is provided then let's read it in so we can validate the 24 // scrape target's certificate properly. 25 if len(c.CAFile) > 0 { 26 b, err := readCAFile(c.CAFile) 27 if err != nil { 28 return nil, err 29 } 30 if !updateRootCA(tlsConfig, b) { 31 return nil, fmt.Errorf("unable to use specified CA cert %s", c.CAFile) 32 } 33 } 34 35 if len(c.ServerName) > 0 { 36 tlsConfig.ServerName = c.ServerName 37 } 38 // If a client cert & key is provided then configure TLS config accordingly. 39 if len(c.CertFile) > 0 && len(c.KeyFile) == 0 { 40 return nil, fmt.Errorf("client cert file %q specified without client key file", c.CertFile) 41 } else if len(c.KeyFile) > 0 && len(c.CertFile) == 0 { 42 return nil, fmt.Errorf("client key file %q specified without client cert file", c.KeyFile) 43 } else if len(c.CertFile) > 0 && len(c.KeyFile) > 0 { 44 // Verify that client cert and key are valid. 45 if _, err := c.getClientCertificate(nil); err != nil { 46 return nil, err 47 } 48 tlsConfig.GetClientCertificate = c.getClientCertificate 49 } 50 51 return tlsConfig, nil 52 } 53 54 // Connect todo 55 func (c *Config) Connect(host string) (*tls.Conn, error) { 56 conf, err := c.NewTLSConfig() 57 if err != nil { 58 return nil, err 59 } 60 return tls.Dial("tcp", host, conf) 61 } 62 63 // getClientCertificate reads the pair of client cert and key from disk and returns a tls.Certificate. 64 func (c *Config) getClientCertificate(*tls.CertificateRequestInfo) (*tls.Certificate, error) { 65 cert, err := tls.LoadX509KeyPair(c.CertFile, c.KeyFile) 66 if err != nil { 67 return nil, fmt.Errorf("unable to use specified client cert (%s) & key (%s): %s", c.CertFile, c.KeyFile, err) 68 } 69 return &cert, nil 70 } 71 72 // readCAFile reads the CA cert file from disk. 73 func readCAFile(f string) ([]byte, error) { 74 data, err := ioutil.ReadFile(f) 75 if err != nil { 76 return nil, fmt.Errorf("unable to load specified CA cert %s: %s", f, err) 77 } 78 return data, nil 79 } 80 81 // updateRootCA parses the given byte slice as a series of PEM encoded certificates and updates tls.Config.RootCAs. 82 func updateRootCA(cfg *tls.Config, b []byte) bool { 83 caCertPool := x509.NewCertPool() 84 if !caCertPool.AppendCertsFromPEM(b) { 85 return false 86 } 87 cfg.RootCAs = caCertPool 88 return true 89 }