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