github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/credentials/xds/xds_server_test.go (about) 1 /* 2 * 3 * Copyright 2020 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package xds 20 21 import ( 22 "context" 23 "errors" 24 "fmt" 25 "io/ioutil" 26 "net" 27 "strings" 28 "testing" 29 "time" 30 31 "github.com/hxx258456/ccgo/x509" 32 33 tls "github.com/hxx258456/ccgo/gmtls" 34 35 "github.com/hxx258456/ccgo/grpc/credentials" 36 "github.com/hxx258456/ccgo/grpc/credentials/tls/certprovider" 37 xdsinternal "github.com/hxx258456/ccgo/grpc/internal/credentials/xds" 38 "github.com/hxx258456/ccgo/grpc/testdata" 39 ) 40 41 func makeClientTLSConfig(t *testing.T, mTLS bool) *tls.Config { 42 t.Helper() 43 44 pemData, err := ioutil.ReadFile(testdata.Path("x509/server_ca_cert.pem")) 45 if err != nil { 46 t.Fatal(err) 47 } 48 roots := x509.NewCertPool() 49 roots.AppendCertsFromPEM(pemData) 50 51 var certs []tls.Certificate 52 if mTLS { 53 cert, err := tls.LoadX509KeyPair(testdata.Path("x509/client1_cert.pem"), testdata.Path("x509/client1_key.pem")) 54 if err != nil { 55 t.Fatal(err) 56 } 57 certs = append(certs, cert) 58 } 59 60 return &tls.Config{ 61 Certificates: certs, 62 RootCAs: roots, 63 ServerName: "*.test.example.com", 64 // Setting this to true completely turns off the certificate validation 65 // on the client side. So, the client side handshake always seems to 66 // succeed. But if we want to turn this ON, we will need to generate 67 // certificates which work with localhost, or supply a custom 68 // verification function. So, the server credentials tests will rely 69 // solely on the success/failure of the server-side handshake. 70 InsecureSkipVerify: true, 71 } 72 } 73 74 // Helper function to create a real TLS server credentials which is used as 75 // fallback credentials from multiple tests. 76 func makeFallbackServerCreds(t *testing.T) credentials.TransportCredentials { 77 t.Helper() 78 79 creds, err := credentials.NewServerTLSFromFile(testdata.Path("x509/server1_cert.pem"), testdata.Path("x509/server1_key.pem")) 80 if err != nil { 81 t.Fatal(err) 82 } 83 return creds 84 } 85 86 type errorCreds struct { 87 credentials.TransportCredentials 88 } 89 90 // TestServerCredsWithoutFallback verifies that the call to 91 // NewServerCredentials() fails when no fallback is specified. 92 func (s) TestServerCredsWithoutFallback(t *testing.T) { 93 if _, err := NewServerCredentials(ServerOptions{}); err == nil { 94 t.Fatal("NewServerCredentials() succeeded without specifying fallback") 95 } 96 } 97 98 type wrapperConn struct { 99 net.Conn 100 xdsHI *xdsinternal.HandshakeInfo 101 deadline time.Time 102 handshakeInfoErr error 103 } 104 105 func (wc *wrapperConn) XDSHandshakeInfo() (*xdsinternal.HandshakeInfo, error) { 106 return wc.xdsHI, wc.handshakeInfoErr 107 } 108 109 func (wc *wrapperConn) GetDeadline() time.Time { 110 return wc.deadline 111 } 112 113 func newWrappedConn(conn net.Conn, xdsHI *xdsinternal.HandshakeInfo, deadline time.Time) *wrapperConn { 114 return &wrapperConn{Conn: conn, xdsHI: xdsHI, deadline: deadline} 115 } 116 117 // TestServerCredsInvalidHandshakeInfo verifies scenarios where the passed in 118 // HandshakeInfo is invalid because it does not contain the expected certificate 119 // providers. 120 func (s) TestServerCredsInvalidHandshakeInfo(t *testing.T) { 121 opts := ServerOptions{FallbackCreds: &errorCreds{}} 122 creds, err := NewServerCredentials(opts) 123 if err != nil { 124 t.Fatalf("NewServerCredentials(%v) failed: %v", opts, err) 125 } 126 127 info := xdsinternal.NewHandshakeInfo(&fakeProvider{}, nil) 128 conn := newWrappedConn(nil, info, time.Time{}) 129 if _, _, err := creds.ServerHandshake(conn); err == nil { 130 t.Fatal("ServerHandshake succeeded without identity certificate provider in HandshakeInfo") 131 } 132 } 133 134 // TestServerCredsProviderFailure verifies the cases where an expected 135 // certificate provider is missing in the HandshakeInfo value in the context. 136 func (s) TestServerCredsProviderFailure(t *testing.T) { 137 opts := ServerOptions{FallbackCreds: &errorCreds{}} 138 creds, err := NewServerCredentials(opts) 139 if err != nil { 140 t.Fatalf("NewServerCredentials(%v) failed: %v", opts, err) 141 } 142 143 tests := []struct { 144 desc string 145 rootProvider certprovider.Provider 146 identityProvider certprovider.Provider 147 wantErr string 148 }{ 149 { 150 desc: "erroring identity provider", 151 identityProvider: &fakeProvider{err: errors.New("identity provider error")}, 152 wantErr: "identity provider error", 153 }, 154 { 155 desc: "erroring root provider", 156 identityProvider: &fakeProvider{km: &certprovider.KeyMaterial{}}, 157 rootProvider: &fakeProvider{err: errors.New("root provider error")}, 158 wantErr: "root provider error", 159 }, 160 } 161 for _, test := range tests { 162 t.Run(test.desc, func(t *testing.T) { 163 info := xdsinternal.NewHandshakeInfo(test.rootProvider, test.identityProvider) 164 conn := newWrappedConn(nil, info, time.Time{}) 165 if _, _, err := creds.ServerHandshake(conn); err == nil || !strings.Contains(err.Error(), test.wantErr) { 166 t.Fatalf("ServerHandshake() returned error: %q, wantErr: %q", err, test.wantErr) 167 } 168 }) 169 } 170 } 171 172 // TestServerCredsHandshake_XDSHandshakeInfoError verifies the case where the 173 // call to XDSHandshakeInfo() from the ServerHandshake() method returns an 174 // error, and the test verifies that the ServerHandshake() fails with the 175 // expected error. 176 func (s) TestServerCredsHandshake_XDSHandshakeInfoError(t *testing.T) { 177 opts := ServerOptions{FallbackCreds: &errorCreds{}} 178 creds, err := NewServerCredentials(opts) 179 if err != nil { 180 t.Fatalf("NewServerCredentials(%v) failed: %v", opts, err) 181 } 182 183 // Create a test server which uses the xDS server credentials created above 184 // to perform TLS handshake on incoming connections. 185 ts := newTestServerWithHandshakeFunc(func(rawConn net.Conn) handshakeResult { 186 // Create a wrapped conn which returns a nil HandshakeInfo and a non-nil error. 187 conn := newWrappedConn(rawConn, nil, time.Now().Add(defaultTestTimeout)) 188 hiErr := errors.New("xdsHandshakeInfo error") 189 conn.handshakeInfoErr = hiErr 190 191 // Invoke the ServerHandshake() method on the xDS credentials and verify 192 // that the error returned by the XDSHandshakeInfo() method on the 193 // wrapped conn is returned here. 194 _, _, err := creds.ServerHandshake(conn) 195 if !errors.Is(err, hiErr) { 196 return handshakeResult{err: fmt.Errorf("ServerHandshake() returned err: %v, wantErr: %v", err, hiErr)} 197 } 198 return handshakeResult{} 199 }) 200 defer ts.stop() 201 202 // Dial the test server, but don't trigger the TLS handshake. This will 203 // cause ServerHandshake() to fail. 204 rawConn, err := net.Dial("tcp", ts.address) 205 if err != nil { 206 t.Fatalf("net.Dial(%s) failed: %v", ts.address, err) 207 } 208 defer rawConn.Close() 209 210 // Read handshake result from the testServer which will return an error if 211 // the handshake succeeded. 212 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 213 defer cancel() 214 val, err := ts.hsResult.Receive(ctx) 215 if err != nil { 216 t.Fatalf("testServer failed to return handshake result: %v", err) 217 } 218 hsr := val.(handshakeResult) 219 if hsr.err != nil { 220 t.Fatalf("testServer handshake failure: %v", hsr.err) 221 } 222 } 223 224 // TestServerCredsHandshakeTimeout verifies the case where the client does not 225 // send required handshake data before the deadline set on the net.Conn passed 226 // to ServerHandshake(). 227 func (s) TestServerCredsHandshakeTimeout(t *testing.T) { 228 opts := ServerOptions{FallbackCreds: &errorCreds{}} 229 creds, err := NewServerCredentials(opts) 230 if err != nil { 231 t.Fatalf("NewServerCredentials(%v) failed: %v", opts, err) 232 } 233 234 // Create a test server which uses the xDS server credentials created above 235 // to perform TLS handshake on incoming connections. 236 ts := newTestServerWithHandshakeFunc(func(rawConn net.Conn) handshakeResult { 237 hi := xdsinternal.NewHandshakeInfo(makeRootProvider(t, "x509/client_ca_cert.pem"), makeIdentityProvider(t, "x509/server2_cert.pem", "x509/server2_key.pem")) 238 hi.SetRequireClientCert(true) 239 240 // Create a wrapped conn which can return the HandshakeInfo created 241 // above with a very small deadline. 242 d := time.Now().Add(defaultTestShortTimeout) 243 rawConn.SetDeadline(d) 244 conn := newWrappedConn(rawConn, hi, d) 245 246 // ServerHandshake() on the xDS credentials is expected to fail. 247 if _, _, err := creds.ServerHandshake(conn); err == nil { 248 return handshakeResult{err: errors.New("ServerHandshake() succeeded when expected to timeout")} 249 } 250 return handshakeResult{} 251 }) 252 defer ts.stop() 253 254 // Dial the test server, but don't trigger the TLS handshake. This will 255 // cause ServerHandshake() to fail. 256 rawConn, err := net.Dial("tcp", ts.address) 257 if err != nil { 258 t.Fatalf("net.Dial(%s) failed: %v", ts.address, err) 259 } 260 defer rawConn.Close() 261 262 // Read handshake result from the testServer and expect a failure result. 263 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 264 defer cancel() 265 val, err := ts.hsResult.Receive(ctx) 266 if err != nil { 267 t.Fatalf("testServer failed to return handshake result: %v", err) 268 } 269 hsr := val.(handshakeResult) 270 if hsr.err != nil { 271 t.Fatalf("testServer handshake failure: %v", hsr.err) 272 } 273 } 274 275 // TestServerCredsHandshakeFailure verifies the case where the server-side 276 // credentials uses a root certificate which does not match the certificate 277 // presented by the client, and hence the handshake must fail. 278 func (s) TestServerCredsHandshakeFailure(t *testing.T) { 279 opts := ServerOptions{FallbackCreds: &errorCreds{}} 280 creds, err := NewServerCredentials(opts) 281 if err != nil { 282 t.Fatalf("NewServerCredentials(%v) failed: %v", opts, err) 283 } 284 285 // Create a test server which uses the xDS server credentials created above 286 // to perform TLS handshake on incoming connections. 287 ts := newTestServerWithHandshakeFunc(func(rawConn net.Conn) handshakeResult { 288 // Create a HandshakeInfo which has a root provider which does not match 289 // the certificate sent by the client. 290 hi := xdsinternal.NewHandshakeInfo(makeRootProvider(t, "x509/server_ca_cert.pem"), makeIdentityProvider(t, "x509/client2_cert.pem", "x509/client2_key.pem")) 291 hi.SetRequireClientCert(true) 292 293 // Create a wrapped conn which can return the HandshakeInfo and 294 // configured deadline to the xDS credentials' ServerHandshake() 295 // method. 296 conn := newWrappedConn(rawConn, hi, time.Now().Add(defaultTestTimeout)) 297 298 // ServerHandshake() on the xDS credentials is expected to fail. 299 if _, _, err := creds.ServerHandshake(conn); err == nil { 300 return handshakeResult{err: errors.New("ServerHandshake() succeeded when expected to fail")} 301 } 302 return handshakeResult{} 303 }) 304 defer ts.stop() 305 306 // Dial the test server, and trigger the TLS handshake. 307 rawConn, err := net.Dial("tcp", ts.address) 308 if err != nil { 309 t.Fatalf("net.Dial(%s) failed: %v", ts.address, err) 310 } 311 defer rawConn.Close() 312 tlsConn := tls.Client(rawConn, makeClientTLSConfig(t, true)) 313 tlsConn.SetDeadline(time.Now().Add(defaultTestTimeout)) 314 if err := tlsConn.Handshake(); err != nil { 315 t.Fatal(err) 316 } 317 318 // Read handshake result from the testServer which will return an error if 319 // the handshake succeeded. 320 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 321 defer cancel() 322 val, err := ts.hsResult.Receive(ctx) 323 if err != nil { 324 t.Fatalf("testServer failed to return handshake result: %v", err) 325 } 326 hsr := val.(handshakeResult) 327 if hsr.err != nil { 328 t.Fatalf("testServer handshake failure: %v", hsr.err) 329 } 330 } 331 332 // TestServerCredsHandshakeSuccess verifies success handshake cases. 333 func (s) TestServerCredsHandshakeSuccess(t *testing.T) { 334 tests := []struct { 335 desc string 336 fallbackCreds credentials.TransportCredentials 337 rootProvider certprovider.Provider 338 identityProvider certprovider.Provider 339 requireClientCert bool 340 }{ 341 { 342 desc: "fallback", 343 fallbackCreds: makeFallbackServerCreds(t), 344 }, 345 { 346 desc: "TLS", 347 fallbackCreds: &errorCreds{}, 348 identityProvider: makeIdentityProvider(t, "x509/server2_cert.pem", "x509/server2_key.pem"), 349 }, 350 { 351 desc: "mTLS", 352 fallbackCreds: &errorCreds{}, 353 identityProvider: makeIdentityProvider(t, "x509/server2_cert.pem", "x509/server2_key.pem"), 354 rootProvider: makeRootProvider(t, "x509/client_ca_cert.pem"), 355 requireClientCert: true, 356 }, 357 } 358 359 for _, test := range tests { 360 t.Run(test.desc, func(t *testing.T) { 361 // Create an xDS server credentials. 362 opts := ServerOptions{FallbackCreds: test.fallbackCreds} 363 creds, err := NewServerCredentials(opts) 364 if err != nil { 365 t.Fatalf("NewServerCredentials(%v) failed: %v", opts, err) 366 } 367 368 // Create a test server which uses the xDS server credentials 369 // created above to perform TLS handshake on incoming connections. 370 ts := newTestServerWithHandshakeFunc(func(rawConn net.Conn) handshakeResult { 371 // Create a HandshakeInfo with information from the test table. 372 hi := xdsinternal.NewHandshakeInfo(test.rootProvider, test.identityProvider) 373 hi.SetRequireClientCert(test.requireClientCert) 374 375 // Create a wrapped conn which can return the HandshakeInfo and 376 // configured deadline to the xDS credentials' ServerHandshake() 377 // method. 378 conn := newWrappedConn(rawConn, hi, time.Now().Add(defaultTestTimeout)) 379 380 // Invoke the ServerHandshake() method on the xDS credentials 381 // and make some sanity checks before pushing the result for 382 // inspection by the main test body. 383 _, ai, err := creds.ServerHandshake(conn) 384 if err != nil { 385 return handshakeResult{err: fmt.Errorf("ServerHandshake() failed: %v", err)} 386 } 387 if ai.AuthType() != "tls" { 388 return handshakeResult{err: fmt.Errorf("ServerHandshake returned authType %q, want %q", ai.AuthType(), "tls")} 389 } 390 info, ok := ai.(credentials.TLSInfo) 391 if !ok { 392 return handshakeResult{err: fmt.Errorf("ServerHandshake returned authInfo of type %T, want %T", ai, credentials.TLSInfo{})} 393 } 394 return handshakeResult{connState: info.State} 395 }) 396 defer ts.stop() 397 398 // Dial the test server, and trigger the TLS handshake. 399 rawConn, err := net.Dial("tcp", ts.address) 400 if err != nil { 401 t.Fatalf("net.Dial(%s) failed: %v", ts.address, err) 402 } 403 defer rawConn.Close() 404 tlsConn := tls.Client(rawConn, makeClientTLSConfig(t, test.requireClientCert)) 405 tlsConn.SetDeadline(time.Now().Add(defaultTestTimeout)) 406 if err := tlsConn.Handshake(); err != nil { 407 t.Fatal(err) 408 } 409 410 // Read the handshake result from the testServer which contains the 411 // TLS connection state on the server-side and compare it with the 412 // one received on the client-side. 413 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 414 defer cancel() 415 val, err := ts.hsResult.Receive(ctx) 416 if err != nil { 417 t.Fatalf("testServer failed to return handshake result: %v", err) 418 } 419 hsr := val.(handshakeResult) 420 if hsr.err != nil { 421 t.Fatalf("testServer handshake failure: %v", hsr.err) 422 } 423 424 // AuthInfo contains a variety of information. We only verify a 425 // subset here. This is the same subset which is verified in TLS 426 // credentials tests. 427 if err := compareConnState(tlsConn.ConnectionState(), hsr.connState); err != nil { 428 t.Fatal(err) 429 } 430 }) 431 } 432 } 433 434 func (s) TestServerCredsProviderSwitch(t *testing.T) { 435 opts := ServerOptions{FallbackCreds: &errorCreds{}} 436 creds, err := NewServerCredentials(opts) 437 if err != nil { 438 t.Fatalf("NewServerCredentials(%v) failed: %v", opts, err) 439 } 440 441 // The first time the handshake function is invoked, it returns a 442 // HandshakeInfo which is expected to fail. Further invocations return a 443 // HandshakeInfo which is expected to succeed. 444 cnt := 0 445 // Create a test server which uses the xDS server credentials created above 446 // to perform TLS handshake on incoming connections. 447 ts := newTestServerWithHandshakeFunc(func(rawConn net.Conn) handshakeResult { 448 cnt++ 449 var hi *xdsinternal.HandshakeInfo 450 if cnt == 1 { 451 // Create a HandshakeInfo which has a root provider which does not match 452 // the certificate sent by the client. 453 hi = xdsinternal.NewHandshakeInfo(makeRootProvider(t, "x509/server_ca_cert.pem"), makeIdentityProvider(t, "x509/client2_cert.pem", "x509/client2_key.pem")) 454 hi.SetRequireClientCert(true) 455 456 // Create a wrapped conn which can return the HandshakeInfo and 457 // configured deadline to the xDS credentials' ServerHandshake() 458 // method. 459 conn := newWrappedConn(rawConn, hi, time.Now().Add(defaultTestTimeout)) 460 461 // ServerHandshake() on the xDS credentials is expected to fail. 462 if _, _, err := creds.ServerHandshake(conn); err == nil { 463 return handshakeResult{err: errors.New("ServerHandshake() succeeded when expected to fail")} 464 } 465 return handshakeResult{} 466 } 467 468 hi = xdsinternal.NewHandshakeInfo(makeRootProvider(t, "x509/client_ca_cert.pem"), makeIdentityProvider(t, "x509/server1_cert.pem", "x509/server1_key.pem")) 469 hi.SetRequireClientCert(true) 470 471 // Create a wrapped conn which can return the HandshakeInfo and 472 // configured deadline to the xDS credentials' ServerHandshake() 473 // method. 474 conn := newWrappedConn(rawConn, hi, time.Now().Add(defaultTestTimeout)) 475 476 // Invoke the ServerHandshake() method on the xDS credentials 477 // and make some sanity checks before pushing the result for 478 // inspection by the main test body. 479 _, ai, err := creds.ServerHandshake(conn) 480 if err != nil { 481 return handshakeResult{err: fmt.Errorf("ServerHandshake() failed: %v", err)} 482 } 483 if ai.AuthType() != "tls" { 484 return handshakeResult{err: fmt.Errorf("ServerHandshake returned authType %q, want %q", ai.AuthType(), "tls")} 485 } 486 info, ok := ai.(credentials.TLSInfo) 487 if !ok { 488 return handshakeResult{err: fmt.Errorf("ServerHandshake returned authInfo of type %T, want %T", ai, credentials.TLSInfo{})} 489 } 490 return handshakeResult{connState: info.State} 491 }) 492 defer ts.stop() 493 494 for i := 0; i < 5; i++ { 495 // Dial the test server, and trigger the TLS handshake. 496 rawConn, err := net.Dial("tcp", ts.address) 497 if err != nil { 498 t.Fatalf("net.Dial(%s) failed: %v", ts.address, err) 499 } 500 defer rawConn.Close() 501 tlsConn := tls.Client(rawConn, makeClientTLSConfig(t, true)) 502 tlsConn.SetDeadline(time.Now().Add(defaultTestTimeout)) 503 if err := tlsConn.Handshake(); err != nil { 504 t.Fatal(err) 505 } 506 507 // Read the handshake result from the testServer which contains the 508 // TLS connection state on the server-side and compare it with the 509 // one received on the client-side. 510 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 511 defer cancel() 512 val, err := ts.hsResult.Receive(ctx) 513 if err != nil { 514 t.Fatalf("testServer failed to return handshake result: %v", err) 515 } 516 hsr := val.(handshakeResult) 517 if hsr.err != nil { 518 t.Fatalf("testServer handshake failure: %v", hsr.err) 519 } 520 if i == 0 { 521 // We expect the first handshake to fail. So, we skip checks which 522 // compare connection state. 523 continue 524 } 525 // AuthInfo contains a variety of information. We only verify a 526 // subset here. This is the same subset which is verified in TLS 527 // credentials tests. 528 if err := compareConnState(tlsConn.ConnectionState(), hsr.connState); err != nil { 529 t.Fatal(err) 530 } 531 } 532 } 533 534 // TestServerClone verifies the Clone() method on client credentials. 535 func (s) TestServerClone(t *testing.T) { 536 opts := ServerOptions{FallbackCreds: makeFallbackServerCreds(t)} 537 orig, err := NewServerCredentials(opts) 538 if err != nil { 539 t.Fatalf("NewServerCredentials(%v) failed: %v", opts, err) 540 } 541 542 // The credsImpl does not have any exported fields, and it does not make 543 // sense to use any cmp options to look deep into. So, all we make sure here 544 // is that the cloned object points to a different location in memory. 545 if clone := orig.Clone(); clone == orig { 546 t.Fatal("return value from Clone() doesn't point to new credentials instance") 547 } 548 }