github.com/kaituanwang/hyperledger@v2.0.1+incompatible/core/comm/client_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package comm_test 8 9 import ( 10 "bytes" 11 "context" 12 "crypto/tls" 13 "crypto/x509" 14 "io/ioutil" 15 "net" 16 "path/filepath" 17 "sync" 18 "sync/atomic" 19 "testing" 20 "time" 21 22 "github.com/golang/protobuf/proto" 23 "github.com/hyperledger/fabric/common/crypto/tlsgen" 24 "github.com/hyperledger/fabric/common/flogging" 25 "github.com/hyperledger/fabric/core/comm" 26 "github.com/hyperledger/fabric/core/comm/testpb" 27 "github.com/pkg/errors" 28 "github.com/stretchr/testify/assert" 29 "github.com/stretchr/testify/require" 30 "google.golang.org/grpc" 31 "google.golang.org/grpc/connectivity" 32 "google.golang.org/grpc/credentials" 33 ) 34 35 const testTimeout = 1 * time.Second // conservative 36 37 type echoServer struct{} 38 39 func (es *echoServer) EchoCall(ctx context.Context, 40 echo *testpb.Echo) (*testpb.Echo, error) { 41 return echo, nil 42 } 43 44 func TestNewGRPCClient_GoodConfig(t *testing.T) { 45 t.Parallel() 46 testCerts := loadCerts(t) 47 48 config := comm.ClientConfig{} 49 client, err := comm.NewGRPCClient(config) 50 assert.NoError(t, err) 51 assert.Equal(t, tls.Certificate{}, client.Certificate()) 52 assert.False(t, client.TLSEnabled()) 53 assert.False(t, client.MutualTLSRequired()) 54 55 secOpts := comm.SecureOptions{ 56 UseTLS: false, 57 } 58 config.SecOpts = secOpts 59 client, err = comm.NewGRPCClient(config) 60 assert.NoError(t, err) 61 assert.Equal(t, tls.Certificate{}, client.Certificate()) 62 assert.False(t, client.TLSEnabled()) 63 assert.False(t, client.MutualTLSRequired()) 64 65 secOpts = comm.SecureOptions{ 66 UseTLS: true, 67 ServerRootCAs: [][]byte{testCerts.caPEM}, 68 RequireClientCert: false, 69 } 70 config.SecOpts = secOpts 71 client, err = comm.NewGRPCClient(config) 72 assert.NoError(t, err) 73 assert.True(t, client.TLSEnabled()) 74 assert.False(t, client.MutualTLSRequired()) 75 76 secOpts = comm.SecureOptions{ 77 Certificate: testCerts.certPEM, 78 Key: testCerts.keyPEM, 79 UseTLS: true, 80 ServerRootCAs: [][]byte{testCerts.caPEM}, 81 RequireClientCert: true, 82 } 83 config.SecOpts = secOpts 84 client, err = comm.NewGRPCClient(config) 85 assert.NoError(t, err) 86 assert.True(t, client.TLSEnabled()) 87 assert.True(t, client.MutualTLSRequired()) 88 assert.Equal(t, testCerts.clientCert, client.Certificate()) 89 } 90 91 func TestNewGRPCClient_BadConfig(t *testing.T) { 92 t.Parallel() 93 testCerts := loadCerts(t) 94 95 // bad root cert 96 config := comm.ClientConfig{ 97 SecOpts: comm.SecureOptions{ 98 UseTLS: true, 99 ServerRootCAs: [][]byte{[]byte(badPEM)}, 100 }, 101 } 102 _, err := comm.NewGRPCClient(config) 103 assert.Contains(t, err.Error(), "error adding root certificate") 104 105 // missing key 106 missing := "both Key and Certificate are required when using mutual TLS" 107 config.SecOpts = comm.SecureOptions{ 108 Certificate: []byte("cert"), 109 UseTLS: true, 110 RequireClientCert: true, 111 } 112 _, err = comm.NewGRPCClient(config) 113 assert.Equal(t, missing, err.Error()) 114 115 // missing cert 116 config.SecOpts = comm.SecureOptions{ 117 Key: []byte("key"), 118 UseTLS: true, 119 RequireClientCert: true, 120 } 121 _, err = comm.NewGRPCClient(config) 122 assert.Equal(t, missing, err.Error()) 123 124 // bad key 125 failed := "failed to load client certificate" 126 config.SecOpts = comm.SecureOptions{ 127 Certificate: testCerts.certPEM, 128 Key: []byte(badPEM), 129 UseTLS: true, 130 RequireClientCert: true, 131 } 132 _, err = comm.NewGRPCClient(config) 133 assert.Contains(t, err.Error(), failed) 134 135 // bad cert 136 config.SecOpts = comm.SecureOptions{ 137 Certificate: []byte(badPEM), 138 Key: testCerts.keyPEM, 139 UseTLS: true, 140 RequireClientCert: true, 141 } 142 _, err = comm.NewGRPCClient(config) 143 assert.Contains(t, err.Error(), failed) 144 } 145 146 func TestNewConnection(t *testing.T) { 147 t.Parallel() 148 testCerts := loadCerts(t) 149 150 l, err := net.Listen("tcp", "127.0.0.1:0") 151 require.NoError(t, err) 152 badAddress := l.Addr().String() 153 defer l.Close() 154 155 certPool := x509.NewCertPool() 156 ok := certPool.AppendCertsFromPEM(testCerts.caPEM) 157 if !ok { 158 t.Fatal("failed to create test root cert pool") 159 } 160 161 tests := []struct { 162 name string 163 clientAddress string 164 config comm.ClientConfig 165 serverTLS *tls.Config 166 success bool 167 errorMsg string 168 }{ 169 { 170 name: "client / server same port", 171 config: comm.ClientConfig{ 172 Timeout: testTimeout, 173 }, 174 success: true, 175 }, 176 { 177 name: "client / server wrong port", 178 clientAddress: badAddress, 179 config: comm.ClientConfig{ 180 Timeout: time.Second, 181 }, 182 success: false, 183 errorMsg: "(connection refused|context deadline exceeded)", 184 }, 185 { 186 name: "client / server wrong port but with asynchronous should succeed", 187 clientAddress: badAddress, 188 config: comm.ClientConfig{ 189 AsyncConnect: true, 190 Timeout: testTimeout, 191 }, 192 success: true, 193 }, 194 { 195 name: "client TLS / server no TLS", 196 config: comm.ClientConfig{ 197 SecOpts: comm.SecureOptions{ 198 Certificate: testCerts.certPEM, 199 Key: testCerts.keyPEM, 200 UseTLS: true, 201 ServerRootCAs: [][]byte{testCerts.caPEM}, 202 RequireClientCert: true, 203 }, 204 Timeout: time.Second, 205 }, 206 success: false, 207 errorMsg: "context deadline exceeded", 208 }, 209 { 210 name: "client TLS / server TLS match", 211 config: comm.ClientConfig{ 212 SecOpts: comm.SecureOptions{ 213 Certificate: testCerts.certPEM, 214 Key: testCerts.keyPEM, 215 UseTLS: true, 216 ServerRootCAs: [][]byte{testCerts.caPEM}, 217 }, 218 Timeout: testTimeout, 219 }, 220 serverTLS: &tls.Config{ 221 Certificates: []tls.Certificate{testCerts.serverCert}, 222 }, 223 success: true, 224 }, 225 { 226 name: "client TLS / server TLS no server roots", 227 config: comm.ClientConfig{ 228 SecOpts: comm.SecureOptions{ 229 Certificate: testCerts.certPEM, 230 Key: testCerts.keyPEM, 231 UseTLS: true, 232 ServerRootCAs: [][]byte{}, 233 }, 234 Timeout: testTimeout, 235 }, 236 serverTLS: &tls.Config{ 237 Certificates: []tls.Certificate{testCerts.serverCert}, 238 }, 239 success: false, 240 errorMsg: "context deadline exceeded", 241 }, 242 { 243 name: "client TLS / server TLS missing client cert", 244 config: comm.ClientConfig{ 245 SecOpts: comm.SecureOptions{ 246 Certificate: testCerts.certPEM, 247 Key: testCerts.keyPEM, 248 UseTLS: true, 249 ServerRootCAs: [][]byte{testCerts.caPEM}, 250 }, 251 Timeout: testTimeout, 252 }, 253 serverTLS: &tls.Config{ 254 Certificates: []tls.Certificate{testCerts.serverCert}, 255 ClientAuth: tls.RequireAndVerifyClientCert, 256 MaxVersion: tls.VersionTLS12, // https://github.com/golang/go/issues/33368 257 }, 258 success: false, 259 errorMsg: "tls: bad certificate", 260 }, 261 { 262 name: "client TLS / server TLS client cert", 263 config: comm.ClientConfig{ 264 SecOpts: comm.SecureOptions{ 265 Certificate: testCerts.certPEM, 266 Key: testCerts.keyPEM, 267 UseTLS: true, 268 RequireClientCert: true, 269 ServerRootCAs: [][]byte{testCerts.caPEM}, 270 }, 271 Timeout: testTimeout, 272 }, 273 serverTLS: &tls.Config{ 274 Certificates: []tls.Certificate{testCerts.serverCert}, 275 ClientAuth: tls.RequireAndVerifyClientCert, 276 ClientCAs: certPool, 277 }, 278 success: true, 279 }, 280 { 281 name: "server TLS pinning success", 282 config: comm.ClientConfig{ 283 SecOpts: comm.SecureOptions{ 284 VerifyCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { 285 if bytes.Equal(rawCerts[0], testCerts.serverCert.Certificate[0]) { 286 return nil 287 } 288 panic("mismatched certificate") 289 }, 290 Certificate: testCerts.certPEM, 291 Key: testCerts.keyPEM, 292 UseTLS: true, 293 RequireClientCert: true, 294 ServerRootCAs: [][]byte{testCerts.caPEM}, 295 }, 296 Timeout: testTimeout, 297 }, 298 serverTLS: &tls.Config{ 299 Certificates: []tls.Certificate{testCerts.serverCert}, 300 ClientAuth: tls.RequireAndVerifyClientCert, 301 ClientCAs: certPool, 302 }, 303 success: true, 304 }, 305 { 306 name: "server TLS pinning failure", 307 config: comm.ClientConfig{ 308 SecOpts: comm.SecureOptions{ 309 VerifyCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { 310 return errors.New("TLS certificate mismatch") 311 }, 312 Certificate: testCerts.certPEM, 313 Key: testCerts.keyPEM, 314 UseTLS: true, 315 RequireClientCert: true, 316 ServerRootCAs: [][]byte{testCerts.caPEM}, 317 }, 318 Timeout: testTimeout, 319 }, 320 serverTLS: &tls.Config{ 321 Certificates: []tls.Certificate{testCerts.serverCert}, 322 ClientAuth: tls.RequireAndVerifyClientCert, 323 ClientCAs: certPool, 324 }, 325 success: false, 326 errorMsg: "context deadline exceeded", 327 }, 328 } 329 330 for _, test := range tests { 331 test := test 332 t.Run(test.name, func(t *testing.T) { 333 t.Parallel() 334 lis, err := net.Listen("tcp", "127.0.0.1:0") 335 if err != nil { 336 t.Fatalf("error creating server for test: %v", err) 337 } 338 defer lis.Close() 339 serverOpts := []grpc.ServerOption{} 340 if test.serverTLS != nil { 341 serverOpts = append(serverOpts, grpc.Creds(credentials.NewTLS(test.serverTLS))) 342 } 343 srv := grpc.NewServer(serverOpts...) 344 defer srv.Stop() 345 go srv.Serve(lis) 346 client, err := comm.NewGRPCClient(test.config) 347 if err != nil { 348 t.Fatalf("error creating client for test: %v", err) 349 } 350 address := lis.Addr().String() 351 if test.clientAddress != "" { 352 address = test.clientAddress 353 } 354 conn, err := client.NewConnection(address) 355 if test.success { 356 assert.NoError(t, err) 357 assert.NotNil(t, conn) 358 } else { 359 t.Log(errors.WithStack(err)) 360 assert.Regexp(t, test.errorMsg, err.Error()) 361 } 362 }) 363 } 364 } 365 366 func TestSetServerRootCAs(t *testing.T) { 367 t.Parallel() 368 testCerts := loadCerts(t) 369 370 config := comm.ClientConfig{ 371 SecOpts: comm.SecureOptions{ 372 UseTLS: true, 373 ServerRootCAs: [][]byte{testCerts.caPEM}, 374 }, 375 Timeout: testTimeout, 376 } 377 client, err := comm.NewGRPCClient(config) 378 if err != nil { 379 t.Fatalf("error creating base client: %v", err) 380 } 381 382 // set up test TLS server 383 lis, err := net.Listen("tcp", "127.0.0.1:0") 384 if err != nil { 385 t.Fatalf("failed to create listener for test server: %v", err) 386 } 387 address := lis.Addr().String() 388 t.Logf("server listening on [%s]", lis.Addr().String()) 389 t.Logf("client will use [%s]", address) 390 defer lis.Close() 391 srv := grpc.NewServer(grpc.Creds(credentials.NewTLS(&tls.Config{ 392 Certificates: []tls.Certificate{testCerts.serverCert}, 393 }))) 394 defer srv.Stop() 395 go srv.Serve(lis) 396 397 // initial config should work 398 t.Log("running initial good config") 399 conn, err := client.NewConnection(address) 400 assert.NoError(t, err) 401 assert.NotNil(t, conn) 402 if conn != nil { 403 conn.Close() 404 } 405 406 // no root testCerts 407 t.Log("running bad config") 408 err = client.SetServerRootCAs([][]byte{}) 409 assert.NoError(t, err) 410 // now connection should fail 411 _, err = client.NewConnection(address) 412 assert.Error(t, err) 413 414 // good root cert 415 t.Log("running good config") 416 err = client.SetServerRootCAs([][]byte{[]byte(testCerts.caPEM)}) 417 assert.NoError(t, err) 418 // now connection should succeed again 419 conn, err = client.NewConnection(address) 420 assert.NoError(t, err) 421 assert.NotNil(t, conn) 422 if conn != nil { 423 conn.Close() 424 } 425 426 // bad root cert 427 t.Log("running bad root cert") 428 err = client.SetServerRootCAs([][]byte{[]byte(badPEM)}) 429 assert.Contains(t, err.Error(), "error adding root certificate") 430 } 431 432 func TestSetMessageSize(t *testing.T) { 433 t.Parallel() 434 435 // setup test server 436 lis, err := net.Listen("tcp", "127.0.0.1:0") 437 if err != nil { 438 t.Fatalf("failed to create listener for test server: %v", err) 439 } 440 srv, err := comm.NewGRPCServerFromListener(lis, comm.ServerConfig{}) 441 if err != nil { 442 t.Fatalf("failed to create test server: %v", err) 443 } 444 testpb.RegisterEchoServiceServer(srv.Server(), &echoServer{}) 445 defer srv.Stop() 446 go srv.Start() 447 448 var tests = []struct { 449 name string 450 maxRecvSize int 451 maxSendSize int 452 failRecv bool 453 failSend bool 454 }{ 455 { 456 name: "defaults should pass", 457 failRecv: false, 458 failSend: false, 459 }, 460 { 461 name: "non-defaults should pass", 462 failRecv: false, 463 failSend: false, 464 maxRecvSize: 20, 465 maxSendSize: 20, 466 }, 467 { 468 name: "recv should fail", 469 failRecv: true, 470 failSend: false, 471 maxRecvSize: 1, 472 }, 473 { 474 name: "send should fail", 475 failRecv: false, 476 failSend: true, 477 maxSendSize: 1, 478 }, 479 } 480 481 // set up test client 482 client, err := comm.NewGRPCClient(comm.ClientConfig{ 483 Timeout: testTimeout, 484 }) 485 if err != nil { 486 t.Fatalf("error creating test client: %v", err) 487 } 488 // run tests 489 for _, test := range tests { 490 test := test 491 address := lis.Addr().String() 492 t.Run(test.name, func(t *testing.T) { 493 t.Log(test.name) 494 if test.maxRecvSize > 0 { 495 client.SetMaxRecvMsgSize(test.maxRecvSize) 496 } 497 if test.maxSendSize > 0 { 498 client.SetMaxSendMsgSize(test.maxSendSize) 499 } 500 conn, err := client.NewConnection(address) 501 assert.NoError(t, err) 502 defer conn.Close() 503 // create service client from conn 504 svcClient := testpb.NewEchoServiceClient(conn) 505 callCtx := context.Background() 506 callCtx, cancel := context.WithTimeout(callCtx, testTimeout) 507 defer cancel() 508 //invoke service 509 echo := &testpb.Echo{ 510 Payload: []byte{0, 0, 0, 0, 0}, 511 } 512 resp, err := svcClient.EchoCall(callCtx, echo) 513 if !test.failRecv && !test.failSend { 514 assert.NoError(t, err) 515 assert.True(t, proto.Equal(echo, resp)) 516 } 517 if test.failSend { 518 t.Logf("send error: %v", err) 519 assert.Contains(t, err.Error(), "trying to send message larger than max") 520 } 521 if test.failRecv { 522 t.Logf("recv error: %v", err) 523 assert.Contains(t, err.Error(), "received message larger than max") 524 } 525 }) 526 } 527 } 528 529 type testCerts struct { 530 caPEM []byte 531 certPEM []byte 532 keyPEM []byte 533 clientCert tls.Certificate 534 serverCert tls.Certificate 535 } 536 537 func loadCerts(t *testing.T) testCerts { 538 t.Helper() 539 540 var certs testCerts 541 var err error 542 certs.caPEM, err = ioutil.ReadFile(filepath.Join("testdata", "certs", "Org1-cert.pem")) 543 if err != nil { 544 t.Fatalf("unexpected error reading root cert for test: %v", err) 545 } 546 certs.certPEM, err = ioutil.ReadFile(filepath.Join("testdata", "certs", "Org1-client1-cert.pem")) 547 if err != nil { 548 t.Fatalf("unexpected error reading cert for test: %v", err) 549 } 550 certs.keyPEM, err = ioutil.ReadFile(filepath.Join("testdata", "certs", "Org1-client1-key.pem")) 551 if err != nil { 552 t.Fatalf("unexpected error reading key for test: %v", err) 553 } 554 certs.clientCert, err = tls.X509KeyPair(certs.certPEM, certs.keyPEM) 555 if err != nil { 556 t.Fatalf("unexpected error loading certificate for test: %v", err) 557 } 558 certs.serverCert, err = tls.LoadX509KeyPair( 559 filepath.Join("testdata", "certs", "Org1-server1-cert.pem"), 560 filepath.Join("testdata", "certs", "Org1-server1-key.pem"), 561 ) 562 assert.NoError(t, err) 563 564 return certs 565 } 566 567 func TestServerNameOverride(t *testing.T) { 568 tlsOption := comm.ServerNameOverride("override-name") 569 testConfig := &tls.Config{} 570 tlsOption(testConfig) 571 assert.Equal(t, &tls.Config{ 572 ServerName: "override-name", 573 }, testConfig) 574 } 575 576 func TestCertPoolOverride(t *testing.T) { 577 tlsOption := comm.CertPoolOverride(&x509.CertPool{}) 578 testConfig := &tls.Config{} 579 assert.NotEqual(t, &tls.Config{ 580 RootCAs: &x509.CertPool{}, 581 }, testConfig) 582 tlsOption(testConfig) 583 assert.Equal(t, &tls.Config{ 584 RootCAs: &x509.CertPool{}, 585 }, testConfig) 586 } 587 588 func TestDynamicClientTLSLoading(t *testing.T) { 589 t.Parallel() 590 ca1, err := tlsgen.NewCA() 591 assert.NoError(t, err) 592 593 ca2, err := tlsgen.NewCA() 594 assert.NoError(t, err) 595 596 clientKP, err := ca1.NewClientCertKeyPair() 597 assert.NoError(t, err) 598 599 serverKP, err := ca2.NewServerCertKeyPair("127.0.0.1") 600 assert.NoError(t, err) 601 602 client, err := comm.NewGRPCClient(comm.ClientConfig{ 603 AsyncConnect: true, 604 Timeout: time.Second * 1, 605 SecOpts: comm.SecureOptions{ 606 UseTLS: true, 607 ServerRootCAs: [][]byte{ca1.CertBytes()}, 608 Certificate: clientKP.Cert, 609 Key: clientKP.Key, 610 }, 611 }) 612 assert.NoError(t, err) 613 614 server, err := comm.NewGRPCServer("127.0.0.1:0", comm.ServerConfig{ 615 Logger: flogging.MustGetLogger("test"), 616 SecOpts: comm.SecureOptions{ 617 UseTLS: true, 618 Key: serverKP.Key, 619 Certificate: serverKP.Cert, 620 }, 621 }) 622 assert.NoError(t, err) 623 624 var wg sync.WaitGroup 625 wg.Add(1) 626 627 go func() { 628 defer wg.Done() 629 server.Start() 630 }() 631 632 var dynamicRootCerts atomic.Value 633 dynamicRootCerts.Store(ca1.CertBytes()) 634 635 conn, err := client.NewConnection(server.Address(), func(tlsConfig *tls.Config) { 636 tlsConfig.RootCAs = x509.NewCertPool() 637 tlsConfig.RootCAs.AppendCertsFromPEM(dynamicRootCerts.Load().([]byte)) 638 }) 639 assert.NoError(t, err) 640 assert.NotNil(t, conn) 641 642 waitForConnState := func(state connectivity.State, succeedOrFail string) { 643 deadline := time.Now().Add(time.Second * 30) 644 for conn.GetState() != state { 645 time.Sleep(time.Millisecond * 10) 646 if time.Now().After(deadline) { 647 t.Fatalf("Test timed out, waited for connection to %s", succeedOrFail) 648 } 649 } 650 } 651 652 // Poll the connection state to wait for it to fail 653 waitForConnState(connectivity.TransientFailure, "fail") 654 655 // Update the TLS root CAs with the good one 656 dynamicRootCerts.Store(ca2.CertBytes()) 657 658 // Reset exponential back-off to make the test faster 659 conn.ResetConnectBackoff() 660 661 // Poll the connection state to wait for it to succeed 662 waitForConnState(connectivity.Ready, "succeed") 663 664 err = conn.Close() 665 assert.NoError(t, err) 666 667 server.Stop() 668 wg.Wait() 669 }