From 001e9aa9cf638180133aa2f87ca44d21b430413e Mon Sep 17 00:00:00 2001 From: Devin Carr Date: Tue, 25 Aug 2026 17:19:15 -0700 Subject: [PATCH] TUN-10725: Remove unused certificate configuration --- tlsconfig/{certreloader.go => origin_ca.go} | 73 +++----------- tlsconfig/tlsconfig.go | 102 -------------------- tlsconfig/tlsconfig_test.go | 79 +++------------ 3 files changed, 22 insertions(+), 232 deletions(-) rename tlsconfig/{certreloader.go => origin_ca.go} (66%) delete mode 100644 tlsconfig/tlsconfig.go diff --git a/tlsconfig/certreloader.go b/tlsconfig/origin_ca.go similarity index 66% rename from tlsconfig/certreloader.go rename to tlsconfig/origin_ca.go index def07013..1716ea66 100644 --- a/tlsconfig/certreloader.go +++ b/tlsconfig/origin_ca.go @@ -1,3 +1,4 @@ +// Package tlsconfig builds base TLS configuration for edge and origin connections. package tlsconfig import ( @@ -6,9 +7,7 @@ import ( "fmt" "os" "runtime" - "sync" - "github.com/getsentry/sentry-go" "github.com/pkg/errors" "github.com/rs/zerolog" ) @@ -17,59 +16,6 @@ const ( OriginCAPoolFlag = "origin-ca-pool" ) -// CertReloader can load and reload a TLS certificate from a particular filepath. -// Hooks into tls.Config's GetCertificate to allow a TLS server to update its certificate without restarting. -type CertReloader struct { - sync.Mutex - certificate *tls.Certificate - certPath string - keyPath string -} - -// NewCertReloader makes a CertReloader. It loads the cert during initialization to make sure certPath and keyPath are valid -func NewCertReloader(certPath, keyPath string) (*CertReloader, error) { - cr := new(CertReloader) - cr.certPath = certPath - cr.keyPath = keyPath - if err := cr.LoadCert(); err != nil { - return nil, err - } - return cr, nil -} - -// Cert returns the TLS certificate most recently read by the CertReloader. -// This method works as a direct utility method for tls.Config#Cert. -func (cr *CertReloader) Cert(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) { - cr.Lock() - defer cr.Unlock() - return cr.certificate, nil -} - -// ClientCert returns the TLS certificate most recently read by the CertReloader. -// This method works as a direct utility method for tls.Config#ClientCert. -func (cr *CertReloader) ClientCert(certRequestInfo *tls.CertificateRequestInfo) (*tls.Certificate, error) { - cr.Lock() - defer cr.Unlock() - return cr.certificate, nil -} - -// LoadCert loads a TLS certificate from the CertReloader's specified filepath. -// Call this after writing a new certificate to the disk (e.g. after renewing a certificate) -func (cr *CertReloader) LoadCert() error { - cr.Lock() - defer cr.Unlock() - - cert, err := tls.LoadX509KeyPair(cr.certPath, cr.keyPath) - - // Keep the old certificate if there's a problem reading the new one. - if err != nil { - sentry.CaptureException(fmt.Errorf("error parsing X509 key pair: %v", err)) - return err - } - cr.certificate = &cert - return nil -} - func LoadOriginCA(originCAPoolFilename string, log *zerolog.Logger) (*x509.CertPool, error) { var originCustomCAPool []byte @@ -128,15 +74,18 @@ func LoadCustomOriginCA(originCAFilename string) (*x509.CertPool, error) { } func CreateTunnelConfig(caCert string, serverName string) (*tls.Config, error) { - var rootCAs []string + tlsConfig := &tls.Config{ServerName: serverName} if caCert != "" { - rootCAs = append(rootCAs, caCert) - } + caCertPEM, err := os.ReadFile(caCert) //nolint:gosec + if err != nil { + return nil, fmt.Errorf("read CA certificate %s: %w", caCert, err) + } - userConfig := &TLSParameters{RootCAs: rootCAs, ServerName: serverName} - tlsConfig, err := GetConfig(userConfig) - if err != nil { - return nil, err + rootCAPool := x509.NewCertPool() + if !rootCAPool.AppendCertsFromPEM(caCertPEM) { + return nil, fmt.Errorf("parse CA certificate %s", caCert) + } + tlsConfig.RootCAs = rootCAPool } if tlsConfig.RootCAs == nil { diff --git a/tlsconfig/tlsconfig.go b/tlsconfig/tlsconfig.go deleted file mode 100644 index 3e6cea20..00000000 --- a/tlsconfig/tlsconfig.go +++ /dev/null @@ -1,102 +0,0 @@ -// Package tlsconfig provides convenience functions for configuring TLS connections from the -// command line. -package tlsconfig - -import ( - "crypto/tls" - "crypto/x509" - "os" - - "github.com/pkg/errors" -) - -// Config is the user provided parameters to create a tls.Config -type TLSParameters struct { - Cert string - Key string - GetCertificate *CertReloader - GetClientCertificate *CertReloader - ClientCAs []string - RootCAs []string - ServerName string - CurvePreferences []tls.CurveID - MinVersion uint16 // min tls version. If zero, TLS1.0 is defined as minimum. - MaxVersion uint16 // max tls version. If zero, last TLS version is used defined as limit (currently TLS1.3) -} - -// GetConfig returns a TLS configuration according to the Config set by the user. -func GetConfig(p *TLSParameters) (*tls.Config, error) { - tlsconfig := &tls.Config{} - if p.Cert != "" && p.Key != "" { - cert, err := tls.LoadX509KeyPair(p.Cert, p.Key) - if err != nil { - return nil, errors.Wrap(err, "Error parsing X509 key pair") - } - tlsconfig.Certificates = []tls.Certificate{cert} - // BuildNameToCertificate parses Certificates and builds NameToCertificate from common name - // and SAN fields of leaf certificates - tlsconfig.BuildNameToCertificate() - } - - if p.GetCertificate != nil { - // GetCertificate is called when client supplies SNI info or Certificates is empty. - // Order of retrieving certificate is GetCertificate, NameToCertificate and lastly first element of Certificates - tlsconfig.GetCertificate = p.GetCertificate.Cert - } - - if p.GetClientCertificate != nil { - // GetClientCertificate is called when using an HTTP client library and mTLS is required. - tlsconfig.GetClientCertificate = p.GetClientCertificate.ClientCert - } - - if len(p.ClientCAs) > 0 { - // set of root certificate authorities that servers use if required to verify a client certificate - // by the policy in ClientAuth - clientCAs, err := LoadCert(p.ClientCAs) - if err != nil { - return nil, errors.Wrap(err, "Error loading client CAs") - } - tlsconfig.ClientCAs = clientCAs - // server's policy for TLS Client Authentication. Default is no client cert - tlsconfig.ClientAuth = tls.RequireAndVerifyClientCert - } - - if len(p.RootCAs) > 0 { - rootCAs, err := LoadCert(p.RootCAs) - if err != nil { - return nil, errors.Wrap(err, "Error loading root CAs") - } - tlsconfig.RootCAs = rootCAs - } - - if p.ServerName != "" { - tlsconfig.ServerName = p.ServerName - } - - if len(p.CurvePreferences) > 0 { - tlsconfig.CurvePreferences = p.CurvePreferences - } else { - // Cloudflare optimize CurveP256 - tlsconfig.CurvePreferences = []tls.CurveID{tls.CurveP256} - } - - tlsconfig.MinVersion = p.MinVersion - tlsconfig.MaxVersion = p.MaxVersion - - return tlsconfig, nil -} - -// LoadCert creates a CertPool containing all certificates in a PEM-format file. -func LoadCert(certPaths []string) (*x509.CertPool, error) { - ca := x509.NewCertPool() - for _, certPath := range certPaths { - caCert, err := os.ReadFile(certPath) - if err != nil { - return nil, errors.Wrapf(err, "Error reading certificate %s", certPath) - } - if !ca.AppendCertsFromPEM(caCert) { - return nil, errors.Wrapf(err, "Error parsing certificate %s", certPath) - } - } - return ca, nil -} diff --git a/tlsconfig/tlsconfig_test.go b/tlsconfig/tlsconfig_test.go index 26eb1056..631bf07c 100644 --- a/tlsconfig/tlsconfig_test.go +++ b/tlsconfig/tlsconfig_test.go @@ -1,82 +1,25 @@ package tlsconfig import ( - "crypto/tls" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) -// testcert.pem and testcert2.pem are Generated using `openssl req -newkey rsa:512 -nodes -x509 -days 3650` -const ( - testcertCommonName = "localhost" -) - -func TestGetFromEmptyConfig(t *testing.T) { - c := &TLSParameters{} - - tlsConfig, err := GetConfig(c) - assert.NoError(t, err) - assert.Empty(t, tlsConfig.Certificates) - - assert.Empty(t, tlsConfig.NameToCertificate) - - assert.Nil(t, tlsConfig.ClientCAs) - assert.Equal(t, tls.NoClientCert, tlsConfig.ClientAuth) - - assert.Nil(t, tlsConfig.RootCAs) - - assert.Len(t, tlsConfig.CurvePreferences, 1) - assert.Equal(t, tls.CurveP256, tlsConfig.CurvePreferences[0]) -} - -func TestGetConfig(t *testing.T) { - cert, err := tls.LoadX509KeyPair("testcert.pem", "testkey.pem") - assert.NoError(t, err) - - c := &TLSParameters{ - Cert: "testcert.pem", - Key: "testkey.pem", - ClientCAs: []string{"testcert.pem", "testcert2.pem"}, - RootCAs: []string{"testcert.pem", "testcert2.pem"}, - ServerName: "test", - CurvePreferences: []tls.CurveID{tls.CurveP384}, - } - tlsConfig, err := GetConfig(c) - assert.NoError(t, err) - assert.Len(t, tlsConfig.Certificates, 1) - assert.Equal(t, cert, tlsConfig.Certificates[0]) - - assert.Equal(t, cert, *tlsConfig.NameToCertificate[testcertCommonName]) - - assert.NotNil(t, tlsConfig.ClientCAs) - assert.Equal(t, tls.RequireAndVerifyClientCert, tlsConfig.ClientAuth) +func TestCreateTunnelConfig(t *testing.T) { + t.Parallel() + tlsConfig, err := CreateTunnelConfig("testcert.pem", "edge.example.com") + require.NoError(t, err) + assert.Equal(t, "edge.example.com", tlsConfig.ServerName) assert.NotNil(t, tlsConfig.RootCAs) - - assert.Len(t, tlsConfig.CurvePreferences, 1) - assert.Equal(t, tls.CurveP384, tlsConfig.CurvePreferences[0]) + assert.Empty(t, tlsConfig.CurvePreferences) } -func TestCertReloader(t *testing.T) { - expectedCert, err := tls.LoadX509KeyPair("testcert.pem", "testkey.pem") - assert.NoError(t, err) +func TestCreateTunnelConfigRequiresServerName(t *testing.T) { + t.Parallel() - certReloader, err := NewCertReloader("testcert.pem", "testkey.pem") - assert.NoError(t, err) - - chi := &tls.ClientHelloInfo{ServerName: testcertCommonName} - cert, err := certReloader.Cert(chi) - assert.NoError(t, err) - assert.Equal(t, expectedCert, *cert) - - c := &TLSParameters{ - GetCertificate: certReloader, - } - tlsConfig, err := GetConfig(c) - assert.NoError(t, err) - - cert, err = tlsConfig.GetCertificate(chi) - assert.NoError(t, err) - assert.Equal(t, expectedCert, *cert) + _, err := CreateTunnelConfig("testcert.pem", "") + assert.EqualError(t, err, "either ServerName or InsecureSkipVerify must be specified in the tls.Config") }