github.com/robertojrojas/docker@v1.9.1/pkg/tlsconfig/config.go (about)

     1  // Package tlsconfig provides primitives to retrieve secure-enough TLS configurations for both clients and servers.
     2  //
     3  // As a reminder from https://golang.org/pkg/crypto/tls/#Config:
     4  //	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.
     5  //	A Config may be reused; the tls package will also not modify it.
     6  package tlsconfig
     7  
     8  import (
     9  	"crypto/tls"
    10  	"crypto/x509"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"os"
    14  
    15  	"github.com/Sirupsen/logrus"
    16  )
    17  
    18  // Options represents the information needed to create client and server TLS configurations.
    19  type Options struct {
    20  	CAFile string
    21  
    22  	// If either CertFile or KeyFile is empty, Client() will not load them
    23  	// preventing the client from authenticating to the server.
    24  	// However, Server() requires them and will error out if they are empty.
    25  	CertFile string
    26  	KeyFile  string
    27  
    28  	// client-only option
    29  	InsecureSkipVerify bool
    30  	// server-only option
    31  	ClientAuth tls.ClientAuthType
    32  }
    33  
    34  // Extra (server-side) accepted CBC cipher suites - will phase out in the future
    35  var acceptedCBCCiphers = []uint16{
    36  	tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
    37  	tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
    38  	tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
    39  	tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
    40  	tls.TLS_RSA_WITH_AES_256_CBC_SHA,
    41  	tls.TLS_RSA_WITH_AES_128_CBC_SHA,
    42  }
    43  
    44  // Client TLS cipher suites (dropping CBC ciphers for client preferred suite set)
    45  var clientCipherSuites = []uint16{
    46  	tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
    47  	tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
    48  }
    49  
    50  // For use by code which already has a crypto/tls options struct but wants to
    51  // use a commonly accepted set of TLS cipher suites, with known weak algorithms removed
    52  var DefaultServerAcceptedCiphers = append(clientCipherSuites, acceptedCBCCiphers...)
    53  
    54  // ServerDefault is a secure-enough TLS configuration for the server TLS configuration.
    55  var ServerDefault = tls.Config{
    56  	// Avoid fallback to SSL protocols < TLS1.0
    57  	MinVersion:               tls.VersionTLS10,
    58  	PreferServerCipherSuites: true,
    59  	CipherSuites:             DefaultServerAcceptedCiphers,
    60  }
    61  
    62  // ClientDefault is a secure-enough TLS configuration for the client TLS configuration.
    63  var ClientDefault = tls.Config{
    64  	// Prefer TLS1.2 as the client minimum
    65  	MinVersion:   tls.VersionTLS12,
    66  	CipherSuites: clientCipherSuites,
    67  }
    68  
    69  // certPool returns an X.509 certificate pool from `caFile`, the certificate file.
    70  func certPool(caFile string) (*x509.CertPool, error) {
    71  	// If we should verify the server, we need to load a trusted ca
    72  	certPool := x509.NewCertPool()
    73  	pem, err := ioutil.ReadFile(caFile)
    74  	if err != nil {
    75  		return nil, fmt.Errorf("Could not read CA certificate %q: %v", caFile, err)
    76  	}
    77  	if !certPool.AppendCertsFromPEM(pem) {
    78  		return nil, fmt.Errorf("failed to append certificates from PEM file: %q", caFile)
    79  	}
    80  	s := certPool.Subjects()
    81  	subjects := make([]string, len(s))
    82  	for i, subject := range s {
    83  		subjects[i] = string(subject)
    84  	}
    85  	logrus.Debugf("Trusting certs with subjects: %v", subjects)
    86  	return certPool, nil
    87  }
    88  
    89  // Client returns a TLS configuration meant to be used by a client.
    90  func Client(options Options) (*tls.Config, error) {
    91  	tlsConfig := ClientDefault
    92  	tlsConfig.InsecureSkipVerify = options.InsecureSkipVerify
    93  	if !options.InsecureSkipVerify {
    94  		CAs, err := certPool(options.CAFile)
    95  		if err != nil {
    96  			return nil, err
    97  		}
    98  		tlsConfig.RootCAs = CAs
    99  	}
   100  
   101  	if options.CertFile != "" && options.KeyFile != "" {
   102  		tlsCert, err := tls.LoadX509KeyPair(options.CertFile, options.KeyFile)
   103  		if err != nil {
   104  			return nil, fmt.Errorf("Could not load X509 key pair: %v. Make sure the key is not encrypted", err)
   105  		}
   106  		tlsConfig.Certificates = []tls.Certificate{tlsCert}
   107  	}
   108  
   109  	return &tlsConfig, nil
   110  }
   111  
   112  // Server returns a TLS configuration meant to be used by a server.
   113  func Server(options Options) (*tls.Config, error) {
   114  	tlsConfig := ServerDefault
   115  	tlsConfig.ClientAuth = options.ClientAuth
   116  	tlsCert, err := tls.LoadX509KeyPair(options.CertFile, options.KeyFile)
   117  	if err != nil {
   118  		if os.IsNotExist(err) {
   119  			return nil, fmt.Errorf("Could not load X509 key pair (cert: %q, key: %q): %v", options.CertFile, options.KeyFile, err)
   120  		}
   121  		return nil, fmt.Errorf("Error reading X509 key pair (cert: %q, key: %q): %v. Make sure the key is not encrypted.", options.CertFile, options.KeyFile, err)
   122  	}
   123  	tlsConfig.Certificates = []tls.Certificate{tlsCert}
   124  	if options.ClientAuth >= tls.VerifyClientCertIfGiven {
   125  		CAs, err := certPool(options.CAFile)
   126  		if err != nil {
   127  			return nil, err
   128  		}
   129  		tlsConfig.ClientCAs = CAs
   130  	}
   131  	return &tlsConfig, nil
   132  }