Refactor TLS code with a new `tlsconfig` package
| ... | ... |
@@ -1,6 +1,7 @@ |
| 1 | 1 |
package server |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "crypto/tls" |
|
| 4 | 5 |
"encoding/base64" |
| 5 | 6 |
"encoding/json" |
| 6 | 7 |
"fmt" |
| ... | ... |
@@ -44,11 +45,7 @@ type ServerConfig struct {
|
| 44 | 44 |
CorsHeaders string |
| 45 | 45 |
Version string |
| 46 | 46 |
SocketGroup string |
| 47 |
- Tls bool |
|
| 48 |
- TlsVerify bool |
|
| 49 |
- TlsCa string |
|
| 50 |
- TlsCert string |
|
| 51 |
- TlsKey string |
|
| 47 |
+ TLSConfig *tls.Config |
|
| 52 | 48 |
} |
| 53 | 49 |
|
| 54 | 50 |
type Server struct {
|
| ... | ... |
@@ -1435,22 +1432,15 @@ func (s *Server) ping(version version.Version, w http.ResponseWriter, r *http.Re |
| 1435 | 1435 |
} |
| 1436 | 1436 |
|
| 1437 | 1437 |
func (s *Server) initTcpSocket(addr string) (l net.Listener, err error) {
|
| 1438 |
- if !s.cfg.TlsVerify {
|
|
| 1438 |
+ if s.cfg.TLSConfig == nil || s.cfg.TLSConfig.ClientAuth != tls.RequireAndVerifyClientCert {
|
|
| 1439 | 1439 |
logrus.Warn("/!\\ DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
|
| 1440 | 1440 |
} |
| 1441 |
- |
|
| 1442 |
- var c *sockets.TlsConfig |
|
| 1443 |
- if s.cfg.Tls || s.cfg.TlsVerify {
|
|
| 1444 |
- c = sockets.NewTlsConfig(s.cfg.TlsCert, s.cfg.TlsKey, s.cfg.TlsCa, s.cfg.TlsVerify) |
|
| 1445 |
- } |
|
| 1446 |
- |
|
| 1447 |
- if l, err = sockets.NewTcpSocket(addr, c, s.start); err != nil {
|
|
| 1441 |
+ if l, err = sockets.NewTcpSocket(addr, s.cfg.TLSConfig, s.start); err != nil {
|
|
| 1448 | 1442 |
return nil, err |
| 1449 | 1443 |
} |
| 1450 | 1444 |
if err := allocateDaemonPort(addr); err != nil {
|
| 1451 | 1445 |
return nil, err |
| 1452 | 1446 |
} |
| 1453 |
- |
|
| 1454 | 1447 |
return |
| 1455 | 1448 |
} |
| 1456 | 1449 |
|
| ... | ... |
@@ -3,6 +3,7 @@ |
| 3 | 3 |
package main |
| 4 | 4 |
|
| 5 | 5 |
import ( |
| 6 |
+ "crypto/tls" |
|
| 6 | 7 |
"fmt" |
| 7 | 8 |
"io" |
| 8 | 9 |
"os" |
| ... | ... |
@@ -21,6 +22,7 @@ import ( |
| 21 | 21 |
"github.com/docker/docker/pkg/signal" |
| 22 | 22 |
"github.com/docker/docker/pkg/system" |
| 23 | 23 |
"github.com/docker/docker/pkg/timeutils" |
| 24 |
+ "github.com/docker/docker/pkg/tlsconfig" |
|
| 24 | 25 |
"github.com/docker/docker/registry" |
| 25 | 26 |
"github.com/docker/docker/utils" |
| 26 | 27 |
) |
| ... | ... |
@@ -112,11 +114,17 @@ func mainDaemon() {
|
| 112 | 112 |
CorsHeaders: daemonCfg.CorsHeaders, |
| 113 | 113 |
Version: dockerversion.VERSION, |
| 114 | 114 |
SocketGroup: daemonCfg.SocketGroup, |
| 115 |
- Tls: *flTls, |
|
| 116 |
- TlsVerify: *flTlsVerify, |
|
| 117 |
- TlsCa: *flCa, |
|
| 118 |
- TlsCert: *flCert, |
|
| 119 |
- TlsKey: *flKey, |
|
| 115 |
+ } |
|
| 116 |
+ |
|
| 117 |
+ if *flTls {
|
|
| 118 |
+ if *flTlsVerify {
|
|
| 119 |
+ tlsOptions.ClientAuth = tls.RequireAndVerifyClientCert |
|
| 120 |
+ } |
|
| 121 |
+ tlsConfig, err := tlsconfig.Server(tlsOptions) |
|
| 122 |
+ if err != nil {
|
|
| 123 |
+ logrus.Fatal(err) |
|
| 124 |
+ } |
|
| 125 |
+ serverConfig.TLSConfig = tlsConfig |
|
| 120 | 126 |
} |
| 121 | 127 |
|
| 122 | 128 |
api := apiserver.New(serverConfig) |
| ... | ... |
@@ -2,9 +2,7 @@ package main |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"crypto/tls" |
| 5 |
- "crypto/x509" |
|
| 6 | 5 |
"fmt" |
| 7 |
- "io/ioutil" |
|
| 8 | 6 |
"os" |
| 9 | 7 |
"runtime" |
| 10 | 8 |
"strings" |
| ... | ... |
@@ -16,6 +14,7 @@ import ( |
| 16 | 16 |
flag "github.com/docker/docker/pkg/mflag" |
| 17 | 17 |
"github.com/docker/docker/pkg/reexec" |
| 18 | 18 |
"github.com/docker/docker/pkg/term" |
| 19 |
+ "github.com/docker/docker/pkg/tlsconfig" |
|
| 19 | 20 |
"github.com/docker/docker/utils" |
| 20 | 21 |
) |
| 21 | 22 |
|
| ... | ... |
@@ -85,6 +84,12 @@ func main() {
|
| 85 | 85 |
|
| 86 | 86 |
setDefaultConfFlag(flTrustKey, defaultTrustKeyFile) |
| 87 | 87 |
|
| 88 |
+ // Regardless of whether the user sets it to true or false, if they |
|
| 89 |
+ // specify --tlsverify at all then we need to turn on tls |
|
| 90 |
+ if flag.IsSet("-tlsverify") {
|
|
| 91 |
+ *flTls = true |
|
| 92 |
+ } |
|
| 93 |
+ |
|
| 88 | 94 |
if *flDaemon {
|
| 89 | 95 |
if *flHelp {
|
| 90 | 96 |
flag.Usage() |
| ... | ... |
@@ -94,59 +99,35 @@ func main() {
|
| 94 | 94 |
return |
| 95 | 95 |
} |
| 96 | 96 |
|
| 97 |
+ // From here on, we assume we're a client, not a server. |
|
| 98 |
+ |
|
| 97 | 99 |
if len(flHosts) > 1 {
|
| 98 | 100 |
fmt.Fprintf(os.Stderr, "Please specify only one -H") |
| 99 | 101 |
os.Exit(0) |
| 100 | 102 |
} |
| 101 | 103 |
protoAddrParts := strings.SplitN(flHosts[0], "://", 2) |
| 102 | 104 |
|
| 103 |
- var ( |
|
| 104 |
- cli *client.DockerCli |
|
| 105 |
- tlsConfig tls.Config |
|
| 106 |
- ) |
|
| 107 |
- tlsConfig.InsecureSkipVerify = true |
|
| 108 |
- |
|
| 109 |
- // Regardless of whether the user sets it to true or false, if they |
|
| 110 |
- // specify --tlsverify at all then we need to turn on tls |
|
| 111 |
- if flag.IsSet("-tlsverify") {
|
|
| 112 |
- *flTls = true |
|
| 113 |
- } |
|
| 114 |
- |
|
| 115 |
- // If we should verify the server, we need to load a trusted ca |
|
| 116 |
- if *flTlsVerify {
|
|
| 117 |
- certPool := x509.NewCertPool() |
|
| 118 |
- file, err := ioutil.ReadFile(*flCa) |
|
| 119 |
- if err != nil {
|
|
| 120 |
- fmt.Fprintf(os.Stderr, "Couldn't read ca cert %s: %s\n", *flCa, err) |
|
| 121 |
- os.Exit(1) |
|
| 105 |
+ var tlsConfig *tls.Config |
|
| 106 |
+ if *flTls {
|
|
| 107 |
+ tlsOptions.InsecureSkipVerify = !*flTlsVerify |
|
| 108 |
+ if !flag.IsSet("-tlscert") {
|
|
| 109 |
+ if _, err := os.Stat(tlsOptions.CertFile); os.IsNotExist(err) {
|
|
| 110 |
+ tlsOptions.CertFile = "" |
|
| 111 |
+ } |
|
| 122 | 112 |
} |
| 123 |
- certPool.AppendCertsFromPEM(file) |
|
| 124 |
- tlsConfig.RootCAs = certPool |
|
| 125 |
- tlsConfig.InsecureSkipVerify = false |
|
| 126 |
- } |
|
| 127 |
- |
|
| 128 |
- // If tls is enabled, try to load and send client certificates |
|
| 129 |
- if *flTls || *flTlsVerify {
|
|
| 130 |
- _, errCert := os.Stat(*flCert) |
|
| 131 |
- _, errKey := os.Stat(*flKey) |
|
| 132 |
- if errCert == nil && errKey == nil {
|
|
| 133 |
- *flTls = true |
|
| 134 |
- cert, err := tls.LoadX509KeyPair(*flCert, *flKey) |
|
| 135 |
- if err != nil {
|
|
| 136 |
- fmt.Fprintf(os.Stderr, "Couldn't load X509 key pair: %q. Make sure the key is encrypted\n", err) |
|
| 137 |
- os.Exit(1) |
|
| 113 |
+ if !flag.IsSet("-tlskey") {
|
|
| 114 |
+ if _, err := os.Stat(tlsOptions.KeyFile); os.IsNotExist(err) {
|
|
| 115 |
+ tlsOptions.KeyFile = "" |
|
| 138 | 116 |
} |
| 139 |
- tlsConfig.Certificates = []tls.Certificate{cert}
|
|
| 140 | 117 |
} |
| 141 |
- // Avoid fallback to SSL protocols < TLS1.0 |
|
| 142 |
- tlsConfig.MinVersion = tls.VersionTLS10 |
|
| 143 |
- } |
|
| 144 |
- |
|
| 145 |
- if *flTls || *flTlsVerify {
|
|
| 146 |
- cli = client.NewDockerCli(stdin, stdout, stderr, *flTrustKey, protoAddrParts[0], protoAddrParts[1], &tlsConfig) |
|
| 147 |
- } else {
|
|
| 148 |
- cli = client.NewDockerCli(stdin, stdout, stderr, *flTrustKey, protoAddrParts[0], protoAddrParts[1], nil) |
|
| 118 |
+ var err error |
|
| 119 |
+ tlsConfig, err = tlsconfig.Client(tlsOptions) |
|
| 120 |
+ if err != nil {
|
|
| 121 |
+ fmt.Fprintln(stderr, err) |
|
| 122 |
+ os.Exit(1) |
|
| 123 |
+ } |
|
| 149 | 124 |
} |
| 125 |
+ cli := client.NewDockerCli(stdin, stdout, stderr, *flTrustKey, protoAddrParts[0], protoAddrParts[1], tlsConfig) |
|
| 150 | 126 |
|
| 151 | 127 |
if err := cli.Cmd(flag.Args()...); err != nil {
|
| 152 | 128 |
if sterr, ok := err.(client.StatusError); ok {
|
| ... | ... |
@@ -10,6 +10,7 @@ import ( |
| 10 | 10 |
"github.com/docker/docker/opts" |
| 11 | 11 |
"github.com/docker/docker/pkg/homedir" |
| 12 | 12 |
flag "github.com/docker/docker/pkg/mflag" |
| 13 |
+ "github.com/docker/docker/pkg/tlsconfig" |
|
| 13 | 14 |
) |
| 14 | 15 |
|
| 15 | 16 |
type command struct {
|
| ... | ... |
@@ -94,10 +95,8 @@ var ( |
| 94 | 94 |
flTlsVerify = flag.Bool([]string{"-tlsverify"}, dockerTlsVerify, "Use TLS and verify the remote")
|
| 95 | 95 |
|
| 96 | 96 |
// these are initialized in init() below since their default values depend on dockerCertPath which isn't fully initialized until init() runs |
| 97 |
+ tlsOptions tlsconfig.Options |
|
| 97 | 98 |
flTrustKey *string |
| 98 |
- flCa *string |
|
| 99 |
- flCert *string |
|
| 100 |
- flKey *string |
|
| 101 | 99 |
flHosts []string |
| 102 | 100 |
) |
| 103 | 101 |
|
| ... | ... |
@@ -116,9 +115,9 @@ func init() {
|
| 116 | 116 |
// TODO use flag flag.String([]string{"i", "-identity"}, "", "Path to libtrust key file")
|
| 117 | 117 |
flTrustKey = &placeholderTrustKey |
| 118 | 118 |
|
| 119 |
- flCa = flag.String([]string{"-tlscacert"}, filepath.Join(dockerCertPath, defaultCaFile), "Trust certs signed only by this CA")
|
|
| 120 |
- flCert = flag.String([]string{"-tlscert"}, filepath.Join(dockerCertPath, defaultCertFile), "Path to TLS certificate file")
|
|
| 121 |
- flKey = flag.String([]string{"-tlskey"}, filepath.Join(dockerCertPath, defaultKeyFile), "Path to TLS key file")
|
|
| 119 |
+ flag.StringVar(&tlsOptions.CAFile, []string{"-tlscacert"}, filepath.Join(dockerCertPath, defaultCaFile), "Trust certs signed only by this CA")
|
|
| 120 |
+ flag.StringVar(&tlsOptions.CertFile, []string{"-tlscert"}, filepath.Join(dockerCertPath, defaultCertFile), "Path to TLS certificate file")
|
|
| 121 |
+ flag.StringVar(&tlsOptions.KeyFile, []string{"-tlskey"}, filepath.Join(dockerCertPath, defaultKeyFile), "Path to TLS key file")
|
|
| 122 | 122 |
opts.HostListVar(&flHosts, []string{"H", "-host"}, "Daemon socket(s) to connect to")
|
| 123 | 123 |
|
| 124 | 124 |
flag.Usage = func() {
|
| ... | ... |
@@ -2,68 +2,19 @@ package sockets |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"crypto/tls" |
| 5 |
- "crypto/x509" |
|
| 6 |
- "fmt" |
|
| 7 |
- "io/ioutil" |
|
| 8 | 5 |
"net" |
| 9 |
- "os" |
|
| 10 | 6 |
|
| 11 | 7 |
"github.com/docker/docker/pkg/listenbuffer" |
| 12 | 8 |
) |
| 13 | 9 |
|
| 14 |
-type TlsConfig struct {
|
|
| 15 |
- CA string |
|
| 16 |
- Certificate string |
|
| 17 |
- Key string |
|
| 18 |
- Verify bool |
|
| 19 |
-} |
|
| 20 |
- |
|
| 21 |
-func NewTlsConfig(tlsCert, tlsKey, tlsCA string, verify bool) *TlsConfig {
|
|
| 22 |
- return &TlsConfig{
|
|
| 23 |
- Verify: verify, |
|
| 24 |
- Certificate: tlsCert, |
|
| 25 |
- Key: tlsKey, |
|
| 26 |
- CA: tlsCA, |
|
| 27 |
- } |
|
| 28 |
-} |
|
| 29 |
- |
|
| 30 |
-func NewTcpSocket(addr string, config *TlsConfig, activate <-chan struct{}) (net.Listener, error) {
|
|
| 10 |
+func NewTcpSocket(addr string, tlsConfig *tls.Config, activate <-chan struct{}) (net.Listener, error) {
|
|
| 31 | 11 |
l, err := listenbuffer.NewListenBuffer("tcp", addr, activate)
|
| 32 | 12 |
if err != nil {
|
| 33 | 13 |
return nil, err |
| 34 | 14 |
} |
| 35 |
- if config != nil {
|
|
| 36 |
- if l, err = setupTls(l, config); err != nil {
|
|
| 37 |
- return nil, err |
|
| 38 |
- } |
|
| 15 |
+ if tlsConfig != nil {
|
|
| 16 |
+ tlsConfig.NextProtos = []string{"http/1.1"}
|
|
| 17 |
+ l = tls.NewListener(l, tlsConfig) |
|
| 39 | 18 |
} |
| 40 | 19 |
return l, nil |
| 41 | 20 |
} |
| 42 |
- |
|
| 43 |
-func setupTls(l net.Listener, config *TlsConfig) (net.Listener, error) {
|
|
| 44 |
- tlsCert, err := tls.LoadX509KeyPair(config.Certificate, config.Key) |
|
| 45 |
- if err != nil {
|
|
| 46 |
- if os.IsNotExist(err) {
|
|
| 47 |
- return nil, fmt.Errorf("Could not load X509 key pair (%s, %s): %v", config.Certificate, config.Key, err)
|
|
| 48 |
- } |
|
| 49 |
- return nil, fmt.Errorf("Error reading X509 key pair (%s, %s): %q. Make sure the key is encrypted.",
|
|
| 50 |
- config.Certificate, config.Key, err) |
|
| 51 |
- } |
|
| 52 |
- tlsConfig := &tls.Config{
|
|
| 53 |
- NextProtos: []string{"http/1.1"},
|
|
| 54 |
- Certificates: []tls.Certificate{tlsCert},
|
|
| 55 |
- // Avoid fallback on insecure SSL protocols |
|
| 56 |
- MinVersion: tls.VersionTLS10, |
|
| 57 |
- } |
|
| 58 |
- if config.CA != "" {
|
|
| 59 |
- certPool := x509.NewCertPool() |
|
| 60 |
- file, err := ioutil.ReadFile(config.CA) |
|
| 61 |
- if err != nil {
|
|
| 62 |
- return nil, fmt.Errorf("Could not read CA certificate: %v", err)
|
|
| 63 |
- } |
|
| 64 |
- certPool.AppendCertsFromPEM(file) |
|
| 65 |
- tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert |
|
| 66 |
- tlsConfig.ClientCAs = certPool |
|
| 67 |
- } |
|
| 68 |
- return tls.NewListener(l, tlsConfig), nil |
|
| 69 |
-} |
| 70 | 21 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,107 @@ |
| 0 |
+// Package tlsconfig provides primitives to retrieve secure-enough TLS configurations for both clients and servers. |
|
| 1 |
+// |
|
| 2 |
+// As a reminder from https://golang.org/pkg/crypto/tls/#Config: |
|
| 3 |
+// A Config structure is used to configure a TLS client or server. After one has been passed to a TLS function it must not be modified. |
|
| 4 |
+// A Config may be reused; the tls package will also not modify it. |
|
| 5 |
+package tlsconfig |
|
| 6 |
+ |
|
| 7 |
+import ( |
|
| 8 |
+ "crypto/tls" |
|
| 9 |
+ "crypto/x509" |
|
| 10 |
+ "fmt" |
|
| 11 |
+ "io/ioutil" |
|
| 12 |
+ "os" |
|
| 13 |
+ |
|
| 14 |
+ "github.com/Sirupsen/logrus" |
|
| 15 |
+) |
|
| 16 |
+ |
|
| 17 |
+// Options represents the information needed to create client and server TLS configurations. |
|
| 18 |
+type Options struct {
|
|
| 19 |
+ InsecureSkipVerify bool |
|
| 20 |
+ ClientAuth tls.ClientAuthType |
|
| 21 |
+ CAFile string |
|
| 22 |
+ CertFile string |
|
| 23 |
+ KeyFile string |
|
| 24 |
+} |
|
| 25 |
+ |
|
| 26 |
+// Default is a secure-enough TLS configuration. |
|
| 27 |
+var Default = tls.Config{
|
|
| 28 |
+ // Avoid fallback to SSL protocols < TLS1.0 |
|
| 29 |
+ MinVersion: tls.VersionTLS10, |
|
| 30 |
+ PreferServerCipherSuites: true, |
|
| 31 |
+ CipherSuites: []uint16{
|
|
| 32 |
+ tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, |
|
| 33 |
+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, |
|
| 34 |
+ tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, |
|
| 35 |
+ tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, |
|
| 36 |
+ tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, |
|
| 37 |
+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, |
|
| 38 |
+ tls.TLS_RSA_WITH_AES_128_CBC_SHA, |
|
| 39 |
+ tls.TLS_RSA_WITH_AES_256_CBC_SHA, |
|
| 40 |
+ }, |
|
| 41 |
+} |
|
| 42 |
+ |
|
| 43 |
+// certPool returns an X.509 certificate pool from `caFile`, the certificate file. |
|
| 44 |
+func certPool(caFile string) (*x509.CertPool, error) {
|
|
| 45 |
+ // If we should verify the server, we need to load a trusted ca |
|
| 46 |
+ certPool := x509.NewCertPool() |
|
| 47 |
+ pem, err := ioutil.ReadFile(caFile) |
|
| 48 |
+ if err != nil {
|
|
| 49 |
+ return nil, fmt.Errorf("Could not read CA certificate %s: %v", caFile, err)
|
|
| 50 |
+ } |
|
| 51 |
+ if !certPool.AppendCertsFromPEM(pem) {
|
|
| 52 |
+ return nil, fmt.Errorf("failed to append certificates from PEM file: %s", caFile)
|
|
| 53 |
+ } |
|
| 54 |
+ s := certPool.Subjects() |
|
| 55 |
+ subjects := make([]string, len(s)) |
|
| 56 |
+ for i, subject := range s {
|
|
| 57 |
+ subjects[i] = string(subject) |
|
| 58 |
+ } |
|
| 59 |
+ logrus.Debugf("Trusting certs with subjects: %v", subjects)
|
|
| 60 |
+ return certPool, nil |
|
| 61 |
+} |
|
| 62 |
+ |
|
| 63 |
+// Client returns a TLS configuration meant to be used by a client. |
|
| 64 |
+func Client(options Options) (*tls.Config, error) {
|
|
| 65 |
+ tlsConfig := Default |
|
| 66 |
+ tlsConfig.InsecureSkipVerify = options.InsecureSkipVerify |
|
| 67 |
+ if !options.InsecureSkipVerify {
|
|
| 68 |
+ CAs, err := certPool(options.CAFile) |
|
| 69 |
+ if err != nil {
|
|
| 70 |
+ return nil, err |
|
| 71 |
+ } |
|
| 72 |
+ tlsConfig.RootCAs = CAs |
|
| 73 |
+ } |
|
| 74 |
+ |
|
| 75 |
+ if options.CertFile != "" && options.KeyFile != "" {
|
|
| 76 |
+ tlsCert, err := tls.LoadX509KeyPair(options.CertFile, options.KeyFile) |
|
| 77 |
+ if err != nil {
|
|
| 78 |
+ return nil, fmt.Errorf("Could not load X509 key pair: %v. Make sure the key is not encrypted", err)
|
|
| 79 |
+ } |
|
| 80 |
+ tlsConfig.Certificates = []tls.Certificate{tlsCert}
|
|
| 81 |
+ } |
|
| 82 |
+ |
|
| 83 |
+ return &tlsConfig, nil |
|
| 84 |
+} |
|
| 85 |
+ |
|
| 86 |
+// Server returns a TLS configuration meant to be used by a server. |
|
| 87 |
+func Server(options Options) (*tls.Config, error) {
|
|
| 88 |
+ tlsConfig := Default |
|
| 89 |
+ tlsConfig.ClientAuth = options.ClientAuth |
|
| 90 |
+ tlsCert, err := tls.LoadX509KeyPair(options.CertFile, options.KeyFile) |
|
| 91 |
+ if err != nil {
|
|
| 92 |
+ if os.IsNotExist(err) {
|
|
| 93 |
+ return nil, fmt.Errorf("Could not load X509 key pair (%s, %s): %v", options.CertFile, options.KeyFile, err)
|
|
| 94 |
+ } |
|
| 95 |
+ return nil, fmt.Errorf("Error reading X509 key pair (%s, %s): %v. Make sure the key is not encrypted.", options.CertFile, options.KeyFile, err)
|
|
| 96 |
+ } |
|
| 97 |
+ tlsConfig.Certificates = []tls.Certificate{tlsCert}
|
|
| 98 |
+ if options.ClientAuth >= tls.VerifyClientCertIfGiven {
|
|
| 99 |
+ CAs, err := certPool(options.CAFile) |
|
| 100 |
+ if err != nil {
|
|
| 101 |
+ return nil, err |
|
| 102 |
+ } |
|
| 103 |
+ tlsConfig.ClientCAs = CAs |
|
| 104 |
+ } |
|
| 105 |
+ return &tlsConfig, nil |
|
| 106 |
+} |