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