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