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