github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/helper/tlsutil/config_test.go (about)

     1  package tlsutil
     2  
     3  import (
     4  	"crypto/tls"
     5  	"crypto/x509"
     6  	"fmt"
     7  	"io"
     8  	"net"
     9  	"os"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/hashicorp/nomad/ci"
    14  	"github.com/hashicorp/nomad/nomad/structs/config"
    15  	"github.com/hashicorp/yamux"
    16  	"github.com/stretchr/testify/assert"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  const (
    21  	// See README.md for documentation
    22  	cacert  = "./testdata/ca.pem"
    23  	foocert = "./testdata/nomad-foo.pem"
    24  	fookey  = "./testdata/nomad-foo-key.pem"
    25  	badcert = "./testdata/nomad-bad.pem"
    26  	badkey  = "./testdata/nomad-bad-key.pem"
    27  )
    28  
    29  func TestConfig_AppendCA_None(t *testing.T) {
    30  	ci.Parallel(t)
    31  
    32  	require := require.New(t)
    33  
    34  	conf := &Config{}
    35  	pool := x509.NewCertPool()
    36  	err := conf.AppendCA(pool)
    37  
    38  	require.Nil(err)
    39  }
    40  
    41  func TestConfig_AppendCA_Valid(t *testing.T) {
    42  	ci.Parallel(t)
    43  
    44  	require := require.New(t)
    45  
    46  	conf := &Config{
    47  		CAFile: cacert,
    48  	}
    49  	pool := x509.NewCertPool()
    50  	err := conf.AppendCA(pool)
    51  
    52  	require.Nil(err)
    53  }
    54  
    55  func TestConfig_AppendCA_Valid_MultipleCerts(t *testing.T) {
    56  	ci.Parallel(t)
    57  
    58  	require := require.New(t)
    59  
    60  	certs := `
    61  -----BEGIN CERTIFICATE-----
    62  MIICMzCCAdqgAwIBAgIUNZ9L86Xp9EuDH0/qyAesh599LXQwCgYIKoZIzj0EAwIw
    63  eDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh
    64  biBGcmFuY2lzY28xEjAQBgNVBAoTCUhhc2hpQ29ycDEOMAwGA1UECxMFTm9tYWQx
    65  GDAWBgNVBAMTD25vbWFkLmhhc2hpY29ycDAeFw0xNjExMTAxOTQ4MDBaFw0yMTEx
    66  MDkxOTQ4MDBaMHgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYw
    67  FAYDVQQHEw1TYW4gRnJhbmNpc2NvMRIwEAYDVQQKEwlIYXNoaUNvcnAxDjAMBgNV
    68  BAsTBU5vbWFkMRgwFgYDVQQDEw9ub21hZC5oYXNoaWNvcnAwWTATBgcqhkjOPQIB
    69  BggqhkjOPQMBBwNCAARfJmTdHzYIMPD8SK+kj5Gc79fmpOcg6wnb4JNVwCqWw9O+
    70  uNdZJZWSi4Q/4HojM5FTSBqYxNgSrmY/o3oQrCPlo0IwQDAOBgNVHQ8BAf8EBAMC
    71  AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOjVq/BectnhcKn6EHUD4NJFm
    72  /UAwCgYIKoZIzj0EAwIDRwAwRAIgTemDJGSGtcQPXLWKiQNw4SKO9wAPhn/WoKW4
    73  Ln2ZUe8CIDsQswBQS7URbqnKYDye2Y4befJkr4fmhhmMQb2ex9A4
    74  -----END CERTIFICATE-----
    75  -----BEGIN CERTIFICATE-----
    76  MIICNTCCAZagAwIBAgIRANjgoh5iVZI26+Hz/K65G0UwCgYIKoZIzj0EAwQwNjEb
    77  MBkGA1UEChMSSGFzaGlDb3JwIFRyYWluaW5nMRcwFQYDVQQDEw5zZXJ2aWNlLmNv
    78  bnN1bDAeFw0xODA4MjMxNzM0NTBaFw0xODA5MjIxNzM0NTBaMDYxGzAZBgNVBAoT
    79  Ekhhc2hpQ29ycCBUcmFpbmluZzEXMBUGA1UEAxMOc2VydmljZS5jb25zdWwwgZsw
    80  EAYHKoZIzj0CAQYFK4EEACMDgYYABAGjC4sWsOfirS/DQ9/e7PdQeJwlOjziiOx/
    81  CALjS6ryEDkZPqRqMuoFXfudAmfdk6tl8AT1IKMVcgiQU5jkm7fliwFIk48uh+n2
    82  obqZjwDyM76VYBVSYi6i3BPXown1ivIMJNQS1txnWZLZHsv+WxbHydS+GNOAwKDK
    83  KsXj9dEhd36pvaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
    84  HQYDVR0OBBYEFIk3oG2hu0FxueW4e7fL+FdMOquBMAoGCCqGSM49BAMEA4GMADCB
    85  iAJCAPIPwPyk+8Ymj7Zlvb5qIUQg+UxoacAeJtFZrJ8xQjro0YjsM33O86rAfw+x
    86  sWWGul4Ews93KFBXvhbKCwb0F0PhAkIAh2z7COsKcQzvBoIy+Kx92+9j/sUjlzzl
    87  TttDu+g2VdbcBwVDZ49X2Md6OY2N3G8Irdlj+n+mCQJaHwVt52DRzz0=
    88  -----END CERTIFICATE-----
    89  `
    90  
    91  	tmpCAFile, err := os.CreateTemp("/tmp", "test_ca_file")
    92  	require.NoError(err)
    93  	defer os.Remove(tmpCAFile.Name())
    94  
    95  	_, err = tmpCAFile.Write([]byte(certs))
    96  	require.NoError(err)
    97  	tmpCAFile.Close()
    98  
    99  	conf := &Config{
   100  		CAFile: tmpCAFile.Name(),
   101  	}
   102  	pool := x509.NewCertPool()
   103  	require.NoError(conf.AppendCA(pool))
   104  
   105  	require.Len(pool.Subjects(), 2)
   106  }
   107  
   108  // TestConfig_AppendCA_Valid_Whitespace asserts that a PEM file containing
   109  // trailing whitespace is valid.
   110  func TestConfig_AppendCA_Valid_Whitespace(t *testing.T) {
   111  	ci.Parallel(t)
   112  
   113  	require := require.New(t)
   114  
   115  	const cacertWhitespace = "./testdata/ca-whitespace.pem"
   116  	conf := &Config{
   117  		CAFile: cacertWhitespace,
   118  	}
   119  	pool := x509.NewCertPool()
   120  	require.NoError(conf.AppendCA(pool))
   121  
   122  	require.Len(pool.Subjects(), 1)
   123  }
   124  
   125  // TestConfig_AppendCA_Invalid_MultipleCerts_Whitespace asserts that a PEM file
   126  // containing non-PEM data between certificate blocks is still valid.
   127  func TestConfig_AppendCA_Valid_MultipleCerts_ExtraData(t *testing.T) {
   128  	ci.Parallel(t)
   129  
   130  	require := require.New(t)
   131  
   132  	certs := `
   133  Did you know...
   134  -----BEGIN CERTIFICATE-----
   135  MIICMzCCAdqgAwIBAgIUNZ9L86Xp9EuDH0/qyAesh599LXQwCgYIKoZIzj0EAwIw
   136  eDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh
   137  biBGcmFuY2lzY28xEjAQBgNVBAoTCUhhc2hpQ29ycDEOMAwGA1UECxMFTm9tYWQx
   138  GDAWBgNVBAMTD25vbWFkLmhhc2hpY29ycDAeFw0xNjExMTAxOTQ4MDBaFw0yMTEx
   139  MDkxOTQ4MDBaMHgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYw
   140  FAYDVQQHEw1TYW4gRnJhbmNpc2NvMRIwEAYDVQQKEwlIYXNoaUNvcnAxDjAMBgNV
   141  BAsTBU5vbWFkMRgwFgYDVQQDEw9ub21hZC5oYXNoaWNvcnAwWTATBgcqhkjOPQIB
   142  BggqhkjOPQMBBwNCAARfJmTdHzYIMPD8SK+kj5Gc79fmpOcg6wnb4JNVwCqWw9O+
   143  uNdZJZWSi4Q/4HojM5FTSBqYxNgSrmY/o3oQrCPlo0IwQDAOBgNVHQ8BAf8EBAMC
   144  AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOjVq/BectnhcKn6EHUD4NJFm
   145  /UAwCgYIKoZIzj0EAwIDRwAwRAIgTemDJGSGtcQPXLWKiQNw4SKO9wAPhn/WoKW4
   146  Ln2ZUe8CIDsQswBQS7URbqnKYDye2Y4befJkr4fmhhmMQb2ex9A4
   147  -----END CERTIFICATE-----
   148  
   149  ...PEM parsers don't care about data...
   150  
   151  -----BEGIN CERTIFICATE-----
   152  MIICNTCCAZagAwIBAgIRANjgoh5iVZI26+Hz/K65G0UwCgYIKoZIzj0EAwQwNjEb
   153  MBkGA1UEChMSSGFzaGlDb3JwIFRyYWluaW5nMRcwFQYDVQQDEw5zZXJ2aWNlLmNv
   154  bnN1bDAeFw0xODA4MjMxNzM0NTBaFw0xODA5MjIxNzM0NTBaMDYxGzAZBgNVBAoT
   155  Ekhhc2hpQ29ycCBUcmFpbmluZzEXMBUGA1UEAxMOc2VydmljZS5jb25zdWwwgZsw
   156  EAYHKoZIzj0CAQYFK4EEACMDgYYABAGjC4sWsOfirS/DQ9/e7PdQeJwlOjziiOx/
   157  CALjS6ryEDkZPqRqMuoFXfudAmfdk6tl8AT1IKMVcgiQU5jkm7fliwFIk48uh+n2
   158  obqZjwDyM76VYBVSYi6i3BPXown1ivIMJNQS1txnWZLZHsv+WxbHydS+GNOAwKDK
   159  KsXj9dEhd36pvaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
   160  HQYDVR0OBBYEFIk3oG2hu0FxueW4e7fL+FdMOquBMAoGCCqGSM49BAMEA4GMADCB
   161  iAJCAPIPwPyk+8Ymj7Zlvb5qIUQg+UxoacAeJtFZrJ8xQjro0YjsM33O86rAfw+x
   162  sWWGul4Ews93KFBXvhbKCwb0F0PhAkIAh2z7COsKcQzvBoIy+Kx92+9j/sUjlzzl
   163  TttDu+g2VdbcBwVDZ49X2Md6OY2N3G8Irdlj+n+mCQJaHwVt52DRzz0=
   164  -----END CERTIFICATE-----
   165  
   166  ...outside of -----XXX----- blocks?
   167  `
   168  
   169  	tmpCAFile, err := os.CreateTemp("/tmp", "test_ca_file_extra")
   170  	require.NoError(err)
   171  	defer os.Remove(tmpCAFile.Name())
   172  	_, err = tmpCAFile.Write([]byte(certs))
   173  	require.NoError(err)
   174  	tmpCAFile.Close()
   175  
   176  	conf := &Config{
   177  		CAFile: tmpCAFile.Name(),
   178  	}
   179  	pool := x509.NewCertPool()
   180  	err = conf.AppendCA(pool)
   181  
   182  	require.NoError(err)
   183  	require.Len(pool.Subjects(), 2)
   184  }
   185  
   186  // TestConfig_AppendCA_Invalid_MultipleCerts asserts only the valid certificate
   187  // is returned.
   188  func TestConfig_AppendCA_Invalid_MultipleCerts(t *testing.T) {
   189  	ci.Parallel(t)
   190  
   191  	require := require.New(t)
   192  
   193  	certs := `
   194  -----BEGIN CERTIFICATE-----
   195  MIICMzCCAdqgAwIBAgIUNZ9L86Xp9EuDH0/qyAesh599LXQwCgYIKoZIzj0EAwIw
   196  eDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh
   197  biBGcmFuY2lzY28xEjAQBgNVBAoTCUhhc2hpQ29ycDEOMAwGA1UECxMFTm9tYWQx
   198  GDAWBgNVBAMTD25vbWFkLmhhc2hpY29ycDAeFw0xNjExMTAxOTQ4MDBaFw0yMTEx
   199  MDkxOTQ4MDBaMHgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYw
   200  FAYDVQQHEw1TYW4gRnJhbmNpc2NvMRIwEAYDVQQKEwlIYXNoaUNvcnAxDjAMBgNV
   201  BAsTBU5vbWFkMRgwFgYDVQQDEw9ub21hZC5oYXNoaWNvcnAwWTATBgcqhkjOPQIB
   202  BggqhkjOPQMBBwNCAARfJmTdHzYIMPD8SK+kj5Gc79fmpOcg6wnb4JNVwCqWw9O+
   203  uNdZJZWSi4Q/4HojM5FTSBqYxNgSrmY/o3oQrCPlo0IwQDAOBgNVHQ8BAf8EBAMC
   204  AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOjVq/BectnhcKn6EHUD4NJFm
   205  /UAwCgYIKoZIzj0EAwIDRwAwRAIgTemDJGSGtcQPXLWKiQNw4SKO9wAPhn/WoKW4
   206  Ln2ZUe8CIDsQswBQS7URbqnKYDye2Y4befJkr4fmhhmMQb2ex9A4
   207  -----END CERTIFICATE-----
   208  -----BEGIN CERTIFICATE-----
   209  Invalid
   210  -----END CERTIFICATE-----`
   211  
   212  	tmpCAFile, err := os.CreateTemp("/tmp", "test_ca_file")
   213  	require.NoError(err)
   214  	defer os.Remove(tmpCAFile.Name())
   215  	_, err = tmpCAFile.Write([]byte(certs))
   216  	require.NoError(err)
   217  	tmpCAFile.Close()
   218  
   219  	conf := &Config{
   220  		CAFile: tmpCAFile.Name(),
   221  	}
   222  	pool := x509.NewCertPool()
   223  	require.NoError(conf.AppendCA(pool))
   224  
   225  	require.Len(pool.Subjects(), 1)
   226  }
   227  
   228  func TestConfig_AppendCA_Invalid(t *testing.T) {
   229  	ci.Parallel(t)
   230  
   231  	require := require.New(t)
   232  	{
   233  		conf := &Config{
   234  			CAFile: "invalidFile",
   235  		}
   236  		pool := x509.NewCertPool()
   237  		err := conf.AppendCA(pool)
   238  		require.NotNil(err)
   239  		require.Contains(err.Error(), "Failed to read CA file")
   240  		require.Equal(len(pool.Subjects()), 0)
   241  	}
   242  
   243  	{
   244  		tmpFile, err := os.CreateTemp("/tmp", "test_ca_file")
   245  		require.Nil(err)
   246  		defer os.Remove(tmpFile.Name())
   247  		_, err = tmpFile.Write([]byte("Invalid CA Content!"))
   248  		require.Nil(err)
   249  
   250  		conf := &Config{
   251  			CAFile: tmpFile.Name(),
   252  		}
   253  		pool := x509.NewCertPool()
   254  		err = conf.AppendCA(pool)
   255  		require.Error(err)
   256  		require.Contains(err.Error(), "Failed to parse any valid certificates in CA file:")
   257  		require.Equal(len(pool.Subjects()), 0)
   258  	}
   259  }
   260  
   261  func TestConfig_CACertificate_Valid(t *testing.T) {
   262  	ci.Parallel(t)
   263  
   264  	conf := &Config{
   265  		CAFile: cacert,
   266  	}
   267  	pool := x509.NewCertPool()
   268  	err := conf.AppendCA(pool)
   269  	if err != nil {
   270  		t.Fatalf("err: %v", err)
   271  	}
   272  	if len(pool.Subjects()) == 0 {
   273  		t.Fatalf("expected cert")
   274  	}
   275  }
   276  
   277  func TestConfig_LoadKeyPair_None(t *testing.T) {
   278  	ci.Parallel(t)
   279  
   280  	conf := &Config{
   281  		KeyLoader: &config.KeyLoader{},
   282  	}
   283  	cert, err := conf.LoadKeyPair()
   284  	if err != nil {
   285  		t.Fatalf("err: %v", err)
   286  	}
   287  	if cert != nil {
   288  		t.Fatalf("bad: %v", cert)
   289  	}
   290  }
   291  
   292  func TestConfig_LoadKeyPair_Valid(t *testing.T) {
   293  	ci.Parallel(t)
   294  
   295  	conf := &Config{
   296  		CertFile:  foocert,
   297  		KeyFile:   fookey,
   298  		KeyLoader: &config.KeyLoader{},
   299  	}
   300  	cert, err := conf.LoadKeyPair()
   301  	if err != nil {
   302  		t.Fatalf("err: %v", err)
   303  	}
   304  	if cert == nil {
   305  		t.Fatalf("expected cert")
   306  	}
   307  }
   308  
   309  func TestConfig_OutgoingTLS_MissingCA(t *testing.T) {
   310  	ci.Parallel(t)
   311  
   312  	conf := &Config{
   313  		VerifyOutgoing: true,
   314  	}
   315  	tls, err := conf.OutgoingTLSConfig()
   316  	if err == nil {
   317  		t.Fatalf("expected err")
   318  	}
   319  	if tls != nil {
   320  		t.Fatalf("bad: %v", tls)
   321  	}
   322  }
   323  
   324  func TestConfig_OutgoingTLS_OnlyCA(t *testing.T) {
   325  	ci.Parallel(t)
   326  
   327  	conf := &Config{
   328  		CAFile: cacert,
   329  	}
   330  	tls, err := conf.OutgoingTLSConfig()
   331  	if err != nil {
   332  		t.Fatalf("err: %v", err)
   333  	}
   334  	if tls != nil {
   335  		t.Fatalf("expected no config")
   336  	}
   337  }
   338  
   339  func TestConfig_OutgoingTLS_VerifyOutgoing(t *testing.T) {
   340  	ci.Parallel(t)
   341  
   342  	conf := &Config{
   343  		VerifyOutgoing: true,
   344  		CAFile:         cacert,
   345  	}
   346  	tls, err := conf.OutgoingTLSConfig()
   347  	if err != nil {
   348  		t.Fatalf("err: %v", err)
   349  	}
   350  	if tls == nil {
   351  		t.Fatalf("expected config")
   352  	}
   353  	if len(tls.RootCAs.Subjects()) != 1 {
   354  		t.Fatalf("expect root cert")
   355  	}
   356  	if !tls.InsecureSkipVerify {
   357  		t.Fatalf("should skip built-in verification")
   358  	}
   359  }
   360  
   361  func TestConfig_OutgoingTLS_VerifyHostname(t *testing.T) {
   362  	ci.Parallel(t)
   363  
   364  	conf := &Config{
   365  		VerifyServerHostname: true,
   366  		CAFile:               cacert,
   367  	}
   368  	tls, err := conf.OutgoingTLSConfig()
   369  	if err != nil {
   370  		t.Fatalf("err: %v", err)
   371  	}
   372  	if tls == nil {
   373  		t.Fatalf("expected config")
   374  	}
   375  	if len(tls.RootCAs.Subjects()) != 1 {
   376  		t.Fatalf("expect root cert")
   377  	}
   378  	if tls.InsecureSkipVerify {
   379  		t.Fatalf("should not skip built-in verification")
   380  	}
   381  }
   382  
   383  func TestConfig_OutgoingTLS_WithKeyPair(t *testing.T) {
   384  	ci.Parallel(t)
   385  
   386  	assert := assert.New(t)
   387  
   388  	conf := &Config{
   389  		VerifyOutgoing: true,
   390  		CAFile:         cacert,
   391  		CertFile:       foocert,
   392  		KeyFile:        fookey,
   393  		KeyLoader:      &config.KeyLoader{},
   394  	}
   395  	tlsConf, err := conf.OutgoingTLSConfig()
   396  	assert.Nil(err)
   397  	assert.NotNil(tlsConf)
   398  	assert.Equal(len(tlsConf.RootCAs.Subjects()), 1)
   399  	assert.True(tlsConf.InsecureSkipVerify)
   400  
   401  	clientHelloInfo := &tls.ClientHelloInfo{}
   402  	cert, err := tlsConf.GetCertificate(clientHelloInfo)
   403  	assert.Nil(err)
   404  	assert.NotNil(cert)
   405  }
   406  
   407  func TestConfig_OutgoingTLS_PreferServerCipherSuites(t *testing.T) {
   408  	ci.Parallel(t)
   409  
   410  	require := require.New(t)
   411  
   412  	{
   413  		conf := &Config{
   414  			VerifyOutgoing: true,
   415  			CAFile:         cacert,
   416  		}
   417  		tlsConfig, err := conf.OutgoingTLSConfig()
   418  		require.Nil(err)
   419  		require.Equal(tlsConfig.PreferServerCipherSuites, false)
   420  	}
   421  	{
   422  		conf := &Config{
   423  			VerifyOutgoing:           true,
   424  			CAFile:                   cacert,
   425  			PreferServerCipherSuites: true,
   426  		}
   427  		tlsConfig, err := conf.OutgoingTLSConfig()
   428  		require.Nil(err)
   429  		require.Equal(tlsConfig.PreferServerCipherSuites, true)
   430  	}
   431  }
   432  
   433  func TestConfig_OutgoingTLS_TLSCipherSuites(t *testing.T) {
   434  	ci.Parallel(t)
   435  
   436  	require := require.New(t)
   437  
   438  	{
   439  		defaultCiphers := []uint16{
   440  			tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
   441  			tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
   442  			tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
   443  		}
   444  		conf := &Config{
   445  			VerifyOutgoing: true,
   446  			CAFile:         cacert,
   447  			CipherSuites:   defaultCiphers,
   448  		}
   449  		tlsConfig, err := conf.OutgoingTLSConfig()
   450  		require.Nil(err)
   451  		require.Equal(tlsConfig.CipherSuites, defaultCiphers)
   452  	}
   453  	{
   454  		conf := &Config{
   455  			VerifyOutgoing: true,
   456  			CAFile:         cacert,
   457  			CipherSuites:   []uint16{tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305},
   458  		}
   459  		tlsConfig, err := conf.OutgoingTLSConfig()
   460  		require.Nil(err)
   461  		require.Equal(tlsConfig.CipherSuites, []uint16{tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305})
   462  	}
   463  }
   464  
   465  func startTLSServer(config *Config) (net.Conn, chan error) {
   466  	errc := make(chan error, 1)
   467  
   468  	tlsConfigServer, err := config.IncomingTLSConfig()
   469  	if err != nil {
   470  		errc <- err
   471  		return nil, errc
   472  	}
   473  
   474  	client, server := net.Pipe()
   475  
   476  	// Use yamux to buffer the reads, otherwise it's easy to deadlock
   477  	muxConf := yamux.DefaultConfig()
   478  	serverSession, _ := yamux.Server(server, muxConf)
   479  	clientSession, _ := yamux.Client(client, muxConf)
   480  	clientConn, _ := clientSession.Open()
   481  	serverConn, _ := serverSession.Accept()
   482  
   483  	go func() {
   484  		tlsServer := tls.Server(serverConn, tlsConfigServer)
   485  		if err := tlsServer.Handshake(); err != nil {
   486  			errc <- err
   487  		}
   488  		close(errc)
   489  		// Because net.Pipe() is unbuffered, if both sides
   490  		// Close() simultaneously, we will deadlock as they
   491  		// both send an alert and then block. So we make the
   492  		// server read any data from the client until error or
   493  		// EOF, which will allow the client to Close(), and
   494  		// *then* we Close() the server.
   495  		io.Copy(io.Discard, tlsServer)
   496  		tlsServer.Close()
   497  	}()
   498  	return clientConn, errc
   499  }
   500  
   501  // TODO sign the certificates for "server.regionFoo.nomad
   502  func TestConfig_outgoingWrapper_OK(t *testing.T) {
   503  	ci.Parallel(t)
   504  
   505  	config := &Config{
   506  		CAFile:               cacert,
   507  		CertFile:             foocert,
   508  		KeyFile:              fookey,
   509  		VerifyServerHostname: true,
   510  		VerifyOutgoing:       true,
   511  		KeyLoader:            &config.KeyLoader{},
   512  	}
   513  
   514  	client, errc := startTLSServer(config)
   515  	if client == nil {
   516  		t.Fatalf("startTLSServer err: %v", <-errc)
   517  	}
   518  
   519  	wrap, err := config.OutgoingTLSWrapper()
   520  	if err != nil {
   521  		t.Fatalf("OutgoingTLSWrapper err: %v", err)
   522  	}
   523  
   524  	tlsClient, err := wrap("regionFoo", client)
   525  	if err != nil {
   526  		t.Fatalf("wrapTLS err: %v", err)
   527  	}
   528  	defer tlsClient.Close()
   529  	if err := tlsClient.(*tls.Conn).Handshake(); err != nil {
   530  		t.Fatalf("write err: %v", err)
   531  	}
   532  
   533  	err = <-errc
   534  	if err != nil {
   535  		t.Fatalf("server: %v", err)
   536  	}
   537  }
   538  
   539  func TestConfig_outgoingWrapper_BadCert(t *testing.T) {
   540  	ci.Parallel(t)
   541  	// TODO this test is currently hanging, need to investigate more.
   542  	t.SkipNow()
   543  	config := &Config{
   544  		CAFile:               cacert,
   545  		CertFile:             foocert,
   546  		KeyFile:              fookey,
   547  		VerifyServerHostname: true,
   548  		VerifyOutgoing:       true,
   549  	}
   550  
   551  	client, errc := startTLSServer(config)
   552  	if client == nil {
   553  		t.Fatalf("startTLSServer err: %v", <-errc)
   554  	}
   555  
   556  	wrap, err := config.OutgoingTLSWrapper()
   557  	if err != nil {
   558  		t.Fatalf("OutgoingTLSWrapper err: %v", err)
   559  	}
   560  
   561  	tlsClient, err := wrap("regionFoo", client)
   562  	if err != nil {
   563  		t.Fatalf("wrapTLS err: %v", err)
   564  	}
   565  	defer tlsClient.Close()
   566  	err = tlsClient.(*tls.Conn).Handshake()
   567  
   568  	if _, ok := err.(x509.HostnameError); !ok {
   569  		t.Fatalf("should get hostname err: %v", err)
   570  	}
   571  
   572  	<-errc
   573  }
   574  
   575  func TestConfig_wrapTLS_OK(t *testing.T) {
   576  	ci.Parallel(t)
   577  
   578  	config := &Config{
   579  		CAFile:         cacert,
   580  		CertFile:       foocert,
   581  		KeyFile:        fookey,
   582  		VerifyOutgoing: true,
   583  		KeyLoader:      &config.KeyLoader{},
   584  	}
   585  
   586  	client, errc := startTLSServer(config)
   587  	if client == nil {
   588  		t.Fatalf("startTLSServer err: %v", <-errc)
   589  	}
   590  
   591  	clientConfig, err := config.OutgoingTLSConfig()
   592  	if err != nil {
   593  		t.Fatalf("OutgoingTLSConfig err: %v", err)
   594  	}
   595  
   596  	tlsClient, err := WrapTLSClient(client, clientConfig)
   597  	if err != nil {
   598  		t.Fatalf("wrapTLS err: %v", err)
   599  	} else {
   600  		tlsClient.Close()
   601  	}
   602  	err = <-errc
   603  	if err != nil {
   604  		t.Fatalf("server: %v", err)
   605  	}
   606  }
   607  
   608  func TestConfig_wrapTLS_BadCert(t *testing.T) {
   609  	ci.Parallel(t)
   610  
   611  	serverConfig := &Config{
   612  		CAFile:    cacert,
   613  		CertFile:  badcert,
   614  		KeyFile:   badkey,
   615  		KeyLoader: &config.KeyLoader{},
   616  	}
   617  
   618  	client, errc := startTLSServer(serverConfig)
   619  	if client == nil {
   620  		t.Fatalf("startTLSServer err: %v", <-errc)
   621  	}
   622  
   623  	clientConfig := &Config{
   624  		CAFile:         cacert,
   625  		VerifyOutgoing: true,
   626  	}
   627  
   628  	clientTLSConfig, err := clientConfig.OutgoingTLSConfig()
   629  	if err != nil {
   630  		t.Fatalf("OutgoingTLSConfig err: %v", err)
   631  	}
   632  
   633  	tlsClient, err := WrapTLSClient(client, clientTLSConfig)
   634  	if err == nil {
   635  		t.Fatalf("wrapTLS no err")
   636  	}
   637  	if tlsClient != nil {
   638  		t.Fatalf("returned a client")
   639  	}
   640  
   641  	err = <-errc
   642  	if err != nil {
   643  		t.Fatalf("server: %v", err)
   644  	}
   645  }
   646  
   647  func TestConfig_IncomingTLS(t *testing.T) {
   648  	ci.Parallel(t)
   649  
   650  	assert := assert.New(t)
   651  
   652  	conf := &Config{
   653  		VerifyIncoming: true,
   654  		CAFile:         cacert,
   655  		CertFile:       foocert,
   656  		KeyFile:        fookey,
   657  		KeyLoader:      &config.KeyLoader{},
   658  	}
   659  	tlsC, err := conf.IncomingTLSConfig()
   660  	if err != nil {
   661  		t.Fatalf("err: %v", err)
   662  	}
   663  	if tlsC == nil {
   664  		t.Fatalf("expected config")
   665  	}
   666  	if len(tlsC.ClientCAs.Subjects()) != 1 {
   667  		t.Fatalf("expect client cert")
   668  	}
   669  	if tlsC.ClientAuth != tls.RequireAndVerifyClientCert {
   670  		t.Fatalf("should not skip verification")
   671  	}
   672  
   673  	clientHelloInfo := &tls.ClientHelloInfo{}
   674  	cert, err := tlsC.GetCertificate(clientHelloInfo)
   675  	assert.Nil(err)
   676  	assert.NotNil(cert)
   677  }
   678  
   679  func TestConfig_IncomingTLS_MissingCA(t *testing.T) {
   680  	ci.Parallel(t)
   681  
   682  	conf := &Config{
   683  		VerifyIncoming: true,
   684  		CertFile:       foocert,
   685  		KeyFile:        fookey,
   686  		KeyLoader:      &config.KeyLoader{},
   687  	}
   688  	_, err := conf.IncomingTLSConfig()
   689  	if err == nil {
   690  		t.Fatalf("expected err")
   691  	}
   692  }
   693  
   694  func TestConfig_IncomingTLS_MissingKey(t *testing.T) {
   695  	ci.Parallel(t)
   696  
   697  	conf := &Config{
   698  		VerifyIncoming: true,
   699  		CAFile:         cacert,
   700  	}
   701  	_, err := conf.IncomingTLSConfig()
   702  	if err == nil {
   703  		t.Fatalf("expected err")
   704  	}
   705  }
   706  
   707  func TestConfig_IncomingTLS_NoVerify(t *testing.T) {
   708  	ci.Parallel(t)
   709  
   710  	conf := &Config{}
   711  	tlsC, err := conf.IncomingTLSConfig()
   712  	if err != nil {
   713  		t.Fatalf("err: %v", err)
   714  	}
   715  	if tlsC == nil {
   716  		t.Fatalf("expected config")
   717  	}
   718  	if len(tlsC.ClientCAs.Subjects()) != 0 {
   719  		t.Fatalf("do not expect client cert")
   720  	}
   721  	if tlsC.ClientAuth != tls.NoClientCert {
   722  		t.Fatalf("should skip verification")
   723  	}
   724  	if len(tlsC.Certificates) != 0 {
   725  		t.Fatalf("unexpected client cert")
   726  	}
   727  }
   728  
   729  func TestConfig_IncomingTLS_PreferServerCipherSuites(t *testing.T) {
   730  	ci.Parallel(t)
   731  
   732  	require := require.New(t)
   733  
   734  	{
   735  		conf := &Config{}
   736  		tlsConfig, err := conf.IncomingTLSConfig()
   737  		require.Nil(err)
   738  		require.Equal(tlsConfig.PreferServerCipherSuites, false)
   739  	}
   740  	{
   741  		conf := &Config{
   742  			PreferServerCipherSuites: true,
   743  		}
   744  		tlsConfig, err := conf.IncomingTLSConfig()
   745  		require.Nil(err)
   746  		require.Equal(tlsConfig.PreferServerCipherSuites, true)
   747  	}
   748  }
   749  
   750  func TestConfig_IncomingTLS_TLSCipherSuites(t *testing.T) {
   751  	ci.Parallel(t)
   752  
   753  	require := require.New(t)
   754  
   755  	{
   756  		defaultCiphers := []uint16{
   757  			tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
   758  			tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
   759  			tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
   760  		}
   761  		conf := &Config{
   762  			CipherSuites: defaultCiphers,
   763  		}
   764  		tlsConfig, err := conf.IncomingTLSConfig()
   765  		require.Nil(err)
   766  		require.Equal(tlsConfig.CipherSuites, defaultCiphers)
   767  	}
   768  	{
   769  		conf := &Config{
   770  			CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305},
   771  		}
   772  		tlsConfig, err := conf.IncomingTLSConfig()
   773  		require.Nil(err)
   774  		require.Equal(tlsConfig.CipherSuites, []uint16{tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305})
   775  	}
   776  }
   777  
   778  // This test relies on the fact that the specified certificate has an ECDSA
   779  // signature algorithm
   780  func TestConfig_ParseCiphers_Valid(t *testing.T) {
   781  	ci.Parallel(t)
   782  
   783  	require := require.New(t)
   784  
   785  	tlsConfig := &config.TLSConfig{
   786  		CertFile:  foocert,
   787  		KeyFile:   fookey,
   788  		KeyLoader: &config.KeyLoader{},
   789  		TLSCipherSuites: strings.Join([]string{
   790  			"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
   791  			"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
   792  			"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
   793  			"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
   794  			"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
   795  			"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
   796  			"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
   797  			"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
   798  			"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
   799  			"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
   800  			"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
   801  			"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
   802  			"TLS_RSA_WITH_AES_128_GCM_SHA256",
   803  			"TLS_RSA_WITH_AES_256_GCM_SHA384",
   804  			"TLS_RSA_WITH_AES_128_CBC_SHA256",
   805  			"TLS_RSA_WITH_AES_128_CBC_SHA",
   806  			"TLS_RSA_WITH_AES_256_CBC_SHA",
   807  		}, ","),
   808  	}
   809  
   810  	expectedCiphers := []uint16{
   811  		tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
   812  		tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
   813  		tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
   814  		tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
   815  		tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
   816  		tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
   817  		tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
   818  		tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
   819  		tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
   820  		tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
   821  		tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
   822  		tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
   823  		tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
   824  		tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
   825  		tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
   826  		tls.TLS_RSA_WITH_AES_128_CBC_SHA,
   827  		tls.TLS_RSA_WITH_AES_256_CBC_SHA,
   828  	}
   829  
   830  	parsedCiphers, err := ParseCiphers(tlsConfig)
   831  	require.Nil(err)
   832  	require.Equal(parsedCiphers, expectedCiphers)
   833  }
   834  
   835  // This test relies on the fact that the specified certificate has an ECDSA
   836  // signature algorithm
   837  func TestConfig_ParseCiphers_Default(t *testing.T) {
   838  	ci.Parallel(t)
   839  
   840  	require := require.New(t)
   841  
   842  	expectedCiphers := []uint16{
   843  		tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
   844  		tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
   845  		tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
   846  		tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
   847  		tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
   848  		tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
   849  		tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
   850  		tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
   851  		tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
   852  		tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
   853  	}
   854  
   855  	empty := &config.TLSConfig{
   856  		CertFile:  foocert,
   857  		KeyFile:   fookey,
   858  		KeyLoader: &config.KeyLoader{},
   859  	}
   860  	parsedCiphers, err := ParseCiphers(empty)
   861  	require.Nil(err)
   862  	require.Equal(parsedCiphers, expectedCiphers)
   863  }
   864  
   865  // This test relies on the fact that the specified certificate has an ECDSA
   866  // signature algorithm
   867  func TestConfig_ParseCiphers_Invalid(t *testing.T) {
   868  	ci.Parallel(t)
   869  
   870  	require := require.New(t)
   871  
   872  	invalidCiphers := []string{
   873  		"TLS_RSA_RSA_WITH_RC4_128_SHA",
   874  		"INVALID_CIPHER",
   875  	}
   876  
   877  	for _, cipher := range invalidCiphers {
   878  		tlsConfig := &config.TLSConfig{
   879  			TLSCipherSuites: cipher,
   880  			CertFile:        foocert,
   881  			KeyFile:         fookey,
   882  			KeyLoader:       &config.KeyLoader{},
   883  		}
   884  		parsedCiphers, err := ParseCiphers(tlsConfig)
   885  		require.NotNil(err)
   886  		require.Equal(fmt.Sprintf("unsupported TLS cipher %q", cipher), err.Error())
   887  		require.Equal(0, len(parsedCiphers))
   888  	}
   889  }
   890  
   891  // This test relies on the fact that the specified certificate has an ECDSA
   892  // signature algorithm
   893  func TestConfig_ParseCiphers_SupportedSignature(t *testing.T) {
   894  	ci.Parallel(t)
   895  
   896  	require := require.New(t)
   897  
   898  	// Supported signature
   899  	{
   900  		tlsConfig := &config.TLSConfig{
   901  			TLSCipherSuites: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
   902  			CertFile:        foocert,
   903  			KeyFile:         fookey,
   904  			KeyLoader:       &config.KeyLoader{},
   905  		}
   906  		parsedCiphers, err := ParseCiphers(tlsConfig)
   907  		require.Nil(err)
   908  		require.Equal(1, len(parsedCiphers))
   909  	}
   910  
   911  	// Unsupported signature
   912  	{
   913  		tlsConfig := &config.TLSConfig{
   914  			TLSCipherSuites: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
   915  			CertFile:        foocert,
   916  			KeyFile:         fookey,
   917  			KeyLoader:       &config.KeyLoader{},
   918  		}
   919  		parsedCiphers, err := ParseCiphers(tlsConfig)
   920  		require.NotNil(err)
   921  		require.Equal(0, len(parsedCiphers))
   922  	}
   923  }
   924  
   925  func TestConfig_ParseMinVersion_Valid(t *testing.T) {
   926  	ci.Parallel(t)
   927  
   928  	require := require.New(t)
   929  
   930  	validVersions := []string{"tls10",
   931  		"tls11",
   932  		"tls12",
   933  	}
   934  
   935  	expected := map[string]uint16{
   936  		"tls10": tls.VersionTLS10,
   937  		"tls11": tls.VersionTLS11,
   938  		"tls12": tls.VersionTLS12,
   939  	}
   940  
   941  	for _, version := range validVersions {
   942  		parsedVersion, err := ParseMinVersion(version)
   943  		require.Nil(err)
   944  		require.Equal(expected[version], parsedVersion)
   945  	}
   946  }
   947  
   948  func TestConfig_ParseMinVersion_Invalid(t *testing.T) {
   949  	ci.Parallel(t)
   950  
   951  	require := require.New(t)
   952  
   953  	invalidVersions := []string{"tls13",
   954  		"tls15",
   955  	}
   956  
   957  	for _, version := range invalidVersions {
   958  		parsedVersion, err := ParseMinVersion(version)
   959  		require.NotNil(err)
   960  		require.Equal(fmt.Sprintf("unsupported TLS version %q", version), err.Error())
   961  		require.Equal(uint16(0), parsedVersion)
   962  	}
   963  }
   964  
   965  func TestConfig_NewTLSConfiguration(t *testing.T) {
   966  	ci.Parallel(t)
   967  
   968  	require := require.New(t)
   969  
   970  	conf := &config.TLSConfig{
   971  		TLSCipherSuites: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
   972  		CertFile:        foocert,
   973  		KeyFile:         fookey,
   974  		KeyLoader:       &config.KeyLoader{},
   975  	}
   976  
   977  	tlsConf, err := NewTLSConfiguration(conf, true, true)
   978  	require.Nil(err)
   979  	require.True(tlsConf.VerifyIncoming)
   980  	require.True(tlsConf.VerifyOutgoing)
   981  
   982  	expectedCiphers := []uint16{
   983  		tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
   984  		tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
   985  	}
   986  	require.Equal(tlsConf.CipherSuites, expectedCiphers)
   987  }
   988  
   989  func TestConfig_ShouldReloadRPCConnections(t *testing.T) {
   990  	ci.Parallel(t)
   991  
   992  	require := require.New(t)
   993  
   994  	type shouldReloadTestInput struct {
   995  		old          *config.TLSConfig
   996  		new          *config.TLSConfig
   997  		shouldReload bool
   998  		errorStr     string
   999  	}
  1000  
  1001  	testInput := []*shouldReloadTestInput{
  1002  		{
  1003  			old: &config.TLSConfig{
  1004  				CAFile:   cacert,
  1005  				CertFile: badcert,
  1006  				KeyFile:  badkey,
  1007  			},
  1008  			new: &config.TLSConfig{
  1009  				CAFile:   cacert,
  1010  				CertFile: badcert,
  1011  				KeyFile:  badkey,
  1012  			},
  1013  			shouldReload: false,
  1014  			errorStr:     "Same TLS Configuration should not reload",
  1015  		},
  1016  		{
  1017  			old: &config.TLSConfig{
  1018  				CAFile:   cacert,
  1019  				CertFile: badcert,
  1020  				KeyFile:  badkey,
  1021  			},
  1022  			new: &config.TLSConfig{
  1023  				CAFile:   cacert,
  1024  				CertFile: foocert,
  1025  				KeyFile:  fookey,
  1026  			},
  1027  			shouldReload: true,
  1028  			errorStr:     "Different TLS Configuration should reload",
  1029  		},
  1030  		{
  1031  			old: &config.TLSConfig{
  1032  				CAFile:    cacert,
  1033  				CertFile:  badcert,
  1034  				KeyFile:   badkey,
  1035  				EnableRPC: true,
  1036  			},
  1037  			new: &config.TLSConfig{
  1038  				CAFile:    cacert,
  1039  				CertFile:  badcert,
  1040  				KeyFile:   badkey,
  1041  				EnableRPC: false,
  1042  			},
  1043  			shouldReload: true,
  1044  			errorStr:     "Downgrading RPC connections should force reload",
  1045  		},
  1046  		{
  1047  			old: nil,
  1048  			new: &config.TLSConfig{
  1049  				CAFile:    cacert,
  1050  				CertFile:  badcert,
  1051  				KeyFile:   badkey,
  1052  				EnableRPC: true,
  1053  			},
  1054  			shouldReload: true,
  1055  			errorStr:     "Upgrading RPC connections should force reload",
  1056  		},
  1057  		{
  1058  			old: &config.TLSConfig{
  1059  				CAFile:    cacert,
  1060  				CertFile:  badcert,
  1061  				KeyFile:   badkey,
  1062  				EnableRPC: true,
  1063  			},
  1064  			new:          nil,
  1065  			shouldReload: true,
  1066  			errorStr:     "Downgrading RPC connections should force reload",
  1067  		},
  1068  	}
  1069  
  1070  	for _, testCase := range testInput {
  1071  		shouldReload, err := ShouldReloadRPCConnections(testCase.old, testCase.new)
  1072  		require.NoError(err)
  1073  		require.Equal(shouldReload, testCase.shouldReload, testCase.errorStr)
  1074  	}
  1075  }