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