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(¬ification, 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(¬ification, 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(¬ification, 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