github.com/chenchun/docker@v1.3.2-0.20150629222414-20467faf132b/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  	InsecureSkipVerify bool
    21  	ClientAuth         tls.ClientAuthType
    22  	CAFile             string
    23  	CertFile           string
    24  	KeyFile            string
    25  }
    26  
    27  // Extra (server-side) accepted CBC cipher suites - will phase out in the future
    28  var acceptedCBCCiphers = []uint16{
    29  	tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
    30  	tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
    31  	tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
    32  	tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
    33  	tls.TLS_RSA_WITH_AES_256_CBC_SHA,
    34  	tls.TLS_RSA_WITH_AES_128_CBC_SHA,
    35  }
    36  
    37  // Client TLS cipher suites (dropping CBC ciphers for client preferred suite set)
    38  var clientCipherSuites = []uint16{
    39  	tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
    40  	tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
    41  }
    42  
    43  // For use by code which already has a crypto/tls options struct but wants to
    44  // use a commonly accepted set of TLS cipher suites, with known weak algorithms removed
    45  var DefaultServerAcceptedCiphers = append(clientCipherSuites, acceptedCBCCiphers...)
    46  
    47  // ServerDefault is a secure-enough TLS configuration for the server TLS configuration.
    48  var ServerDefault = tls.Config{
    49  	// Avoid fallback to SSL protocols < TLS1.0
    50  	MinVersion:               tls.VersionTLS10,
    51  	PreferServerCipherSuites: true,
    52  	CipherSuites:             DefaultServerAcceptedCiphers,
    53  }
    54  
    55  // ClientDefault is a secure-enough TLS configuration for the client TLS configuration.
    56  var ClientDefault = tls.Config{
    57  	// Prefer TLS1.2 as the client minimum
    58  	MinVersion:   tls.VersionTLS12,
    59  	CipherSuites: clientCipherSuites,
    60  }
    61  
    62  // certPool returns an X.509 certificate pool from `caFile`, the certificate file.
    63  func certPool(caFile string) (*x509.CertPool, error) {
    64  	// If we should verify the server, we need to load a trusted ca
    65  	certPool := x509.NewCertPool()
    66  	pem, err := ioutil.ReadFile(caFile)
    67  	if err != nil {
    68  		return nil, fmt.Errorf("Could not read CA certificate %s: %v", caFile, err)
    69  	}
    70  	if !certPool.AppendCertsFromPEM(pem) {
    71  		return nil, fmt.Errorf("failed to append certificates from PEM file: %s", caFile)
    72  	}
    73  	s := certPool.Subjects()
    74  	subjects := make([]string, len(s))
    75  	for i, subject := range s {
    76  		subjects[i] = string(subject)
    77  	}
    78  	logrus.Debugf("Trusting certs with subjects: %v", subjects)
    79  	return certPool, nil
    80  }
    81  
    82  // Client returns a TLS configuration meant to be used by a client.
    83  func Client(options Options) (*tls.Config, error) {
    84  	tlsConfig := ClientDefault
    85  	tlsConfig.InsecureSkipVerify = options.InsecureSkipVerify
    86  	if !options.InsecureSkipVerify {
    87  		CAs, err := certPool(options.CAFile)
    88  		if err != nil {
    89  			return nil, err
    90  		}
    91  		tlsConfig.RootCAs = CAs
    92  	}
    93  
    94  	if options.CertFile != "" && options.KeyFile != "" {
    95  		tlsCert, err := tls.LoadX509KeyPair(options.CertFile, options.KeyFile)
    96  		if err != nil {
    97  			return nil, fmt.Errorf("Could not load X509 key pair: %v. Make sure the key is not encrypted", err)
    98  		}
    99  		tlsConfig.Certificates = []tls.Certificate{tlsCert}
   100  	}
   101  
   102  	return &tlsConfig, nil
   103  }
   104  
   105  // Server returns a TLS configuration meant to be used by a server.
   106  func Server(options Options) (*tls.Config, error) {
   107  	tlsConfig := ServerDefault
   108  	tlsConfig.ClientAuth = options.ClientAuth
   109  	tlsCert, err := tls.LoadX509KeyPair(options.CertFile, options.KeyFile)
   110  	if err != nil {
   111  		if os.IsNotExist(err) {
   112  			return nil, fmt.Errorf("Could not load X509 key pair (%s, %s): %v", options.CertFile, options.KeyFile, err)
   113  		}
   114  		return nil, fmt.Errorf("Error reading X509 key pair (%s, %s): %v. Make sure the key is not encrypted.", options.CertFile, options.KeyFile, err)
   115  	}
   116  	tlsConfig.Certificates = []tls.Certificate{tlsCert}
   117  	if options.ClientAuth >= tls.VerifyClientCertIfGiven {
   118  		CAs, err := certPool(options.CAFile)
   119  		if err != nil {
   120  			return nil, err
   121  		}
   122  		tlsConfig.ClientCAs = CAs
   123  	}
   124  	return &tlsConfig, nil
   125  }