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 "src/core/lib/security/credentials/tls/grpc_tls_certificate_verifier.h"
18
19 #include <grpc/support/alloc.h>
20 #include <grpc/support/port_platform.h>
21 #include <grpc/support/string_util.h>
22 #include <string.h>
23
24 #include <string>
25 #include <utility>
26
27 #include "absl/log/check.h"
28 #include "absl/strings/string_view.h"
29 #include "src/core/lib/debug/trace.h"
30 #include "src/core/lib/iomgr/exec_ctx.h"
31 #include "src/core/lib/security/credentials/tls/tls_utils.h"
32 #include "src/core/util/host_port.h"
33
34 namespace grpc_core {
35
36 //
37 // ExternalCertificateVerifier
38 //
39
Verify(grpc_tls_custom_verification_check_request * request,std::function<void (absl::Status)> callback,absl::Status * sync_status)40 bool ExternalCertificateVerifier::Verify(
41 grpc_tls_custom_verification_check_request* request,
42 std::function<void(absl::Status)> callback, absl::Status* sync_status) {
43 {
44 MutexLock lock(&mu_);
45 request_map_.emplace(request, std::move(callback));
46 }
47 // Invoke the caller-specified verification logic embedded in
48 // external_verifier_.
49 grpc_status_code status_code = GRPC_STATUS_OK;
50 char* error_details = nullptr;
51 bool is_done = external_verifier_->verify(external_verifier_->user_data,
52 request, &OnVerifyDone, this,
53 &status_code, &error_details);
54 if (is_done) {
55 if (status_code != GRPC_STATUS_OK) {
56 *sync_status = absl::Status(static_cast<absl::StatusCode>(status_code),
57 error_details);
58 }
59 MutexLock lock(&mu_);
60 request_map_.erase(request);
61 }
62 gpr_free(error_details);
63 return is_done;
64 }
65
type() const66 UniqueTypeName ExternalCertificateVerifier::type() const {
67 static UniqueTypeName::Factory kFactory("External");
68 return kFactory.Create();
69 }
70
OnVerifyDone(grpc_tls_custom_verification_check_request * request,void * callback_arg,grpc_status_code status,const char * error_details)71 void ExternalCertificateVerifier::OnVerifyDone(
72 grpc_tls_custom_verification_check_request* request, void* callback_arg,
73 grpc_status_code status, const char* error_details) {
74 ExecCtx exec_ctx;
75 auto* self = static_cast<ExternalCertificateVerifier*>(callback_arg);
76 std::function<void(absl::Status)> callback;
77 {
78 MutexLock lock(&self->mu_);
79 auto it = self->request_map_.find(request);
80 if (it != self->request_map_.end()) {
81 callback = std::move(it->second);
82 self->request_map_.erase(it);
83 }
84 }
85 if (callback != nullptr) {
86 absl::Status return_status;
87 if (status != GRPC_STATUS_OK) {
88 return_status =
89 absl::Status(static_cast<absl::StatusCode>(status), error_details);
90 }
91 callback(return_status);
92 }
93 }
94
95 //
96 // NoOpCertificateVerifier
97 //
98
type() const99 UniqueTypeName NoOpCertificateVerifier::type() const {
100 static UniqueTypeName::Factory kFactory("NoOp");
101 return kFactory.Create();
102 }
103
104 //
105 // HostNameCertificateVerifier
106 //
107
Verify(grpc_tls_custom_verification_check_request * request,std::function<void (absl::Status)>,absl::Status * sync_status)108 bool HostNameCertificateVerifier::Verify(
109 grpc_tls_custom_verification_check_request* request,
110 std::function<void(absl::Status)>, absl::Status* sync_status) {
111 CHECK_NE(request, nullptr);
112 // Extract the target name, and remove its port.
113 const char* target_name = request->target_name;
114 if (target_name == nullptr) {
115 *sync_status = absl::Status(absl::StatusCode::kUnauthenticated,
116 "Target name is not specified.");
117 return true; // synchronous check
118 }
119 absl::string_view target_host;
120 absl::string_view ignored_port;
121 SplitHostPort(target_name, &target_host, &ignored_port);
122 if (target_host.empty()) {
123 *sync_status = absl::Status(absl::StatusCode::kUnauthenticated,
124 "Failed to split hostname and port.");
125 return true; // synchronous check
126 }
127 // IPv6 zone-id should not be included in comparisons.
128 const size_t zone_id = target_host.find('%');
129 if (zone_id != absl::string_view::npos) {
130 target_host.remove_suffix(target_host.size() - zone_id);
131 }
132 // Perform the hostname check.
133 // First check the DNS field. We allow prefix or suffix wildcard matching.
134 char** dns_names = request->peer_info.san_names.dns_names;
135 size_t dns_names_size = request->peer_info.san_names.dns_names_size;
136 if (dns_names != nullptr && dns_names_size > 0) {
137 for (size_t i = 0; i < dns_names_size; ++i) {
138 const char* dns_name = dns_names[i];
139 // We are using the target name sent from the client as a matcher to match
140 // against identity name on the peer cert.
141 if (VerifySubjectAlternativeName(dns_name, std::string(target_host))) {
142 return true; // synchronous check
143 }
144 }
145 }
146 // Then check the IP address. We only allow exact matching.
147 char** ip_names = request->peer_info.san_names.ip_names;
148 size_t ip_names_size = request->peer_info.san_names.ip_names_size;
149 if (ip_names != nullptr && ip_names_size > 0) {
150 for (size_t i = 0; i < ip_names_size; ++i) {
151 const char* ip_name = ip_names[i];
152 if (target_host == ip_name) {
153 return true; // synchronous check
154 }
155 }
156 }
157 // If there's no SAN, try the CN.
158 if (dns_names_size == 0) {
159 const char* common_name = request->peer_info.common_name;
160 // We are using the target name sent from the client as a matcher to match
161 // against identity name on the peer cert.
162 if (common_name != nullptr &&
163 VerifySubjectAlternativeName(common_name, std::string(target_host))) {
164 return true; // synchronous check
165 }
166 }
167 *sync_status = absl::Status(absl::StatusCode::kUnauthenticated,
168 "Hostname Verification Check failed.");
169 return true; // synchronous check
170 }
171
type() const172 UniqueTypeName HostNameCertificateVerifier::type() const {
173 static UniqueTypeName::Factory kFactory("Hostname");
174 return kFactory.Create();
175 }
176
177 } // namespace grpc_core
178
179 //
180 // Wrapper APIs declared in grpc_security.h
181 //
182
grpc_tls_certificate_verifier_verify(grpc_tls_certificate_verifier * verifier,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 grpc_tls_certificate_verifier_verify(
184 grpc_tls_certificate_verifier* verifier,
185 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 grpc_core::ExecCtx exec_ctx;
189 std::function<void(absl::Status)> async_cb =
190 [callback, request, callback_arg](absl::Status async_status) {
191 callback(request, callback_arg,
192 static_cast<grpc_status_code>(async_status.code()),
193 std::string(async_status.message()).c_str());
194 };
195 absl::Status sync_status_cpp;
196 bool is_done = verifier->Verify(request, async_cb, &sync_status_cpp);
197 if (is_done) {
198 if (!sync_status_cpp.ok()) {
199 *sync_status = static_cast<grpc_status_code>(sync_status_cpp.code());
200 *sync_error_details =
201 gpr_strdup(std::string(sync_status_cpp.message()).c_str());
202 }
203 }
204 return is_done;
205 }
206
grpc_tls_certificate_verifier_cancel(grpc_tls_certificate_verifier * verifier,grpc_tls_custom_verification_check_request * request)207 void grpc_tls_certificate_verifier_cancel(
208 grpc_tls_certificate_verifier* verifier,
209 grpc_tls_custom_verification_check_request* request) {
210 grpc_core::ExecCtx exec_ctx;
211 verifier->Cancel(request);
212 }
213
grpc_tls_certificate_verifier_external_create(grpc_tls_certificate_verifier_external * external_verifier)214 grpc_tls_certificate_verifier* grpc_tls_certificate_verifier_external_create(
215 grpc_tls_certificate_verifier_external* external_verifier) {
216 grpc_core::ExecCtx exec_ctx;
217 return new grpc_core::ExternalCertificateVerifier(external_verifier);
218 }
219
grpc_tls_certificate_verifier_no_op_create()220 grpc_tls_certificate_verifier* grpc_tls_certificate_verifier_no_op_create() {
221 grpc_core::ExecCtx exec_ctx;
222 return new grpc_core::NoOpCertificateVerifier();
223 }
224
225 grpc_tls_certificate_verifier*
grpc_tls_certificate_verifier_host_name_create()226 grpc_tls_certificate_verifier_host_name_create() {
227 grpc_core::ExecCtx exec_ctx;
228 return new grpc_core::HostNameCertificateVerifier();
229 }
230
grpc_tls_certificate_verifier_release(grpc_tls_certificate_verifier * verifier)231 void grpc_tls_certificate_verifier_release(
232 grpc_tls_certificate_verifier* verifier) {
233 GRPC_TRACE_LOG(api, INFO)
234 << "grpc_tls_certificate_verifier_release(verifier=" << verifier << ")";
235 grpc_core::ExecCtx exec_ctx;
236 if (verifier != nullptr) verifier->Unref();
237 }
238