github.com/tschmi5/nomad@v0.11.8/helper/tlsutil/config_test.go (about)

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