From 90cfbe422973457b3d2021323ce6c941c4520ce8 Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Mon, 22 Apr 2024 07:12:07 +0000 Subject: [PATCH] Revert "ssl: More comprehensive testing of SSL credentials, part 1. (#35433)" This reverts commit 40d1776e0761e85c2d5b0215460ddd79122e142b. --- src/core/tsi/ssl_transport_security.cc | 4 - src/core/tsi/ssl_transport_security.h | 3 - test/cpp/end2end/BUILD | 1 - test/cpp/end2end/ssl_credentials_test.cc | 497 +++-------------------- 4 files changed, 64 insertions(+), 441 deletions(-) diff --git a/src/core/tsi/ssl_transport_security.cc b/src/core/tsi/ssl_transport_security.cc index d705abc1c2c..9235782bb29 100644 --- a/src/core/tsi/ssl_transport_security.cc +++ b/src/core/tsi/ssl_transport_security.cc @@ -1282,10 +1282,6 @@ void tsi_ssl_session_cache_unref(tsi_ssl_session_cache* cache) { tsi::SslSessionLRUCache::FromC(cache)->Unref(); } -size_t tsi_ssl_session_cache_size(tsi_ssl_session_cache* cache) { - return tsi::SslSessionLRUCache::FromC(cache)->Size(); -} - // --- tsi_frame_protector methods implementation. --- static tsi_result ssl_protector_protect(tsi_frame_protector* self, diff --git a/src/core/tsi/ssl_transport_security.h b/src/core/tsi/ssl_transport_security.h index d925f08840b..da3b260adbd 100644 --- a/src/core/tsi/ssl_transport_security.h +++ b/src/core/tsi/ssl_transport_security.h @@ -81,9 +81,6 @@ void tsi_ssl_session_cache_ref(tsi_ssl_session_cache* cache); // Decrement reference counter of \a cache. void tsi_ssl_session_cache_unref(tsi_ssl_session_cache* cache); -// Returns the size of the cache. -size_t tsi_ssl_session_cache_size(tsi_ssl_session_cache* cache); - // --- tsi_ssl_key_logger object --- // Experimental SSL Key logging functionality to enable decryption of diff --git a/test/cpp/end2end/BUILD b/test/cpp/end2end/BUILD index 36125889baa..d8a09d6d3c0 100644 --- a/test/cpp/end2end/BUILD +++ b/test/cpp/end2end/BUILD @@ -1068,7 +1068,6 @@ grpc_cc_test( grpc_cc_test( name = "ssl_credentials_test", - timeout = "long", srcs = ["ssl_credentials_test.cc"], data = [ "//src/core/tsi/test_creds:ca.pem", diff --git a/test/cpp/end2end/ssl_credentials_test.cc b/test/cpp/end2end/ssl_credentials_test.cc index 092fe427aed..82cba482ca0 100644 --- a/test/cpp/end2end/ssl_credentials_test.cc +++ b/test/cpp/end2end/ssl_credentials_test.cc @@ -15,11 +15,7 @@ // limitations under the License. // // -#include "src/core/lib/security/credentials/ssl/ssl_credentials.h" - #include -#include -#include #include #include @@ -34,67 +30,34 @@ #include #include -#include "src/core/lib/gprpp/cpp_impl_of.h" -#include "src/core/tsi/ssl_transport_security.h" -#include "src/cpp/client/secure_credentials.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" #include "test/core/util/tls_utils.h" #include "test/cpp/end2end/test_service_impl.h" -// TODO(matthewstevenson88): More test cases to add: -// - Use P256, P384, P512 credentials. -// - Use a long certificate chain. -// - Use a large certificate. -// - Large trust bundle. -// - Bad ALPN. -// - More failure modes. -// - Certs containing more SANs. -// - Copy all of this over to tls_credentials_test.cc. -// - Client doesn't have cert but server requests one. -// - Bad session ticket in cache. -// - Use same channel creds object on sequential/concurrent handshakes. -// - Do successful handshake with a localhost server cert. -// - Missing or malformed roots on both sides. - namespace grpc { namespace testing { namespace { -using ::grpc_core::testing::GetFileContents; -using ::testing::HasSubstr; -using ::testing::IsEmpty; -using ::testing::UnorderedElementsAre; - constexpr char kCaCertPath[] = "src/core/tsi/test_creds/ca.pem"; constexpr char kServerCertPath[] = "src/core/tsi/test_creds/server1.pem"; constexpr char kServerKeyPath[] = "src/core/tsi/test_creds/server1.key"; constexpr char kClientCertPath[] = "src/core/tsi/test_creds/client.pem"; constexpr char kClientKeyPath[] = "src/core/tsi/test_creds/client.key"; constexpr char kMessage[] = "Hello"; -constexpr char kTargetNameOverride[] = "foo.test.google.fr"; - -std::size_t GetSessionCacheSize(grpc_ssl_session_cache* cache) { - tsi_ssl_session_cache* tsi_cache = - reinterpret_cast(cache); - return tsi_ssl_session_cache_size(tsi_cache); -} - -struct SslOptions { - grpc_ssl_client_certificate_request_type request_type = - GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE; - bool use_session_cache; -}; -class SslCredentialsTest : public ::testing::TestWithParam { +class SslCredentialsTest : public ::testing::Test { protected: - void RunServer(absl::Notification* notification, - absl::string_view pem_root_certs) { + void RunServer(absl::Notification* notification) { + std::string root_cert = grpc_core::testing::GetFileContents(kCaCertPath); grpc::SslServerCredentialsOptions::PemKeyCertPair key_cert_pair = { - GetFileContents(kServerKeyPath), GetFileContents(kServerCertPath)}; - grpc::SslServerCredentialsOptions ssl_options(GetParam().request_type); + grpc_core::testing::GetFileContents(kServerKeyPath), + grpc_core::testing::GetFileContents(kServerCertPath)}; + // TODO(gtcooke94) Parametrize this test for TLS and mTLS as well + grpc::SslServerCredentialsOptions ssl_options; ssl_options.pem_key_cert_pairs.push_back(key_cert_pair); - ssl_options.pem_root_certs = std::string(pem_root_certs); + ssl_options.pem_root_certs = root_cert; + ssl_options.force_client_auth = true; grpc::ServerBuilder builder; TestServiceImpl service_; @@ -115,226 +78,57 @@ class SslCredentialsTest : public ::testing::TestWithParam { } } - absl::StatusOr> DoRpc( - const SslCredentialsOptions& options, grpc_ssl_session_cache* cache, - bool override_ssl_target_name = true) { - ChannelArguments channel_args; - if (GetParam().use_session_cache) { - channel_args.SetPointer(std::string(GRPC_SSL_SESSION_CACHE_ARG), cache); - } - if (override_ssl_target_name) { - channel_args.SetSslTargetNameOverride(kTargetNameOverride); - } - - auto creds = SslCredentials(options); - std::shared_ptr channel = - grpc::CreateCustomChannel(server_addr_, creds, channel_args); - - auto stub = grpc::testing::EchoTestService::NewStub(channel); - grpc::testing::EchoRequest request; - grpc::testing::EchoResponse response; - request.set_message(kMessage); - ClientContext context; - context.set_deadline(grpc_timeout_seconds_to_deadline(/*time_s=*/10)); - grpc::Status result = stub->Echo(&context, request, &response); - if (!result.ok()) { - return absl::Status(static_cast(result.error_code()), - result.error_message()); - } - EXPECT_EQ(response.message(), kMessage); - return context.auth_context(); - } - - static std::vector GetAuthContextPropertyAsList( - const AuthContext& auth_context, const std::string& property) { - std::vector properties; - for (const grpc::string_ref& property : - auth_context.FindPropertyValues(property)) { - properties.push_back(absl::string_view(property.data(), property.size())); - } - return properties; - } - - static absl::string_view GetAuthContextProperty( - const AuthContext& auth_context, const std::string& property) { - std::vector properties = - GetAuthContextPropertyAsList(auth_context, property); - return properties.size() == 1 ? properties[0] : ""; - } - TestServiceImpl service_; std::unique_ptr server_ = nullptr; std::thread* server_thread_ = nullptr; std::string server_addr_; }; -TEST_P(SslCredentialsTest, FullHandshake) { - server_addr_ = absl::StrCat("localhost:", - std::to_string(grpc_pick_unused_port_or_die())); - absl::Notification notification; - server_thread_ = new std::thread([&]() { - std::string root_cert = GetFileContents(kCaCertPath); - RunServer(¬ification, root_cert); - }); - notification.WaitForNotification(); - - std::string root_cert = GetFileContents(kCaCertPath); - std::string client_key = GetFileContents(kClientKeyPath); - std::string client_cert = GetFileContents(kClientCertPath); - grpc::SslCredentialsOptions ssl_options; - ssl_options.pem_root_certs = root_cert; - ssl_options.pem_private_key = client_key; - ssl_options.pem_cert_chain = client_cert; - - grpc_ssl_session_cache* cache = grpc_ssl_session_cache_create_lru(16); - - auto full_handshake_context = DoRpc(ssl_options, cache); - EXPECT_EQ(full_handshake_context.status(), absl::OkStatus()); - EXPECT_EQ(GetAuthContextProperty(**full_handshake_context, - GRPC_SSL_SESSION_REUSED_PROPERTY), - "false"); - EXPECT_EQ(GetAuthContextProperty(**full_handshake_context, - GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME), - GRPC_SSL_TRANSPORT_SECURITY_TYPE); - EXPECT_EQ(GetAuthContextProperty(**full_handshake_context, - GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME), - "TSI_PRIVACY_AND_INTEGRITY"); - EXPECT_EQ(GetAuthContextProperty(**full_handshake_context, - GRPC_X509_CN_PROPERTY_NAME), - "*.test.google.com"); - EXPECT_EQ(GetAuthContextProperty(**full_handshake_context, - GRPC_X509_SUBJECT_PROPERTY_NAME), - "CN=*.test.google.com,O=Example\\, Co.,L=Chicago,ST=Illinois,C=US"); - EXPECT_THAT( - GetAuthContextPropertyAsList(**full_handshake_context, - GRPC_X509_SAN_PROPERTY_NAME), - UnorderedElementsAre("*.test.google.fr", "waterzooi.test.google.be", - "*.test.youtube.com", "192.168.1.3")); - EXPECT_EQ(GetAuthContextProperty(**full_handshake_context, - GRPC_X509_PEM_CERT_PROPERTY_NAME), - GetFileContents(kServerCertPath)); - EXPECT_EQ(GetAuthContextProperty(**full_handshake_context, - GRPC_X509_PEM_CERT_CHAIN_PROPERTY_NAME), - GetFileContents(kServerCertPath)); - EXPECT_THAT( - GetAuthContextPropertyAsList(**full_handshake_context, - GRPC_PEER_DNS_PROPERTY_NAME), - UnorderedElementsAre("*.test.google.fr", "waterzooi.test.google.be", - "*.test.youtube.com")); - EXPECT_THAT(GetAuthContextPropertyAsList(**full_handshake_context, - GRPC_PEER_URI_PROPERTY_NAME), - IsEmpty()); - EXPECT_THAT(GetAuthContextPropertyAsList(**full_handshake_context, - GRPC_PEER_EMAIL_PROPERTY_NAME), - IsEmpty()); - EXPECT_THAT(GetAuthContextPropertyAsList(**full_handshake_context, - GRPC_PEER_IP_PROPERTY_NAME), - UnorderedElementsAre("192.168.1.3")); - EXPECT_EQ(GetAuthContextProperty(**full_handshake_context, - GRPC_PEER_SPIFFE_ID_PROPERTY_NAME), - ""); - if (GetParam().use_session_cache) { - EXPECT_EQ(GetSessionCacheSize(cache), 1); +void DoRpc(const std::string& server_addr, + const SslCredentialsOptions& ssl_options, + grpc_ssl_session_cache* cache, bool expect_session_reuse) { + ChannelArguments channel_args; + channel_args.SetPointer(std::string(GRPC_SSL_SESSION_CACHE_ARG), cache); + channel_args.SetSslTargetNameOverride("foo.test.google.fr"); + + std::shared_ptr channel = grpc::CreateCustomChannel( + server_addr, grpc::SslCredentials(ssl_options), channel_args); + + auto stub = grpc::testing::EchoTestService::NewStub(channel); + grpc::testing::EchoRequest request; + grpc::testing::EchoResponse response; + request.set_message(kMessage); + ClientContext context; + context.set_deadline(grpc_timeout_seconds_to_deadline(/*time_s=*/10)); + grpc::Status result = stub->Echo(&context, request, &response); + EXPECT_TRUE(result.ok()); + if (!result.ok()) { + gpr_log(GPR_ERROR, "%s, %s", result.error_message().c_str(), + result.error_details().c_str()); + } + EXPECT_EQ(response.message(), kMessage); + std::shared_ptr auth_context = context.auth_context(); + std::vector properties = + auth_context->FindPropertyValues(GRPC_SSL_SESSION_REUSED_PROPERTY); + ASSERT_EQ(properties.size(), 1u); + if (expect_session_reuse) { + EXPECT_EQ("true", ToString(properties[0])); + } else { + EXPECT_EQ("false", ToString(properties[0])); } - - grpc_ssl_session_cache_destroy(cache); -} - -TEST_P(SslCredentialsTest, ResumedHandshake) { - // Skip this test if session caching is disabled. - if (!GetParam().use_session_cache) return; - - server_addr_ = absl::StrCat("localhost:", - std::to_string(grpc_pick_unused_port_or_die())); - absl::Notification notification; - server_thread_ = new std::thread([&]() { - std::string root_cert = GetFileContents(kCaCertPath); - RunServer(¬ification, root_cert); - }); - notification.WaitForNotification(); - - std::string root_cert = GetFileContents(kCaCertPath); - std::string client_key = GetFileContents(kClientKeyPath); - std::string client_cert = GetFileContents(kClientCertPath); - grpc::SslCredentialsOptions ssl_options; - ssl_options.pem_root_certs = root_cert; - ssl_options.pem_private_key = client_key; - ssl_options.pem_cert_chain = client_cert; - - grpc_ssl_session_cache* cache = grpc_ssl_session_cache_create_lru(16); - - auto full_handshake_context = DoRpc(ssl_options, cache); - EXPECT_EQ(full_handshake_context.status(), absl::OkStatus()); - EXPECT_EQ(GetAuthContextProperty(**full_handshake_context, - GRPC_SSL_SESSION_REUSED_PROPERTY), - "false"); - - auto resumed_handshake_context = DoRpc(ssl_options, cache); - EXPECT_EQ(resumed_handshake_context.status(), absl::OkStatus()); - EXPECT_EQ(GetAuthContextProperty(**resumed_handshake_context, - GRPC_SSL_SESSION_REUSED_PROPERTY), - "true"); - EXPECT_EQ(GetAuthContextProperty(**resumed_handshake_context, - GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME), - GRPC_SSL_TRANSPORT_SECURITY_TYPE); - EXPECT_EQ(GetAuthContextProperty(**resumed_handshake_context, - GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME), - "TSI_PRIVACY_AND_INTEGRITY"); - EXPECT_EQ(GetAuthContextProperty(**resumed_handshake_context, - GRPC_X509_CN_PROPERTY_NAME), - "*.test.google.com"); - EXPECT_EQ(GetAuthContextProperty(**resumed_handshake_context, - GRPC_X509_SUBJECT_PROPERTY_NAME), - "CN=*.test.google.com,O=Example\\, Co.,L=Chicago,ST=Illinois,C=US"); - EXPECT_THAT( - GetAuthContextPropertyAsList(**resumed_handshake_context, - GRPC_X509_SAN_PROPERTY_NAME), - UnorderedElementsAre("*.test.google.fr", "waterzooi.test.google.be", - "*.test.youtube.com", "192.168.1.3")); - EXPECT_EQ(GetAuthContextProperty(**resumed_handshake_context, - GRPC_X509_PEM_CERT_PROPERTY_NAME), - GetFileContents(kServerCertPath)); - EXPECT_EQ(GetAuthContextProperty(**resumed_handshake_context, - GRPC_X509_PEM_CERT_CHAIN_PROPERTY_NAME), - GetFileContents(kServerCertPath)); - EXPECT_THAT( - GetAuthContextPropertyAsList(**resumed_handshake_context, - GRPC_PEER_DNS_PROPERTY_NAME), - UnorderedElementsAre("*.test.google.fr", "waterzooi.test.google.be", - "*.test.youtube.com")); - EXPECT_THAT(GetAuthContextPropertyAsList(**resumed_handshake_context, - GRPC_PEER_URI_PROPERTY_NAME), - IsEmpty()); - EXPECT_THAT(GetAuthContextPropertyAsList(**resumed_handshake_context, - GRPC_PEER_EMAIL_PROPERTY_NAME), - IsEmpty()); - EXPECT_THAT(GetAuthContextPropertyAsList(**resumed_handshake_context, - GRPC_PEER_IP_PROPERTY_NAME), - UnorderedElementsAre("192.168.1.3")); - EXPECT_EQ(GetAuthContextProperty(**resumed_handshake_context, - GRPC_PEER_SPIFFE_ID_PROPERTY_NAME), - ""); - EXPECT_EQ(GetSessionCacheSize(cache), 1); - - grpc_ssl_session_cache_destroy(cache); } -TEST_P(SslCredentialsTest, SequentialResumption) { - // Skip this test if session caching is disabled. - if (!GetParam().use_session_cache) return; - +TEST_F(SslCredentialsTest, SequentialResumption) { server_addr_ = absl::StrCat("localhost:", std::to_string(grpc_pick_unused_port_or_die())); absl::Notification notification; - server_thread_ = new std::thread([&]() { - std::string root_cert = GetFileContents(kCaCertPath); - RunServer(¬ification, root_cert); - }); + server_thread_ = new std::thread([&]() { RunServer(¬ification); }); notification.WaitForNotification(); - std::string root_cert = GetFileContents(kCaCertPath); - std::string client_key = GetFileContents(kClientKeyPath); - std::string client_cert = GetFileContents(kClientCertPath); + std::string root_cert = grpc_core::testing::GetFileContents(kCaCertPath); + std::string client_key = grpc_core::testing::GetFileContents(kClientKeyPath); + std::string client_cert = + grpc_core::testing::GetFileContents(kClientCertPath); grpc::SslCredentialsOptions ssl_options; ssl_options.pem_root_certs = root_cert; ssl_options.pem_private_key = client_key; @@ -342,38 +136,25 @@ TEST_P(SslCredentialsTest, SequentialResumption) { grpc_ssl_session_cache* cache = grpc_ssl_session_cache_create_lru(16); - auto full_handshake_context = DoRpc(ssl_options, cache); - EXPECT_EQ(full_handshake_context.status(), absl::OkStatus()); - EXPECT_EQ(GetAuthContextProperty(**full_handshake_context, - GRPC_SSL_SESSION_REUSED_PROPERTY), - "false"); + DoRpc(server_addr_, ssl_options, cache, /*expect_session_reuse=*/false); for (int i = 0; i < 10; i++) { - auto resumed_handshake_context = DoRpc(ssl_options, cache); - EXPECT_EQ(resumed_handshake_context.status(), absl::OkStatus()); - EXPECT_EQ(GetAuthContextProperty(**resumed_handshake_context, - GRPC_SSL_SESSION_REUSED_PROPERTY), - "true"); + DoRpc(server_addr_, ssl_options, cache, /*expect_session_reuse=*/true); } grpc_ssl_session_cache_destroy(cache); } -TEST_P(SslCredentialsTest, ConcurrentResumption) { - // Skip this test if session caching is disabled. - if (!GetParam().use_session_cache) return; - +TEST_F(SslCredentialsTest, ConcurrentResumption) { server_addr_ = absl::StrCat("localhost:", std::to_string(grpc_pick_unused_port_or_die())); absl::Notification notification; - server_thread_ = new std::thread([&]() { - std::string root_cert = GetFileContents(kCaCertPath); - RunServer(¬ification, root_cert); - }); + server_thread_ = new std::thread([&]() { RunServer(¬ification); }); notification.WaitForNotification(); - std::string root_cert = GetFileContents(kCaCertPath); - std::string client_key = GetFileContents(kClientKeyPath); - std::string client_cert = GetFileContents(kClientCertPath); + std::string root_cert = grpc_core::testing::GetFileContents(kCaCertPath); + std::string client_key = grpc_core::testing::GetFileContents(kClientKeyPath); + std::string client_cert = + grpc_core::testing::GetFileContents(kClientCertPath); grpc::SslCredentialsOptions ssl_options; ssl_options.pem_root_certs = root_cert; ssl_options.pem_private_key = client_key; @@ -381,20 +162,12 @@ TEST_P(SslCredentialsTest, ConcurrentResumption) { grpc_ssl_session_cache* cache = grpc_ssl_session_cache_create_lru(16); - auto full_handshake_context = DoRpc(ssl_options, cache); - EXPECT_EQ(full_handshake_context.status(), absl::OkStatus()); - EXPECT_EQ(GetAuthContextProperty(**full_handshake_context, - GRPC_SSL_SESSION_REUSED_PROPERTY), - "false"); + DoRpc(server_addr_, ssl_options, cache, /*expect_session_reuse=*/false); std::vector threads; threads.reserve(10); for (int i = 0; i < 10; i++) { threads.push_back(std::thread([&]() { - auto resumed_handshake_context = DoRpc(ssl_options, cache); - EXPECT_EQ(resumed_handshake_context.status(), absl::OkStatus()); - EXPECT_EQ(GetAuthContextProperty(**resumed_handshake_context, - GRPC_SSL_SESSION_REUSED_PROPERTY), - "true"); + DoRpc(server_addr_, ssl_options, cache, /*expect_session_reuse=*/true); })); } for (auto& t : threads) { @@ -404,19 +177,17 @@ TEST_P(SslCredentialsTest, ConcurrentResumption) { grpc_ssl_session_cache_destroy(cache); } -TEST_P(SslCredentialsTest, ResumptionFailsDueToNoCapacityInCache) { +TEST_F(SslCredentialsTest, ResumptionFailsDueToNoCapacityInCache) { server_addr_ = absl::StrCat("localhost:", std::to_string(grpc_pick_unused_port_or_die())); absl::Notification notification; - server_thread_ = new std::thread([&]() { - std::string root_cert = GetFileContents(kCaCertPath); - RunServer(¬ification, root_cert); - }); + server_thread_ = new std::thread([&]() { RunServer(¬ification); }); notification.WaitForNotification(); - std::string root_cert = GetFileContents(kCaCertPath); - std::string client_key = GetFileContents(kClientKeyPath); - std::string client_cert = GetFileContents(kClientCertPath); + std::string root_cert = grpc_core::testing::GetFileContents(kCaCertPath); + std::string client_key = grpc_core::testing::GetFileContents(kClientKeyPath); + std::string client_cert = + grpc_core::testing::GetFileContents(kClientCertPath); grpc::SslCredentialsOptions ssl_options; ssl_options.pem_root_certs = root_cert; ssl_options.pem_private_key = client_key; @@ -424,152 +195,12 @@ TEST_P(SslCredentialsTest, ResumptionFailsDueToNoCapacityInCache) { grpc_ssl_session_cache* cache = grpc_ssl_session_cache_create_lru(0); - for (int i = 0; i < 2; ++i) { - auto full_handshake_context = DoRpc(ssl_options, cache); - EXPECT_EQ(full_handshake_context.status(), absl::OkStatus()); - EXPECT_EQ(GetAuthContextProperty(**full_handshake_context, - GRPC_SSL_SESSION_REUSED_PROPERTY), - "false"); - } + DoRpc(server_addr_, ssl_options, cache, /*expect_session_reuse=*/false); + DoRpc(server_addr_, ssl_options, cache, /*expect_session_reuse=*/false); grpc_ssl_session_cache_destroy(cache); } -TEST_P(SslCredentialsTest, ServerCertificateIsUntrusted) { - server_addr_ = absl::StrCat("localhost:", - std::to_string(grpc_pick_unused_port_or_die())); - absl::Notification notification; - server_thread_ = new std::thread([&]() { - std::string root_cert = GetFileContents(kCaCertPath); - RunServer(¬ification, root_cert); - }); - notification.WaitForNotification(); - - // Use the client's own leaf cert as the root cert, so that the server's cert - // will not be trusted by the client. - std::string root_cert = GetFileContents(kClientCertPath); - std::string client_key = GetFileContents(kClientKeyPath); - std::string client_cert = GetFileContents(kClientCertPath); - grpc::SslCredentialsOptions ssl_options; - ssl_options.pem_root_certs = root_cert; - ssl_options.pem_private_key = client_key; - ssl_options.pem_cert_chain = client_cert; - - grpc_ssl_session_cache* cache = grpc_ssl_session_cache_create_lru(0); - - auto auth_context = DoRpc(ssl_options, cache); - EXPECT_EQ(auth_context.status().code(), absl::StatusCode::kUnavailable); - EXPECT_THAT(auth_context.status().message(), - HasSubstr("CERTIFICATE_VERIFY_FAILED")); - EXPECT_EQ(GetSessionCacheSize(cache), 0); - - grpc_ssl_session_cache_destroy(cache); -} - -TEST_P(SslCredentialsTest, ClientCertificateIsUntrusted) { - // Skip this test if the client certificate is not requested. - if (GetParam().request_type == grpc_ssl_client_certificate_request_type:: - GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE) { - return; - } - - server_addr_ = absl::StrCat("localhost:", - std::to_string(grpc_pick_unused_port_or_die())); - absl::Notification notification; - server_thread_ = new std::thread([&]() { - // Use the server's own leaf cert as the root cert, so that the client's - // cert will not be trusted by the server. - std::string root_cert = GetFileContents(kServerCertPath); - RunServer(¬ification, root_cert); - }); - notification.WaitForNotification(); - - std::string root_cert = GetFileContents(kCaCertPath); - std::string client_key = GetFileContents(kClientKeyPath); - std::string client_cert = GetFileContents(kClientCertPath); - grpc::SslCredentialsOptions ssl_options; - ssl_options.pem_root_certs = root_cert; - ssl_options.pem_private_key = client_key; - ssl_options.pem_cert_chain = client_cert; - - grpc_ssl_session_cache* cache = grpc_ssl_session_cache_create_lru(0); - - auto auth_context = DoRpc(ssl_options, cache); - if (GetParam().request_type == - grpc_ssl_client_certificate_request_type:: - GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY || - GetParam().request_type == - grpc_ssl_client_certificate_request_type:: - GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY) { - EXPECT_EQ(auth_context.status().code(), absl::StatusCode::kUnavailable); - // TODO(matthewstevenson88): Investigate having a more descriptive error - // message for the client. - EXPECT_THAT(auth_context.status().message(), - HasSubstr("failed to connect")); - EXPECT_EQ(GetSessionCacheSize(cache), 0); - } else { - // TODO(matthewstevenson88): The handshake fails with a certificate - // verification error in these cases. This is a bug. Fix this. - } - - grpc_ssl_session_cache_destroy(cache); -} - -TEST_P(SslCredentialsTest, ServerHostnameVerificationFails) { - server_addr_ = absl::StrCat("localhost:", - std::to_string(grpc_pick_unused_port_or_die())); - absl::Notification notification; - server_thread_ = new std::thread([&]() { - std::string root_cert = GetFileContents(kCaCertPath); - RunServer(¬ification, root_cert); - }); - notification.WaitForNotification(); - - std::string root_cert = GetFileContents(kCaCertPath); - std::string client_key = GetFileContents(kClientKeyPath); - std::string client_cert = GetFileContents(kClientCertPath); - grpc::SslCredentialsOptions ssl_options; - ssl_options.pem_root_certs = root_cert; - ssl_options.pem_private_key = client_key; - ssl_options.pem_cert_chain = client_cert; - - grpc_ssl_session_cache* cache = grpc_ssl_session_cache_create_lru(0); - - auto auth_context = - DoRpc(ssl_options, cache, /*override_ssl_target_name=*/false); - EXPECT_EQ(auth_context.status().code(), absl::StatusCode::kUnavailable); - // TODO(matthewstevenson88): Logs say "No match found for server name: - // localhost." but this error is not propagated to the user. Fix this. - EXPECT_FALSE(auth_context.status().message().empty()); - EXPECT_EQ(GetSessionCacheSize(cache), 0); - - grpc_ssl_session_cache_destroy(cache); -} - -std::vector GetSslOptions() { - std::vector ssl_options; - for (grpc_ssl_client_certificate_request_type type : - {grpc_ssl_client_certificate_request_type:: - GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE, - grpc_ssl_client_certificate_request_type:: - GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY, - grpc_ssl_client_certificate_request_type:: - GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY, - grpc_ssl_client_certificate_request_type:: - GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY, - grpc_ssl_client_certificate_request_type:: - GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY}) { - for (bool use_session_cache : {false, true}) { - SslOptions option = {type, use_session_cache}; - ssl_options.push_back(option); - } - } - return ssl_options; -} - -INSTANTIATE_TEST_SUITE_P(SslCredentials, SslCredentialsTest, - ::testing::ValuesIn(GetSslOptions())); - } // namespace } // namespace testing } // namespace grpc