github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/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 }