cloudflare/cloudflared

Public

mirrored from https://github.com/cloudflare/cloudflaredAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
2018.11.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

tlsconfig/tlsconfig.go

155lines · modecode

1// Package tlsconfig provides convenience functions for configuring TLS connections from the
2// command line.
3package tlsconfig
4
5import (
6 "crypto/tls"
7 "crypto/x509"
8 "io/ioutil"
9 "net"
10
11 "github.com/cloudflare/cloudflared/log"
12 "github.com/pkg/errors"
13 "gopkg.in/urfave/cli.v2"
14 "runtime"
15)
16
17var logger = log.CreateLogger()
18
19// CLIFlags names the flags used to configure TLS for a command or subsystem.
20// The nil value for a field means the flag is ignored.
21type CLIFlags struct {
22 Cert string
23 Key string
24 ClientCert string
25 RootCA string
26}
27
28// GetConfig returns a TLS configuration according to the flags defined in f and
29// set by the user.
30func (f CLIFlags) GetConfig(c *cli.Context) *tls.Config {
31 config := &tls.Config{}
32
33 if c.IsSet(f.Cert) && c.IsSet(f.Key) {
34 cert, err := tls.LoadX509KeyPair(c.String(f.Cert), c.String(f.Key))
35 if err != nil {
36 logger.WithError(err).Fatal("Error parsing X509 key pair")
37 }
38 config.Certificates = []tls.Certificate{cert}
39 config.BuildNameToCertificate()
40 }
41 return f.finishGettingConfig(c, config)
42}
43
44func (f CLIFlags) GetConfigReloadableCert(c *cli.Context, cr *CertReloader) *tls.Config {
45 config := &tls.Config{
46 GetCertificate: cr.Cert,
47 }
48 config.BuildNameToCertificate()
49 return f.finishGettingConfig(c, config)
50}
51
52func (f CLIFlags) finishGettingConfig(c *cli.Context, config *tls.Config) *tls.Config {
53 if c.IsSet(f.ClientCert) {
54 // set of root certificate authorities that servers use if required to verify a client certificate
55 // by the policy in ClientAuth
56 config.ClientCAs = LoadCert(c.String(f.ClientCert))
57 // server's policy for TLS Client Authentication. Default is no client cert
58 config.ClientAuth = tls.RequireAndVerifyClientCert
59 }
60 // set of root certificate authorities that clients use when verifying server certificates
61 if c.IsSet(f.RootCA) {
62 config.RootCAs = LoadCert(c.String(f.RootCA))
63 }
64 // we optimize CurveP256
65 config.CurvePreferences = []tls.CurveID{tls.CurveP256}
66 return config
67}
68
69// LoadCert creates a CertPool containing all certificates in a PEM-format file.
70func LoadCert(certPath string) *x509.CertPool {
71 caCert, err := ioutil.ReadFile(certPath)
72 if err != nil {
73 logger.WithError(err).Fatalf("Error reading certificate %s", certPath)
74 }
75 ca := x509.NewCertPool()
76 if !ca.AppendCertsFromPEM(caCert) {
77 logger.WithError(err).Fatalf("Error parsing certificate %s", certPath)
78 }
79 return ca
80}
81
82func LoadGlobalCertPool() (*x509.CertPool, error) {
83 success := false
84
85 // First, obtain the system certificate pool
86 certPool, systemCertPoolErr := x509.SystemCertPool()
87 if systemCertPoolErr != nil {
88 if runtime.GOOS != "windows" {
89 logger.Warnf("error obtaining the system certificates: %s", systemCertPoolErr)
90 }
91 certPool = x509.NewCertPool()
92 } else {
93 success = true
94 }
95
96 // Next, append the Cloudflare CA pool into the system pool
97 if !certPool.AppendCertsFromPEM(cloudflareRootCA) {
98 logger.Warn("could not append the CF certificate to the cloudflared certificate pool")
99 } else {
100 success = true
101 }
102
103 if success != true { // Obtaining any of the CAs has failed; this is a fatal error
104 return nil, errors.New("error loading any of the CAs into the global certificate pool")
105 }
106
107 // Finally, add the Hello certificate into the pool (since it's self-signed)
108 helloCertificate, err := GetHelloCertificateX509()
109 if err != nil {
110 logger.Warn("error obtaining the Hello server certificate")
111 }
112
113 certPool.AddCert(helloCertificate)
114
115 return certPool, nil
116}
117
118func LoadOriginCertPool(originCAPoolPEM []byte) (*x509.CertPool, error) {
119 success := false
120
121 // Get the global pool
122 certPool, globalPoolErr := LoadGlobalCertPool()
123 if globalPoolErr != nil {
124 certPool = x509.NewCertPool()
125 } else {
126 success = true
127 }
128
129 // Then, add any custom origin CA pool the user may have passed
130 if originCAPoolPEM != nil {
131 if !certPool.AppendCertsFromPEM(originCAPoolPEM) {
132 logger.Warn("could not append the provided origin CA to the cloudflared certificate pool")
133 } else {
134 success = true
135 }
136 }
137
138 if success != true {
139 return nil, errors.New("error loading any of the CAs into the origin certificate pool")
140 }
141
142 return certPool, nil
143}
144
145func CreateTunnelConfig(c *cli.Context, addrs []string) *tls.Config {
146 tlsConfig := CLIFlags{RootCA: "cacert"}.GetConfig(c)
147 if tlsConfig.RootCAs == nil {
148 tlsConfig.RootCAs = GetCloudflareRootCA()
149 tlsConfig.ServerName = "cftunnel.com"
150 } else if len(addrs) > 0 {
151 // Set for development environments and for testing specific origintunneld instances
152 tlsConfig.ServerName, _, _ = net.SplitHostPort(addrs[0])
153 }
154 return tlsConfig
155}
156