Use either a system pool or custom CA pool when connecting from client->daemon (+go-connections version bump)
| ... | ... |
@@ -250,8 +250,9 @@ func newHTTPClient(host string, tlsOptions *tlsconfig.Options) (*http.Client, er |
| 250 | 250 |
// let the api client configure the default transport. |
| 251 | 251 |
return nil, nil |
| 252 | 252 |
} |
| 253 |
- |
|
| 254 |
- config, err := tlsconfig.Client(*tlsOptions) |
|
| 253 |
+ opts := *tlsOptions |
|
| 254 |
+ opts.ExclusiveRootPools = true |
|
| 255 |
+ config, err := tlsconfig.Client(opts) |
|
| 255 | 256 |
if err != nil {
|
| 256 | 257 |
return nil, err |
| 257 | 258 |
} |
| ... | ... |
@@ -17,7 +17,7 @@ github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3 |
| 17 | 17 |
golang.org/x/net c427ad74c6d7a814201695e9ffde0c5d400a7674 |
| 18 | 18 |
golang.org/x/sys 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9 |
| 19 | 19 |
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1 |
| 20 |
-github.com/docker/go-connections 7da10c8c50cad14494ec818dcdfb6506265c0086 |
|
| 20 |
+github.com/docker/go-connections a2afab9802043837035592f1c24827fb70766de9 |
|
| 21 | 21 |
golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756 |
| 22 | 22 |
|
| 23 | 23 |
github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5 |
| ... | ... |
@@ -29,6 +29,11 @@ type Options struct {
|
| 29 | 29 |
InsecureSkipVerify bool |
| 30 | 30 |
// server-only option |
| 31 | 31 |
ClientAuth tls.ClientAuthType |
| 32 |
+ // If ExclusiveRootPools is set, then if a CA file is provided, the root pool used for TLS |
|
| 33 |
+ // creds will include exclusively the roots in that CA file. If no CA file is provided, |
|
| 34 |
+ // the system pool will be used. |
|
| 35 |
+ ExclusiveRootPools bool |
|
| 36 |
+ MinVersion uint16 |
|
| 32 | 37 |
} |
| 33 | 38 |
|
| 34 | 39 |
// Extra (server-side) accepted CBC cipher suites - will phase out in the future |
| ... | ... |
@@ -46,6 +51,15 @@ var acceptedCBCCiphers = []uint16{
|
| 46 | 46 |
// known weak algorithms removed. |
| 47 | 47 |
var DefaultServerAcceptedCiphers = append(clientCipherSuites, acceptedCBCCiphers...) |
| 48 | 48 |
|
| 49 |
+// allTLSVersions lists all the TLS versions and is used by the code that validates |
|
| 50 |
+// a uint16 value as a TLS version. |
|
| 51 |
+var allTLSVersions = map[uint16]struct{}{
|
|
| 52 |
+ tls.VersionSSL30: {},
|
|
| 53 |
+ tls.VersionTLS10: {},
|
|
| 54 |
+ tls.VersionTLS11: {},
|
|
| 55 |
+ tls.VersionTLS12: {},
|
|
| 56 |
+} |
|
| 57 |
+ |
|
| 49 | 58 |
// ServerDefault returns a secure-enough TLS configuration for the server TLS configuration. |
| 50 | 59 |
func ServerDefault() *tls.Config {
|
| 51 | 60 |
return &tls.Config{
|
| ... | ... |
@@ -66,11 +80,19 @@ func ClientDefault() *tls.Config {
|
| 66 | 66 |
} |
| 67 | 67 |
|
| 68 | 68 |
// certPool returns an X.509 certificate pool from `caFile`, the certificate file. |
| 69 |
-func certPool(caFile string) (*x509.CertPool, error) {
|
|
| 69 |
+func certPool(caFile string, exclusivePool bool) (*x509.CertPool, error) {
|
|
| 70 | 70 |
// If we should verify the server, we need to load a trusted ca |
| 71 |
- certPool, err := SystemCertPool() |
|
| 72 |
- if err != nil {
|
|
| 73 |
- return nil, fmt.Errorf("failed to read system certificates: %v", err)
|
|
| 71 |
+ var ( |
|
| 72 |
+ certPool *x509.CertPool |
|
| 73 |
+ err error |
|
| 74 |
+ ) |
|
| 75 |
+ if exclusivePool {
|
|
| 76 |
+ certPool = x509.NewCertPool() |
|
| 77 |
+ } else {
|
|
| 78 |
+ certPool, err = SystemCertPool() |
|
| 79 |
+ if err != nil {
|
|
| 80 |
+ return nil, fmt.Errorf("failed to read system certificates: %v", err)
|
|
| 81 |
+ } |
|
| 74 | 82 |
} |
| 75 | 83 |
pem, err := ioutil.ReadFile(caFile) |
| 76 | 84 |
if err != nil {
|
| ... | ... |
@@ -83,12 +105,34 @@ func certPool(caFile string) (*x509.CertPool, error) {
|
| 83 | 83 |
return certPool, nil |
| 84 | 84 |
} |
| 85 | 85 |
|
| 86 |
+// isValidMinVersion checks that the input value is a valid tls minimum version |
|
| 87 |
+func isValidMinVersion(version uint16) bool {
|
|
| 88 |
+ _, ok := allTLSVersions[version] |
|
| 89 |
+ return ok |
|
| 90 |
+} |
|
| 91 |
+ |
|
| 92 |
+// adjustMinVersion sets the MinVersion on `config`, the input configuration. |
|
| 93 |
+// It assumes the current MinVersion on the `config` is the lowest allowed. |
|
| 94 |
+func adjustMinVersion(options Options, config *tls.Config) error {
|
|
| 95 |
+ if options.MinVersion > 0 {
|
|
| 96 |
+ if !isValidMinVersion(options.MinVersion) {
|
|
| 97 |
+ return fmt.Errorf("Invalid minimum TLS version: %x", options.MinVersion)
|
|
| 98 |
+ } |
|
| 99 |
+ if options.MinVersion < config.MinVersion {
|
|
| 100 |
+ return fmt.Errorf("Requested minimum TLS version is too low. Should be at-least: %x", config.MinVersion)
|
|
| 101 |
+ } |
|
| 102 |
+ config.MinVersion = options.MinVersion |
|
| 103 |
+ } |
|
| 104 |
+ |
|
| 105 |
+ return nil |
|
| 106 |
+} |
|
| 107 |
+ |
|
| 86 | 108 |
// Client returns a TLS configuration meant to be used by a client. |
| 87 | 109 |
func Client(options Options) (*tls.Config, error) {
|
| 88 | 110 |
tlsConfig := ClientDefault() |
| 89 | 111 |
tlsConfig.InsecureSkipVerify = options.InsecureSkipVerify |
| 90 | 112 |
if !options.InsecureSkipVerify && options.CAFile != "" {
|
| 91 |
- CAs, err := certPool(options.CAFile) |
|
| 113 |
+ CAs, err := certPool(options.CAFile, options.ExclusiveRootPools) |
|
| 92 | 114 |
if err != nil {
|
| 93 | 115 |
return nil, err |
| 94 | 116 |
} |
| ... | ... |
@@ -103,6 +147,10 @@ func Client(options Options) (*tls.Config, error) {
|
| 103 | 103 |
tlsConfig.Certificates = []tls.Certificate{tlsCert}
|
| 104 | 104 |
} |
| 105 | 105 |
|
| 106 |
+ if err := adjustMinVersion(options, tlsConfig); err != nil {
|
|
| 107 |
+ return nil, err |
|
| 108 |
+ } |
|
| 109 |
+ |
|
| 106 | 110 |
return tlsConfig, nil |
| 107 | 111 |
} |
| 108 | 112 |
|
| ... | ... |
@@ -119,11 +167,16 @@ func Server(options Options) (*tls.Config, error) {
|
| 119 | 119 |
} |
| 120 | 120 |
tlsConfig.Certificates = []tls.Certificate{tlsCert}
|
| 121 | 121 |
if options.ClientAuth >= tls.VerifyClientCertIfGiven && options.CAFile != "" {
|
| 122 |
- CAs, err := certPool(options.CAFile) |
|
| 122 |
+ CAs, err := certPool(options.CAFile, options.ExclusiveRootPools) |
|
| 123 | 123 |
if err != nil {
|
| 124 | 124 |
return nil, err |
| 125 | 125 |
} |
| 126 | 126 |
tlsConfig.ClientCAs = CAs |
| 127 | 127 |
} |
| 128 |
+ |
|
| 129 |
+ if err := adjustMinVersion(options, tlsConfig); err != nil {
|
|
| 130 |
+ return nil, err |
|
| 131 |
+ } |
|
| 132 |
+ |
|
| 128 | 133 |
return tlsConfig, nil |
| 129 | 134 |
} |