xref: /aosp_15_r20/external/grpc-grpc/test/core/util/tls_utils.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 //
2 // Copyright 2020 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 #include "test/core/util/tls_utils.h"
17 
18 #include <stdio.h>
19 
20 #include "absl/strings/str_cat.h"
21 
22 #include <grpc/slice.h>
23 #include <grpc/support/alloc.h>
24 #include <grpc/support/log.h>
25 #include <grpc/support/string_util.h>
26 #include <grpc/support/time.h>
27 
28 #include "src/core/lib/gpr/tmpfile.h"
29 #include "src/core/lib/gprpp/load_file.h"
30 #include "src/core/lib/iomgr/error.h"
31 #include "src/core/lib/slice/slice_internal.h"
32 #include "test/core/util/test_config.h"
33 
34 namespace grpc_core {
35 
36 namespace testing {
37 
TmpFile(absl::string_view data)38 TmpFile::TmpFile(absl::string_view data) {
39   name_ = CreateTmpFileAndWriteData(data);
40   GPR_ASSERT(!name_.empty());
41 }
42 
~TmpFile()43 TmpFile::~TmpFile() { GPR_ASSERT(remove(name_.c_str()) == 0); }
44 
RewriteFile(absl::string_view data)45 void TmpFile::RewriteFile(absl::string_view data) {
46   // Create a new file containing new data.
47   std::string new_name = CreateTmpFileAndWriteData(data);
48   GPR_ASSERT(!new_name.empty());
49 #ifdef GPR_WINDOWS
50   // Remove the old file.
51   // On Windows rename requires that the new name not exist, whereas
52   // on posix systems rename does an atomic replacement of the new
53   // name.
54   GPR_ASSERT(remove(name_.c_str()) == 0);
55 #endif
56   // Rename the new file to the original name.
57   GPR_ASSERT(rename(new_name.c_str(), name_.c_str()) == 0);
58 }
59 
CreateTmpFileAndWriteData(absl::string_view data)60 std::string TmpFile::CreateTmpFileAndWriteData(absl::string_view data) {
61   char* name = nullptr;
62   FILE* file_descriptor = gpr_tmpfile("test", &name);
63   GPR_ASSERT(fwrite(data.data(), 1, data.size(), file_descriptor) ==
64              data.size());
65   GPR_ASSERT(fclose(file_descriptor) == 0);
66   GPR_ASSERT(file_descriptor != nullptr);
67   GPR_ASSERT(name != nullptr);
68   std::string name_to_return = name;
69   gpr_free(name);
70   return name_to_return;
71 }
72 
MakeCertKeyPairs(absl::string_view private_key,absl::string_view certs)73 PemKeyCertPairList MakeCertKeyPairs(absl::string_view private_key,
74                                     absl::string_view certs) {
75   if (private_key.empty() && certs.empty()) {
76     return {};
77   }
78   return PemKeyCertPairList{PemKeyCertPair(private_key, certs)};
79 }
80 
GetFileContents(const std::string & path)81 std::string GetFileContents(const std::string& path) {
82   auto slice = LoadFile(path, /*add_null_terminator=*/false);
83   if (!slice.ok()) {
84     Crash(absl::StrCat("error loading file ", path, ": ",
85                        slice.status().ToString()));
86   }
87   return std::string(slice->as_string_view());
88 }
89 
Verify(void * user_data,grpc_tls_custom_verification_check_request *,grpc_tls_on_custom_verification_check_done_cb,void *,grpc_status_code * sync_status,char ** sync_error_details)90 int SyncExternalVerifier::Verify(void* user_data,
91                                  grpc_tls_custom_verification_check_request*,
92                                  grpc_tls_on_custom_verification_check_done_cb,
93                                  void*, grpc_status_code* sync_status,
94                                  char** sync_error_details) {
95   auto* self = static_cast<SyncExternalVerifier*>(user_data);
96   if (self->success_) {
97     *sync_status = GRPC_STATUS_OK;
98     return true;  // Synchronous call
99   }
100   *sync_status = GRPC_STATUS_UNAUTHENTICATED;
101   *sync_error_details = gpr_strdup("SyncExternalVerifier failed");
102   return true;  // Synchronous call
103 }
104 
Destruct(void * user_data)105 void SyncExternalVerifier::Destruct(void* user_data) {
106   auto* self = static_cast<SyncExternalVerifier*>(user_data);
107   delete self;
108 }
109 
~AsyncExternalVerifier()110 AsyncExternalVerifier::~AsyncExternalVerifier() {
111   // Tell the thread to shut down.
112   {
113     MutexLock lock(&mu_);
114     queue_.push_back(Request{nullptr, nullptr, nullptr, true});
115   }
116   // Wait for thread to exit.
117   thread_.Join();
118   grpc_shutdown();
119 }
120 
Verify(void * user_data,grpc_tls_custom_verification_check_request * request,grpc_tls_on_custom_verification_check_done_cb callback,void * callback_arg,grpc_status_code *,char **)121 int AsyncExternalVerifier::Verify(
122     void* user_data, grpc_tls_custom_verification_check_request* request,
123     grpc_tls_on_custom_verification_check_done_cb callback, void* callback_arg,
124     grpc_status_code*, char**) {
125   auto* self = static_cast<AsyncExternalVerifier*>(user_data);
126   // Add request to queue to be picked up by worker thread.
127   MutexLock lock(&self->mu_);
128   self->queue_.push_back(Request{request, callback, callback_arg, false});
129   return false;  // Asynchronous call
130 }
131 
132 namespace {
133 
DestroyExternalVerifier(void * arg)134 void DestroyExternalVerifier(void* arg) {
135   auto* verifier = static_cast<AsyncExternalVerifier*>(arg);
136   delete verifier;
137 }
138 
139 }  // namespace
140 
Destruct(void * user_data)141 void AsyncExternalVerifier::Destruct(void* user_data) {
142   auto* self = static_cast<AsyncExternalVerifier*>(user_data);
143   // Spawn a detached thread to destroy the verifier, to make sure that we
144   // don't try to join the worker thread from within the worker thread.
145   Thread destroy_thread("DestroyExternalVerifier", DestroyExternalVerifier,
146                         self, nullptr, Thread::Options().set_joinable(false));
147   destroy_thread.Start();
148 }
149 
WorkerThread(void * arg)150 void AsyncExternalVerifier::WorkerThread(void* arg) {
151   auto* self = static_cast<AsyncExternalVerifier*>(arg);
152   while (true) {
153     // Check queue for work.
154     bool got_request = false;
155     Request request;
156     {
157       MutexLock lock(&self->mu_);
158       if (!self->queue_.empty()) {
159         got_request = true;
160         request = self->queue_.front();
161         self->queue_.pop_front();
162       }
163     }
164     // If nothing found in the queue, sleep for a bit and try again.
165     if (!got_request) {
166       gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(100));
167       continue;
168     }
169     // If we're being told to shut down, return.
170     if (request.shutdown) {
171       return;
172     }
173     // Process the request.
174     if (self->success_) {
175       request.callback(request.request, request.callback_arg, GRPC_STATUS_OK,
176                        "");
177     } else {
178       request.callback(request.request, request.callback_arg,
179                        GRPC_STATUS_UNAUTHENTICATED,
180                        "AsyncExternalVerifier failed");
181     }
182   }
183 }
184 
Verify(void * user_data,grpc_tls_custom_verification_check_request * request,grpc_tls_on_custom_verification_check_done_cb,void *,grpc_status_code * sync_status,char ** sync_error_details)185 int PeerPropertyExternalVerifier::Verify(
186     void* user_data, grpc_tls_custom_verification_check_request* request,
187     grpc_tls_on_custom_verification_check_done_cb, void*,
188     grpc_status_code* sync_status, char** sync_error_details) {
189   auto* self = static_cast<PeerPropertyExternalVerifier*>(user_data);
190   if (request->peer_info.verified_root_cert_subject !=
191       self->expected_verified_root_cert_subject_) {
192     *sync_status = GRPC_STATUS_UNAUTHENTICATED;
193     *sync_error_details = gpr_strdup("PeerPropertyExternalVerifier failed");
194     return true;
195   } else {
196     *sync_status = GRPC_STATUS_OK;
197     return true;  // Synchronous call
198   }
199   return true;  // Synchronous call
200 }
201 
Destruct(void * user_data)202 void PeerPropertyExternalVerifier::Destruct(void* user_data) {
203   auto* self = static_cast<PeerPropertyExternalVerifier*>(user_data);
204   delete self;
205 }
206 
207 }  // namespace testing
208 
209 }  // namespace grpc_core
210