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 }