github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/security/tls.go (about)

     1  // Copyright 2014 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package security
    12  
    13  import (
    14  	"crypto/tls"
    15  	"crypto/x509"
    16  
    17  	"github.com/cockroachdb/errors"
    18  )
    19  
    20  // EmbeddedCertsDir is the certs directory inside embedded assets.
    21  // Embedded*{Cert,Key} are the filenames for embedded certs.
    22  const (
    23  	EmbeddedCertsDir     = "test_certs"
    24  	EmbeddedCACert       = "ca.crt"
    25  	EmbeddedCAKey        = "ca.key"
    26  	EmbeddedClientCACert = "ca-client.crt"
    27  	EmbeddedClientCAKey  = "ca-client.key"
    28  	EmbeddedUICACert     = "ca-ui.crt"
    29  	EmbeddedUICAKey      = "ca-ui.key"
    30  	EmbeddedNodeCert     = "node.crt"
    31  	EmbeddedNodeKey      = "node.key"
    32  	EmbeddedRootCert     = "client.root.crt"
    33  	EmbeddedRootKey      = "client.root.key"
    34  	EmbeddedTestUserCert = "client.testuser.crt"
    35  	EmbeddedTestUserKey  = "client.testuser.key"
    36  )
    37  
    38  // LoadServerTLSConfig creates a server TLSConfig by loading the CA and server certs.
    39  // The following paths must be passed:
    40  // - sslCA: path to the CA certificate
    41  // - sslClientCA: path to the CA certificate to verify client certificates,
    42  //                can be the same as sslCA
    43  // - sslCert: path to the server certificate
    44  // - sslCertKey: path to the server key
    45  // If the path is prefixed with "embedded=", load the embedded certs.
    46  func LoadServerTLSConfig(sslCA, sslClientCA, sslCert, sslCertKey string) (*tls.Config, error) {
    47  	certPEM, err := assetLoaderImpl.ReadFile(sslCert)
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  	keyPEM, err := assetLoaderImpl.ReadFile(sslCertKey)
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  	caPEM, err := assetLoaderImpl.ReadFile(sslCA)
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  	clientCAPEM, err := assetLoaderImpl.ReadFile(sslClientCA)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	return newServerTLSConfig(certPEM, keyPEM, caPEM, clientCAPEM)
    64  }
    65  
    66  // newServerTLSConfig creates a server TLSConfig from the supplied byte strings containing
    67  // - the certificate of this node (should be signed by the CA),
    68  // - the private key of this node.
    69  // - the certificate of the cluster CA, used to verify other server certificates
    70  // - the certificate of the client CA, used to verify client certificates
    71  //
    72  // caClientPEM can be equal to caPEM (shared CA) or nil (use system CA pool).
    73  func newServerTLSConfig(certPEM, keyPEM, caPEM, caClientPEM []byte) (*tls.Config, error) {
    74  	cfg, err := newBaseTLSConfigWithCertificate(certPEM, keyPEM, caPEM)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	cfg.ClientAuth = tls.VerifyClientCertIfGiven
    79  
    80  	if caClientPEM != nil {
    81  		certPool := x509.NewCertPool()
    82  
    83  		if !certPool.AppendCertsFromPEM(caClientPEM) {
    84  			return nil, errors.Errorf("failed to parse client CA PEM data to pool")
    85  		}
    86  		cfg.ClientCAs = certPool
    87  	}
    88  
    89  	// Use the default cipher suite from golang (RC4 is going away in 1.5).
    90  	// Prefer the server-specified suite.
    91  	cfg.PreferServerCipherSuites = true
    92  	// Should we disable session resumption? This may break forward secrecy.
    93  	// cfg.SessionTicketsDisabled = true
    94  	return cfg, nil
    95  }
    96  
    97  // newUIServerTLSConfig creates a server TLSConfig for the Admin UI. It does not
    98  // use client authentication or a CA.
    99  // It needs:
   100  // - the server certificate (should be signed by the CA used by HTTP clients to the admin UI)
   101  // - the private key for the certificate
   102  func newUIServerTLSConfig(certPEM, keyPEM []byte) (*tls.Config, error) {
   103  	cfg, err := newBaseTLSConfigWithCertificate(certPEM, keyPEM, nil)
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  
   108  	// Use the default cipher suite from golang (RC4 is going away in 1.5).
   109  	// Prefer the server-specified suite.
   110  	cfg.PreferServerCipherSuites = true
   111  	// Should we disable session resumption? This may break forward secrecy.
   112  	// cfg.SessionTicketsDisabled = true
   113  	return cfg, nil
   114  }
   115  
   116  // LoadClientTLSConfig creates a client TLSConfig by loading the CA and client certs.
   117  // The following paths must be passed:
   118  // - sslCA: path to the CA certificate
   119  // - sslCert: path to the client certificate
   120  // - sslCertKey: path to the client key
   121  // If the path is prefixed with "embedded=", load the embedded certs.
   122  func LoadClientTLSConfig(sslCA, sslCert, sslCertKey string) (*tls.Config, error) {
   123  	certPEM, err := assetLoaderImpl.ReadFile(sslCert)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  	keyPEM, err := assetLoaderImpl.ReadFile(sslCertKey)
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  	caPEM, err := assetLoaderImpl.ReadFile(sslCA)
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  
   136  	return newClientTLSConfig(certPEM, keyPEM, caPEM)
   137  }
   138  
   139  // newClientTLSConfig creates a client TLSConfig from the supplied byte strings containing:
   140  // - the certificate of this client (should be signed by the CA),
   141  // - the private key of this client.
   142  // - the certificate of the cluster CA (use system cert pool if nil)
   143  func newClientTLSConfig(certPEM, keyPEM, caPEM []byte) (*tls.Config, error) {
   144  	return newBaseTLSConfigWithCertificate(certPEM, keyPEM, caPEM)
   145  }
   146  
   147  // newUIClientTLSConfig creates a client TLSConfig to talk to the Admin UI.
   148  // It does not include client certificates and takes an optional CA certificate.
   149  func newUIClientTLSConfig(caPEM []byte) (*tls.Config, error) {
   150  	return newBaseTLSConfig(caPEM)
   151  }
   152  
   153  // newBaseTLSConfigWithCertificate returns a tls.Config initialized with the
   154  // passed-in certificate and optional CA certificate.
   155  func newBaseTLSConfigWithCertificate(certPEM, keyPEM, caPEM []byte) (*tls.Config, error) {
   156  	cert, err := tls.X509KeyPair(certPEM, keyPEM)
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  
   161  	cfg, err := newBaseTLSConfig(caPEM)
   162  	if err != nil {
   163  		return nil, err
   164  	}
   165  
   166  	cfg.Certificates = []tls.Certificate{cert}
   167  	return cfg, nil
   168  }
   169  
   170  // newBaseTLSConfig returns a tls.Config. If caPEM != nil, it is set in RootCAs.
   171  func newBaseTLSConfig(caPEM []byte) (*tls.Config, error) {
   172  	var certPool *x509.CertPool
   173  	if caPEM != nil {
   174  		certPool = x509.NewCertPool()
   175  
   176  		if !certPool.AppendCertsFromPEM(caPEM) {
   177  			return nil, errors.Errorf("failed to parse PEM data to pool")
   178  		}
   179  	}
   180  
   181  	return &tls.Config{
   182  		RootCAs: certPool,
   183  
   184  		// This is Go's default list of cipher suites (as of go 1.8.3),
   185  		// with the following differences:
   186  		// - 3DES-based cipher suites have been removed. This cipher is
   187  		//   vulnerable to the Sweet32 attack and is sometimes reported by
   188  		//   security scanners. (This is arguably a false positive since
   189  		//   it will never be selected: Any TLS1.2 implementation MUST
   190  		//   include at least one cipher higher in the priority list, but
   191  		//   there's also no reason to keep it around)
   192  		// - AES is always prioritized over ChaCha20. Go makes this decision
   193  		//   by default based on the presence or absence of hardware AES
   194  		//   acceleration.
   195  		//   TODO(bdarnell): do the same detection here. See
   196  		//   https://github.com/golang/go/issues/21167
   197  		//
   198  		// Note that some TLS cipher suite guidance (such as Mozilla's[1])
   199  		// recommend replacing the CBC_SHA suites below with CBC_SHA384 or
   200  		// CBC_SHA256 variants. We do not do this because Go does not
   201  		// currerntly implement the CBC_SHA384 suites, and its CBC_SHA256
   202  		// implementation is vulnerable to the Lucky13 attack and is disabled
   203  		// by default.[2]
   204  		//
   205  		// [1]: https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
   206  		// [2]: https://github.com/golang/go/commit/48d8edb5b21db190f717e035b4d9ab61a077f9d7
   207  		CipherSuites: []uint16{
   208  			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
   209  			tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
   210  			tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
   211  			tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
   212  			tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
   213  			tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
   214  			tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
   215  			tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
   216  			tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
   217  			tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
   218  			tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
   219  			tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
   220  			tls.TLS_RSA_WITH_AES_128_CBC_SHA,
   221  			tls.TLS_RSA_WITH_AES_256_CBC_SHA,
   222  		},
   223  
   224  		MinVersion: tls.VersionTLS12,
   225  	}, nil
   226  }