1 //
2 //
3 // Copyright 2018 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include "src/core/lib/security/security_connector/local/local_security_connector.h"
20
21 #include <grpc/grpc.h>
22 #include <grpc/grpc_security_constants.h>
23 #include <grpc/support/alloc.h>
24 #include <grpc/support/port_platform.h>
25 #include <grpc/support/string_util.h>
26 #include <string.h>
27
28 #include <string>
29 #include <utility>
30
31 #include "absl/log/check.h"
32 #include "absl/log/log.h"
33 #include "absl/status/status.h"
34 #include "absl/status/statusor.h"
35 #include "absl/strings/match.h"
36 #include "absl/strings/string_view.h"
37 #include "absl/types/optional.h"
38 #include "src/core/client_channel/client_channel_filter.h"
39 #include "src/core/handshaker/handshaker.h"
40 #include "src/core/handshaker/security/security_handshaker.h"
41 #include "src/core/lib/address_utils/parse_address.h"
42 #include "src/core/lib/address_utils/sockaddr_utils.h"
43 #include "src/core/lib/channel/channel_args.h"
44 #include "src/core/lib/experiments/experiments.h"
45 #include "src/core/lib/iomgr/closure.h"
46 #include "src/core/lib/iomgr/endpoint.h"
47 #include "src/core/lib/iomgr/error.h"
48 #include "src/core/lib/iomgr/exec_ctx.h"
49 #include "src/core/lib/iomgr/iomgr_fwd.h"
50 #include "src/core/lib/iomgr/resolved_address.h"
51 #include "src/core/lib/iomgr/sockaddr.h"
52 #include "src/core/lib/iomgr/socket_utils.h"
53 #include "src/core/lib/iomgr/unix_sockets_posix.h"
54 #include "src/core/lib/promise/arena_promise.h"
55 #include "src/core/lib/promise/promise.h"
56 #include "src/core/lib/security/context/security_context.h"
57 #include "src/core/lib/security/credentials/credentials.h"
58 #include "src/core/lib/security/credentials/local/local_credentials.h"
59 #include "src/core/tsi/local_transport_security.h"
60 #include "src/core/tsi/transport_security.h"
61 #include "src/core/tsi/transport_security_interface.h"
62 #include "src/core/util/debug_location.h"
63 #include "src/core/util/ref_counted_ptr.h"
64 #include "src/core/util/uri.h"
65
66 #define GRPC_UDS_URI_PATTERN "unix:"
67 #define GRPC_ABSTRACT_UDS_URI_PATTERN "unix-abstract:"
68 #define GRPC_LOCAL_TRANSPORT_SECURITY_TYPE "local"
69
70 namespace {
71
local_auth_context_create(const tsi_peer * peer)72 grpc_core::RefCountedPtr<grpc_auth_context> local_auth_context_create(
73 const tsi_peer* peer) {
74 // Create auth context.
75 grpc_core::RefCountedPtr<grpc_auth_context> ctx =
76 grpc_core::MakeRefCounted<grpc_auth_context>(nullptr);
77 grpc_auth_context_add_cstring_property(
78 ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
79 GRPC_LOCAL_TRANSPORT_SECURITY_TYPE);
80 CHECK(grpc_auth_context_set_peer_identity_property_name(
81 ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME) == 1);
82 CHECK_EQ(peer->property_count, 1u);
83 const tsi_peer_property* prop = &peer->properties[0];
84 CHECK_NE(prop, nullptr);
85 CHECK_EQ(strcmp(prop->name, TSI_SECURITY_LEVEL_PEER_PROPERTY), 0);
86 grpc_auth_context_add_property(ctx.get(),
87 GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME,
88 prop->value.data, prop->value.length);
89 return ctx;
90 }
91
local_check_peer(tsi_peer peer,grpc_endpoint * ep,grpc_core::RefCountedPtr<grpc_auth_context> * auth_context,grpc_closure * on_peer_checked,grpc_local_connect_type type)92 void local_check_peer(tsi_peer peer, grpc_endpoint* ep,
93 grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
94 grpc_closure* on_peer_checked,
95 grpc_local_connect_type type) {
96 grpc_resolved_address resolved_addr;
97 bool is_endpoint_local = false;
98 absl::string_view local_addr = grpc_endpoint_get_local_address(ep);
99 absl::StatusOr<grpc_core::URI> uri = grpc_core::URI::Parse(local_addr);
100 if (!uri.ok() || !grpc_parse_uri(*uri, &resolved_addr)) {
101 LOG(ERROR) << "Could not parse endpoint address: " << local_addr;
102 } else {
103 grpc_resolved_address addr_normalized;
104 grpc_resolved_address* addr =
105 grpc_sockaddr_is_v4mapped(&resolved_addr, &addr_normalized)
106 ? &addr_normalized
107 : &resolved_addr;
108 grpc_sockaddr* sock_addr = reinterpret_cast<grpc_sockaddr*>(&addr->addr);
109 // UDS
110 if (type == UDS && grpc_is_unix_socket(addr)) {
111 is_endpoint_local = true;
112 // IPV4
113 } else if (type == LOCAL_TCP && sock_addr->sa_family == GRPC_AF_INET) {
114 const grpc_sockaddr_in* addr4 =
115 reinterpret_cast<const grpc_sockaddr_in*>(sock_addr);
116 if (grpc_htonl(addr4->sin_addr.s_addr) == INADDR_LOOPBACK) {
117 is_endpoint_local = true;
118 }
119 // IPv6
120 } else if (type == LOCAL_TCP && sock_addr->sa_family == GRPC_AF_INET6) {
121 const grpc_sockaddr_in6* addr6 =
122 reinterpret_cast<const grpc_sockaddr_in6*>(addr);
123 if (memcmp(&addr6->sin6_addr, &in6addr_loopback,
124 sizeof(in6addr_loopback)) == 0) {
125 is_endpoint_local = true;
126 }
127 }
128 }
129 grpc_error_handle error;
130 if (!is_endpoint_local) {
131 error =
132 GRPC_ERROR_CREATE("Endpoint is neither UDS or TCP loopback address.");
133 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
134 return;
135 }
136 // Add TSI_SECURITY_LEVEL_PEER_PROPERTY type peer property.
137 size_t new_property_count = peer.property_count + 1;
138 tsi_peer_property* new_properties = static_cast<tsi_peer_property*>(
139 gpr_zalloc(sizeof(*new_properties) * new_property_count));
140 for (size_t i = 0; i < peer.property_count; i++) {
141 new_properties[i] = peer.properties[i];
142 }
143 if (peer.properties != nullptr) gpr_free(peer.properties);
144 peer.properties = new_properties;
145 // Set security level to PRIVACY_AND_INTEGRITY for UDS, or NONE otherwise.
146 const char* security_level;
147 if (grpc_core::IsLocalConnectorSecureEnabled()) {
148 security_level = tsi_security_level_to_string(
149 type == UDS ? TSI_PRIVACY_AND_INTEGRITY : TSI_SECURITY_NONE);
150 } else {
151 security_level = tsi_security_level_to_string(TSI_PRIVACY_AND_INTEGRITY);
152 }
153 tsi_result result = tsi_construct_string_peer_property_from_cstring(
154 TSI_SECURITY_LEVEL_PEER_PROPERTY, security_level,
155 &peer.properties[peer.property_count]);
156 if (result != TSI_OK) return;
157 peer.property_count++;
158 // Create an auth context which is necessary to pass the santiy check in
159 // {client, server}_auth_filter that verifies if the peer's auth context is
160 // obtained during handshakes. The auth context is only checked for its
161 // existence and not actually used.
162 //
163 *auth_context = local_auth_context_create(&peer);
164 tsi_peer_destruct(&peer);
165 error = *auth_context != nullptr
166 ? absl::OkStatus()
167 : GRPC_ERROR_CREATE("Could not create local auth context");
168 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
169 }
170
171 class grpc_local_channel_security_connector final
172 : public grpc_channel_security_connector {
173 public:
grpc_local_channel_security_connector(grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,const char * target_name)174 grpc_local_channel_security_connector(
175 grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
176 grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
177 const char* target_name)
178 : grpc_channel_security_connector({}, std::move(channel_creds),
179 std::move(request_metadata_creds)),
180 target_name_(gpr_strdup(target_name)) {}
181
~grpc_local_channel_security_connector()182 ~grpc_local_channel_security_connector() override { gpr_free(target_name_); }
183
add_handshakers(const grpc_core::ChannelArgs & args,grpc_pollset_set *,grpc_core::HandshakeManager * handshake_manager)184 void add_handshakers(
185 const grpc_core::ChannelArgs& args,
186 grpc_pollset_set* /*interested_parties*/,
187 grpc_core::HandshakeManager* handshake_manager) override {
188 tsi_handshaker* handshaker = nullptr;
189 CHECK(tsi_local_handshaker_create(&handshaker) == TSI_OK);
190 handshake_manager->Add(
191 grpc_core::SecurityHandshakerCreate(handshaker, this, args));
192 }
193
cmp(const grpc_security_connector * other_sc) const194 int cmp(const grpc_security_connector* other_sc) const override {
195 auto* other =
196 reinterpret_cast<const grpc_local_channel_security_connector*>(
197 other_sc);
198 int c = channel_security_connector_cmp(other);
199 if (c != 0) return c;
200 return strcmp(target_name_, other->target_name_);
201 }
202
check_peer(tsi_peer peer,grpc_endpoint * ep,const grpc_core::ChannelArgs &,grpc_core::RefCountedPtr<grpc_auth_context> * auth_context,grpc_closure * on_peer_checked)203 void check_peer(tsi_peer peer, grpc_endpoint* ep,
204 const grpc_core::ChannelArgs& /*args*/,
205 grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
206 grpc_closure* on_peer_checked) override {
207 grpc_local_credentials* creds =
208 reinterpret_cast<grpc_local_credentials*>(mutable_channel_creds());
209 local_check_peer(peer, ep, auth_context, on_peer_checked,
210 creds->connect_type());
211 }
212
cancel_check_peer(grpc_closure *,grpc_error_handle)213 void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
214 grpc_error_handle /*error*/) override {}
215
CheckCallHost(absl::string_view host,grpc_auth_context *)216 grpc_core::ArenaPromise<absl::Status> CheckCallHost(
217 absl::string_view host, grpc_auth_context*) override {
218 if (host.empty() || host != target_name_) {
219 return grpc_core::Immediate(absl::UnauthenticatedError(
220 "local call host does not match target name"));
221 }
222 return grpc_core::ImmediateOkStatus();
223 }
224
target_name() const225 const char* target_name() const { return target_name_; }
226
227 private:
228 char* target_name_;
229 };
230
231 class grpc_local_server_security_connector final
232 : public grpc_server_security_connector {
233 public:
grpc_local_server_security_connector(grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)234 explicit grpc_local_server_security_connector(
235 grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)
236 : grpc_server_security_connector({}, std::move(server_creds)) {}
237 ~grpc_local_server_security_connector() override = default;
238
add_handshakers(const grpc_core::ChannelArgs & args,grpc_pollset_set *,grpc_core::HandshakeManager * handshake_manager)239 void add_handshakers(
240 const grpc_core::ChannelArgs& args,
241 grpc_pollset_set* /*interested_parties*/,
242 grpc_core::HandshakeManager* handshake_manager) override {
243 tsi_handshaker* handshaker = nullptr;
244 CHECK(tsi_local_handshaker_create(&handshaker) == TSI_OK);
245 handshake_manager->Add(
246 grpc_core::SecurityHandshakerCreate(handshaker, this, args));
247 }
248
check_peer(tsi_peer peer,grpc_endpoint * ep,const grpc_core::ChannelArgs &,grpc_core::RefCountedPtr<grpc_auth_context> * auth_context,grpc_closure * on_peer_checked)249 void check_peer(tsi_peer peer, grpc_endpoint* ep,
250 const grpc_core::ChannelArgs& /*args*/,
251 grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
252 grpc_closure* on_peer_checked) override {
253 grpc_local_server_credentials* creds =
254 static_cast<grpc_local_server_credentials*>(mutable_server_creds());
255 local_check_peer(peer, ep, auth_context, on_peer_checked,
256 creds->connect_type());
257 }
258
cancel_check_peer(grpc_closure *,grpc_error_handle)259 void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
260 grpc_error_handle /*error*/) override {}
261
cmp(const grpc_security_connector * other) const262 int cmp(const grpc_security_connector* other) const override {
263 return server_security_connector_cmp(
264 static_cast<const grpc_server_security_connector*>(other));
265 }
266 };
267 } // namespace
268
269 grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_local_channel_security_connector_create(grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,const grpc_core::ChannelArgs & args,const char * target_name)270 grpc_local_channel_security_connector_create(
271 grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
272 grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
273 const grpc_core::ChannelArgs& args, const char* target_name) {
274 if (channel_creds == nullptr || target_name == nullptr) {
275 LOG(ERROR) << "Invalid arguments to "
276 "grpc_local_channel_security_connector_create()";
277 return nullptr;
278 }
279 // Perform sanity check on UDS address. For TCP local connection, the check
280 // will be done during check_peer procedure.
281 grpc_local_credentials* creds =
282 static_cast<grpc_local_credentials*>(channel_creds.get());
283 absl::string_view server_uri_str =
284 args.GetString(GRPC_ARG_SERVER_URI).value_or("");
285 if (creds->connect_type() == UDS &&
286 !absl::StartsWith(server_uri_str, GRPC_UDS_URI_PATTERN) &&
287 !absl::StartsWith(server_uri_str, GRPC_ABSTRACT_UDS_URI_PATTERN)) {
288 LOG(ERROR) << "Invalid UDS target name to "
289 "grpc_local_channel_security_connector_create()";
290 return nullptr;
291 }
292 return grpc_core::MakeRefCounted<grpc_local_channel_security_connector>(
293 channel_creds, request_metadata_creds, target_name);
294 }
295
296 grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_local_server_security_connector_create(grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)297 grpc_local_server_security_connector_create(
298 grpc_core::RefCountedPtr<grpc_server_credentials> server_creds) {
299 if (server_creds == nullptr) {
300 LOG(ERROR)
301 << "Invalid arguments to grpc_local_server_security_connector_create()";
302 return nullptr;
303 }
304 return grpc_core::MakeRefCounted<grpc_local_server_security_connector>(
305 std::move(server_creds));
306 }
307