From b63d5dd0a34a8525c2527bbdfbcc74a5ff4b3897 Mon Sep 17 00:00:00 2001 From: Josef Johansson Date: Fri, 21 May 2021 15:54:42 +0200 Subject: [PATCH] plugins/common/tls/config.go: Filter client certs by dns names Signed-off-by: Josef Johansson --- plugins/common/tls/config.go | 46 +++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/plugins/common/tls/config.go b/plugins/common/tls/config.go index 586ec8fd4a417..aa0518785240d 100644 --- a/plugins/common/tls/config.go +++ b/plugins/common/tls/config.go @@ -4,6 +4,7 @@ import ( "crypto/tls" "crypto/x509" "fmt" + "github.com/influxdata/telegraf/internal/choice" "os" "strings" ) @@ -24,12 +25,13 @@ type ClientConfig struct { // ServerConfig represents the standard server TLS config. type ServerConfig struct { - TLSCert string `toml:"tls_cert"` - TLSKey string `toml:"tls_key"` - TLSAllowedCACerts []string `toml:"tls_allowed_cacerts"` - TLSCipherSuites []string `toml:"tls_cipher_suites"` - TLSMinVersion string `toml:"tls_min_version"` - TLSMaxVersion string `toml:"tls_max_version"` + TLSCert string `toml:"tls_cert"` + TLSKey string `toml:"tls_key"` + TLSAllowedCACerts []string `toml:"tls_allowed_cacerts"` + TLSCipherSuites []string `toml:"tls_cipher_suites"` + TLSMinVersion string `toml:"tls_min_version"` + TLSMaxVersion string `toml:"tls_max_version"` + TLSAllowedDNSNames []string `toml:"tls_allowed_dns_names"` } // TLSConfig returns a tls.Config, may be nil without error if TLS is not @@ -141,6 +143,12 @@ func (c *ServerConfig) TLSConfig() (*tls.Config, error) { "tls min version %q can't be greater than tls max version %q", tlsConfig.MinVersion, tlsConfig.MaxVersion) } + // Since clientAuth is tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert + // there must be certs to validate. + if len(c.TLSAllowedCACerts) > 0 && len(c.TLSAllowedDNSNames) > 0 { + tlsConfig.VerifyPeerCertificate = c.verifyPeerCertificate + } + return tlsConfig, nil } @@ -152,8 +160,7 @@ func makeCertPool(certFiles []string) (*x509.CertPool, error) { return nil, fmt.Errorf( "could not read certificate %q: %v", certFile, err) } - ok := pool.AppendCertsFromPEM(pem) - if !ok { + if !pool.AppendCertsFromPEM(pem) { return nil, fmt.Errorf( "could not parse any PEM certificates %q: %v", certFile, err) } @@ -172,3 +179,26 @@ func loadCertificate(config *tls.Config, certFile, keyFile string) error { config.BuildNameToCertificate() return nil } + +func (c *ServerConfig) verifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { + // The certificate chain is client + intermediate + root. + // Let's review the client certificate. + cert, err := x509.ParseCertificate(rawCerts[0]) + if err != nil { + return fmt.Errorf("could not validate peer certificate: %v", err) + } + + allowed := false + for _, name := range cert.DNSNames { + if choice.Contains(name, c.TLSAllowedDNSNames) { + allowed = true + } + } + + if !allowed { + return fmt.Errorf( + "peer certificate not in allowed DNS Name list: %v", cert.DNSNames) + } + + return nil +}