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