From ee6ba1e85e0f980a3d6411d9d0154e6f6b44a641 Mon Sep 17 00:00:00 2001 From: vishalnayak Date: Tue, 12 Jul 2016 19:32:47 -0400 Subject: [PATCH] Make 'tls_min_version' configurable --- builtin/credential/ldap/path_config.go | 61 +++++++++++-------- builtin/logical/cassandra/backend.go | 21 ++++--- .../cassandra/path_config_connection.go | 19 +++++- builtin/logical/cassandra/util.go | 13 ++-- command/server/listener.go | 11 +--- helper/certutil/types.go | 2 +- physical/consul.go | 2 +- 7 files changed, 75 insertions(+), 54 deletions(-) diff --git a/builtin/credential/ldap/path_config.go b/builtin/credential/ldap/path_config.go index 19414fc7ad..d34fbfecc7 100644 --- a/builtin/credential/ldap/path_config.go +++ b/builtin/credential/ldap/path_config.go @@ -8,7 +8,9 @@ import ( "net/url" "strings" + "github.com/fatih/structs" "github.com/go-ldap/ldap" + "github.com/hashicorp/vault/helper/tlsutil" "github.com/hashicorp/vault/logical" "github.com/hashicorp/vault/logical/framework" ) @@ -71,6 +73,12 @@ func pathConfig(b *backend) *framework.Path { Type: framework.TypeBool, Description: "Issue a StartTLS command after establishing unencrypted connection (optional)", }, + + "tls_min_version": &framework.FieldSchema{ + Type: framework.TypeString, + Default: "tls12", + Description: "Minimum TLS version to use. Accepted values are 'tls10', 'tls11' or 'tls12'. Defaults to 'tls12'", + }, }, Callbacks: map[logical.Operation]framework.OperationFunc{ @@ -110,20 +118,14 @@ func (b *backend) pathConfigRead( return nil, nil } + // Convert the struct into a map + data := structs.New(cfg).Map() + + // Convert the integer representing the TLS version into string of + // the form 'tls10', 'tls11' or 'tls12' + data["tls_min_version"] = tlsutil.TLSReverseLookup[data["tls_min_version"].(uint16)] return &logical.Response{ - Data: map[string]interface{}{ - "url": cfg.Url, - "userdn": cfg.UserDN, - "groupdn": cfg.GroupDN, - "upndomain": cfg.UPNDomain, - "userattr": cfg.UserAttr, - "certificate": cfg.Certificate, - "insecure_tls": cfg.InsecureTLS, - "starttls": cfg.StartTLS, - "binddn": cfg.BindDN, - "bindpass": cfg.BindPassword, - "discoverdn": cfg.DiscoverDN, - }, + Data: data, }, nil } @@ -159,6 +161,14 @@ func (b *backend) pathConfigWrite( if insecureTLS { cfg.InsecureTLS = insecureTLS } + tlsMinVersion := d.Get("tls_min_version").(string) + if tlsMinVersion != "" { + var ok bool + cfg.TLSMinVersion, ok = tlsutil.TLSLookup[tlsMinVersion] + if !ok { + return logical.ErrorResponse("failed to set 'tls_min_version'"), nil + } + } startTLS := d.Get("starttls").(bool) if startTLS { cfg.StartTLS = startTLS @@ -200,22 +210,23 @@ func (b *backend) pathConfigWrite( } type ConfigEntry struct { - Url string - UserDN string - GroupDN string - UPNDomain string - UserAttr string - Certificate string - InsecureTLS bool - StartTLS bool - BindDN string - BindPassword string - DiscoverDN bool + Url string `json:"url" structs:"url" mapstructure:"url"` + UserDN string `json:"userdn" structs:"userdn" mapstructure:"userdn"` + GroupDN string `json:"groupdn" structs:"groupdn" mapstructure:"groupdn"` + UPNDomain string `json:"upndomain" structs:"upndomain" mapstructure:"upndomain"` + UserAttr string `json:"userattr" structs:"userattr" mapstructure:"userattr"` + Certificate string `json:"certificate" structs:"certificate" mapstructure:"certificate"` + InsecureTLS bool `json:"insecure_tls" structs:"insecure_tls" mapstructure:"insecure_tls"` + StartTLS bool `json:"starttls" structs:"starttls" mapstructure:"starttls"` + BindDN string `json:"binddn" structs:"binddn" mapstructure:"binddn"` + BindPassword string `json:"bindpass" structs:"bindpass" mapstructure:"bindpass"` + DiscoverDN bool `json:"discoverdn" structs:"discoverdn" mapstructure:"discoverdn"` + TLSMinVersion uint16 `json:"tls_min_version" structs:"tls_min_version" mapstructure:"tls_min_version"` } func (c *ConfigEntry) GetTLSConfig(host string) (*tls.Config, error) { tlsConfig := &tls.Config{ - MinVersion: VersionTLS12, + MinVersion: c.TLSMinVersion, ServerName: host, } if c.InsecureTLS { diff --git a/builtin/logical/cassandra/backend.go b/builtin/logical/cassandra/backend.go index 0b5d393224..5776c8604e 100644 --- a/builtin/logical/cassandra/backend.go +++ b/builtin/logical/cassandra/backend.go @@ -46,16 +46,17 @@ type backend struct { } type sessionConfig struct { - Hosts string `json:"hosts" structs:"hosts"` - Username string `json:"username" structs:"username"` - Password string `json:"password" structs:"password"` - TLS bool `json:"tls" structs:"tls"` - InsecureTLS bool `json:"insecure_tls" structs:"insecure_tls"` - Certificate string `json:"certificate" structs:"certificate"` - PrivateKey string `json:"private_key" structs:"private_key"` - IssuingCA string `json:"issuing_ca" structs:"issuing_ca"` - ProtocolVersion int `json:"protocol_version" structs:"protocol_version"` - ConnectTimeout int `json:"connect_timeout" structs:"connect_timeout"` + Hosts string `json:"hosts" structs:"hosts" mapstructure:"hosts"` + Username string `json:"username" structs:"username" mapstructure:"username"` + Password string `json:"password" structs:"password" mapstructure:"password"` + TLS bool `json:"tls" structs:"tls" mapstructure:"tls"` + InsecureTLS bool `json:"insecure_tls" structs:"insecure_tls" mapstructure:"insecure_tls"` + Certificate string `json:"certificate" structs:"certificate" mapstructure:"certificate"` + PrivateKey string `json:"private_key" structs:"private_key" mapstructure:"private_key"` + IssuingCA string `json:"issuing_ca" structs:"issuing_ca" mapstructure:"issuing_ca"` + ProtocolVersion int `json:"protocol_version" structs:"protocol_version" mapstructure:"protocol_version"` + ConnectTimeout int `json:"connect_timeout" structs:"connect_timeout" mapstructure:"connect_timeout"` + TLSMinVersion uint16 `json:"tls_min_version" structs:"tls_min_version" mapstructure:"tls_min_version"` } // DB returns the database connection. diff --git a/builtin/logical/cassandra/path_config_connection.go b/builtin/logical/cassandra/path_config_connection.go index a684313e9a..84ae3ef58d 100644 --- a/builtin/logical/cassandra/path_config_connection.go +++ b/builtin/logical/cassandra/path_config_connection.go @@ -5,6 +5,7 @@ import ( "github.com/fatih/structs" "github.com/hashicorp/vault/helper/certutil" + "github.com/hashicorp/vault/helper/tlsutil" "github.com/hashicorp/vault/logical" "github.com/hashicorp/vault/logical/framework" ) @@ -40,6 +41,12 @@ set, this is automatically set to true`, effect if a CA certificate is provided`, }, + "tls_min_version": &framework.FieldSchema{ + Type: framework.TypeString, + Default: "tls12", + Description: "Minimum TLS version to use. Accepted values are 'tls10', 'tls11' or 'tls12'. Defaults to 'tls12'", + }, + "pem_bundle": &framework.FieldSchema{ Type: framework.TypeString, Description: `PEM-format, concatenated unencrypted secret key @@ -98,8 +105,9 @@ func (b *backend) pathConnectionRead( config.PrivateKey = "**********" } + d := structs.New(config).Map() return &logical.Response{ - Data: structs.New(config).Map(), + Data: d, }, nil } @@ -128,6 +136,15 @@ func (b *backend) pathConnectionWrite( ConnectTimeout: data.Get("connect_timeout").(int), } + tlsMinVersion := data.Get("tls_min_version").(string) + if tlsMinVersion != "" { + var ok bool + config.TLSMinVersion, ok = tlsutil.TLSLookup[tlsMinVersion] + if !ok { + return logical.ErrorResponse("failed to set 'tls_min_version'"), nil + } + } + if config.InsecureTLS { config.TLS = true } diff --git a/builtin/logical/cassandra/util.go b/builtin/logical/cassandra/util.go index b728452155..08fdb7d223 100644 --- a/builtin/logical/cassandra/util.go +++ b/builtin/logical/cassandra/util.go @@ -48,11 +48,7 @@ func createSession(cfg *sessionConfig, s logical.Storage) (*gocql.Session, error clusterConfig.Timeout = time.Duration(cfg.ConnectTimeout) * time.Second if cfg.TLS { - tlsConfig := &tls.Config{ - InsecureSkipVerify: cfg.InsecureTLS, - MinVersion: VersionTLS12, - } - + var tlsConfig *tls.Config if len(cfg.Certificate) > 0 || len(cfg.IssuingCA) > 0 { if len(cfg.Certificate) > 0 && len(cfg.PrivateKey) == 0 { return nil, fmt.Errorf("Found certificate for TLS authentication but no private key") @@ -65,18 +61,19 @@ func createSession(cfg *sessionConfig, s logical.Storage) (*gocql.Session, error } if len(cfg.IssuingCA) > 0 { certBundle.IssuingCA = cfg.IssuingCA - tlsConfig.InsecureSkipVerify = false } parsedCertBundle, err := certBundle.ToParsedCertBundle() if err != nil { - return nil, fmt.Errorf("Error parsing certificate bundle: %s", err) + return nil, fmt.Errorf("failed to parse certificate bundle: %s", err) } tlsConfig, err = parsedCertBundle.GetTLSConfig(certutil.TLSClient) if err != nil { - return nil, fmt.Errorf("Error getting TLS configuration: %s", err) + return nil, fmt.Errorf("failed to get TLS configuration: %s", err) } + tlsConfig.InsecureSkipVerify = cfg.InsecureTLS + tlsConfig.MinVersion = cfg.TLSMinVersion } clusterConfig.SslOpts = &gocql.SslOptions{ diff --git a/command/server/listener.go b/command/server/listener.go index 051ab2e8b9..7948bda988 100644 --- a/command/server/listener.go +++ b/command/server/listener.go @@ -10,6 +10,8 @@ import ( "net" "strconv" "sync" + + "github.com/hashicorp/vault/helper/tlsutil" ) // ListenerFactory is the factory function to create a listener. @@ -21,13 +23,6 @@ var BuiltinListeners = map[string]ListenerFactory{ "atlas": atlasListenerFactory, } -// tlsLookup maps the tls_min_version configuration to the internal value -var tlsLookup = map[string]uint16{ - "tls10": tls.VersionTLS10, - "tls11": tls.VersionTLS11, - "tls12": tls.VersionTLS12, -} - // NewListener creates a new listener of the given type with the given // configuration. The type is looked up in the BuiltinListeners map. func NewListener(t string, config map[string]string, logger io.Writer) (net.Listener, map[string]string, ReloadFunc, error) { @@ -81,7 +76,7 @@ func listenerWrapTLS( tlsConf := &tls.Config{} tlsConf.GetCertificate = cg.getCertificate tlsConf.NextProtos = []string{"http/1.1"} - tlsConf.MinVersion, ok = tlsLookup[tlsvers] + tlsConf.MinVersion, ok = tlsutil.TLSLookup[tlsvers] if !ok { return nil, nil, nil, fmt.Errorf("'tls_min_version' value %s not supported, please specify one of [tls10,tls11,tls12]", tlsvers) } diff --git a/helper/certutil/types.go b/helper/certutil/types.go index 29d9a72389..6767a8d241 100644 --- a/helper/certutil/types.go +++ b/helper/certutil/types.go @@ -438,7 +438,7 @@ func (p *ParsedCertBundle) GetTLSConfig(usage TLSUsage) (*tls.Config, error) { tlsConfig := &tls.Config{ NextProtos: []string{"http/1.1"}, - MinVersion: VersionTLS12, + MinVersion: tls.VersionTLS12, } if p.Certificate != nil { diff --git a/physical/consul.go b/physical/consul.go index a3c4603004..439760d17d 100644 --- a/physical/consul.go +++ b/physical/consul.go @@ -191,7 +191,7 @@ func setupTLSConfig(conf map[string]string) (*tls.Config, error) { } tlsClientConfig := &tls.Config{ - MinVersion: VersionTLS12, + MinVersion: tls.VersionTLS12, InsecureSkipVerify: insecureSkipVerify, ServerName: serverName[0], }