From c9e99945ec5859f099e7c8b9ca16ecf73317646a Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Tue, 8 Dec 2020 15:15:39 -0800 Subject: [PATCH] Add SANs matching for xDS credentials --- BUILD | 56 +--- BUILD.gn | 4 +- CMakeLists.txt | 42 ++- Makefile | 8 +- build_autogenerated.yaml | 21 +- config.m4 | 2 +- config.w32 | 2 +- gRPC-C++.podspec | 4 +- gRPC-Core.podspec | 6 +- grpc.gemspec | 4 +- grpc.gyp | 2 +- include/grpc/grpc_security.h | 4 + package.xml | 4 +- .../client_channel/lb_policy/xds/cds.cc | 23 +- src/core/ext/xds/xds_api.cc | 250 ++++++++++++-- src/core/ext/xds/xds_api.h | 51 ++- src/core/ext/xds/xds_certificate_provider.cc | 10 +- src/core/ext/xds/xds_certificate_provider.h | 32 +- src/core/ext/xds/xds_client.cc | 9 +- .../lib/security/credentials/tls/tls_utils.cc | 91 ++++++ .../lib/security/credentials/tls/tls_utils.h | 38 +++ .../credentials/xds/xds_credentials.cc | 58 +++- .../credentials/xds/xds_credentials.h | 6 + .../tls/tls_security_connector.cc | 42 +++ src/proto/grpc/testing/xds/v3/BUILD | 3 + src/proto/grpc/testing/xds/v3/string.proto | 29 ++ src/python/grpcio/grpc_core_dependencies.py | 2 +- test/core/security/BUILD | 14 + test/core/security/xds_credentials_test.cc | 306 ++++++++++++++++++ test/core/xds/BUILD | 1 + .../core/xds/xds_certificate_provider_test.cc | 13 +- test/cpp/end2end/xds_end2end_test.cc | 300 +++++++++++++++-- tools/doxygen/Doxyfile.c++.internal | 4 +- tools/doxygen/Doxyfile.core.internal | 4 +- tools/run_tests/generated/tests.json | 24 ++ 35 files changed, 1292 insertions(+), 177 deletions(-) create mode 100644 src/core/lib/security/credentials/tls/tls_utils.cc create mode 100644 src/core/lib/security/credentials/tls/tls_utils.h create mode 100644 test/core/security/xds_credentials_test.cc diff --git a/BUILD b/BUILD index 89e4fc0f58b..c4bae380111 100644 --- a/BUILD +++ b/BUILD @@ -327,7 +327,6 @@ grpc_cc_library( "grpc_lb_policy_xds_cluster_impl", "grpc_lb_policy_xds_cluster_manager", "grpc_resolver_xds", - "grpc_xds_credentials", ], }, standalone = True, @@ -1343,45 +1342,33 @@ grpc_cc_library( ) grpc_cc_library( - name = "grpc_xds_credentials", + name = "grpc_xds_client", srcs = [ "src/core/ext/xds/certificate_provider_registry.cc", "src/core/ext/xds/certificate_provider_store.cc", + "src/core/ext/xds/file_watcher_certificate_provider_factory.cc", + "src/core/ext/xds/xds_api.cc", + "src/core/ext/xds/xds_bootstrap.cc", "src/core/ext/xds/xds_certificate_provider.cc", + "src/core/ext/xds/xds_client.cc", + "src/core/ext/xds/xds_client_stats.cc", "src/core/lib/security/credentials/xds/xds_credentials.cc", ], hdrs = [ "src/core/ext/xds/certificate_provider_factory.h", "src/core/ext/xds/certificate_provider_registry.h", "src/core/ext/xds/certificate_provider_store.h", - "src/core/ext/xds/xds_certificate_provider.h", - "src/core/lib/security/credentials/xds/xds_credentials.h", - ], - external_deps = [ - "absl/functional:bind_front", - ], - language = "c++", - deps = [ - "grpc_secure", - ], -) - -grpc_cc_library( - name = "grpc_xds_client", - srcs = [ - "src/core/ext/xds/xds_api.cc", - "src/core/ext/xds/xds_bootstrap.cc", - "src/core/ext/xds/xds_client.cc", - "src/core/ext/xds/xds_client_stats.cc", - ], - hdrs = [ + "src/core/ext/xds/file_watcher_certificate_provider_factory.h", "src/core/ext/xds/xds_api.h", "src/core/ext/xds/xds_bootstrap.h", + "src/core/ext/xds/xds_certificate_provider.h", "src/core/ext/xds/xds_channel_args.h", "src/core/ext/xds/xds_client.h", "src/core/ext/xds/xds_client_stats.h", + "src/core/lib/security/credentials/xds/xds_credentials.h", ], external_deps = [ + "absl/functional:bind_front", "upb_lib", "upb_textformat_lib", "re2", @@ -1392,25 +1379,8 @@ grpc_cc_library( "envoy_ads_upbdefs", "grpc_base", "grpc_client_channel", - "grpc_file_watcher_certificate_provider_factory", - "grpc_google_mesh_ca_certificate_provider_factory", + "grpc_secure", "grpc_transport_chttp2_client_secure", - "grpc_xds_credentials", - ], -) - -grpc_cc_library( - name = "grpc_file_watcher_certificate_provider_factory", - srcs = [ - "src/core/ext/xds/file_watcher_certificate_provider_factory.cc", - ], - hdrs = [ - "src/core/ext/xds/file_watcher_certificate_provider_factory.h", - ], - language = "c++", - deps = [ - "grpc_base", - "grpc_xds_credentials", ], ) @@ -1425,7 +1395,7 @@ grpc_cc_library( language = "c++", deps = [ "grpc_base", - "grpc_xds_credentials", + "grpc_xds_client", ], ) @@ -1841,6 +1811,7 @@ grpc_cc_library( "src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.cc", "src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc", "src/core/lib/security/credentials/tls/tls_credentials.cc", + "src/core/lib/security/credentials/tls/tls_utils.cc", "src/core/lib/security/security_connector/alts/alts_security_connector.cc", "src/core/lib/security/security_connector/fake/fake_security_connector.cc", "src/core/lib/security/security_connector/insecure/insecure_security_connector.cc", @@ -1886,6 +1857,7 @@ grpc_cc_library( "src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h", "src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h", "src/core/lib/security/credentials/tls/tls_credentials.h", + "src/core/lib/security/credentials/tls/tls_utils.h", "src/core/lib/security/security_connector/alts/alts_security_connector.h", "src/core/lib/security/security_connector/fake/fake_security_connector.h", "src/core/lib/security/security_connector/insecure/insecure_security_connector.h", diff --git a/BUILD.gn b/BUILD.gn index b43ac2edee9..441fc2019d3 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -728,8 +728,6 @@ config("grpc_config") { "src/core/ext/xds/certificate_provider_store.h", "src/core/ext/xds/file_watcher_certificate_provider_factory.cc", "src/core/ext/xds/file_watcher_certificate_provider_factory.h", - "src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc", - "src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h", "src/core/ext/xds/xds_api.cc", "src/core/ext/xds/xds_api.h", "src/core/ext/xds/xds_bootstrap.cc", @@ -1047,6 +1045,8 @@ config("grpc_config") { "src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h", "src/core/lib/security/credentials/tls/tls_credentials.cc", "src/core/lib/security/credentials/tls/tls_credentials.h", + "src/core/lib/security/credentials/tls/tls_utils.cc", + "src/core/lib/security/credentials/tls/tls_utils.h", "src/core/lib/security/credentials/xds/xds_credentials.cc", "src/core/lib/security/credentials/xds/xds_credentials.h", "src/core/lib/security/security_connector/alts/alts_security_connector.cc", diff --git a/CMakeLists.txt b/CMakeLists.txt index 6920179cd4f..0bca1ef7479 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -947,6 +947,7 @@ if(gRPC_BUILD_TESTS) add_dependencies(buildtests_cxx xds_bootstrap_test) add_dependencies(buildtests_cxx xds_certificate_provider_test) add_dependencies(buildtests_cxx xds_credentials_end2end_test) + add_dependencies(buildtests_cxx xds_credentials_test) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) add_dependencies(buildtests_cxx xds_end2end_test) endif() @@ -1715,7 +1716,6 @@ add_library(grpc src/core/ext/xds/certificate_provider_registry.cc src/core/ext/xds/certificate_provider_store.cc src/core/ext/xds/file_watcher_certificate_provider_factory.cc - src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc src/core/ext/xds/xds_api.cc src/core/ext/xds/xds_bootstrap.cc src/core/ext/xds/xds_certificate_provider.cc @@ -1881,6 +1881,7 @@ add_library(grpc src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.cc src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc src/core/lib/security/credentials/tls/tls_credentials.cc + src/core/lib/security/credentials/tls/tls_utils.cc src/core/lib/security/credentials/xds/xds_credentials.cc src/core/lib/security/security_connector/alts/alts_security_connector.cc src/core/lib/security/security_connector/fake/fake_security_connector.cc @@ -11324,6 +11325,7 @@ endif() if(gRPC_BUILD_TESTS) add_executable(google_mesh_ca_certificate_provider_factory_test + src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc test/core/xds/google_mesh_ca_certificate_provider_factory_test.cc third_party/googletest/googletest/src/gtest-all.cc third_party/googletest/googlemock/src/gmock-all.cc @@ -15428,6 +15430,44 @@ target_link_libraries(xds_credentials_end2end_test ) +endif() +if(gRPC_BUILD_TESTS) + +add_executable(xds_credentials_test + test/core/security/xds_credentials_test.cc + third_party/googletest/googletest/src/gtest-all.cc + third_party/googletest/googlemock/src/gmock-all.cc +) + +target_include_directories(xds_credentials_test + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + ${_gRPC_RE2_INCLUDE_DIR} + ${_gRPC_SSL_INCLUDE_DIR} + ${_gRPC_UPB_GENERATED_DIR} + ${_gRPC_UPB_GRPC_GENERATED_DIR} + ${_gRPC_UPB_INCLUDE_DIR} + ${_gRPC_ZLIB_INCLUDE_DIR} + third_party/googletest/googletest/include + third_party/googletest/googletest + third_party/googletest/googlemock/include + third_party/googletest/googlemock + ${_gRPC_PROTO_GENS_DIR} +) + +target_link_libraries(xds_credentials_test + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc_test_util + grpc + gpr + address_sorting + upb +) + + endif() if(gRPC_BUILD_TESTS) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) diff --git a/Makefile b/Makefile index 67dcf0a2794..f632b8fe6f7 100644 --- a/Makefile +++ b/Makefile @@ -1566,12 +1566,12 @@ $(GENDIR)/src/proto/grpc/testing/xds/v3/string.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/xds/v3/string.grpc.pb.cc: protoc_dep_error else -$(GENDIR)/src/proto/grpc/testing/xds/v3/string.pb.cc: src/proto/grpc/testing/xds/v3/string.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) +$(GENDIR)/src/proto/grpc/testing/xds/v3/string.pb.cc: src/proto/grpc/testing/xds/v3/string.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/xds/v3/regex.pb.cc $(E) "[PROTOC] Generating protobuf CC file from $<" $(Q) mkdir -p `dirname $@` $(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $< -$(GENDIR)/src/proto/grpc/testing/xds/v3/string.grpc.pb.cc: src/proto/grpc/testing/xds/v3/string.proto $(GENDIR)/src/proto/grpc/testing/xds/v3/string.pb.cc $(PROTOBUF_DEP) $(PROTOC_PLUGINS) +$(GENDIR)/src/proto/grpc/testing/xds/v3/string.grpc.pb.cc: src/proto/grpc/testing/xds/v3/string.proto $(GENDIR)/src/proto/grpc/testing/xds/v3/string.pb.cc $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/xds/v3/regex.pb.cc $(GENDIR)/src/proto/grpc/testing/xds/v3/regex.grpc.pb.cc $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" $(Q) mkdir -p `dirname $@` $(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $< @@ -2141,7 +2141,6 @@ LIBGRPC_SRC = \ src/core/ext/xds/certificate_provider_registry.cc \ src/core/ext/xds/certificate_provider_store.cc \ src/core/ext/xds/file_watcher_certificate_provider_factory.cc \ - src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc \ src/core/ext/xds/xds_api.cc \ src/core/ext/xds/xds_bootstrap.cc \ src/core/ext/xds/xds_certificate_provider.cc \ @@ -2307,6 +2306,7 @@ LIBGRPC_SRC = \ src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.cc \ src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc \ src/core/lib/security/credentials/tls/tls_credentials.cc \ + src/core/lib/security/credentials/tls/tls_utils.cc \ src/core/lib/security/credentials/xds/xds_credentials.cc \ src/core/lib/security/security_connector/alts/alts_security_connector.cc \ src/core/lib/security/security_connector/fake/fake_security_connector.cc \ @@ -4812,7 +4812,6 @@ src/core/ext/upbdefs-generated/validate/validate.upbdefs.c: $(OPENSSL_DEP) src/core/ext/xds/certificate_provider_registry.cc: $(OPENSSL_DEP) src/core/ext/xds/certificate_provider_store.cc: $(OPENSSL_DEP) src/core/ext/xds/file_watcher_certificate_provider_factory.cc: $(OPENSSL_DEP) -src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc: $(OPENSSL_DEP) src/core/ext/xds/xds_api.cc: $(OPENSSL_DEP) src/core/ext/xds/xds_bootstrap.cc: $(OPENSSL_DEP) src/core/ext/xds/xds_certificate_provider.cc: $(OPENSSL_DEP) @@ -4854,6 +4853,7 @@ src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc: $(OPE src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.cc: $(OPENSSL_DEP) src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc: $(OPENSSL_DEP) src/core/lib/security/credentials/tls/tls_credentials.cc: $(OPENSSL_DEP) +src/core/lib/security/credentials/tls/tls_utils.cc: $(OPENSSL_DEP) src/core/lib/security/credentials/xds/xds_credentials.cc: $(OPENSSL_DEP) src/core/lib/security/security_connector/alts/alts_security_connector.cc: $(OPENSSL_DEP) src/core/lib/security/security_connector/fake/fake_security_connector.cc: $(OPENSSL_DEP) diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index 153ebff08c7..3dd7034abdf 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -632,7 +632,6 @@ libs: - src/core/ext/xds/certificate_provider_registry.h - src/core/ext/xds/certificate_provider_store.h - src/core/ext/xds/file_watcher_certificate_provider_factory.h - - src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h - src/core/ext/xds/xds_api.h - src/core/ext/xds/xds_bootstrap.h - src/core/ext/xds/xds_certificate_provider.h @@ -785,6 +784,7 @@ libs: - src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h - src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h - src/core/lib/security/credentials/tls/tls_credentials.h + - src/core/lib/security/credentials/tls/tls_utils.h - src/core/lib/security/credentials/xds/xds_credentials.h - src/core/lib/security/security_connector/alts/alts_security_connector.h - src/core/lib/security/security_connector/fake/fake_security_connector.h @@ -1136,7 +1136,6 @@ libs: - src/core/ext/xds/certificate_provider_registry.cc - src/core/ext/xds/certificate_provider_store.cc - src/core/ext/xds/file_watcher_certificate_provider_factory.cc - - src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc - src/core/ext/xds/xds_api.cc - src/core/ext/xds/xds_bootstrap.cc - src/core/ext/xds/xds_certificate_provider.cc @@ -1302,6 +1301,7 @@ libs: - src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.cc - src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc - src/core/lib/security/credentials/tls/tls_credentials.cc + - src/core/lib/security/credentials/tls/tls_utils.cc - src/core/lib/security/credentials/xds/xds_credentials.cc - src/core/lib/security/security_connector/alts/alts_security_connector.cc - src/core/lib/security/security_connector/fake/fake_security_connector.cc @@ -6091,8 +6091,10 @@ targets: gtest: true build: test language: c++ - headers: [] + headers: + - src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h src: + - src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc - test/core/xds/google_mesh_ca_certificate_provider_factory_test.cc deps: - grpc_test_util @@ -7919,6 +7921,19 @@ targets: - gpr - address_sorting - upb +- name: xds_credentials_test + gtest: true + build: test + language: c++ + headers: [] + src: + - test/core/security/xds_credentials_test.cc + deps: + - grpc_test_util + - grpc + - gpr + - address_sorting + - upb - name: xds_end2end_test gtest: true build: test diff --git a/config.m4 b/config.m4 index 564013dc9c1..4b450dedf16 100644 --- a/config.m4 +++ b/config.m4 @@ -312,7 +312,6 @@ if test "$PHP_GRPC" != "no"; then src/core/ext/xds/certificate_provider_registry.cc \ src/core/ext/xds/certificate_provider_store.cc \ src/core/ext/xds/file_watcher_certificate_provider_factory.cc \ - src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc \ src/core/ext/xds/xds_api.cc \ src/core/ext/xds/xds_bootstrap.cc \ src/core/ext/xds/xds_certificate_provider.cc \ @@ -522,6 +521,7 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.cc \ src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc \ src/core/lib/security/credentials/tls/tls_credentials.cc \ + src/core/lib/security/credentials/tls/tls_utils.cc \ src/core/lib/security/credentials/xds/xds_credentials.cc \ src/core/lib/security/security_connector/alts/alts_security_connector.cc \ src/core/lib/security/security_connector/fake/fake_security_connector.cc \ diff --git a/config.w32 b/config.w32 index 824d7fd69d1..a2cb370c28e 100644 --- a/config.w32 +++ b/config.w32 @@ -279,7 +279,6 @@ if (PHP_GRPC != "no") { "src\\core\\ext\\xds\\certificate_provider_registry.cc " + "src\\core\\ext\\xds\\certificate_provider_store.cc " + "src\\core\\ext\\xds\\file_watcher_certificate_provider_factory.cc " + - "src\\core\\ext\\xds\\google_mesh_ca_certificate_provider_factory.cc " + "src\\core\\ext\\xds\\xds_api.cc " + "src\\core\\ext\\xds\\xds_bootstrap.cc " + "src\\core\\ext\\xds\\xds_certificate_provider.cc " + @@ -489,6 +488,7 @@ if (PHP_GRPC != "no") { "src\\core\\lib\\security\\credentials\\tls\\grpc_tls_certificate_provider.cc " + "src\\core\\lib\\security\\credentials\\tls\\grpc_tls_credentials_options.cc " + "src\\core\\lib\\security\\credentials\\tls\\tls_credentials.cc " + + "src\\core\\lib\\security\\credentials\\tls\\tls_utils.cc " + "src\\core\\lib\\security\\credentials\\xds\\xds_credentials.cc " + "src\\core\\lib\\security\\security_connector\\alts\\alts_security_connector.cc " + "src\\core\\lib\\security\\security_connector\\fake\\fake_security_connector.cc " + diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index af3cfcedc93..f3416989ea2 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -448,7 +448,6 @@ Pod::Spec.new do |s| 'src/core/ext/xds/certificate_provider_registry.h', 'src/core/ext/xds/certificate_provider_store.h', 'src/core/ext/xds/file_watcher_certificate_provider_factory.h', - 'src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h', 'src/core/ext/xds/xds_api.h', 'src/core/ext/xds/xds_bootstrap.h', 'src/core/ext/xds/xds_certificate_provider.h', @@ -632,6 +631,7 @@ Pod::Spec.new do |s| 'src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h', 'src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h', 'src/core/lib/security/credentials/tls/tls_credentials.h', + 'src/core/lib/security/credentials/tls/tls_utils.h', 'src/core/lib/security/credentials/xds/xds_credentials.h', 'src/core/lib/security/security_connector/alts/alts_security_connector.h', 'src/core/lib/security/security_connector/fake/fake_security_connector.h', @@ -1059,7 +1059,6 @@ Pod::Spec.new do |s| 'src/core/ext/xds/certificate_provider_registry.h', 'src/core/ext/xds/certificate_provider_store.h', 'src/core/ext/xds/file_watcher_certificate_provider_factory.h', - 'src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h', 'src/core/ext/xds/xds_api.h', 'src/core/ext/xds/xds_bootstrap.h', 'src/core/ext/xds/xds_certificate_provider.h', @@ -1243,6 +1242,7 @@ Pod::Spec.new do |s| 'src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h', 'src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h', 'src/core/lib/security/credentials/tls/tls_credentials.h', + 'src/core/lib/security/credentials/tls/tls_utils.h', 'src/core/lib/security/credentials/xds/xds_credentials.h', 'src/core/lib/security/security_connector/alts/alts_security_connector.h', 'src/core/lib/security/security_connector/fake/fake_security_connector.h', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 6241dcb7d85..06d2a5a21ea 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -711,8 +711,6 @@ Pod::Spec.new do |s| 'src/core/ext/xds/certificate_provider_store.h', 'src/core/ext/xds/file_watcher_certificate_provider_factory.cc', 'src/core/ext/xds/file_watcher_certificate_provider_factory.h', - 'src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc', - 'src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h', 'src/core/ext/xds/xds_api.cc', 'src/core/ext/xds/xds_api.h', 'src/core/ext/xds/xds_bootstrap.cc', @@ -1105,6 +1103,8 @@ Pod::Spec.new do |s| 'src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h', 'src/core/lib/security/credentials/tls/tls_credentials.cc', 'src/core/lib/security/credentials/tls/tls_credentials.h', + 'src/core/lib/security/credentials/tls/tls_utils.cc', + 'src/core/lib/security/credentials/tls/tls_utils.h', 'src/core/lib/security/credentials/xds/xds_credentials.cc', 'src/core/lib/security/credentials/xds/xds_credentials.h', 'src/core/lib/security/security_connector/alts/alts_security_connector.cc', @@ -1589,7 +1589,6 @@ Pod::Spec.new do |s| 'src/core/ext/xds/certificate_provider_registry.h', 'src/core/ext/xds/certificate_provider_store.h', 'src/core/ext/xds/file_watcher_certificate_provider_factory.h', - 'src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h', 'src/core/ext/xds/xds_api.h', 'src/core/ext/xds/xds_bootstrap.h', 'src/core/ext/xds/xds_certificate_provider.h', @@ -1773,6 +1772,7 @@ Pod::Spec.new do |s| 'src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h', 'src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h', 'src/core/lib/security/credentials/tls/tls_credentials.h', + 'src/core/lib/security/credentials/tls/tls_utils.h', 'src/core/lib/security/credentials/xds/xds_credentials.h', 'src/core/lib/security/security_connector/alts/alts_security_connector.h', 'src/core/lib/security/security_connector/fake/fake_security_connector.h', diff --git a/grpc.gemspec b/grpc.gemspec index 6930bae1f87..e3966d64194 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -626,8 +626,6 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/xds/certificate_provider_store.h ) s.files += %w( src/core/ext/xds/file_watcher_certificate_provider_factory.cc ) s.files += %w( src/core/ext/xds/file_watcher_certificate_provider_factory.h ) - s.files += %w( src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc ) - s.files += %w( src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h ) s.files += %w( src/core/ext/xds/xds_api.cc ) s.files += %w( src/core/ext/xds/xds_api.h ) s.files += %w( src/core/ext/xds/xds_bootstrap.cc ) @@ -1020,6 +1018,8 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h ) s.files += %w( src/core/lib/security/credentials/tls/tls_credentials.cc ) s.files += %w( src/core/lib/security/credentials/tls/tls_credentials.h ) + s.files += %w( src/core/lib/security/credentials/tls/tls_utils.cc ) + s.files += %w( src/core/lib/security/credentials/tls/tls_utils.h ) s.files += %w( src/core/lib/security/credentials/xds/xds_credentials.cc ) s.files += %w( src/core/lib/security/credentials/xds/xds_credentials.h ) s.files += %w( src/core/lib/security/security_connector/alts/alts_security_connector.cc ) diff --git a/grpc.gyp b/grpc.gyp index c6b00e7d1a3..5ed95707fb6 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -724,7 +724,6 @@ 'src/core/ext/xds/certificate_provider_registry.cc', 'src/core/ext/xds/certificate_provider_store.cc', 'src/core/ext/xds/file_watcher_certificate_provider_factory.cc', - 'src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc', 'src/core/ext/xds/xds_api.cc', 'src/core/ext/xds/xds_bootstrap.cc', 'src/core/ext/xds/xds_certificate_provider.cc', @@ -890,6 +889,7 @@ 'src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.cc', 'src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc', 'src/core/lib/security/credentials/tls/tls_credentials.cc', + 'src/core/lib/security/credentials/tls/tls_utils.cc', 'src/core/lib/security/credentials/xds/xds_credentials.cc', 'src/core/lib/security/security_connector/alts/alts_security_connector.cc', 'src/core/lib/security/security_connector/fake/fake_security_connector.cc', diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index 5928a2352e4..51339291754 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -942,6 +942,8 @@ typedef void (*grpc_tls_on_server_authorization_check_done_cb)( - target_name is the name of an endpoint the channel is connecting to. - peer_cert represents a complete certificate chain including both signing and leaf certificates. + - \a subject_alternative_names is an array of size + \a subject_alternative_names_size consisting of pointers to strings. - status and error_details contain information about errors occurred when a server authorization check request is scheduled/cancelled. @@ -961,6 +963,8 @@ struct grpc_tls_server_authorization_check_arg { const char* target_name; const char* peer_cert; const char* peer_cert_full_chain; + char** subject_alternative_names; + size_t subject_alternative_names_size; grpc_status_code status; grpc_tls_error_details* error_details; grpc_tls_server_authorization_check_config* config; diff --git a/package.xml b/package.xml index 86a65539804..ab66c008e3c 100644 --- a/package.xml +++ b/package.xml @@ -606,8 +606,6 @@ - - @@ -1000,6 +998,8 @@ + + diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc b/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc index cf343c81cb9..7613406a3d4 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc +++ b/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc @@ -321,15 +321,8 @@ void CdsLb::UpdateLocked(UpdateArgs args) { void CdsLb::OnClusterChanged(XdsApi::CdsUpdate cluster_data) { if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) { - gpr_log(GPR_INFO, - "[cdslb %p] received CDS update from xds client %p: " - "eds_service_name=%s lrs_load_reporting_server_name=%s " - "max_concurrent_requests=%d", - this, xds_client_.get(), cluster_data.eds_service_name.c_str(), - cluster_data.lrs_load_reporting_server_name.has_value() - ? cluster_data.lrs_load_reporting_server_name.value().c_str() - : "(unset)", - cluster_data.max_concurrent_requests); + gpr_log(GPR_INFO, "[cdslb %p] received CDS update from xds client %p: %s", + this, xds_client_.get(), cluster_data.ToString().c_str()); } grpc_error* error = GRPC_ERROR_NONE; error = UpdateXdsCertificateProvider(cluster_data); @@ -517,6 +510,9 @@ grpc_error* CdsLb::UpdateXdsCertificateProvider( } identity_certificate_provider_ = std::move(new_identity_provider); } + const std::vector& match_subject_alt_names = + cluster_data.common_tls_context.combined_validation_context + .default_validation_context.match_subject_alt_names; if (!root_provider_instance_name.empty() && !identity_provider_instance_name.empty()) { // Using mTLS configuration @@ -528,6 +524,8 @@ grpc_error* CdsLb::UpdateXdsCertificateProvider( xds_certificate_provider_->UpdateIdentityCertNameAndDistributor( identity_provider_cert_name, identity_certificate_provider_->distributor()); + xds_certificate_provider_->UpdateSubjectAlternativeNameMatchers( + match_subject_alt_names); } else { // Existing xDS certificate provider does not have mTLS configuration. // Create new certificate provider so that new subchannel connectors are @@ -535,7 +533,8 @@ grpc_error* CdsLb::UpdateXdsCertificateProvider( xds_certificate_provider_ = MakeRefCounted( root_provider_cert_name, root_certificate_provider_->distributor(), identity_provider_cert_name, - identity_certificate_provider_->distributor()); + identity_certificate_provider_->distributor(), + match_subject_alt_names); } } else if (!root_provider_instance_name.empty()) { // Using TLS configuration @@ -544,13 +543,15 @@ grpc_error* CdsLb::UpdateXdsCertificateProvider( !xds_certificate_provider_->ProvidesIdentityCerts()) { xds_certificate_provider_->UpdateRootCertNameAndDistributor( root_provider_cert_name, root_certificate_provider_->distributor()); + xds_certificate_provider_->UpdateSubjectAlternativeNameMatchers( + match_subject_alt_names); } else { // Existing xDS certificate provider does not have TLS configuration. // Create new certificate provider so that new subchannel connectors are // created. xds_certificate_provider_ = MakeRefCounted( root_provider_cert_name, root_certificate_provider_->distributor(), - "", nullptr); + "", nullptr, match_subject_alt_names); } } else { // No configuration provided. diff --git a/src/core/ext/xds/xds_api.cc b/src/core/ext/xds/xds_api.cc index 8ec9dfe9bd9..9bb6b3b745f 100644 --- a/src/core/ext/xds/xds_api.cc +++ b/src/core/ext/xds/xds_api.cc @@ -429,38 +429,207 @@ XdsApi::RdsUpdate::VirtualHost* XdsApi::RdsUpdate::FindVirtualHostForDomain( // XdsApi::StringMatcher // +XdsApi::StringMatcher::StringMatcher(StringMatcherType type, + const std::string& matcher, + bool ignore_case) + : type_(type), ignore_case_(ignore_case) { + if (type_ == StringMatcherType::SAFE_REGEX) { + regex_matcher_ = absl::make_unique(matcher); + } else { + string_matcher_ = matcher; + } +} + XdsApi::StringMatcher::StringMatcher(const StringMatcher& other) - : type(other.type) { - switch (type) { + : type_(other.type_), ignore_case_(other.ignore_case_) { + switch (type_) { case StringMatcherType::SAFE_REGEX: - regex_match = absl::make_unique(other.regex_match->pattern()); + regex_matcher_ = absl::make_unique(other.regex_matcher_->pattern()); break; default: - string_matcher = other.string_matcher; + string_matcher_ = other.string_matcher_; } } XdsApi::StringMatcher& XdsApi::StringMatcher::operator=( const StringMatcher& other) { - type = other.type; - switch (type) { + type_ = other.type_; + switch (type_) { case StringMatcherType::SAFE_REGEX: - regex_match = absl::make_unique(other.regex_match->pattern()); + regex_matcher_ = absl::make_unique(other.regex_matcher_->pattern()); break; default: - string_matcher = other.string_matcher; + string_matcher_ = other.string_matcher_; } + ignore_case_ = other.ignore_case_; return *this; } bool XdsApi::StringMatcher::operator==(const StringMatcher& other) const { - if (type != other.type) return false; - switch (type) { + if (type_ != other.type_ || ignore_case_ != other.ignore_case_) return false; + switch (type_) { case StringMatcherType::SAFE_REGEX: - return regex_match->pattern() != other.regex_match->pattern(); + return regex_matcher_->pattern() == other.regex_matcher_->pattern(); default: - return string_matcher != other.string_matcher; + return string_matcher_ == other.string_matcher_; + } +} + +bool XdsApi::StringMatcher::Match(absl::string_view value) const { + switch (type_) { + case XdsApi::StringMatcher::StringMatcherType::EXACT: + return ignore_case_ ? absl::EqualsIgnoreCase(value, string_matcher_) + : value == string_matcher_; + case XdsApi::StringMatcher::StringMatcherType::PREFIX: + return ignore_case_ ? absl::StartsWithIgnoreCase(value, string_matcher_) + : absl::StartsWith(value, string_matcher_); + case XdsApi::StringMatcher::StringMatcherType::SUFFIX: + return ignore_case_ ? absl::EndsWithIgnoreCase(value, string_matcher_) + : absl::EndsWith(value, string_matcher_); + case XdsApi::StringMatcher::StringMatcherType::CONTAINS: + return ignore_case_ + ? absl::StrContains(absl::AsciiStrToLower(value), + absl::AsciiStrToLower(string_matcher_)) + : absl::StrContains(value, string_matcher_); + case XdsApi::StringMatcher::StringMatcherType::SAFE_REGEX: + // ignore_case_ is ignored for SAFE_REGEX + return RE2::FullMatch(std::string(value), *regex_matcher_); + default: + return false; + } +} + +std::string XdsApi::StringMatcher::ToString() const { + switch (type_) { + case StringMatcherType::EXACT: + return absl::StrFormat("StringMatcher{exact=%s%s}", string_matcher_, + ignore_case_ ? ", ignore_case" : ""); + case StringMatcherType::PREFIX: + return absl::StrFormat("StringMatcher{prefix=%s%s}", string_matcher_, + ignore_case_ ? ", ignore_case" : ""); + case StringMatcherType::SUFFIX: + return absl::StrFormat("StringMatcher{suffix=%s%s}", string_matcher_, + ignore_case_ ? ", ignore_case" : ""); + case StringMatcherType::CONTAINS: + return absl::StrFormat("StringMatcher{contains=%s%s}", string_matcher_, + ignore_case_ ? ", ignore_case" : ""); + case StringMatcherType::SAFE_REGEX: + return absl::StrFormat("StringMatcher{safe_regex=%s}", + regex_matcher_->pattern()); + default: + return ""; + } +} + +// +// XdsApi::CommonTlsContext::CertificateValidationContext +// + +std::string XdsApi::CommonTlsContext::CertificateValidationContext::ToString() + const { + std::vector contents; + for (const auto& match : match_subject_alt_names) { + contents.push_back(match.ToString()); + } + return absl::StrFormat("{match_subject_alt_names=[%s]}", + absl::StrJoin(contents, ", ")); +} + +bool XdsApi::CommonTlsContext::CertificateValidationContext::Empty() const { + return match_subject_alt_names.empty(); +} + +// +// XdsApi::CommonTlsContext::CertificateValidationContext +// + +std::string XdsApi::CommonTlsContext::CertificateProviderInstance::ToString() + const { + absl::InlinedVector contents; + if (!instance_name.empty()) { + contents.push_back(absl::StrFormat("instance_name=%s", instance_name)); + } + if (!certificate_name.empty()) { + contents.push_back( + absl::StrFormat("certificate_name=%s", certificate_name)); + } + return absl::StrCat("{", absl::StrJoin(contents, ", "), "}"); +} + +bool XdsApi::CommonTlsContext::CertificateProviderInstance::Empty() const { + return instance_name.empty() && certificate_name.empty(); +} + +// +// XdsApi::CommonTlsContext::CombinedCertificateValidationContext +// + +std::string +XdsApi::CommonTlsContext::CombinedCertificateValidationContext::ToString() + const { + absl::InlinedVector contents; + if (!default_validation_context.Empty()) { + contents.push_back(absl::StrFormat("default_validation_context=%s", + default_validation_context.ToString())); + } + if (!validation_context_certificate_provider_instance.Empty()) { + contents.push_back(absl::StrFormat( + "validation_context_certificate_provider_instance=%s", + validation_context_certificate_provider_instance.ToString())); + } + return absl::StrCat("{", absl::StrJoin(contents, ", "), "}"); +} + +bool XdsApi::CommonTlsContext::CombinedCertificateValidationContext::Empty() + const { + return default_validation_context.Empty() && + validation_context_certificate_provider_instance.Empty(); +} + +// +// XdsApi::CommonTlsContext +// + +std::string XdsApi::CommonTlsContext::ToString() const { + absl::InlinedVector contents; + if (!tls_certificate_certificate_provider_instance.Empty()) { + contents.push_back(absl::StrFormat( + "tls_certificate_certificate_provider_instance=%s", + tls_certificate_certificate_provider_instance.ToString())); + } + if (!combined_validation_context.Empty()) { + contents.push_back(absl::StrFormat("combined_validation_context=%s", + combined_validation_context.ToString())); + } + return absl::StrCat("{", absl::StrJoin(contents, ", "), "}"); +} + +bool XdsApi::CommonTlsContext::Empty() const { + return tls_certificate_certificate_provider_instance.Empty() && + combined_validation_context.Empty(); +} + +// +// XdsApi::CdsUpdate +// + +std::string XdsApi::CdsUpdate::ToString() const { + absl::InlinedVector contents; + if (!eds_service_name.empty()) { + contents.push_back( + absl::StrFormat("eds_service_name=%s", eds_service_name)); } + if (!common_tls_context.Empty()) { + contents.push_back(absl::StrFormat("common_tls_context=%s", + common_tls_context.ToString())); + } + if (lrs_load_reporting_server_name.has_value()) { + contents.push_back(absl::StrFormat("lrs_load_reporting_server_name=%s", + lrs_load_reporting_server_name.value())); + } + contents.push_back( + absl::StrFormat("max_concurrent_requests=%d", max_concurrent_requests)); + return absl::StrCat("{", absl::StrJoin(contents, ", "), "}"); } // @@ -1442,47 +1611,59 @@ grpc_error* CommonTlsContextParse( envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_match_subject_alt_names( default_validation_context, &len); for (size_t i = 0; i < len; ++i) { - XdsApi::StringMatcher matcher; + XdsApi::StringMatcher::StringMatcherType type; + std::string matcher; if (envoy_type_matcher_v3_StringMatcher_has_exact( subject_alt_names_matchers[i])) { - matcher.type = XdsApi::StringMatcher::StringMatcherType::EXACT; - matcher.string_matcher = + type = XdsApi::StringMatcher::StringMatcherType::EXACT; + matcher = UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_exact( subject_alt_names_matchers[i])); } else if (envoy_type_matcher_v3_StringMatcher_has_prefix( subject_alt_names_matchers[i])) { - matcher.type = XdsApi::StringMatcher::StringMatcherType::PREFIX; - matcher.string_matcher = + type = XdsApi::StringMatcher::StringMatcherType::PREFIX; + matcher = UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_prefix( subject_alt_names_matchers[i])); } else if (envoy_type_matcher_v3_StringMatcher_has_suffix( subject_alt_names_matchers[i])) { - matcher.type = XdsApi::StringMatcher::StringMatcherType::SUFFIX; - matcher.string_matcher = + type = XdsApi::StringMatcher::StringMatcherType::SUFFIX; + matcher = UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_suffix( subject_alt_names_matchers[i])); + } else if (envoy_type_matcher_v3_StringMatcher_has_contains( + subject_alt_names_matchers[i])) { + type = XdsApi::StringMatcher::StringMatcherType::CONTAINS; + matcher = + UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_contains( + subject_alt_names_matchers[i])); } else if (envoy_type_matcher_v3_StringMatcher_has_safe_regex( subject_alt_names_matchers[i])) { - matcher.type = XdsApi::StringMatcher::StringMatcherType::SAFE_REGEX; + type = XdsApi::StringMatcher::StringMatcherType::SAFE_REGEX; auto* regex_matcher = envoy_type_matcher_v3_StringMatcher_safe_regex( subject_alt_names_matchers[i]); - std::unique_ptr regex = - absl::make_unique(UpbStringToStdString( - envoy_type_matcher_v3_RegexMatcher_regex(regex_matcher))); - if (!regex->ok()) { - return GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "Invalid regex string specified in string matcher."); - } - matcher.regex_match = std::move(regex); + matcher = UpbStringToStdString( + envoy_type_matcher_v3_RegexMatcher_regex(regex_matcher)); } else { return GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Invalid StringMatcher specified"); } - matcher.ignore_case = envoy_type_matcher_v3_StringMatcher_ignore_case( + bool ignore_case = envoy_type_matcher_v3_StringMatcher_ignore_case( subject_alt_names_matchers[i]); + XdsApi::StringMatcher string_matcher(type, matcher, ignore_case); + if (type == XdsApi::StringMatcher::StringMatcherType::SAFE_REGEX) { + if (!string_matcher.regex_matcher()->ok()) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Invalid regex string specified in string matcher."); + } + if (ignore_case) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "StringMatcher: ignore_case has no effect for SAFE_REGEX."); + } + } common_tls_context->combined_validation_context - .default_validation_context.match_subject_alt_names.emplace_back( - matcher); + .default_validation_context.match_subject_alt_names.push_back( + std::move(string_matcher)); } } auto* validation_context_certificate_provider_instance = @@ -1608,6 +1789,13 @@ grpc_error* CdsResponseParse( if (error != GRPC_ERROR_NONE) return error; } } + if (cds_update.common_tls_context.combined_validation_context + .validation_context_certificate_provider_instance + .instance_name.empty()) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "TLS configuration provided but no " + "validation_context_certificate_provider_instance found."); + } } } } diff --git a/src/core/ext/xds/xds_api.h b/src/core/ext/xds/xds_api.h index 885dd2c6a73..f2a67072912 100644 --- a/src/core/ext/xds/xds_api.h +++ b/src/core/ext/xds/xds_api.h @@ -175,23 +175,40 @@ class XdsApi { VirtualHost* FindVirtualHostForDomain(const std::string& domain); }; - struct StringMatcher { + class StringMatcher { + public: enum class StringMatcherType { - EXACT, // value stored in string_matcher_field - PREFIX, // value stored in string_matcher_field - SUFFIX, // value stored in string_matcher_field - SAFE_REGEX, // use regex_match field - CONTAINS, // value stored in string_matcher_field + EXACT, // value stored in string_matcher_ field + PREFIX, // value stored in string_matcher_ field + SUFFIX, // value stored in string_matcher_ field + SAFE_REGEX, // pattern stored in regex_matcher_ field + CONTAINS, // value stored in string_matcher_ field }; - StringMatcherType type; - std::string string_matcher; - std::unique_ptr regex_match; - bool ignore_case; StringMatcher() = default; StringMatcher(const StringMatcher& other); + StringMatcher(StringMatcherType type, const std::string& matcher, + bool ignore_case = false); StringMatcher& operator=(const StringMatcher& other); bool operator==(const StringMatcher& other) const; + + bool Match(absl::string_view value) const; + + std::string ToString() const; + + StringMatcherType type() const { return type_; } + + // Valid for EXACT, PREFIX, SUFFIX and CONTAINS + const std::string& string_matcher() const { return string_matcher_; } + + // Valid for SAFE_REGEX + RE2* regex_matcher() const { return regex_matcher_.get(); } + + private: + StringMatcherType type_ = StringMatcherType::EXACT; + std::string string_matcher_; + std::unique_ptr regex_matcher_; + bool ignore_case_ = false; }; struct CommonTlsContext { @@ -201,6 +218,9 @@ class XdsApi { bool operator==(const CertificateValidationContext& other) const { return match_subject_alt_names == other.match_subject_alt_names; } + + std::string ToString() const; + bool Empty() const; }; struct CertificateProviderInstance { @@ -211,6 +231,9 @@ class XdsApi { return instance_name == other.instance_name && certificate_name == other.certificate_name; } + + std::string ToString() const; + bool Empty() const; }; struct CombinedCertificateValidationContext { @@ -223,6 +246,9 @@ class XdsApi { validation_context_certificate_provider_instance == other.validation_context_certificate_provider_instance; } + + std::string ToString() const; + bool Empty() const; }; CertificateProviderInstance tls_certificate_certificate_provider_instance; @@ -233,6 +259,9 @@ class XdsApi { other.tls_certificate_certificate_provider_instance && combined_validation_context == other.combined_validation_context; } + + std::string ToString() const; + bool Empty() const; }; // TODO(roth): When we can use absl::variant<>, consider using that @@ -280,6 +309,8 @@ class XdsApi { other.lrs_load_reporting_server_name && max_concurrent_requests == other.max_concurrent_requests; } + + std::string ToString() const; }; using CdsUpdateMap = std::map; diff --git a/src/core/ext/xds/xds_certificate_provider.cc b/src/core/ext/xds/xds_certificate_provider.cc index 1cc98d5a03e..f285b6db3a4 100644 --- a/src/core/ext/xds/xds_certificate_provider.cc +++ b/src/core/ext/xds/xds_certificate_provider.cc @@ -102,11 +102,13 @@ XdsCertificateProvider::XdsCertificateProvider( absl::string_view root_cert_name, RefCountedPtr root_cert_distributor, absl::string_view identity_cert_name, - RefCountedPtr identity_cert_distributor) + RefCountedPtr identity_cert_distributor, + std::vector san_matchers) : root_cert_name_(root_cert_name), identity_cert_name_(identity_cert_name), root_cert_distributor_(std::move(root_cert_distributor)), identity_cert_distributor_(std::move(identity_cert_distributor)), + san_matchers_(std::move(san_matchers)), distributor_(MakeRefCounted()) { distributor_->SetWatchStatusCallback( absl::bind_front(&XdsCertificateProvider::WatchStatusCallback, this)); @@ -174,6 +176,12 @@ void XdsCertificateProvider::UpdateIdentityCertNameAndDistributor( identity_cert_distributor_ = std::move(identity_cert_distributor); } +void XdsCertificateProvider::UpdateSubjectAlternativeNameMatchers( + std::vector matchers) { + MutexLock lock(&san_matchers_mu_); + san_matchers_ = std::move(matchers); +} + void XdsCertificateProvider::WatchStatusCallback(std::string cert_name, bool root_being_watched, bool identity_being_watched) { diff --git a/src/core/ext/xds/xds_certificate_provider.h b/src/core/ext/xds/xds_certificate_provider.h index 391137595e8..4d13423a6e5 100644 --- a/src/core/ext/xds/xds_certificate_provider.h +++ b/src/core/ext/xds/xds_certificate_provider.h @@ -21,6 +21,7 @@ #include +#include "src/core/ext/xds/xds_api.h" #include "src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h" #define GRPC_ARG_XDS_CERTIFICATE_PROVIDER \ @@ -34,8 +35,8 @@ class XdsCertificateProvider : public grpc_tls_certificate_provider { absl::string_view root_cert_name, RefCountedPtr root_cert_distributor, absl::string_view identity_cert_name, - RefCountedPtr - identity_cert_distributor); + RefCountedPtr identity_cert_distributor, + std::vector san_matchers); ~XdsCertificateProvider() override; @@ -46,15 +47,28 @@ class XdsCertificateProvider : public grpc_tls_certificate_provider { absl::string_view identity_cert_name, RefCountedPtr identity_cert_distributor); + void UpdateSubjectAlternativeNameMatchers( + std::vector matchers); grpc_core::RefCountedPtr distributor() const override { return distributor_; } - bool ProvidesRootCerts() { return root_cert_distributor_ != nullptr; } + bool ProvidesRootCerts() { + MutexLock lock(&mu_); + return root_cert_distributor_ != nullptr; + } + + bool ProvidesIdentityCerts() { + MutexLock lock(&mu_); + return identity_cert_distributor_ != nullptr; + } - bool ProvidesIdentityCerts() { return identity_cert_distributor_ != nullptr; } + std::vector subject_alternative_name_matchers() { + MutexLock lock(&san_matchers_mu_); + return san_matchers_; + } grpc_arg MakeChannelArg() const; @@ -70,12 +84,22 @@ class XdsCertificateProvider : public grpc_tls_certificate_provider { grpc_tls_certificate_distributor* identity_cert_distributor); Mutex mu_; + // Use a separate mutex for san_matchers_ to avoid deadlocks since + // san_matchers_ needs to be accessed when a handshake is being done and we + // run into a possible deadlock scenario if using the same mutex. The mutex + // deadlock cycle is formed as - + // WatchStatusCallback() -> SetKeyMaterials() -> + // TlsChannelSecurityConnector::TlsChannelCertificateWatcher::OnCertificatesChanged() + // -> HandshakeManager::Add() -> SecurityHandshaker::DoHandshake() -> + // subject_alternative_names_matchers() + Mutex san_matchers_mu_; bool watching_root_certs_ = false; bool watching_identity_certs_ = false; std::string root_cert_name_; std::string identity_cert_name_; RefCountedPtr root_cert_distributor_; RefCountedPtr identity_cert_distributor_; + std::vector san_matchers_; RefCountedPtr distributor_; grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface* root_cert_watcher_ = nullptr; diff --git a/src/core/ext/xds/xds_client.cc b/src/core/ext/xds/xds_client.cc index c9dad45bc82..8ac086acf32 100644 --- a/src/core/ext/xds/xds_client.cc +++ b/src/core/ext/xds/xds_client.cc @@ -1005,13 +1005,8 @@ void XdsClient::ChannelState::AdsCallState::AcceptCdsUpdate( auto& state = cds_state.subscribed_resources[cluster_name]; if (state != nullptr) state->Finish(); if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) { - gpr_log(GPR_INFO, - "[xds_client %p] cluster=%s: eds_service_name=%s, " - "lrs_load_reporting_server_name=%s", - xds_client(), cluster_name, cds_update.eds_service_name.c_str(), - cds_update.lrs_load_reporting_server_name.has_value() - ? cds_update.lrs_load_reporting_server_name.value().c_str() - : "(N/A)"); + gpr_log(GPR_INFO, "[xds_client %p] cluster=%s: %s", xds_client(), + cluster_name, cds_update.ToString().c_str()); } // Record the EDS resource names seen. eds_resource_names_seen.insert(cds_update.eds_service_name.empty() diff --git a/src/core/lib/security/credentials/tls/tls_utils.cc b/src/core/lib/security/credentials/tls/tls_utils.cc new file mode 100644 index 00000000000..b94c2eed5c9 --- /dev/null +++ b/src/core/lib/security/credentials/tls/tls_utils.cc @@ -0,0 +1,91 @@ +// +// +// Copyright 2020 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// + +#include + +#include "src/core/lib/security/credentials/tls/tls_utils.h" + +#include "absl/strings/ascii.h" +#include "absl/strings/match.h" +#include "absl/strings/str_cat.h" + +namespace grpc_core { + +// Based on +// https://github.com/grpc/grpc-java/blob/ca12e7a339add0ef48202fb72434b9dc0df41756/xds/src/main/java/io/grpc/xds/internal/sds/trust/SdsX509TrustManager.java#L62 +bool VerifySubjectAlternativeName(absl::string_view subject_alternative_name, + const std::string& matcher) { + if (subject_alternative_name.empty() || + absl::StartsWith(subject_alternative_name, ".")) { + // Illegal pattern/domain name + return false; + } + if (matcher.empty() || absl::StartsWith(matcher, ".")) { + // Illegal domain name + return false; + } + // Normalize \a subject_alternative_name and \a matcher by turning them into + // absolute domain names if they are not yet absolute. This is needed because + // server certificates do not normally contain absolute names or patterns, but + // they should be treated as absolute. At the same time, any + // subject_alternative_name presented to this method should also be treated as + // absolute for the purposes of matching to the server certificate. + std::string normalized_san = + absl::EndsWith(subject_alternative_name, ".") + ? std::string(subject_alternative_name) + : absl::StrCat(subject_alternative_name, "."); + std::string normalized_matcher = + absl::EndsWith(matcher, ".") ? matcher : absl::StrCat(matcher, "."); + absl::AsciiStrToLower(&normalized_san); + absl::AsciiStrToLower(&normalized_matcher); + if (!absl::StrContains(normalized_san, "*")) { + return normalized_san == normalized_matcher; + } + // WILDCARD PATTERN RULES: + // 1. Asterisk (*) is only permitted in the left-most domain name label and + // must be the only character in that label (i.e., must match the whole + // left-most label). For example, *.example.com is permitted, while + // *a.example.com, a*.example.com, a*b.example.com, a.*.example.com are + // not permitted. + // 2. Asterisk (*) cannot match across domain name labels. + // For example, *.example.com matches test.example.com but does not match + // sub.test.example.com. + // 3. Wildcard patterns for single-label domain names are not permitted. + if (!absl::StartsWith(normalized_san, "*.")) { + // Asterisk (*) is only permitted in the left-most domain name label and + // must be the only character in that label + return false; + } + if (normalized_san == "*.") { + // Wildcard pattern for single-label domain name -- not permitted. + return false; + } + absl::string_view suffix = absl::string_view(normalized_san).substr(1); + if (absl::StrContains(suffix, "*")) { + // Asterisk (*) is not permitted in the suffix + return false; + } + if (!absl::EndsWith(normalized_matcher, suffix)) return false; + int suffix_start_index = normalized_matcher.length() - suffix.length(); + // Asterisk matching across domain labels is not permitted. + return suffix_start_index <= 0 /* should not happen */ || + normalized_matcher.find_last_of('.', suffix_start_index - 1) == + std::string::npos; +} + +} // namespace grpc_core diff --git a/src/core/lib/security/credentials/tls/tls_utils.h b/src/core/lib/security/credentials/tls/tls_utils.h new file mode 100644 index 00000000000..6fe9bb46673 --- /dev/null +++ b/src/core/lib/security/credentials/tls/tls_utils.h @@ -0,0 +1,38 @@ +// +// +// Copyright 2020 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// + +#ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_TLS_TLS_UTILS_H +#define GRPC_CORE_LIB_SECURITY_CREDENTIALS_TLS_TLS_UTILS_H + +#include + +#include +#include + +#include "absl/strings/string_view.h" + +namespace grpc_core { + +// Matches \a subject_alternative_name with \a matcher. Returns true if there +// is a match, false otherwise. +bool VerifySubjectAlternativeName(absl::string_view subject_alternative_name, + const std::string& matcher); + +} // namespace grpc_core + +#endif // GRPC_CORE_LIB_SECURITY_CREDENTIALS_TLS_TLS_UTILS_H diff --git a/src/core/lib/security/credentials/xds/xds_credentials.cc b/src/core/lib/security/credentials/xds/xds_credentials.cc index 744182c03b5..9e00f70fda9 100644 --- a/src/core/lib/security/credentials/xds/xds_credentials.cc +++ b/src/core/lib/security/credentials/xds/xds_credentials.cc @@ -23,6 +23,7 @@ #include "src/core/ext/xds/xds_certificate_provider.h" #include "src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h" #include "src/core/lib/security/credentials/tls/tls_credentials.h" +#include "src/core/lib/security/credentials/tls/tls_utils.h" #include "src/core/lib/uri/uri_parser.h" namespace grpc_core { @@ -31,11 +32,52 @@ const char kCredentialsTypeXds[] = "Xds"; namespace { -int ServerAuthCheckSchedule(void* /* config_user_data */, +bool XdsVerifySubjectAlternativeNames( + const char* const* subject_alternative_names, + size_t subject_alternative_names_size, + const std::vector& matchers) { + if (matchers.empty()) return true; + for (size_t i = 0; i < subject_alternative_names_size; ++i) { + for (const auto& matcher : matchers) { + if (matcher.type() == XdsApi::StringMatcher::StringMatcherType::EXACT) { + // For EXACT match, use DNS rules for verifying SANs + // TODO(zhenlian): Right now, the SSL layer does not save the type of + // the SAN, so we are doing a DNS style verification for all SANs when + // the type is EXACT. When we expose the SAN type, change this to only + // do this verification when the SAN type is DNS and match type is + // EXACT. For all other cases, we should use matcher.Match(). + if (VerifySubjectAlternativeName(subject_alternative_names[i], + matcher.string_matcher())) { + return true; + } + } else { + if (matcher.Match(subject_alternative_names[i])) { + return true; + } + } + } + } + return false; +} + +int ServerAuthCheckSchedule(void* config_user_data, grpc_tls_server_authorization_check_arg* arg) { - // TODO(yashykt): To be filled - arg->success = 1; - arg->status = GRPC_STATUS_OK; + XdsCertificateProvider* xds_certificate_provider = + static_cast(config_user_data); + if (XdsVerifySubjectAlternativeNames( + arg->subject_alternative_names, arg->subject_alternative_names_size, + xds_certificate_provider->subject_alternative_name_matchers())) { + arg->success = 1; + arg->status = GRPC_STATUS_OK; + } else { + arg->success = 0; + arg->status = GRPC_STATUS_UNAUTHENTICATED; + if (arg->error_details) { + arg->error_details->set_error_details( + "SANs from certificate did not match SANs from xDS control plane"); + } + } + return 0; /* synchronous check */ } @@ -47,6 +89,14 @@ void ServerAuthCheckDestroy(void* config_user_data) { } // namespace +bool TestOnlyXdsVerifySubjectAlternativeNames( + const char* const* subject_alternative_names, + size_t subject_alternative_names_size, + const std::vector& matchers) { + return XdsVerifySubjectAlternativeNames( + subject_alternative_names, subject_alternative_names_size, matchers); +} + // // XdsCredentials // diff --git a/src/core/lib/security/credentials/xds/xds_credentials.h b/src/core/lib/security/credentials/xds/xds_credentials.h index f78eb31fa20..e12608c9d40 100644 --- a/src/core/lib/security/credentials/xds/xds_credentials.h +++ b/src/core/lib/security/credentials/xds/xds_credentials.h @@ -23,6 +23,7 @@ #include +#include "src/core/ext/xds/xds_api.h" #include "src/core/lib/security/credentials/credentials.h" namespace grpc_core { @@ -58,6 +59,11 @@ class XdsServerCredentials final : public grpc_server_credentials { RefCountedPtr fallback_credentials_; }; +bool TestOnlyXdsVerifySubjectAlternativeNames( + const char* const* subject_alternative_names, + size_t subject_alternative_names_size, + const std::vector& matchers); + } // namespace grpc_core #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_XDS_XDS_CREDENTIALS_H */ diff --git a/src/core/lib/security/security_connector/tls/tls_security_connector.cc b/src/core/lib/security/security_connector/tls/tls_security_connector.cc index 18651eb9db3..96769ccd96c 100644 --- a/src/core/lib/security/security_connector/tls/tls_security_connector.cc +++ b/src/core/lib/security/security_connector/tls/tls_security_connector.cc @@ -243,6 +243,39 @@ void TlsChannelSecurityConnector::check_peer( : check_arg_->peer_cert_full_chain; gpr_free(peer_pem_chain); } + // TODO(zhenlian) - This should be cleaned up as part of the custom + // verification changes. Fill in the subject alternative names + std::vector subject_alternative_names; + for (size_t i = 0; i < peer.property_count; i++) { + const tsi_peer_property* prop = &peer.properties[i]; + if (strcmp(prop->name, + TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) { + char* san = new char[prop->value.length + 1]; + memcpy(san, prop->value.data, prop->value.length); + san[prop->value.length] = '\0'; + subject_alternative_names.emplace_back(san); + } + } + if (check_arg_->subject_alternative_names != nullptr) { + for (size_t i = 0; i < check_arg_->subject_alternative_names_size; + ++i) { + delete check_arg_->subject_alternative_names[i]; + } + delete check_arg_->subject_alternative_names; + } + check_arg_->subject_alternative_names_size = + subject_alternative_names.size(); + if (subject_alternative_names.empty()) { + check_arg_->subject_alternative_names = nullptr; + } else { + check_arg_->subject_alternative_names = + new char*[check_arg_->subject_alternative_names_size]; + for (size_t i = 0; i < check_arg_->subject_alternative_names_size; + ++i) { + check_arg_->subject_alternative_names[i] = + subject_alternative_names[i]; + } + } int callback_status = config->Schedule(check_arg_); /* Server authorization check is handled asynchronously. */ if (callback_status) { @@ -409,6 +442,11 @@ TlsChannelSecurityConnector::ServerAuthorizationCheckArgCreate( void* user_data) { grpc_tls_server_authorization_check_arg* arg = new grpc_tls_server_authorization_check_arg(); + arg->target_name = nullptr; + arg->peer_cert = nullptr; + arg->peer_cert_full_chain = nullptr; + arg->subject_alternative_names = nullptr; + arg->subject_alternative_names_size = 0; arg->error_details = new grpc_tls_error_details(); arg->cb = ServerAuthorizationCheckDone; arg->cb_user_data = user_data; @@ -424,6 +462,10 @@ void TlsChannelSecurityConnector::ServerAuthorizationCheckArgDestroy( gpr_free(const_cast(arg->target_name)); gpr_free(const_cast(arg->peer_cert)); gpr_free(const_cast(arg->peer_cert_full_chain)); + for (size_t i = 0; i < arg->subject_alternative_names_size; ++i) { + delete arg->subject_alternative_names[i]; + } + delete arg->subject_alternative_names; delete arg->error_details; if (arg->destroy_context != nullptr) { arg->destroy_context(arg->context); diff --git a/src/proto/grpc/testing/xds/v3/BUILD b/src/proto/grpc/testing/xds/v3/BUILD index f274e8ae443..1bcfa4b510e 100644 --- a/src/proto/grpc/testing/xds/v3/BUILD +++ b/src/proto/grpc/testing/xds/v3/BUILD @@ -195,6 +195,9 @@ grpc_proto_library( "string.proto", ], well_known_protos = True, + deps = [ + "regex_proto", + ], ) grpc_proto_library( diff --git a/src/proto/grpc/testing/xds/v3/string.proto b/src/proto/grpc/testing/xds/v3/string.proto index 0ab098c7fbd..d7e773089d7 100644 --- a/src/proto/grpc/testing/xds/v3/string.proto +++ b/src/proto/grpc/testing/xds/v3/string.proto @@ -18,6 +18,8 @@ syntax = "proto3"; package envoy.type.matcher.v3; +import "src/proto/grpc/testing/xds/v3/regex.proto"; + message StringMatcher { oneof match_pattern { // The input string must match exactly the string specified here. @@ -26,6 +28,33 @@ message StringMatcher { // // * *abc* only matches the value *abc*. string exact = 1; + + // The input string must have the prefix specified here. + // Note: empty prefix is not allowed, please use regex instead. + // + // Examples: + // + // * *abc* matches the value *abc.xyz* + string prefix = 2; + + // The input string must have the suffix specified here. + // Note: empty prefix is not allowed, please use regex instead. + // + // Examples: + // + // * *abc* matches the value *xyz.abc* + string suffix = 3; + + // The input string must match the regular expression specified here. + RegexMatcher safe_regex = 5; + + // The input string must have the substring specified here. + // Note: empty contains match is not allowed, please use regex instead. + // + // Examples: + // + // * *abc* matches the value *xyz.abc.def* + string contains = 7; } // If true, indicates the exact/prefix/suffix matching should be case insensitive. This has no diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index c5e0e1b567b..253e595e859 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -288,7 +288,6 @@ CORE_SOURCE_FILES = [ 'src/core/ext/xds/certificate_provider_registry.cc', 'src/core/ext/xds/certificate_provider_store.cc', 'src/core/ext/xds/file_watcher_certificate_provider_factory.cc', - 'src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc', 'src/core/ext/xds/xds_api.cc', 'src/core/ext/xds/xds_bootstrap.cc', 'src/core/ext/xds/xds_certificate_provider.cc', @@ -498,6 +497,7 @@ CORE_SOURCE_FILES = [ 'src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.cc', 'src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc', 'src/core/lib/security/credentials/tls/tls_credentials.cc', + 'src/core/lib/security/credentials/tls/tls_utils.cc', 'src/core/lib/security/credentials/xds/xds_credentials.cc', 'src/core/lib/security/security_connector/alts/alts_security_connector.cc', 'src/core/lib/security/security_connector/fake/fake_security_connector.cc', diff --git a/test/core/security/BUILD b/test/core/security/BUILD index 595142fa3ca..0491cb6b279 100644 --- a/test/core/security/BUILD +++ b/test/core/security/BUILD @@ -383,3 +383,17 @@ grpc_cc_test( "//test/core/util:grpc_test_util", ], ) + +grpc_cc_test( + name = "xds_credentials_test", + srcs = ["xds_credentials_test.cc"], + external_deps = [ + "gtest", + ], + deps = [ + "//:gpr", + "//:grpc", + "//:grpc_secure", + "//test/core/util:grpc_test_util", + ], +) diff --git a/test/core/security/xds_credentials_test.cc b/test/core/security/xds_credentials_test.cc new file mode 100644 index 00000000000..373e905f452 --- /dev/null +++ b/test/core/security/xds_credentials_test.cc @@ -0,0 +1,306 @@ +// +// +// Copyright 2020 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// + +#include "src/core/lib/security/credentials/xds/xds_credentials.h" + +#include + +#include + +#include "test/core/util/test_config.h" + +namespace grpc_core { +namespace testing { + +namespace { + +XdsApi::StringMatcher ExactMatcher(const char* string) { + return XdsApi::StringMatcher(XdsApi::StringMatcher::StringMatcherType::EXACT, + string); +} + +XdsApi::StringMatcher PrefixMatcher(const char* string, + bool ignore_case = false) { + return XdsApi::StringMatcher(XdsApi::StringMatcher::StringMatcherType::PREFIX, + string, ignore_case); +} + +XdsApi::StringMatcher SuffixMatcher(const char* string, + bool ignore_case = false) { + return XdsApi::StringMatcher(XdsApi::StringMatcher::StringMatcherType::SUFFIX, + string, ignore_case); +} + +XdsApi::StringMatcher ContainsMatcher(const char* string, + bool ignore_case = false) { + return XdsApi::StringMatcher( + XdsApi::StringMatcher::StringMatcherType::CONTAINS, string, ignore_case); +} + +XdsApi::StringMatcher SafeRegexMatcher(const char* string) { + return XdsApi::StringMatcher( + XdsApi::StringMatcher::StringMatcherType::SAFE_REGEX, string); +} + +TEST(XdsSanMatchingTest, EmptySansList) { + std::vector sans = {}; + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), + {ExactMatcher("a.example.com"), ExactMatcher("b.example.com")})); +} + +TEST(XdsSanMatchingTest, EmptyMatchersList) { + std::vector sans = {"a.example.com", "foo.example.com"}; + EXPECT_TRUE( + TestOnlyXdsVerifySubjectAlternativeNames(sans.data(), sans.size(), {})); +} + +TEST(XdsSanMatchingTest, ExactMatchIllegalValues) { + std::vector sans = {".a.example.com"}; + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), + {ExactMatcher(""), ExactMatcher("a.example.com"), + ExactMatcher(".a.example.com")})); + sans = {""}; + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), + {ExactMatcher(""), ExactMatcher("a.example.com"), + ExactMatcher(".a.example.com")})); + sans = {"a.example.com"}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), + {ExactMatcher(""), ExactMatcher("a.example.com"), + ExactMatcher(".a.example.com")})); +} + +TEST(XdsSanMatchingTest, ExactMatchDns) { + std::vector sans = {"a.example.com"}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("a.example.com")})); + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("b.example.com")})); + sans = {"b.example.com."}; + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("a.example.com.")})); + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("b.example.com.")})); +} + +TEST(XdsSanMatchingTest, ExactMatchWithFullyQualifiedSan) { + std::vector sans = {"a.example.com."}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("a.example.com")})); + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("b.example.com")})); +} + +TEST(XdsSanMatchingTest, ExactMatchWithFullyQualifiedMatcher) { + std::vector sans = {"a.example.com"}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("a.example.com.")})); + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("b.example.com.")})); +} + +TEST(XdsSanMatchingTest, ExactMatchDnsCaseInsensitive) { + std::vector sans = {"A.eXaMpLe.CoM"}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("a.example.com")})); + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("a.ExAmPlE.cOm")})); +} + +TEST(XdsSanMatchingTest, ExactMatchMultipleSansMultipleMatchers) { + std::vector sans = {"a.example.com", "foo.example.com", + "b.example.com"}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), + {ExactMatcher("abc.example.com"), ExactMatcher("foo.example.com"), + ExactMatcher("xyz.example.com")})); +} + +TEST(XdsSanMatchingTest, ExactMatchWildCard) { + std::vector sans = {"*.example.com"}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("a.example.com")})); + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("fOo.ExAmPlE.cOm")})); + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("BaR.eXaMpLe.CoM")})); + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher(".example.com")})); + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("example.com")})); + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("foo.bar.com")})); +} + +TEST(XdsSanMatchingTest, ExactMatchWildCardDoesNotMatchSingleLabelDomain) { + std::vector sans = {"*"}; + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("abc")})); + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("abc.com.")})); + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("bar.baz.com")})); + sans = {"*."}; + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("abc")})); + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("abc.com.")})); + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("bar.baz.com")})); +} + +TEST(XdsSanMatchingTest, ExactMatchAsteriskOnlyPermittedInLeftMostDomainName) { + std::vector sans = {"*.example.*.com"}; + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("abc.example.xyz.com")})); + sans = {"*.exam*ple.com"}; + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("abc.example.com")})); +} + +TEST(XdsSanMatchingTest, + ExactMatchAsteriskMustBeOnlyCharacterInLeftMostDomainName) { + std::vector sans = {"*c.example.com"}; + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("abc.example.com")})); +} + +TEST(XdsSanMatchingTest, + ExactMatchAsteriskMatchingAcrossDomainLabelsNotPermitted) { + std::vector sans = {"*.com"}; + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("abc.example.com")})); + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("foo.bar.baz.com")})); + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ExactMatcher("abc.com")})); +} + +TEST(XdsSanMatchingTest, PrefixMatch) { + std::vector sans = {"abc.com"}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames(sans.data(), sans.size(), + {PrefixMatcher("abc")})); + sans = {"AbC.CoM"}; + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {PrefixMatcher("abc")})); + sans = {"xyz.com"}; + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {PrefixMatcher("abc")})); +} + +TEST(XdsSanMatchingTest, PrefixMatchIgnoreCase) { + std::vector sans = {"aBc.cOm"}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), + {PrefixMatcher("AbC", true /* ignore_case */)})); + sans = {"abc.com"}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), + {PrefixMatcher("AbC", true /* ignore_case */)})); + sans = {"xyz.com"}; + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), + {PrefixMatcher("AbC", true /* ignore_case */)})); +} + +TEST(XdsSanMatchingTest, SuffixMatch) { + std::vector sans = {"abc.com"}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {SuffixMatcher(".com")})); + sans = {"AbC.CoM"}; + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {SuffixMatcher(".com")})); + sans = {"abc.xyz"}; + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {SuffixMatcher(".com")})); +} + +TEST(XdsSanMatchingTest, SuffixMatchIgnoreCase) { + std::vector sans = {"abc.com"}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), + {SuffixMatcher(".CoM", true /* ignore_case */)})); + sans = {"AbC.cOm"}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), + {SuffixMatcher(".CoM", true /* ignore_case */)})); + sans = {"abc.xyz"}; + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), + {SuffixMatcher(".CoM", true /* ignore_case */)})); +} + +TEST(XdsSanMatchingTest, ContainsMatch) { + std::vector sans = {"abc.com"}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ContainsMatcher("abc")})); + sans = {"xyz.abc.com"}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ContainsMatcher("abc")})); + sans = {"foo.AbC.com"}; + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {ContainsMatcher("abc")})); +} + +TEST(XdsSanMatchingTest, ContainsMatchIgnoresCase) { + std::vector sans = {"abc.com"}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), + {ContainsMatcher("AbC", true /* ignore_case */)})); + sans = {"xyz.abc.com"}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), + {ContainsMatcher("AbC", true /* ignore_case */)})); + sans = {"foo.aBc.com"}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), + {ContainsMatcher("AbC", true /* ignore_case */)})); + sans = {"foo.Ab.com"}; + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), + {ContainsMatcher("AbC", true /* ignore_case */)})); +} + +TEST(XdsSanMatchingTest, RegexMatch) { + std::vector sans = {"abc.example.com"}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {SafeRegexMatcher("(abc|xyz).example.com")})); + sans = {"xyz.example.com"}; + EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {SafeRegexMatcher("(abc|xyz).example.com")})); + sans = {"foo.example.com"}; + EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( + sans.data(), sans.size(), {SafeRegexMatcher("(abc|xyz).example.com")})); +} + +} // namespace + +} // namespace testing +} // namespace grpc_core + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + grpc::testing::TestEnvironment env(argc, argv); + grpc_init(); + auto result = RUN_ALL_TESTS(); + grpc_shutdown(); + return result; +} diff --git a/test/core/xds/BUILD b/test/core/xds/BUILD index 4e16a469b8e..e12d115faa5 100644 --- a/test/core/xds/BUILD +++ b/test/core/xds/BUILD @@ -64,6 +64,7 @@ grpc_cc_test( deps = [ "//:gpr", "//:grpc", + "//:grpc_google_mesh_ca_certificate_provider_factory", "//test/core/util:grpc_test_util", ], ) diff --git a/test/core/xds/xds_certificate_provider_test.cc b/test/core/xds/xds_certificate_provider_test.cc index 3bc60b45a9e..fff1c48d47a 100644 --- a/test/core/xds/xds_certificate_provider_test.cc +++ b/test/core/xds/xds_certificate_provider_test.cc @@ -106,7 +106,7 @@ TEST( auto identity_cert_distributor = MakeRefCounted(); XdsCertificateProvider provider("root", root_cert_distributor, "identity", - identity_cert_distributor); + identity_cert_distributor, {}); auto* watcher = new TestCertificatesWatcher; provider.distributor()->WatchTlsCertificates( std::unique_ptr(watcher), "", ""); @@ -175,7 +175,7 @@ TEST(XdsCertificateProviderTest, auto identity_cert_distributor = MakeRefCounted(); XdsCertificateProvider provider("test", root_cert_distributor, "test", - identity_cert_distributor); + identity_cert_distributor, {}); auto* watcher = new TestCertificatesWatcher; provider.distributor()->WatchTlsCertificates( std::unique_ptr(watcher), "", ""); @@ -242,7 +242,8 @@ TEST(XdsCertificateProviderTest, TEST(XdsCertificateProviderTest, RootCertDistributorSameAsIdentityCertDistributorDifferentCertNames) { auto distributor = MakeRefCounted(); - XdsCertificateProvider provider("root", distributor, "identity", distributor); + XdsCertificateProvider provider("root", distributor, "identity", distributor, + {}); auto* watcher = new TestCertificatesWatcher; provider.distributor()->WatchTlsCertificates( std::unique_ptr(watcher), "", ""); @@ -305,7 +306,7 @@ TEST(XdsCertificateProviderTest, TEST(XdsCertificateProviderTest, RootCertDistributorSameAsIdentityCertDistributorSameCertNames) { auto distributor = MakeRefCounted(); - XdsCertificateProvider provider("", distributor, "", distributor); + XdsCertificateProvider provider("", distributor, "", distributor, {}); auto* watcher = new TestCertificatesWatcher; provider.distributor()->WatchTlsCertificates( std::unique_ptr(watcher), "", ""); @@ -368,7 +369,7 @@ TEST(XdsCertificateProviderTest, TEST(XdsCertificateProviderTest, SwapOutDistributorsMultipleTimes) { auto distributor = MakeRefCounted(); distributor->SetKeyMaterials("", kRootCert1, MakeKeyCertPairsType1()); - XdsCertificateProvider provider("", nullptr, "", nullptr); + XdsCertificateProvider provider("", nullptr, "", nullptr, {}); auto* watcher = new TestCertificatesWatcher; provider.distributor()->WatchTlsCertificates( std::unique_ptr(watcher), "", ""); @@ -493,7 +494,7 @@ TEST(XdsCertificateProviderTest, SwapOutDistributorsMultipleTimes) { } TEST(XdsCertificateProviderTest, CertificateNameNotEmpty) { - XdsCertificateProvider provider("", nullptr, "", nullptr); + XdsCertificateProvider provider("", nullptr, "", nullptr, {}); auto* watcher = new TestCertificatesWatcher; provider.distributor()->WatchTlsCertificates( std::unique_ptr(watcher), "test", "test"); diff --git a/test/cpp/end2end/xds_end2end_test.cc b/test/cpp/end2end/xds_end2end_test.cc index fdc7274d503..9fe4de26932 100644 --- a/test/cpp/end2end/xds_end2end_test.cc +++ b/test/cpp/end2end/xds_end2end_test.cc @@ -103,6 +103,7 @@ using ::envoy::config::route::v3::RouteConfiguration; using ::envoy::extensions::filters::network::http_connection_manager::v3:: HttpConnectionManager; using ::envoy::extensions::transport_sockets::tls::v3::UpstreamTlsContext; +using ::envoy::type::matcher::v3::StringMatcher; using ::envoy::type::v3::FractionalPercent; constexpr char kLdsTypeUrl[] = @@ -5311,10 +5312,21 @@ class XdsSecurityTest : public BasicTest { root_cert_ = ReadFile(kCaCertPath); bad_root_cert_ = ReadFile(kBadClientCertPath); identity_pair_ = ReadTlsIdentityPair(kClientKeyPath, kClientCertPath); + // TODO(yashykt): Use different client certs here instead of reusing server + // certs after https://github.com/grpc/grpc/pull/24876 is merged fallback_identity_pair_ = ReadTlsIdentityPair(kServerKeyPath, kServerCertPath); bad_identity_pair_ = ReadTlsIdentityPair(kBadClientKeyPath, kBadClientCertPath); + server_san_exact_.set_exact("*.test.google.fr"); + server_san_prefix_.set_prefix("waterzooi.test.google"); + server_san_suffix_.set_suffix("google.fr"); + server_san_contains_.set_contains("google"); + server_san_regex_.mutable_safe_regex()->mutable_google_re2(); + server_san_regex_.mutable_safe_regex()->set_regex( + "(foo|waterzooi).test.google.(fr|be)"); + bad_san_1_.set_exact("192.168.1.4"); + bad_san_2_.set_exact("foo.test.google.in"); authenticated_identity_ = {"testclient"}; fallback_authenticated_identity_ = {"*.test.google.fr", "waterzooi.test.google.be", @@ -5342,6 +5354,7 @@ class XdsSecurityTest : public BasicTest { absl::string_view root_certificate_name, absl::string_view identity_instance_name, absl::string_view identity_certificate_name, + const std::vector& san_matchers, const std::vector& expected_authenticated_identity, bool test_expects_failure = false) { auto cluster = default_cluster_; @@ -5367,6 +5380,15 @@ class XdsSecurityTest : public BasicTest { ->mutable_validation_context_certificate_provider_instance() ->set_certificate_name(std::string(root_certificate_name)); } + if (!san_matchers.empty()) { + auto* validation_context = + upstream_tls_context.mutable_common_tls_context() + ->mutable_combined_validation_context() + ->mutable_default_validation_context(); + for (const auto& san_matcher : san_matchers) { + *validation_context->add_match_subject_alt_names() = san_matcher; + } + } transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context); } balancers_[0]->ads_service()->SetCdsResource(cluster); @@ -5399,10 +5421,103 @@ class XdsSecurityTest : public BasicTest { grpc_core::PemKeyCertPairList identity_pair_; grpc_core::PemKeyCertPairList fallback_identity_pair_; grpc_core::PemKeyCertPairList bad_identity_pair_; + StringMatcher server_san_exact_; + StringMatcher server_san_prefix_; + StringMatcher server_san_suffix_; + StringMatcher server_san_contains_; + StringMatcher server_san_regex_; + StringMatcher bad_san_1_; + StringMatcher bad_san_2_; std::vector authenticated_identity_; std::vector fallback_authenticated_identity_; }; +TEST_P(XdsSecurityTest, + TLSConfigurationWithoutValidationContextCertificateProviderInstance) { + auto cluster = default_cluster_; + auto* transport_socket = cluster.mutable_transport_socket(); + transport_socket->set_name("envoy.transport_sockets.tls"); + balancers_[0]->ads_service()->SetCdsResource(cluster); + CheckRpcSendFailure(); + const auto& response_state = + balancers_[0]->ads_service()->cds_response_state(); + EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); + EXPECT_EQ(response_state.error_message, + "TLS configuration provided but no " + "validation_context_certificate_provider_instance found."); +} + +TEST_P( + XdsSecurityTest, + MatchSubjectAltNamesProvidedWithoutValidationContextCertificateProviderInstance) { + auto cluster = default_cluster_; + auto* transport_socket = cluster.mutable_transport_socket(); + transport_socket->set_name("envoy.transport_sockets.tls"); + UpstreamTlsContext upstream_tls_context; + auto* validation_context = upstream_tls_context.mutable_common_tls_context() + ->mutable_combined_validation_context() + ->mutable_default_validation_context(); + *validation_context->add_match_subject_alt_names() = server_san_exact_; + transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context); + balancers_[0]->ads_service()->SetCdsResource(cluster); + CheckRpcSendFailure(); + const auto& response_state = + balancers_[0]->ads_service()->cds_response_state(); + EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); + EXPECT_EQ(response_state.error_message, + "TLS configuration provided but no " + "validation_context_certificate_provider_instance found."); +} + +TEST_P( + XdsSecurityTest, + TlsCertificateCertificateProviderInstanceWithoutValidationContextCertificateProviderInstance) { + auto cluster = default_cluster_; + auto* transport_socket = cluster.mutable_transport_socket(); + transport_socket->set_name("envoy.transport_sockets.tls"); + UpstreamTlsContext upstream_tls_context; + upstream_tls_context.mutable_common_tls_context() + ->mutable_tls_certificate_certificate_provider_instance() + ->set_instance_name(std::string("instance_name")); + transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context); + balancers_[0]->ads_service()->SetCdsResource(cluster); + CheckRpcSendFailure(); + const auto& response_state = + balancers_[0]->ads_service()->cds_response_state(); + EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); + EXPECT_EQ(response_state.error_message, + "TLS configuration provided but no " + "validation_context_certificate_provider_instance found."); +} + +TEST_P(XdsSecurityTest, RegexSanMatcherDoesNotAllowIgnoreCase) { + auto cluster = default_cluster_; + auto* transport_socket = cluster.mutable_transport_socket(); + transport_socket->set_name("envoy.transport_sockets.tls"); + UpstreamTlsContext upstream_tls_context; + upstream_tls_context.mutable_common_tls_context() + ->mutable_combined_validation_context() + ->mutable_validation_context_certificate_provider_instance() + ->set_instance_name(std::string("fake_plugin1")); + auto* validation_context = upstream_tls_context.mutable_common_tls_context() + ->mutable_combined_validation_context() + ->mutable_default_validation_context(); + StringMatcher matcher; + matcher.mutable_safe_regex()->mutable_google_re2(); + matcher.mutable_safe_regex()->set_regex( + "(foo|waterzooi).test.google.(fr|be)"); + matcher.set_ignore_case(true); + *validation_context->add_match_subject_alt_names() = matcher; + transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context); + balancers_[0]->ads_service()->SetCdsResource(cluster); + CheckRpcSendFailure(); + const auto& response_state = + balancers_[0]->ads_service()->cds_response_state(); + EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); + EXPECT_EQ(response_state.error_message, + "StringMatcher: ignore_case has no effect for SAFE_REGEX."); +} + TEST_P(XdsSecurityTest, UnknownRootCertificateProvider) { auto cluster = default_cluster_; auto* transport_socket = cluster.mutable_transport_socket(); @@ -5438,12 +5553,78 @@ TEST_P(XdsSecurityTest, UnknownIdentityCertificateProvider) { g_fake1_cert_data_map = nullptr; } -TEST_P(XdsSecurityTest, TestMtlsConfiguration) { +TEST_P(XdsSecurityTest, TestMtlsConfigurationWithNoSanMatchers) { FakeCertificateProvider::CertDataMap fake1_cert_map = { {"", {root_cert_, identity_pair_}}}; g_fake1_cert_data_map = &fake1_cert_map; UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", - "", authenticated_identity_); + "", {}, authenticated_identity_); + g_fake1_cert_data_map = nullptr; +} + +TEST_P(XdsSecurityTest, TestMtlsConfigurationWithExactSanMatcher) { + FakeCertificateProvider::CertDataMap fake1_cert_map = { + {"", {root_cert_, identity_pair_}}}; + g_fake1_cert_data_map = &fake1_cert_map; + UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", + "", {server_san_exact_}, + authenticated_identity_); + g_fake1_cert_data_map = nullptr; +} + +TEST_P(XdsSecurityTest, TestMtlsConfigurationWithPrefixSanMatcher) { + FakeCertificateProvider::CertDataMap fake1_cert_map = { + {"", {root_cert_, identity_pair_}}}; + g_fake1_cert_data_map = &fake1_cert_map; + UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", + "", {server_san_prefix_}, + authenticated_identity_); + g_fake1_cert_data_map = nullptr; +} + +TEST_P(XdsSecurityTest, TestMtlsConfigurationWithSuffixSanMatcher) { + FakeCertificateProvider::CertDataMap fake1_cert_map = { + {"", {root_cert_, identity_pair_}}}; + g_fake1_cert_data_map = &fake1_cert_map; + UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", + "", {server_san_suffix_}, + authenticated_identity_); + g_fake1_cert_data_map = nullptr; +} + +TEST_P(XdsSecurityTest, TestMtlsConfigurationWithContainsSanMatcher) { + FakeCertificateProvider::CertDataMap fake1_cert_map = { + {"", {root_cert_, identity_pair_}}}; + g_fake1_cert_data_map = &fake1_cert_map; + UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", + "", {server_san_contains_}, + authenticated_identity_); + g_fake1_cert_data_map = nullptr; +} + +TEST_P(XdsSecurityTest, TestMtlsConfigurationWithRegexSanMatcher) { + FakeCertificateProvider::CertDataMap fake1_cert_map = { + {"", {root_cert_, identity_pair_}}}; + g_fake1_cert_data_map = &fake1_cert_map; + UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", + "", {server_san_regex_}, + authenticated_identity_); + g_fake1_cert_data_map = nullptr; +} + +TEST_P(XdsSecurityTest, TestMtlsConfigurationWithSanMatchersUpdate) { + FakeCertificateProvider::CertDataMap fake1_cert_map = { + {"", {root_cert_, identity_pair_}}}; + g_fake1_cert_data_map = &fake1_cert_map; + UpdateAndVerifyXdsSecurityConfiguration( + "fake_plugin1", "", "fake_plugin1", "", + {server_san_exact_, server_san_prefix_}, authenticated_identity_); + UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", + "", {bad_san_1_, bad_san_2_}, {}, + true /* failure */); + UpdateAndVerifyXdsSecurityConfiguration( + "fake_plugin1", "", "fake_plugin1", "", + {server_san_prefix_, server_san_regex_}, authenticated_identity_); g_fake1_cert_data_map = nullptr; } @@ -5455,12 +5636,14 @@ TEST_P(XdsSecurityTest, TestMtlsConfigurationWithRootPluginUpdate) { {"", {bad_root_cert_, bad_identity_pair_}}}; g_fake2_cert_data_map = &fake2_cert_map; UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", - "", authenticated_identity_); + "", {server_san_exact_}, + authenticated_identity_); UpdateAndVerifyXdsSecurityConfiguration("fake_plugin2" /* bad root */, "", - "fake_plugin1", "", {}, + "fake_plugin1", "", {}, {}, true /* failure */); UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", - "", authenticated_identity_); + "", {server_san_exact_}, + authenticated_identity_); g_fake1_cert_data_map = nullptr; g_fake2_cert_data_map = nullptr; } @@ -5473,9 +5656,11 @@ TEST_P(XdsSecurityTest, TestMtlsConfigurationWithIdentityPluginUpdate) { {"", {root_cert_, fallback_identity_pair_}}}; g_fake2_cert_data_map = &fake2_cert_map; UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", - "", authenticated_identity_); + "", {server_san_exact_}, + authenticated_identity_); UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin2", - "", fallback_authenticated_identity_); + "", {server_san_exact_}, + fallback_authenticated_identity_); g_fake1_cert_data_map = nullptr; g_fake2_cert_data_map = nullptr; } @@ -5489,12 +5674,13 @@ TEST_P(XdsSecurityTest, TestMtlsConfigurationWithBothPluginsUpdated) { {"good", {root_cert_, fallback_identity_pair_}}}; g_fake2_cert_data_map = &fake2_cert_map; UpdateAndVerifyXdsSecurityConfiguration("fake_plugin2", "", "fake_plugin2", - "", {}, true /* failure */); + "", {}, {}, true /* failure */); UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", - "", authenticated_identity_); - UpdateAndVerifyXdsSecurityConfiguration("fake_plugin2", "good", - "fake_plugin2", "good", - fallback_authenticated_identity_); + "", {server_san_prefix_}, + authenticated_identity_); + UpdateAndVerifyXdsSecurityConfiguration( + "fake_plugin2", "good", "fake_plugin2", "good", {server_san_prefix_}, + fallback_authenticated_identity_); g_fake1_cert_data_map = nullptr; g_fake2_cert_data_map = nullptr; } @@ -5505,9 +5691,11 @@ TEST_P(XdsSecurityTest, TestMtlsConfigurationWithRootCertificateNameUpdate) { {"bad", {bad_root_cert_, bad_identity_pair_}}}; g_fake1_cert_data_map = &fake1_cert_map; UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", - "", authenticated_identity_); + "", {server_san_regex_}, + authenticated_identity_); UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "bad", "fake_plugin1", - "", {}, true /* failure */); + "", {server_san_regex_}, {}, + true /* failure */); g_fake1_cert_data_map = nullptr; } @@ -5518,9 +5706,11 @@ TEST_P(XdsSecurityTest, {"bad", {bad_root_cert_, bad_identity_pair_}}}; g_fake1_cert_data_map = &fake1_cert_map; UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", - "", authenticated_identity_); + "", {server_san_exact_}, + authenticated_identity_); UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", - "bad", {}, true /* failure */); + "bad", {server_san_exact_}, {}, + true /* failure */); g_fake1_cert_data_map = nullptr; } @@ -5531,9 +5721,10 @@ TEST_P(XdsSecurityTest, {"good", {root_cert_, fallback_identity_pair_}}}; g_fake1_cert_data_map = &fake1_cert_map; UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", - "", authenticated_identity_); + "", {server_san_exact_}, + authenticated_identity_); UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", - "good", + "good", {server_san_exact_}, fallback_authenticated_identity_); g_fake1_cert_data_map = nullptr; } @@ -5544,29 +5735,60 @@ TEST_P(XdsSecurityTest, TestMtlsConfigurationWithBothCertificateNamesUpdated) { {"bad", {bad_root_cert_, bad_identity_pair_}}}; g_fake1_cert_data_map = &fake1_cert_map; UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "bad", "fake_plugin1", - "bad", {}, true /* failure */); + "bad", {server_san_prefix_}, {}, + true /* failure */); UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", - "", authenticated_identity_); + "", {server_san_prefix_}, + authenticated_identity_); g_fake1_cert_data_map = nullptr; } -TEST_P(XdsSecurityTest, TestTlsConfiguration) { +TEST_P(XdsSecurityTest, TestTlsConfigurationWithNoSanMatchers) { FakeCertificateProvider::CertDataMap fake1_cert_map = { {"", {root_cert_, identity_pair_}}}; g_fake1_cert_data_map = &fake1_cert_map; - UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "", + UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "", {}, {} /* unauthenticated */); g_fake1_cert_data_map = nullptr; } +TEST_P(XdsSecurityTest, TestTlsConfigurationWithSanMatchers) { + FakeCertificateProvider::CertDataMap fake1_cert_map = { + {"", {root_cert_, identity_pair_}}}; + g_fake1_cert_data_map = &fake1_cert_map; + UpdateAndVerifyXdsSecurityConfiguration( + "fake_plugin1", "", "", "", + {server_san_exact_, server_san_prefix_, server_san_regex_}, + {} /* unauthenticated */); + g_fake1_cert_data_map = nullptr; +} + +TEST_P(XdsSecurityTest, TestTlsConfigurationWithSanMatchersUpdate) { + FakeCertificateProvider::CertDataMap fake1_cert_map = { + {"", {root_cert_, identity_pair_}}}; + g_fake1_cert_data_map = &fake1_cert_map; + UpdateAndVerifyXdsSecurityConfiguration( + "fake_plugin1", "", "", "", {server_san_exact_, server_san_prefix_}, + {} /* unauthenticated */); + UpdateAndVerifyXdsSecurityConfiguration( + "fake_plugin1", "", "", "", {bad_san_1_, bad_san_2_}, + {} /* unauthenticated */, true /* failure */); + UpdateAndVerifyXdsSecurityConfiguration( + "fake_plugin1", "", "", "", {server_san_prefix_, server_san_regex_}, + {} /* unauthenticated */); + g_fake1_cert_data_map = nullptr; +} + TEST_P(XdsSecurityTest, TestTlsConfigurationWithRootCertificateNameUpdate) { FakeCertificateProvider::CertDataMap fake1_cert_map = { {"", {root_cert_, identity_pair_}}, {"bad", {bad_root_cert_, bad_identity_pair_}}}; g_fake1_cert_data_map = &fake1_cert_map; UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "", + {server_san_exact_}, {} /* unauthenticated */); - UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "bad", "", "", {}, + UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "bad", "", "", + {server_san_exact_}, {}, true /* failure */); g_fake1_cert_data_map = nullptr; } @@ -5579,15 +5801,16 @@ TEST_P(XdsSecurityTest, TestTlsConfigurationWithRootPluginUpdate) { {"", {bad_root_cert_, bad_identity_pair_}}}; g_fake2_cert_data_map = &fake2_cert_map; UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "", + {server_san_exact_}, {} /* unauthenticated */); - UpdateAndVerifyXdsSecurityConfiguration("fake_plugin2", "", "", "", {}, - true /* failure */); + UpdateAndVerifyXdsSecurityConfiguration( + "fake_plugin2", "", "", "", {server_san_exact_}, {}, true /* failure */); g_fake1_cert_data_map = nullptr; g_fake2_cert_data_map = nullptr; } TEST_P(XdsSecurityTest, TestFallbackConfiguration) { - UpdateAndVerifyXdsSecurityConfiguration("", "", "", "", + UpdateAndVerifyXdsSecurityConfiguration("", "", "", "", {}, fallback_authenticated_identity_); g_fake1_cert_data_map = nullptr; } @@ -5597,8 +5820,10 @@ TEST_P(XdsSecurityTest, TestMtlsToTls) { {"", {root_cert_, identity_pair_}}}; g_fake1_cert_data_map = &fake1_cert_map; UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", - "", authenticated_identity_); + "", {server_san_exact_}, + authenticated_identity_); UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "", + {server_san_exact_}, {} /* unauthenticated */); g_fake1_cert_data_map = nullptr; } @@ -5608,8 +5833,9 @@ TEST_P(XdsSecurityTest, TestMtlsToFallback) { {"", {root_cert_, identity_pair_}}}; g_fake1_cert_data_map = &fake1_cert_map; UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", - "", authenticated_identity_); - UpdateAndVerifyXdsSecurityConfiguration("", "", "", "", + "", {server_san_exact_}, + authenticated_identity_); + UpdateAndVerifyXdsSecurityConfiguration("", "", "", "", {}, fallback_authenticated_identity_); g_fake1_cert_data_map = nullptr; } @@ -5619,9 +5845,11 @@ TEST_P(XdsSecurityTest, TestTlsToMtls) { {"", {root_cert_, identity_pair_}}}; g_fake1_cert_data_map = &fake1_cert_map; UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "", + {server_san_exact_}, {} /* unauthenticated */); UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", - "", authenticated_identity_); + "", {server_san_exact_}, + authenticated_identity_); g_fake1_cert_data_map = nullptr; } @@ -5630,8 +5858,9 @@ TEST_P(XdsSecurityTest, TestTlsToFallback) { {"", {root_cert_, identity_pair_}}}; g_fake1_cert_data_map = &fake1_cert_map; UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "", + {server_san_exact_}, {} /* unauthenticated */); - UpdateAndVerifyXdsSecurityConfiguration("", "", "", "", + UpdateAndVerifyXdsSecurityConfiguration("", "", "", "", {}, fallback_authenticated_identity_); g_fake1_cert_data_map = nullptr; } @@ -5640,10 +5869,11 @@ TEST_P(XdsSecurityTest, TestFallbackToMtls) { FakeCertificateProvider::CertDataMap fake1_cert_map = { {"", {root_cert_, identity_pair_}}}; g_fake1_cert_data_map = &fake1_cert_map; - UpdateAndVerifyXdsSecurityConfiguration("", "", "", "", + UpdateAndVerifyXdsSecurityConfiguration("", "", "", "", {}, fallback_authenticated_identity_); UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1", - "", authenticated_identity_); + "", {server_san_exact_}, + authenticated_identity_); g_fake1_cert_data_map = nullptr; } @@ -5651,15 +5881,17 @@ TEST_P(XdsSecurityTest, TestFallbackToTls) { FakeCertificateProvider::CertDataMap fake1_cert_map = { {"", {root_cert_, identity_pair_}}}; g_fake1_cert_data_map = &fake1_cert_map; - UpdateAndVerifyXdsSecurityConfiguration("", "", "", "", + UpdateAndVerifyXdsSecurityConfiguration("", "", "", "", {}, fallback_authenticated_identity_); UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "", + {server_san_exact_}, {} /* unauthenticated */); g_fake1_cert_data_map = nullptr; } TEST_P(XdsSecurityTest, TestFileWatcherCertificateProvider) { UpdateAndVerifyXdsSecurityConfiguration("file_plugin", "", "file_plugin", "", + {server_san_exact_}, authenticated_identity_); } diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 012c8fe6211..7afde6fe2eb 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -1558,8 +1558,6 @@ src/core/ext/xds/certificate_provider_store.cc \ src/core/ext/xds/certificate_provider_store.h \ src/core/ext/xds/file_watcher_certificate_provider_factory.cc \ src/core/ext/xds/file_watcher_certificate_provider_factory.h \ -src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc \ -src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h \ src/core/ext/xds/xds_api.cc \ src/core/ext/xds/xds_api.h \ src/core/ext/xds/xds_bootstrap.cc \ @@ -1952,6 +1950,8 @@ src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc \ src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h \ src/core/lib/security/credentials/tls/tls_credentials.cc \ src/core/lib/security/credentials/tls/tls_credentials.h \ +src/core/lib/security/credentials/tls/tls_utils.cc \ +src/core/lib/security/credentials/tls/tls_utils.h \ src/core/lib/security/credentials/xds/xds_credentials.cc \ src/core/lib/security/credentials/xds/xds_credentials.h \ src/core/lib/security/security_connector/alts/alts_security_connector.cc \ diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 97aaed7a40d..0d0f312303f 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -1395,8 +1395,6 @@ src/core/ext/xds/certificate_provider_store.cc \ src/core/ext/xds/certificate_provider_store.h \ src/core/ext/xds/file_watcher_certificate_provider_factory.cc \ src/core/ext/xds/file_watcher_certificate_provider_factory.h \ -src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc \ -src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h \ src/core/ext/xds/xds_api.cc \ src/core/ext/xds/xds_api.h \ src/core/ext/xds/xds_bootstrap.cc \ @@ -1794,6 +1792,8 @@ src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc \ src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h \ src/core/lib/security/credentials/tls/tls_credentials.cc \ src/core/lib/security/credentials/tls/tls_credentials.h \ +src/core/lib/security/credentials/tls/tls_utils.cc \ +src/core/lib/security/credentials/tls/tls_utils.h \ src/core/lib/security/credentials/xds/xds_credentials.cc \ src/core/lib/security/credentials/xds/xds_credentials.h \ src/core/lib/security/security_connector/alts/alts_security_connector.cc \ diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index e3548e789ca..6ca43c94b6c 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -6325,6 +6325,30 @@ ], "uses_polling": true }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "xds_credentials_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "uses_polling": true + }, { "args": [], "boringssl": true,