• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2023 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 #include <grpc/grpc_crl_provider.h>
19 #include <grpc/grpc_security.h>
20 #include <grpcpp/channel.h>
21 #include <grpcpp/client_context.h>
22 #include <grpcpp/create_channel.h>
23 #include <grpcpp/security/credentials.h>
24 #include <grpcpp/security/server_credentials.h>
25 #include <grpcpp/security/tls_certificate_provider.h>
26 #include <grpcpp/security/tls_certificate_verifier.h>
27 #include <grpcpp/security/tls_credentials_options.h>
28 #include <grpcpp/server.h>
29 #include <grpcpp/server_builder.h>
30 #include <grpcpp/support/channel_arguments.h>
31 #include <grpcpp/support/status.h>
32 #include <gtest/gtest.h>
33 
34 #include <memory>
35 #include <string>
36 #include <vector>
37 
38 #include "absl/log/check.h"
39 #include "absl/log/log.h"
40 #include "absl/status/statusor.h"
41 #include "absl/strings/str_cat.h"
42 #include "absl/strings/string_view.h"
43 #include "absl/synchronization/notification.h"
44 #include "src/cpp/client/secure_credentials.h"
45 #include "src/proto/grpc/testing/echo_messages.pb.h"
46 #include "test/core/test_util/port.h"
47 #include "test/core/test_util/test_config.h"
48 #include "test/core/test_util/tls_utils.h"
49 #include "test/cpp/end2end/test_service_impl.h"
50 
51 // CRL Providers not supported for <1.1
52 #if OPENSSL_VERSION_NUMBER >= 0x10100000
53 namespace grpc {
54 namespace testing {
55 namespace {
56 
57 const char* kRootPath = "test/core/tsi/test_creds/crl_data/ca.pem";
58 const char* kRevokedKeyPath = "test/core/tsi/test_creds/crl_data/revoked.key";
59 const char* kRevokedCertPath = "test/core/tsi/test_creds/crl_data/revoked.pem";
60 const char* kValidKeyPath = "test/core/tsi/test_creds/crl_data/valid.key";
61 const char* kValidCertPath = "test/core/tsi/test_creds/crl_data/valid.pem";
62 const char* kRootCrlPath = "test/core/tsi/test_creds/crl_data/crls/current.crl";
63 const char* kCrlDirectoryPath =
64     "test/core/tsi/test_creds/crl_data/crl_provider_test_dir/";
65 constexpr char kMessage[] = "Hello";
66 
67 // This test must be at the top of the file because the
68 // DirectoryReloaderCrlProvider gets the default event engine on construction.
69 // To get the default event engine, grpc_init must have been called, otherwise a
70 // segfault occurs. This test checks that no segfault occurs while getting the
71 // default event engine during the construction of a
72 // DirectoryReloaderCrlProvider. `grpc_init` is global state, so if another test
73 // runs first, then this test could pass because of another test modifying the
74 // global state
TEST(DirectoryReloaderCrlProviderTestNoFixture,Construction)75 TEST(DirectoryReloaderCrlProviderTestNoFixture, Construction) {
76   auto provider = grpc_core::experimental::CreateDirectoryReloaderCrlProvider(
77       kCrlDirectoryPath, std::chrono::seconds(60), nullptr);
78   ASSERT_TRUE(provider.ok()) << provider.status();
79 }
80 
81 class CrlProviderTest : public ::testing::Test {
82  protected:
RunServer(absl::Notification * notification,absl::string_view server_key,absl::string_view server_cert)83   void RunServer(absl::Notification* notification, absl::string_view server_key,
84                  absl::string_view server_cert) {
85     experimental::IdentityKeyCertPair key_cert_pair;
86     std::string root = grpc_core::testing::GetFileContents(kRootPath);
87     key_cert_pair.private_key = server_key.data();
88     key_cert_pair.certificate_chain = server_cert.data();
89     std::vector<experimental::IdentityKeyCertPair> identity_key_cert_pairs;
90     identity_key_cert_pairs.emplace_back(key_cert_pair);
91     auto certificate_provider =
92         std::make_shared<experimental::StaticDataCertificateProvider>(
93             root, identity_key_cert_pairs);
94     grpc::experimental::TlsServerCredentialsOptions options(
95         certificate_provider);
96     options.watch_root_certs();
97     options.set_root_cert_name("root");
98     options.watch_identity_key_cert_pairs();
99     options.set_identity_cert_name("identity");
100     options.set_cert_request_type(
101         GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
102     auto server_credentials = grpc::experimental::TlsServerCredentials(options);
103     CHECK_NE(server_credentials.get(), nullptr);
104 
105     grpc::ServerBuilder builder;
106     TestServiceImpl service_;
107 
108     builder.AddListeningPort(server_addr_, server_credentials);
109     builder.RegisterService("foo.test.google.fr", &service_);
110     server_ = builder.BuildAndStart();
111     notification->Notify();
112     server_->Wait();
113   }
114 
TearDown()115   void TearDown() override {
116     if (server_ != nullptr) {
117       server_->Shutdown();
118       server_thread_->join();
119       delete server_thread_;
120     }
121   }
122 
123   TestServiceImpl service_;
124   std::unique_ptr<Server> server_ = nullptr;
125   std::thread* server_thread_ = nullptr;
126   std::string server_addr_;
127 };
128 
DoRpc(const std::string & server_addr,const experimental::TlsChannelCredentialsOptions & tls_options,bool expect_success)129 void DoRpc(const std::string& server_addr,
130            const experimental::TlsChannelCredentialsOptions& tls_options,
131            bool expect_success) {
132   ChannelArguments channel_args;
133   channel_args.SetSslTargetNameOverride("foo.test.google.fr");
134   std::shared_ptr<Channel> channel = grpc::CreateCustomChannel(
135       server_addr, grpc::experimental::TlsCredentials(tls_options),
136       channel_args);
137 
138   auto stub = grpc::testing::EchoTestService::NewStub(channel);
139   grpc::testing::EchoRequest request;
140   grpc::testing::EchoResponse response;
141   request.set_message(kMessage);
142   ClientContext context;
143   context.set_deadline(grpc_timeout_seconds_to_deadline(/*time_s=*/15));
144   grpc::Status result = stub->Echo(&context, request, &response);
145   if (expect_success) {
146     EXPECT_TRUE(result.ok());
147     if (!result.ok()) {
148       LOG(ERROR) << result.error_message().c_str() << ", "
149                  << result.error_details().c_str();
150     }
151     EXPECT_EQ(response.message(), kMessage);
152   } else {
153     EXPECT_FALSE(result.ok());
154   }
155 }
156 
TEST_F(CrlProviderTest,CrlProviderValidStaticProvider)157 TEST_F(CrlProviderTest, CrlProviderValidStaticProvider) {
158   server_addr_ = absl::StrCat("localhost:",
159                               std::to_string(grpc_pick_unused_port_or_die()));
160   absl::Notification notification;
161   std::string server_key = grpc_core::testing::GetFileContents(kValidKeyPath);
162   std::string server_cert = grpc_core::testing::GetFileContents(kValidCertPath);
163   server_thread_ = new std::thread(
164       [&]() { RunServer(&notification, server_key, server_cert); });
165   notification.WaitForNotification();
166 
167   std::string root_cert = grpc_core::testing::GetFileContents(kRootPath);
168   std::string client_key = grpc_core::testing::GetFileContents(kValidKeyPath);
169   std::string client_cert = grpc_core::testing::GetFileContents(kValidCertPath);
170   experimental::IdentityKeyCertPair key_cert_pair;
171   key_cert_pair.private_key = client_key;
172   key_cert_pair.certificate_chain = client_cert;
173   std::vector<experimental::IdentityKeyCertPair> identity_key_cert_pairs;
174   identity_key_cert_pairs.emplace_back(key_cert_pair);
175   auto certificate_provider =
176       std::make_shared<experimental::StaticDataCertificateProvider>(
177           root_cert, identity_key_cert_pairs);
178   grpc::experimental::TlsChannelCredentialsOptions options;
179   options.set_certificate_provider(certificate_provider);
180   options.watch_root_certs();
181   options.set_root_cert_name("root");
182   options.watch_identity_key_cert_pairs();
183   options.set_identity_cert_name("identity");
184   std::string root_crl = grpc_core::testing::GetFileContents(kRootCrlPath);
185 
186   absl::StatusOr<std::shared_ptr<grpc_core::experimental::CrlProvider>>
187       provider = grpc_core::experimental::CreateStaticCrlProvider({root_crl});
188   ASSERT_TRUE(provider.ok());
189 
190   options.set_crl_provider(*provider);
191   options.set_check_call_host(false);
192   auto verifier = std::make_shared<experimental::NoOpCertificateVerifier>();
193   options.set_certificate_verifier(verifier);
194 
195   DoRpc(server_addr_, options, true);
196 }
197 
TEST_F(CrlProviderTest,CrlProviderRevokedServer)198 TEST_F(CrlProviderTest, CrlProviderRevokedServer) {
199   server_addr_ = absl::StrCat("localhost:",
200                               std::to_string(grpc_pick_unused_port_or_die()));
201   absl::Notification notification;
202   std::string server_key = grpc_core::testing::GetFileContents(kRevokedKeyPath);
203   std::string server_cert =
204       grpc_core::testing::GetFileContents(kRevokedCertPath);
205   server_thread_ = new std::thread(
206       [&]() { RunServer(&notification, server_key, server_cert); });
207   notification.WaitForNotification();
208 
209   std::string root_cert = grpc_core::testing::GetFileContents(kRootPath);
210   std::string client_key = grpc_core::testing::GetFileContents(kValidKeyPath);
211   std::string client_cert = grpc_core::testing::GetFileContents(kValidCertPath);
212   experimental::IdentityKeyCertPair key_cert_pair;
213   key_cert_pair.private_key = client_key;
214   key_cert_pair.certificate_chain = client_cert;
215   std::vector<experimental::IdentityKeyCertPair> identity_key_cert_pairs;
216   identity_key_cert_pairs.emplace_back(key_cert_pair);
217   auto certificate_provider =
218       std::make_shared<experimental::StaticDataCertificateProvider>(
219           root_cert, identity_key_cert_pairs);
220   grpc::experimental::TlsChannelCredentialsOptions options;
221   options.set_certificate_provider(certificate_provider);
222   options.watch_root_certs();
223   options.set_root_cert_name("root");
224   options.watch_identity_key_cert_pairs();
225   options.set_identity_cert_name("identity");
226   std::string root_crl = grpc_core::testing::GetFileContents(kRootCrlPath);
227 
228   absl::StatusOr<std::shared_ptr<grpc_core::experimental::CrlProvider>>
229       provider = grpc_core::experimental::CreateStaticCrlProvider({root_crl});
230   ASSERT_TRUE(provider.ok());
231 
232   options.set_crl_provider(*provider);
233   options.set_check_call_host(false);
234   auto verifier = std::make_shared<experimental::NoOpCertificateVerifier>();
235   options.set_certificate_verifier(verifier);
236 
237   DoRpc(server_addr_, options, false);
238 }
239 
TEST_F(CrlProviderTest,CrlProviderValidReloaderProvider)240 TEST_F(CrlProviderTest, CrlProviderValidReloaderProvider) {
241   server_addr_ = absl::StrCat("localhost:",
242                               std::to_string(grpc_pick_unused_port_or_die()));
243   absl::Notification notification;
244   std::string server_key = grpc_core::testing::GetFileContents(kValidKeyPath);
245   std::string server_cert = grpc_core::testing::GetFileContents(kValidCertPath);
246   server_thread_ = new std::thread(
247       [&]() { RunServer(&notification, server_key, server_cert); });
248   notification.WaitForNotification();
249 
250   std::string root_cert = grpc_core::testing::GetFileContents(kRootPath);
251   std::string client_key = grpc_core::testing::GetFileContents(kValidKeyPath);
252   std::string client_cert = grpc_core::testing::GetFileContents(kValidCertPath);
253   experimental::IdentityKeyCertPair key_cert_pair;
254   key_cert_pair.private_key = client_key;
255   key_cert_pair.certificate_chain = client_cert;
256   std::vector<experimental::IdentityKeyCertPair> identity_key_cert_pairs;
257   identity_key_cert_pairs.emplace_back(key_cert_pair);
258   auto certificate_provider =
259       std::make_shared<experimental::StaticDataCertificateProvider>(
260           root_cert, identity_key_cert_pairs);
261   grpc::experimental::TlsChannelCredentialsOptions options;
262   options.set_certificate_provider(certificate_provider);
263   options.watch_root_certs();
264   options.set_root_cert_name("root");
265   options.watch_identity_key_cert_pairs();
266   options.set_identity_cert_name("identity");
267 
268   absl::StatusOr<std::shared_ptr<grpc_core::experimental::CrlProvider>>
269       provider = grpc_core::experimental::CreateDirectoryReloaderCrlProvider(
270           kCrlDirectoryPath, std::chrono::seconds(60), nullptr);
271   ASSERT_TRUE(provider.ok());
272 
273   options.set_crl_provider(*provider);
274   options.set_check_call_host(false);
275   auto verifier = std::make_shared<experimental::NoOpCertificateVerifier>();
276   options.set_certificate_verifier(verifier);
277 
278   DoRpc(server_addr_, options, true);
279 }
280 
281 }  // namespace
282 }  // namespace testing
283 }  // namespace grpc
284 
285 #endif  // OPENSSL_VERSION_NUMBER >= 0x10100000
286 
main(int argc,char ** argv)287 int main(int argc, char** argv) {
288   grpc::testing::TestEnvironment env(&argc, argv);
289   ::testing::InitGoogleTest(&argc, argv);
290   int ret = RUN_ALL_TESTS();
291   return ret;
292 }
293