tls_key_export_test.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  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. #include <memory>
  15. #include <string>
  16. #include <thread> // NOLINT
  17. #include <vector>
  18. #include "absl/strings/str_cat.h"
  19. #include "absl/strings/string_view.h"
  20. #include "gmock/gmock.h"
  21. #include "gtest/gtest.h"
  22. #include <grpc++/grpc++.h>
  23. #include <grpc/grpc.h>
  24. #include <grpc/grpc_security.h>
  25. #include <grpcpp/security/server_credentials.h>
  26. #include <grpcpp/security/tls_credentials_options.h>
  27. #include <grpcpp/support/channel_arguments.h>
  28. #include "src/core/lib/gpr/tmpfile.h"
  29. #include "src/cpp/client/secure_credentials.h"
  30. #include "src/proto/grpc/testing/echo.grpc.pb.h"
  31. #include "test/core/util/test_config.h"
  32. #include "test/core/util/tls_utils.h"
  33. extern "C" {
  34. #include <openssl/ssl.h>
  35. }
  36. #if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER)
  37. #define TLS_KEY_LOGGING_AVAILABLE
  38. #endif
  39. #define CA_CERT_PATH "src/core/tsi/test_creds/ca.pem"
  40. #define SERVER_KEY_PATH "src/core/tsi/test_creds/server0.key"
  41. #define SERVER_CERT_PATH "src/core/tsi/test_creds/server0.pem"
  42. #define CLIENT_KEY_PATH "src/core/tsi/test_creds/client.key"
  43. #define CLIENT_CERT_PATH "src/core/tsi/test_creds/client.pem"
  44. #define NUM_REQUESTS_PER_CHANNEL 5
  45. using ::grpc::experimental::FileWatcherCertificateProvider;
  46. using ::grpc::experimental::TlsChannelCredentialsOptions;
  47. using ::grpc::experimental::TlsServerCredentialsOptions;
  48. namespace grpc {
  49. namespace testing {
  50. namespace {
  51. class EchoServer final : public EchoTestService::Service {
  52. grpc::Status Echo(grpc::ServerContext* /*context*/,
  53. const EchoRequest* request,
  54. EchoResponse* response) override {
  55. if (request->param().expected_error().code() == 0) {
  56. response->set_message(request->message());
  57. return grpc::Status::OK;
  58. } else {
  59. return grpc::Status(static_cast<grpc::StatusCode>(
  60. request->param().expected_error().code()),
  61. "");
  62. }
  63. }
  64. };
  65. class TestScenario {
  66. public:
  67. TestScenario(int num_listening_ports, bool share_tls_key_log_file,
  68. bool enable_tls_key_logging)
  69. : num_listening_ports_(num_listening_ports),
  70. share_tls_key_log_file_(share_tls_key_log_file),
  71. enable_tls_key_logging_(enable_tls_key_logging) {}
  72. std::string AsString() const {
  73. return absl::StrCat("TestScenario__num_listening_ports_",
  74. num_listening_ports_, "__share_tls_key_log_file_",
  75. (share_tls_key_log_file_ ? "true" : "false"),
  76. "__enable_tls_key_logging_",
  77. (enable_tls_key_logging_ ? "true" : "false"));
  78. }
  79. int num_listening_ports() const { return num_listening_ports_; }
  80. bool share_tls_key_log_file() const { return share_tls_key_log_file_; }
  81. bool enable_tls_key_logging() const { return enable_tls_key_logging_; }
  82. private:
  83. int num_listening_ports_;
  84. bool share_tls_key_log_file_;
  85. bool enable_tls_key_logging_;
  86. };
  87. std::string TestScenarioName(
  88. const ::testing::TestParamInfo<TestScenario>& info) {
  89. return info.param.AsString();
  90. }
  91. int CountOccurrencesInFileContents(std::string file_contents,
  92. std::string search_string) {
  93. int occurrences = 0;
  94. std::string::size_type pos = 0;
  95. while ((pos = file_contents.find(search_string, pos)) != std::string::npos) {
  96. ++occurrences;
  97. pos += search_string.length();
  98. }
  99. return occurrences;
  100. }
  101. class TlsKeyLoggingEnd2EndTest : public ::testing::TestWithParam<TestScenario> {
  102. protected:
  103. std::string CreateTmpFile() {
  104. char* name = nullptr;
  105. FILE* file_descriptor = gpr_tmpfile("GrpcTlsKeyLoggerTest", &name);
  106. GPR_ASSERT(fclose(file_descriptor) == 0);
  107. GPR_ASSERT(file_descriptor != nullptr);
  108. GPR_ASSERT(name != nullptr);
  109. std::string name_to_return = name;
  110. gpr_free(name);
  111. return name_to_return;
  112. }
  113. void SetUp() override {
  114. grpc::ServerBuilder builder;
  115. grpc::ChannelArguments args;
  116. args.SetSslTargetNameOverride("foo.test.google.com.au");
  117. if (GetParam().num_listening_ports() > 0) {
  118. ports_.resize(GetParam().num_listening_ports(), 0);
  119. }
  120. std::string shared_key_log_file_server;
  121. std::string shared_key_log_file_channel;
  122. if (GetParam().share_tls_key_log_file()) {
  123. shared_key_log_file_server = CreateTmpFile();
  124. shared_key_log_file_channel = CreateTmpFile();
  125. }
  126. auto server_certificate_provider =
  127. std::make_shared<FileWatcherCertificateProvider>(
  128. SERVER_KEY_PATH, SERVER_CERT_PATH, CA_CERT_PATH, 1);
  129. auto channel_certificate_provider =
  130. std::make_shared<FileWatcherCertificateProvider>(
  131. CLIENT_KEY_PATH, CLIENT_CERT_PATH, CA_CERT_PATH, 1);
  132. for (int i = 0; i < GetParam().num_listening_ports(); i++) {
  133. // Configure tls credential options for each port
  134. TlsServerCredentialsOptions server_creds_options(
  135. server_certificate_provider);
  136. server_creds_options.set_cert_request_type(
  137. GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
  138. server_creds_options.watch_identity_key_cert_pairs();
  139. server_creds_options.watch_root_certs();
  140. // Set a separate ssl key log file for each port if not shared
  141. if (GetParam().share_tls_key_log_file()) {
  142. tmp_server_tls_key_log_file_by_port_.push_back(
  143. shared_key_log_file_server);
  144. } else {
  145. tmp_server_tls_key_log_file_by_port_.push_back(CreateTmpFile());
  146. }
  147. if (GetParam().enable_tls_key_logging()) {
  148. server_creds_options.set_tls_session_key_log_file_path(
  149. tmp_server_tls_key_log_file_by_port_[i]);
  150. }
  151. builder.AddListeningPort(
  152. "0.0.0.0:0",
  153. grpc::experimental::TlsServerCredentials(server_creds_options),
  154. &ports_[i]);
  155. }
  156. builder.RegisterService(&service_);
  157. server_ = builder.BuildAndStart();
  158. ASSERT_NE(nullptr, server_);
  159. server_thread_ =
  160. std::thread(&TlsKeyLoggingEnd2EndTest::RunServerLoop, this);
  161. for (int i = 0; i < GetParam().num_listening_ports(); i++) {
  162. ASSERT_NE(0, ports_[i]);
  163. server_addresses_.push_back(absl::StrCat("localhost:", ports_[i]));
  164. // Configure tls credential options for each stub. Each stub connects to
  165. // a separate port on the server.
  166. TlsChannelCredentialsOptions channel_creds_options;
  167. channel_creds_options.set_certificate_provider(
  168. channel_certificate_provider);
  169. channel_creds_options.watch_identity_key_cert_pairs();
  170. channel_creds_options.watch_root_certs();
  171. // Set a separate ssl key log file for each port if not shared.
  172. if (GetParam().share_tls_key_log_file()) {
  173. tmp_stub_tls_key_log_file_.push_back(shared_key_log_file_channel);
  174. } else {
  175. tmp_stub_tls_key_log_file_.push_back(CreateTmpFile());
  176. }
  177. if (GetParam().enable_tls_key_logging()) {
  178. channel_creds_options.set_tls_session_key_log_file_path(
  179. tmp_stub_tls_key_log_file_[i]);
  180. }
  181. stubs_.push_back(EchoTestService::NewStub(grpc::CreateCustomChannel(
  182. server_addresses_[i],
  183. grpc::experimental::TlsCredentials(channel_creds_options), args)));
  184. }
  185. }
  186. void TearDown() override {
  187. server_->Shutdown();
  188. server_thread_.join();
  189. // Remove all created files.
  190. for (int i = 0; i < GetParam().num_listening_ports(); i++) {
  191. remove(tmp_stub_tls_key_log_file_[i].c_str());
  192. remove(tmp_server_tls_key_log_file_by_port_[i].c_str());
  193. if (GetParam().share_tls_key_log_file()) {
  194. break;
  195. }
  196. }
  197. }
  198. void RunServerLoop() { server_->Wait(); }
  199. const std::string client_method_name_ = "grpc.testing.EchoTestService/Echo";
  200. const std::string server_method_name_ = "grpc.testing.EchoTestService/Echo";
  201. std::vector<int> ports_;
  202. std::vector<std::string> tmp_server_tls_key_log_file_by_port_;
  203. std::vector<std::string> tmp_stub_tls_key_log_file_;
  204. std::vector<std::string> server_addresses_;
  205. std::vector<std::unique_ptr<EchoTestService::Stub>> stubs_;
  206. EchoServer service_;
  207. std::unique_ptr<grpc::Server> server_;
  208. std::thread server_thread_;
  209. };
  210. TEST_P(TlsKeyLoggingEnd2EndTest, KeyLogging) {
  211. // Cover all valid statuses.
  212. for (int i = 0; i <= NUM_REQUESTS_PER_CHANNEL; ++i) {
  213. for (int j = 0; j < GetParam().num_listening_ports(); ++j) {
  214. EchoRequest request;
  215. request.set_message("foo");
  216. request.mutable_param()->mutable_expected_error()->set_code(0);
  217. EchoResponse response;
  218. grpc::ClientContext context;
  219. grpc::Status status = stubs_[j]->Echo(&context, request, &response);
  220. EXPECT_TRUE(status.ok());
  221. }
  222. }
  223. for (int i = 0; i < GetParam().num_listening_ports(); i++) {
  224. std::string server_key_log = grpc_core::testing::GetFileContents(
  225. tmp_server_tls_key_log_file_by_port_[i].c_str());
  226. std::string channel_key_log = grpc_core::testing::GetFileContents(
  227. tmp_stub_tls_key_log_file_[i].c_str());
  228. if (!GetParam().enable_tls_key_logging()) {
  229. EXPECT_THAT(server_key_log, ::testing::IsEmpty());
  230. EXPECT_THAT(channel_key_log, ::testing::IsEmpty());
  231. }
  232. #ifdef TLS_KEY_LOGGING_AVAILABLE
  233. EXPECT_THAT(server_key_log, ::testing::StrEq(channel_key_log));
  234. if (GetParam().share_tls_key_log_file() &&
  235. GetParam().enable_tls_key_logging()) {
  236. EXPECT_EQ(CountOccurrencesInFileContents(
  237. server_key_log, "CLIENT_HANDSHAKE_TRAFFIC_SECRET"),
  238. GetParam().num_listening_ports());
  239. EXPECT_EQ(CountOccurrencesInFileContents(
  240. server_key_log, "SERVER_HANDSHAKE_TRAFFIC_SECRET"),
  241. GetParam().num_listening_ports());
  242. EXPECT_EQ(CountOccurrencesInFileContents(server_key_log,
  243. "CLIENT_TRAFFIC_SECRET_0"),
  244. GetParam().num_listening_ports());
  245. EXPECT_EQ(CountOccurrencesInFileContents(server_key_log,
  246. "SERVER_TRAFFIC_SECRET_0"),
  247. GetParam().num_listening_ports());
  248. EXPECT_EQ(
  249. CountOccurrencesInFileContents(server_key_log, "EXPORTER_SECRET"),
  250. GetParam().num_listening_ports());
  251. } else if (GetParam().enable_tls_key_logging()) {
  252. EXPECT_EQ(CountOccurrencesInFileContents(
  253. server_key_log, "CLIENT_HANDSHAKE_TRAFFIC_SECRET"),
  254. 1);
  255. EXPECT_EQ(CountOccurrencesInFileContents(
  256. server_key_log, "SERVER_HANDSHAKE_TRAFFIC_SECRET"),
  257. 1);
  258. EXPECT_EQ(CountOccurrencesInFileContents(server_key_log,
  259. "CLIENT_TRAFFIC_SECRET_0"),
  260. 1);
  261. EXPECT_EQ(CountOccurrencesInFileContents(server_key_log,
  262. "SERVER_TRAFFIC_SECRET_0"),
  263. 1);
  264. EXPECT_EQ(
  265. CountOccurrencesInFileContents(server_key_log, "EXPORTER_SECRET"), 1);
  266. }
  267. #else
  268. // If TLS Key logging is not available, the files should be empty.
  269. if (GetParam().enable_tls_key_logging()) {
  270. EXPECT_THAT(server_key_log, ::testing::IsEmpty());
  271. EXPECT_THAT(channel_key_log, ::testing::IsEmpty());
  272. }
  273. #endif
  274. if (GetParam().share_tls_key_log_file()) {
  275. break;
  276. }
  277. }
  278. }
  279. INSTANTIATE_TEST_SUITE_P(TlsKeyLogging, TlsKeyLoggingEnd2EndTest,
  280. ::testing::ValuesIn({TestScenario(5, false, true),
  281. TestScenario(5, true, true),
  282. TestScenario(5, true, false),
  283. TestScenario(5, false, false)}),
  284. &TestScenarioName);
  285. } // namespace
  286. } // namespace testing
  287. } // namespace grpc
  288. int main(int argc, char** argv) {
  289. ::testing::InitGoogleTest(&argc, argv);
  290. grpc::testing::TestEnvironment env(argc, argv);
  291. return RUN_ALL_TESTS();
  292. }