tls_key_export_test.cc
Go to the documentation of this file.
1 // Copyright 2021 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <memory>
16 #include <string>
17 #include <thread> // NOLINT
18 #include <vector>
19 
20 #include "absl/strings/str_cat.h"
21 #include "absl/strings/string_view.h"
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 
25 #include <grpc++/grpc++.h>
26 #include <grpc/grpc.h>
27 #include <grpc/grpc_security.h>
31 
34 #include "src/proto/grpc/testing/echo.grpc.pb.h"
37 
38 extern "C" {
39 #include <openssl/ssl.h>
40 }
41 
42 #if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER)
43 #define TLS_KEY_LOGGING_AVAILABLE
44 #endif
45 
46 #define CA_CERT_PATH "src/core/tsi/test_creds/ca.pem"
47 #define SERVER_KEY_PATH "src/core/tsi/test_creds/server0.key"
48 #define SERVER_CERT_PATH "src/core/tsi/test_creds/server0.pem"
49 #define CLIENT_KEY_PATH "src/core/tsi/test_creds/client.key"
50 #define CLIENT_CERT_PATH "src/core/tsi/test_creds/client.pem"
51 
52 #define NUM_REQUESTS_PER_CHANNEL 5
53 
54 using ::grpc::experimental::FileWatcherCertificateProvider;
55 using ::grpc::experimental::TlsChannelCredentialsOptions;
56 using ::grpc::experimental::TlsServerCredentialsOptions;
57 
58 namespace grpc {
59 namespace testing {
60 namespace {
61 
62 class EchoServer final : public EchoTestService::Service {
63  grpc::Status Echo(grpc::ServerContext* /*context*/,
64  const EchoRequest* request,
65  EchoResponse* response) override {
66  if (request->param().expected_error().code() == 0) {
67  response->set_message(request->message());
68  return grpc::Status::OK;
69  } else {
70  return grpc::Status(static_cast<grpc::StatusCode>(
71  request->param().expected_error().code()),
72  "");
73  }
74  }
75 };
76 
77 class TestScenario {
78  public:
79  TestScenario(int num_listening_ports, bool share_tls_key_log_file,
80  bool enable_tls_key_logging)
81  : num_listening_ports_(num_listening_ports),
82  share_tls_key_log_file_(share_tls_key_log_file),
83  enable_tls_key_logging_(enable_tls_key_logging) {}
84  std::string AsString() const {
85  return absl::StrCat("TestScenario__num_listening_ports_",
86  num_listening_ports_, "__share_tls_key_log_file_",
87  (share_tls_key_log_file_ ? "true" : "false"),
88  "__enable_tls_key_logging_",
89  (enable_tls_key_logging_ ? "true" : "false"));
90  }
91 
92  int num_listening_ports() const { return num_listening_ports_; }
93 
94  bool share_tls_key_log_file() const { return share_tls_key_log_file_; }
95 
96  bool enable_tls_key_logging() const { return enable_tls_key_logging_; }
97 
98  private:
102 };
103 
104 std::string TestScenarioName(
105  const ::testing::TestParamInfo<TestScenario>& info) {
106  return info.param.AsString();
107 }
108 
109 int CountOccurrencesInFileContents(std::string file_contents,
110  std::string search_string) {
111  int occurrences = 0;
112  std::string::size_type pos = 0;
113  while ((pos = file_contents.find(search_string, pos)) != std::string::npos) {
114  ++occurrences;
115  pos += search_string.length();
116  }
117  return occurrences;
118 }
119 
120 class TlsKeyLoggingEnd2EndTest : public ::testing::TestWithParam<TestScenario> {
121  protected:
122  std::string CreateTmpFile() {
123  char* name = nullptr;
124  FILE* file_descriptor = gpr_tmpfile("GrpcTlsKeyLoggerTest", &name);
125  GPR_ASSERT(fclose(file_descriptor) == 0);
126  GPR_ASSERT(file_descriptor != nullptr);
127  GPR_ASSERT(name != nullptr);
128  std::string name_to_return = name;
129  gpr_free(name);
130  return name_to_return;
131  }
132 
133  void SetUp() override {
136  args.SetSslTargetNameOverride("foo.test.google.com.au");
137 
138  if (GetParam().num_listening_ports() > 0) {
139  ports_.resize(GetParam().num_listening_ports(), 0);
140  }
141 
142  std::string shared_key_log_file_server;
143  std::string shared_key_log_file_channel;
144 
145  if (GetParam().share_tls_key_log_file()) {
146  shared_key_log_file_server = CreateTmpFile();
147  shared_key_log_file_channel = CreateTmpFile();
148  }
149 
150  auto server_certificate_provider =
151  std::make_shared<FileWatcherCertificateProvider>(
153 
154  auto channel_certificate_provider =
155  std::make_shared<FileWatcherCertificateProvider>(
157 
158  for (int i = 0; i < GetParam().num_listening_ports(); i++) {
159  // Configure tls credential options for each port
160  TlsServerCredentialsOptions server_creds_options(
161  server_certificate_provider);
162  server_creds_options.set_cert_request_type(
164  server_creds_options.watch_identity_key_cert_pairs();
165  server_creds_options.watch_root_certs();
166 
167  // Set a separate ssl key log file for each port if not shared
168  if (GetParam().share_tls_key_log_file()) {
170  shared_key_log_file_server);
171  } else {
172  tmp_server_tls_key_log_file_by_port_.push_back(CreateTmpFile());
173  }
174 
175  if (GetParam().enable_tls_key_logging()) {
176  server_creds_options.set_tls_session_key_log_file_path(
178  }
179 
180  builder.AddListeningPort(
181  "0.0.0.0:0",
182  grpc::experimental::TlsServerCredentials(server_creds_options),
183  &ports_[i]);
184  }
185 
186  builder.RegisterService(&service_);
187  server_ = builder.BuildAndStart();
188  ASSERT_NE(nullptr, server_);
190  std::thread(&TlsKeyLoggingEnd2EndTest::RunServerLoop, this);
191 
192  for (int i = 0; i < GetParam().num_listening_ports(); i++) {
193  ASSERT_NE(0, ports_[i]);
194  server_addresses_.push_back(absl::StrCat("localhost:", ports_[i]));
195 
196  // Configure tls credential options for each stub. Each stub connects to
197  // a separate port on the server.
198  TlsChannelCredentialsOptions channel_creds_options;
199  channel_creds_options.set_certificate_provider(
200  channel_certificate_provider);
201  channel_creds_options.watch_identity_key_cert_pairs();
202  channel_creds_options.watch_root_certs();
203 
204  // Set a separate ssl key log file for each port if not shared.
205  if (GetParam().share_tls_key_log_file()) {
206  tmp_stub_tls_key_log_file_.push_back(shared_key_log_file_channel);
207  } else {
208  tmp_stub_tls_key_log_file_.push_back(CreateTmpFile());
209  }
210 
211  if (GetParam().enable_tls_key_logging()) {
212  channel_creds_options.set_tls_session_key_log_file_path(
214  }
215 
216  stubs_.push_back(EchoTestService::NewStub(grpc::CreateCustomChannel(
218  grpc::experimental::TlsCredentials(channel_creds_options), args)));
219  }
220  }
221 
222  void TearDown() override {
223  server_->Shutdown();
224  server_thread_.join();
225 
226  // Remove all created files.
227  for (int i = 0; i < GetParam().num_listening_ports(); i++) {
228  remove(tmp_stub_tls_key_log_file_[i].c_str());
230  if (GetParam().share_tls_key_log_file()) {
231  break;
232  }
233  }
234  }
235 
236  void RunServerLoop() { server_->Wait(); }
237 
238  const std::string client_method_name_ = "grpc.testing.EchoTestService/Echo";
239  const std::string server_method_name_ = "grpc.testing.EchoTestService/Echo";
240 
241  std::vector<int> ports_;
242  std::vector<std::string> tmp_server_tls_key_log_file_by_port_;
243  std::vector<std::string> tmp_stub_tls_key_log_file_;
244  std::vector<std::string> server_addresses_;
245  std::vector<std::unique_ptr<EchoTestService::Stub>> stubs_;
247  std::unique_ptr<grpc::Server> server_;
249 };
250 
251 TEST_P(TlsKeyLoggingEnd2EndTest, KeyLogging) {
252  // Cover all valid statuses.
253  for (int i = 0; i <= NUM_REQUESTS_PER_CHANNEL; ++i) {
254  for (int j = 0; j < GetParam().num_listening_ports(); ++j) {
255  EchoRequest request;
256  request.set_message("foo");
257  request.mutable_param()->mutable_expected_error()->set_code(0);
258  EchoResponse response;
261  EXPECT_TRUE(status.ok());
262  }
263  }
264 
265  for (int i = 0; i < GetParam().num_listening_ports(); i++) {
270 
271  if (!GetParam().enable_tls_key_logging()) {
272  EXPECT_THAT(server_key_log, ::testing::IsEmpty());
273  EXPECT_THAT(channel_key_log, ::testing::IsEmpty());
274  }
275 
276 #ifdef TLS_KEY_LOGGING_AVAILABLE
277  EXPECT_THAT(server_key_log, ::testing::StrEq(channel_key_log));
278 
279  if (GetParam().share_tls_key_log_file() &&
280  GetParam().enable_tls_key_logging()) {
281  EXPECT_EQ(CountOccurrencesInFileContents(
282  server_key_log, "CLIENT_HANDSHAKE_TRAFFIC_SECRET"),
283  GetParam().num_listening_ports());
284  EXPECT_EQ(CountOccurrencesInFileContents(
285  server_key_log, "SERVER_HANDSHAKE_TRAFFIC_SECRET"),
286  GetParam().num_listening_ports());
287  EXPECT_EQ(CountOccurrencesInFileContents(server_key_log,
288  "CLIENT_TRAFFIC_SECRET_0"),
289  GetParam().num_listening_ports());
290  EXPECT_EQ(CountOccurrencesInFileContents(server_key_log,
291  "SERVER_TRAFFIC_SECRET_0"),
292  GetParam().num_listening_ports());
293  EXPECT_EQ(
294  CountOccurrencesInFileContents(server_key_log, "EXPORTER_SECRET"),
295  GetParam().num_listening_ports());
296  } else if (GetParam().enable_tls_key_logging()) {
297  EXPECT_EQ(CountOccurrencesInFileContents(
298  server_key_log, "CLIENT_HANDSHAKE_TRAFFIC_SECRET"),
299  1);
300  EXPECT_EQ(CountOccurrencesInFileContents(
301  server_key_log, "SERVER_HANDSHAKE_TRAFFIC_SECRET"),
302  1);
303  EXPECT_EQ(CountOccurrencesInFileContents(server_key_log,
304  "CLIENT_TRAFFIC_SECRET_0"),
305  1);
306  EXPECT_EQ(CountOccurrencesInFileContents(server_key_log,
307  "SERVER_TRAFFIC_SECRET_0"),
308  1);
309  EXPECT_EQ(
310  CountOccurrencesInFileContents(server_key_log, "EXPORTER_SECRET"), 1);
311  }
312 #else
313  // If TLS Key logging is not available, the files should be empty.
314  if (GetParam().enable_tls_key_logging()) {
315  EXPECT_THAT(server_key_log, ::testing::IsEmpty());
316  EXPECT_THAT(channel_key_log, ::testing::IsEmpty());
317  }
318 #endif
319 
320  if (GetParam().share_tls_key_log_file()) {
321  break;
322  }
323  }
324 }
325 
326 INSTANTIATE_TEST_SUITE_P(TlsKeyLogging, TlsKeyLoggingEnd2EndTest,
327  ::testing::ValuesIn({TestScenario(5, false, true),
328  TestScenario(5, true, true),
329  TestScenario(5, true, false),
330  TestScenario(5, false, false)}),
331  &TestScenarioName);
332 
333 } // namespace
334 } // namespace testing
335 } // namespace grpc
336 
337 int main(int argc, char** argv) {
338  ::testing::InitGoogleTest(&argc, argv);
339  grpc::testing::TestEnvironment env(&argc, argv);
340  return RUN_ALL_TESTS();
341 }
share_tls_key_log_file_
bool share_tls_key_log_file_
Definition: tls_key_export_test.cc:100
grpc::EXPECT_THAT
EXPECT_THAT(status.error_message(), ::testing::HasSubstr("subject_token_type"))
testing
Definition: aws_request_signer_test.cc:25
tls_credentials_options.h
grpc::status
auto status
Definition: cpp/client/credentials_test.cc:200
client_method_name_
const std::string client_method_name_
Definition: tls_key_export_test.cc:238
grpc::ServerContext
Definition: grpcpp/impl/codegen/server_context.h:566
CA_CERT_PATH
#define CA_CERT_PATH
Definition: tls_key_export_test.cc:46
absl::str_format_internal::LengthMod::j
@ j
pos
int pos
Definition: libuv/docs/code/tty-gravity/main.c:11
tls_utils.h
generate.env
env
Definition: generate.py:37
absl::StrCat
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: abseil-cpp/absl/strings/str_cat.cc:98
grpc::gpr_free
gpr_free(creds_file_name)
grpc
Definition: grpcpp/alarm.h:33
server_
std::unique_ptr< grpc::Server > server_
Definition: tls_key_export_test.cc:247
server_thread_
std::thread server_thread_
Definition: tls_key_export_test.cc:248
benchmark.request
request
Definition: benchmark.py:77
stubs_
std::vector< std::unique_ptr< EchoTestService::Stub > > stubs_
Definition: tls_key_export_test.cc:245
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
secure_credentials.h
main
int main(int argc, char **argv)
Definition: tls_key_export_test.cc:337
gpr_tmpfile
FILE * gpr_tmpfile(const char *prefix, char **tmp_filename)
setup.name
name
Definition: setup.py:542
grpc_security.h
service_
EchoServer service_
Definition: tls_key_export_test.cc:246
testing::TestWithParam
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1883
SERVER_CERT_PATH
#define SERVER_CERT_PATH
Definition: tls_key_export_test.cc:48
profile_analyzer.builder
builder
Definition: profile_analyzer.py:159
asyncio_get_stats.args
args
Definition: asyncio_get_stats.py:40
GPR_ASSERT
#define GPR_ASSERT(x)
Definition: include/grpc/impl/codegen/log.h:94
channel_arguments.h
gen_stats_data.c_str
def c_str(s, encoding='ascii')
Definition: gen_stats_data.py:38
grpc.StatusCode
Definition: src/python/grpcio/grpc/__init__.py:232
grpc::ServerBuilder
A builder class for the creation and startup of grpc::Server instances.
Definition: grpcpp/server_builder.h:86
grpc::experimental::TlsServerCredentials
std::shared_ptr< ServerCredentials > TlsServerCredentials(const experimental::TlsServerCredentialsOptions &options)
Builds TLS ServerCredentials given TLS options.
Definition: secure_server_credentials.cc:153
ports_
std::vector< int > ports_
Definition: tls_key_export_test.cc:241
grpc.h
enable_tls_key_logging_
bool enable_tls_key_logging_
Definition: tls_key_export_test.cc:101
tmpfile.h
EchoServer
Definition: bm_opencensus_plugin.cc:41
grpc::testing::INSTANTIATE_TEST_SUITE_P
INSTANTIATE_TEST_SUITE_P(HistogramTestCases, HistogramTest, ::testing::Range< int >(0, GRPC_STATS_HISTOGRAM_COUNT))
grpc::Status::OK
static const Status & OK
An OK pre-defined instance.
Definition: include/grpcpp/impl/codegen/status.h:113
grpc++.h
RUN_ALL_TESTS
int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2471
grpc::ASSERT_NE
ASSERT_NE(creds_file_name, nullptr)
CLIENT_KEY_PATH
#define CLIENT_KEY_PATH
Definition: tls_key_export_test.cc:49
server_credentials.h
ssl.h
grpc::ClientContext
Definition: grpcpp/impl/codegen/client_context.h:195
test_config.h
grpc::ChannelArguments
Definition: grpcpp/support/channel_arguments.h:39
testing::InitGoogleTest
GTEST_API_ void InitGoogleTest(int *argc, char **argv)
Definition: bloaty/third_party/googletest/googletest/src/gtest.cc:6106
grpc::experimental::TlsCredentials
std::shared_ptr< ChannelCredentials > TlsCredentials(const TlsChannelCredentialsOptions &options)
Builds TLS Credentials given TLS options.
Definition: secure_credentials.cc:316
benchmark.FILE
FILE
Definition: benchmark.py:21
grpc::fclose
fclose(creds_file)
absl::container_internal::IsEmpty
bool IsEmpty(ctrl_t c)
Definition: abseil-cpp/absl/container/internal/raw_hash_set.h:489
tmp_server_tls_key_log_file_by_port_
std::vector< std::string > tmp_server_tls_key_log_file_by_port_
Definition: tls_key_export_test.cc:242
tmp_stub_tls_key_log_file_
std::vector< std::string > tmp_stub_tls_key_log_file_
Definition: tls_key_export_test.cc:243
asyncio_get_stats.response
response
Definition: asyncio_get_stats.py:28
grpc::testing::TestEnvironment
Definition: test/core/util/test_config.h:54
grpc::CreateCustomChannel
std::shared_ptr< Channel > CreateCustomChannel(const grpc::string &target, const std::shared_ptr< ChannelCredentials > &creds, const ChannelArguments &args)
server_addresses_
std::vector< std::string > server_addresses_
Definition: tls_key_export_test.cc:244
grpc::protobuf::util::Status
GRPC_CUSTOM_UTIL_STATUS Status
Definition: include/grpcpp/impl/codegen/config_protobuf.h:93
NUM_REQUESTS_PER_CHANNEL
#define NUM_REQUESTS_PER_CHANNEL
Definition: tls_key_export_test.cc:52
grpc::Status
Definition: include/grpcpp/impl/codegen/status.h:35
grpc::testing::EXPECT_EQ
EXPECT_EQ(options.token_exchange_service_uri, "https://foo/exchange")
context
grpc::ClientContext context
Definition: istio_echo_server_lib.cc:61
grpc::testing::TEST_P
TEST_P(HistogramTest, IncHistogram)
Definition: stats_test.cc:87
testing::StrEq
PolymorphicMatcher< internal::StrEqualityMatcher< internal::string > > StrEq(const internal::string &str)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8774
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
@ GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
Definition: grpc_security_constants.h:125
grpc::testing::EXPECT_TRUE
EXPECT_TRUE(grpc::experimental::StsCredentialsOptionsFromJson(minimum_valid_json, &options) .ok())
testing::ValuesIn
internal::ParamGenerator< typename std::iterator_traits< ForwardIterator >::value_type > ValuesIn(ForwardIterator begin, ForwardIterator end)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest-param-test.h:297
grpc_core::testing::GetFileContents
std::string GetFileContents(const char *path)
Definition: test/core/util/tls_utils.cc:68
CLIENT_CERT_PATH
#define CLIENT_CERT_PATH
Definition: tls_key_export_test.cc:50
thread
static uv_thread_t thread
Definition: test-async-null-cb.c:29
num_listening_ports_
int num_listening_ports_
Definition: tls_key_export_test.cc:99
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
server_method_name_
const std::string server_method_name_
Definition: tls_key_export_test.cc:239
SERVER_KEY_PATH
#define SERVER_KEY_PATH
Definition: tls_key_export_test.cc:47


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:39