1 //
2 // Copyright 2021 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
17 #include <stddef.h>
18
19 #include <algorithm>
20 #include <functional>
21 #include <map>
22 #include <utility>
23 #include <vector>
24
25 #include <grpc/grpc_security.h>
26 #include <grpc/status.h>
27 #include <grpc/support/alloc.h>
28 #include <grpc/support/log.h>
29 #include <grpc/support/string_util.h>
30 #include <grpcpp/impl/sync.h>
31 #include <grpcpp/security/tls_certificate_verifier.h>
32 #include <grpcpp/support/status.h>
33 #include <grpcpp/support/string_ref.h>
34
35 namespace grpc {
36 namespace experimental {
37
TlsCustomVerificationCheckRequest(grpc_tls_custom_verification_check_request * request)38 TlsCustomVerificationCheckRequest::TlsCustomVerificationCheckRequest(
39 grpc_tls_custom_verification_check_request* request)
40 : c_request_(request) {
41 GPR_ASSERT(c_request_ != nullptr);
42 }
43
target_name() const44 grpc::string_ref TlsCustomVerificationCheckRequest::target_name() const {
45 return c_request_->target_name != nullptr ? c_request_->target_name : "";
46 }
47
peer_cert() const48 grpc::string_ref TlsCustomVerificationCheckRequest::peer_cert() const {
49 return c_request_->peer_info.peer_cert != nullptr
50 ? c_request_->peer_info.peer_cert
51 : "";
52 }
53
peer_cert_full_chain() const54 grpc::string_ref TlsCustomVerificationCheckRequest::peer_cert_full_chain()
55 const {
56 return c_request_->peer_info.peer_cert_full_chain != nullptr
57 ? c_request_->peer_info.peer_cert_full_chain
58 : "";
59 }
60
common_name() const61 grpc::string_ref TlsCustomVerificationCheckRequest::common_name() const {
62 return c_request_->peer_info.common_name != nullptr
63 ? c_request_->peer_info.common_name
64 : "";
65 }
66
verified_root_cert_subject() const67 grpc::string_ref TlsCustomVerificationCheckRequest::verified_root_cert_subject()
68 const {
69 return c_request_->peer_info.verified_root_cert_subject != nullptr
70 ? c_request_->peer_info.verified_root_cert_subject
71 : "";
72 }
73
uri_names() const74 std::vector<grpc::string_ref> TlsCustomVerificationCheckRequest::uri_names()
75 const {
76 std::vector<grpc::string_ref> uri_names;
77 for (size_t i = 0; i < c_request_->peer_info.san_names.uri_names_size; ++i) {
78 uri_names.emplace_back(c_request_->peer_info.san_names.uri_names[i]);
79 }
80 return uri_names;
81 }
82
dns_names() const83 std::vector<grpc::string_ref> TlsCustomVerificationCheckRequest::dns_names()
84 const {
85 std::vector<grpc::string_ref> dns_names;
86 for (size_t i = 0; i < c_request_->peer_info.san_names.dns_names_size; ++i) {
87 dns_names.emplace_back(c_request_->peer_info.san_names.dns_names[i]);
88 }
89 return dns_names;
90 }
91
email_names() const92 std::vector<grpc::string_ref> TlsCustomVerificationCheckRequest::email_names()
93 const {
94 std::vector<grpc::string_ref> email_names;
95 for (size_t i = 0; i < c_request_->peer_info.san_names.email_names_size;
96 ++i) {
97 email_names.emplace_back(c_request_->peer_info.san_names.email_names[i]);
98 }
99 return email_names;
100 }
101
ip_names() const102 std::vector<grpc::string_ref> TlsCustomVerificationCheckRequest::ip_names()
103 const {
104 std::vector<grpc::string_ref> ip_names;
105 for (size_t i = 0; i < c_request_->peer_info.san_names.ip_names_size; ++i) {
106 ip_names.emplace_back(c_request_->peer_info.san_names.ip_names[i]);
107 }
108 return ip_names;
109 }
110
CertificateVerifier(grpc_tls_certificate_verifier * v)111 CertificateVerifier::CertificateVerifier(grpc_tls_certificate_verifier* v)
112 : verifier_(v) {}
113
~CertificateVerifier()114 CertificateVerifier::~CertificateVerifier() {
115 grpc_tls_certificate_verifier_release(verifier_);
116 }
117
Verify(TlsCustomVerificationCheckRequest * request,std::function<void (grpc::Status)> callback,grpc::Status * sync_status)118 bool CertificateVerifier::Verify(TlsCustomVerificationCheckRequest* request,
119 std::function<void(grpc::Status)> callback,
120 grpc::Status* sync_status) {
121 GPR_ASSERT(request != nullptr);
122 GPR_ASSERT(request->c_request() != nullptr);
123 {
124 internal::MutexLock lock(&mu_);
125 request_map_.emplace(request->c_request(), std::move(callback));
126 }
127 grpc_status_code status_code = GRPC_STATUS_OK;
128 char* error_details = nullptr;
129 bool is_done = grpc_tls_certificate_verifier_verify(
130 verifier_, request->c_request(), &AsyncCheckDone, this, &status_code,
131 &error_details);
132 if (is_done) {
133 if (status_code != GRPC_STATUS_OK) {
134 *sync_status = grpc::Status(static_cast<grpc::StatusCode>(status_code),
135 error_details);
136 }
137 internal::MutexLock lock(&mu_);
138 request_map_.erase(request->c_request());
139 }
140 gpr_free(error_details);
141 return is_done;
142 }
143
Cancel(TlsCustomVerificationCheckRequest * request)144 void CertificateVerifier::Cancel(TlsCustomVerificationCheckRequest* request) {
145 GPR_ASSERT(request != nullptr);
146 GPR_ASSERT(request->c_request() != nullptr);
147 grpc_tls_certificate_verifier_cancel(verifier_, request->c_request());
148 }
149
AsyncCheckDone(grpc_tls_custom_verification_check_request * request,void * callback_arg,grpc_status_code status,const char * error_details)150 void CertificateVerifier::AsyncCheckDone(
151 grpc_tls_custom_verification_check_request* request, void* callback_arg,
152 grpc_status_code status, const char* error_details) {
153 auto* self = static_cast<CertificateVerifier*>(callback_arg);
154 std::function<void(grpc::Status)> callback;
155 {
156 internal::MutexLock lock(&self->mu_);
157 auto it = self->request_map_.find(request);
158 if (it != self->request_map_.end()) {
159 callback = std::move(it->second);
160 self->request_map_.erase(it);
161 }
162 }
163 if (callback != nullptr) {
164 grpc::Status return_status;
165 if (status != GRPC_STATUS_OK) {
166 return_status =
167 grpc::Status(static_cast<grpc::StatusCode>(status), error_details);
168 }
169 callback(return_status);
170 }
171 }
172
ExternalCertificateVerifier()173 ExternalCertificateVerifier::ExternalCertificateVerifier() {
174 base_ = new grpc_tls_certificate_verifier_external();
175 base_->user_data = this;
176 base_->verify = VerifyInCoreExternalVerifier;
177 base_->cancel = CancelInCoreExternalVerifier;
178 base_->destruct = DestructInCoreExternalVerifier;
179 }
180
~ExternalCertificateVerifier()181 ExternalCertificateVerifier::~ExternalCertificateVerifier() { delete base_; }
182
VerifyInCoreExternalVerifier(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 * sync_status,char ** sync_error_details)183 int ExternalCertificateVerifier::VerifyInCoreExternalVerifier(
184 void* user_data, grpc_tls_custom_verification_check_request* request,
185 grpc_tls_on_custom_verification_check_done_cb callback, void* callback_arg,
186 grpc_status_code* sync_status, char** sync_error_details) {
187 auto* self = static_cast<ExternalCertificateVerifier*>(user_data);
188 TlsCustomVerificationCheckRequest* cpp_request = nullptr;
189 {
190 internal::MutexLock lock(&self->mu_);
191 auto pair = self->request_map_.emplace(
192 request, AsyncRequestState(callback, callback_arg, request));
193 GPR_ASSERT(pair.second);
194 cpp_request = &pair.first->second.cpp_request;
195 }
196 grpc::Status sync_current_verifier_status;
197 bool is_done = self->Verify(
198 cpp_request,
199 [self, request](grpc::Status status) {
200 grpc_tls_on_custom_verification_check_done_cb callback = nullptr;
201 void* callback_arg = nullptr;
202 {
203 internal::MutexLock lock(&self->mu_);
204 auto it = self->request_map_.find(request);
205 if (it != self->request_map_.end()) {
206 callback = it->second.callback;
207 callback_arg = it->second.callback_arg;
208 self->request_map_.erase(it);
209 }
210 }
211 if (callback != nullptr) {
212 callback(request, callback_arg,
213 static_cast<grpc_status_code>(status.error_code()),
214 status.error_message().c_str());
215 }
216 },
217 &sync_current_verifier_status);
218 if (is_done) {
219 if (!sync_current_verifier_status.ok()) {
220 *sync_status = static_cast<grpc_status_code>(
221 sync_current_verifier_status.error_code());
222 *sync_error_details =
223 gpr_strdup(sync_current_verifier_status.error_message().c_str());
224 }
225 internal::MutexLock lock(&self->mu_);
226 self->request_map_.erase(request);
227 }
228 return is_done;
229 }
230
CancelInCoreExternalVerifier(void * user_data,grpc_tls_custom_verification_check_request * request)231 void ExternalCertificateVerifier::CancelInCoreExternalVerifier(
232 void* user_data, grpc_tls_custom_verification_check_request* request) {
233 auto* self = static_cast<ExternalCertificateVerifier*>(user_data);
234 TlsCustomVerificationCheckRequest* cpp_request = nullptr;
235 {
236 internal::MutexLock lock(&self->mu_);
237 auto it = self->request_map_.find(request);
238 if (it != self->request_map_.end()) {
239 cpp_request = &it->second.cpp_request;
240 }
241 }
242 if (cpp_request != nullptr) {
243 self->Cancel(cpp_request);
244 }
245 }
246
DestructInCoreExternalVerifier(void * user_data)247 void ExternalCertificateVerifier::DestructInCoreExternalVerifier(
248 void* user_data) {
249 auto* self = static_cast<ExternalCertificateVerifier*>(user_data);
250 delete self;
251 }
252
NoOpCertificateVerifier()253 NoOpCertificateVerifier::NoOpCertificateVerifier()
254 : CertificateVerifier(grpc_tls_certificate_verifier_no_op_create()) {}
255
HostNameCertificateVerifier()256 HostNameCertificateVerifier::HostNameCertificateVerifier()
257 : CertificateVerifier(grpc_tls_certificate_verifier_host_name_create()) {}
258
259 } // namespace experimental
260 } // namespace grpc
261