diff --git a/cli/command/cli.go b/cli/command/cli.go index 783e516f3d..77b05d5832 100644 --- a/cli/command/cli.go +++ b/cli/command/cli.go @@ -250,8 +250,9 @@ func newHTTPClient(host string, tlsOptions *tlsconfig.Options) (*http.Client, er // let the api client configure the default transport. return nil, nil } - - config, err := tlsconfig.Client(*tlsOptions) + opts := *tlsOptions + opts.ExclusiveRootPools = true + config, err := tlsconfig.Client(opts) if err != nil { return nil, err } diff --git a/vendor.conf b/vendor.conf index a784d402ba..e7d98d2285 100644 --- a/vendor.conf +++ b/vendor.conf @@ -17,7 +17,7 @@ github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3 golang.org/x/net c427ad74c6d7a814201695e9ffde0c5d400a7674 golang.org/x/sys 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9 github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1 -github.com/docker/go-connections 7da10c8c50cad14494ec818dcdfb6506265c0086 +github.com/docker/go-connections a2afab9802043837035592f1c24827fb70766de9 golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756 github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5 diff --git a/vendor/github.com/docker/go-connections/tlsconfig/config.go b/vendor/github.com/docker/go-connections/tlsconfig/config.go index 44733ff506..0f8684497e 100644 --- a/vendor/github.com/docker/go-connections/tlsconfig/config.go +++ b/vendor/github.com/docker/go-connections/tlsconfig/config.go @@ -29,6 +29,11 @@ type Options struct { InsecureSkipVerify bool // server-only option ClientAuth tls.ClientAuthType + // If ExclusiveRootPools is set, then if a CA file is provided, the root pool used for TLS + // creds will include exclusively the roots in that CA file. If no CA file is provided, + // the system pool will be used. + ExclusiveRootPools bool + MinVersion uint16 } // Extra (server-side) accepted CBC cipher suites - will phase out in the future @@ -46,6 +51,15 @@ var acceptedCBCCiphers = []uint16{ // known weak algorithms removed. var DefaultServerAcceptedCiphers = append(clientCipherSuites, acceptedCBCCiphers...) +// allTLSVersions lists all the TLS versions and is used by the code that validates +// a uint16 value as a TLS version. +var allTLSVersions = map[uint16]struct{}{ + tls.VersionSSL30: {}, + tls.VersionTLS10: {}, + tls.VersionTLS11: {}, + tls.VersionTLS12: {}, +} + // ServerDefault returns a secure-enough TLS configuration for the server TLS configuration. func ServerDefault() *tls.Config { return &tls.Config{ @@ -66,11 +80,19 @@ func ClientDefault() *tls.Config { } // certPool returns an X.509 certificate pool from `caFile`, the certificate file. -func certPool(caFile string) (*x509.CertPool, error) { +func certPool(caFile string, exclusivePool bool) (*x509.CertPool, error) { // If we should verify the server, we need to load a trusted ca - certPool, err := SystemCertPool() - if err != nil { - return nil, fmt.Errorf("failed to read system certificates: %v", err) + var ( + certPool *x509.CertPool + err error + ) + if exclusivePool { + certPool = x509.NewCertPool() + } else { + certPool, err = SystemCertPool() + if err != nil { + return nil, fmt.Errorf("failed to read system certificates: %v", err) + } } pem, err := ioutil.ReadFile(caFile) if err != nil { @@ -83,12 +105,34 @@ func certPool(caFile string) (*x509.CertPool, error) { return certPool, nil } +// isValidMinVersion checks that the input value is a valid tls minimum version +func isValidMinVersion(version uint16) bool { + _, ok := allTLSVersions[version] + return ok +} + +// adjustMinVersion sets the MinVersion on `config`, the input configuration. +// It assumes the current MinVersion on the `config` is the lowest allowed. +func adjustMinVersion(options Options, config *tls.Config) error { + if options.MinVersion > 0 { + if !isValidMinVersion(options.MinVersion) { + return fmt.Errorf("Invalid minimum TLS version: %x", options.MinVersion) + } + if options.MinVersion < config.MinVersion { + return fmt.Errorf("Requested minimum TLS version is too low. Should be at-least: %x", config.MinVersion) + } + config.MinVersion = options.MinVersion + } + + return nil +} + // Client returns a TLS configuration meant to be used by a client. func Client(options Options) (*tls.Config, error) { tlsConfig := ClientDefault() tlsConfig.InsecureSkipVerify = options.InsecureSkipVerify if !options.InsecureSkipVerify && options.CAFile != "" { - CAs, err := certPool(options.CAFile) + CAs, err := certPool(options.CAFile, options.ExclusiveRootPools) if err != nil { return nil, err } @@ -103,6 +147,10 @@ func Client(options Options) (*tls.Config, error) { tlsConfig.Certificates = []tls.Certificate{tlsCert} } + if err := adjustMinVersion(options, tlsConfig); err != nil { + return nil, err + } + return tlsConfig, nil } @@ -119,11 +167,16 @@ func Server(options Options) (*tls.Config, error) { } tlsConfig.Certificates = []tls.Certificate{tlsCert} if options.ClientAuth >= tls.VerifyClientCertIfGiven && options.CAFile != "" { - CAs, err := certPool(options.CAFile) + CAs, err := certPool(options.CAFile, options.ExclusiveRootPools) if err != nil { return nil, err } tlsConfig.ClientCAs = CAs } + + if err := adjustMinVersion(options, tlsConfig); err != nil { + return nil, err + } + return tlsConfig, nil }