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 <grpc/support/port_platform.h>
20
21 #include "src/core/lib/security/security_connector/alts/alts_security_connector.h"
22
23 #include <stdbool.h>
24 #include <string.h>
25
26 #include <grpc/grpc.h>
27 #include <grpc/support/alloc.h>
28 #include <grpc/support/log.h>
29 #include <grpc/support/string_util.h>
30
31 #include "src/core/lib/gprpp/ref_counted_ptr.h"
32 #include "src/core/lib/security/credentials/alts/alts_credentials.h"
33 #include "src/core/lib/security/transport/security_handshaker.h"
34 #include "src/core/lib/slice/slice_internal.h"
35 #include "src/core/lib/transport/transport.h"
36 #include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
37 #include "src/core/tsi/transport_security.h"
38
grpc_alts_set_rpc_protocol_versions(grpc_gcp_rpc_protocol_versions * rpc_versions)39 void grpc_alts_set_rpc_protocol_versions(
40 grpc_gcp_rpc_protocol_versions* rpc_versions) {
41 grpc_gcp_rpc_protocol_versions_set_max(rpc_versions,
42 GRPC_PROTOCOL_VERSION_MAX_MAJOR,
43 GRPC_PROTOCOL_VERSION_MAX_MINOR);
44 grpc_gcp_rpc_protocol_versions_set_min(rpc_versions,
45 GRPC_PROTOCOL_VERSION_MIN_MAJOR,
46 GRPC_PROTOCOL_VERSION_MIN_MINOR);
47 }
48
49 namespace {
50
alts_check_peer(tsi_peer peer,grpc_core::RefCountedPtr<grpc_auth_context> * auth_context,grpc_closure * on_peer_checked)51 void alts_check_peer(tsi_peer peer,
52 grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
53 grpc_closure* on_peer_checked) {
54 *auth_context =
55 grpc_core::internal::grpc_alts_auth_context_from_tsi_peer(&peer);
56 tsi_peer_destruct(&peer);
57 grpc_error_handle error =
58 *auth_context != nullptr
59 ? GRPC_ERROR_NONE
60 : GRPC_ERROR_CREATE_FROM_STATIC_STRING(
61 "Could not get ALTS auth context from TSI peer");
62 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
63 }
64
65 class grpc_alts_channel_security_connector final
66 : public grpc_channel_security_connector {
67 public:
grpc_alts_channel_security_connector(grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,const char * target_name)68 grpc_alts_channel_security_connector(
69 grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
70 grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
71 const char* target_name)
72 : grpc_channel_security_connector(GRPC_ALTS_URL_SCHEME,
73 std::move(channel_creds),
74 std::move(request_metadata_creds)),
75 target_name_(gpr_strdup(target_name)) {}
76
~grpc_alts_channel_security_connector()77 ~grpc_alts_channel_security_connector() override { gpr_free(target_name_); }
78
add_handshakers(const grpc_channel_args * args,grpc_pollset_set * interested_parties,grpc_core::HandshakeManager * handshake_manager)79 void add_handshakers(
80 const grpc_channel_args* args, grpc_pollset_set* interested_parties,
81 grpc_core::HandshakeManager* handshake_manager) override {
82 tsi_handshaker* handshaker = nullptr;
83 const grpc_alts_credentials* creds =
84 static_cast<const grpc_alts_credentials*>(channel_creds());
85 size_t user_specified_max_frame_size = 0;
86 const grpc_arg* arg =
87 grpc_channel_args_find(args, GRPC_ARG_TSI_MAX_FRAME_SIZE);
88 if (arg != nullptr && arg->type == GRPC_ARG_INTEGER) {
89 user_specified_max_frame_size = grpc_channel_arg_get_integer(
90 arg, {0, 0, std::numeric_limits<int>::max()});
91 }
92 GPR_ASSERT(alts_tsi_handshaker_create(
93 creds->options(), target_name_,
94 creds->handshaker_service_url(), true, interested_parties,
95 &handshaker, user_specified_max_frame_size) == TSI_OK);
96 handshake_manager->Add(
97 grpc_core::SecurityHandshakerCreate(handshaker, this, args));
98 }
99
check_peer(tsi_peer peer,grpc_endpoint *,grpc_core::RefCountedPtr<grpc_auth_context> * auth_context,grpc_closure * on_peer_checked)100 void check_peer(tsi_peer peer, grpc_endpoint* /*ep*/,
101 grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
102 grpc_closure* on_peer_checked) override {
103 alts_check_peer(peer, auth_context, on_peer_checked);
104 }
105
cancel_check_peer(grpc_closure *,grpc_error_handle error)106 void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
107 grpc_error_handle error) override {
108 GRPC_ERROR_UNREF(error);
109 }
110
cmp(const grpc_security_connector * other_sc) const111 int cmp(const grpc_security_connector* other_sc) const override {
112 auto* other =
113 reinterpret_cast<const grpc_alts_channel_security_connector*>(other_sc);
114 int c = channel_security_connector_cmp(other);
115 if (c != 0) return c;
116 return strcmp(target_name_, other->target_name_);
117 }
118
check_call_host(absl::string_view host,grpc_auth_context *,grpc_closure *,grpc_error_handle * error)119 bool check_call_host(absl::string_view host,
120 grpc_auth_context* /*auth_context*/,
121 grpc_closure* /*on_call_host_checked*/,
122 grpc_error_handle* error) override {
123 if (host.empty() || host != target_name_) {
124 *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
125 "ALTS call host does not match target name");
126 }
127 return true;
128 }
129
cancel_check_call_host(grpc_closure *,grpc_error_handle error)130 void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
131 grpc_error_handle error) override {
132 GRPC_ERROR_UNREF(error);
133 }
134
135 private:
136 char* target_name_;
137 };
138
139 class grpc_alts_server_security_connector final
140 : public grpc_server_security_connector {
141 public:
grpc_alts_server_security_connector(grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)142 explicit grpc_alts_server_security_connector(
143 grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)
144 : grpc_server_security_connector(GRPC_ALTS_URL_SCHEME,
145 std::move(server_creds)) {}
146
147 ~grpc_alts_server_security_connector() override = default;
148
add_handshakers(const grpc_channel_args * args,grpc_pollset_set * interested_parties,grpc_core::HandshakeManager * handshake_manager)149 void add_handshakers(
150 const grpc_channel_args* args, grpc_pollset_set* interested_parties,
151 grpc_core::HandshakeManager* handshake_manager) override {
152 tsi_handshaker* handshaker = nullptr;
153 const grpc_alts_server_credentials* creds =
154 static_cast<const grpc_alts_server_credentials*>(server_creds());
155 size_t user_specified_max_frame_size = 0;
156 const grpc_arg* arg =
157 grpc_channel_args_find(args, GRPC_ARG_TSI_MAX_FRAME_SIZE);
158 if (arg != nullptr && arg->type == GRPC_ARG_INTEGER) {
159 user_specified_max_frame_size = grpc_channel_arg_get_integer(
160 arg, {0, 0, std::numeric_limits<int>::max()});
161 }
162 GPR_ASSERT(alts_tsi_handshaker_create(
163 creds->options(), nullptr, creds->handshaker_service_url(),
164 false, interested_parties, &handshaker,
165 user_specified_max_frame_size) == TSI_OK);
166 handshake_manager->Add(
167 grpc_core::SecurityHandshakerCreate(handshaker, this, args));
168 }
169
check_peer(tsi_peer peer,grpc_endpoint *,grpc_core::RefCountedPtr<grpc_auth_context> * auth_context,grpc_closure * on_peer_checked)170 void check_peer(tsi_peer peer, grpc_endpoint* /*ep*/,
171 grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
172 grpc_closure* on_peer_checked) override {
173 alts_check_peer(peer, auth_context, on_peer_checked);
174 }
175
cancel_check_peer(grpc_closure *,grpc_error_handle error)176 void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
177 grpc_error_handle error) override {
178 GRPC_ERROR_UNREF(error);
179 }
180
cmp(const grpc_security_connector * other) const181 int cmp(const grpc_security_connector* other) const override {
182 return server_security_connector_cmp(
183 static_cast<const grpc_server_security_connector*>(other));
184 }
185 };
186 } // namespace
187
188 namespace grpc_core {
189 namespace internal {
190 grpc_core::RefCountedPtr<grpc_auth_context>
grpc_alts_auth_context_from_tsi_peer(const tsi_peer * peer)191 grpc_alts_auth_context_from_tsi_peer(const tsi_peer* peer) {
192 if (peer == nullptr) {
193 gpr_log(GPR_ERROR,
194 "Invalid arguments to grpc_alts_auth_context_from_tsi_peer()");
195 return nullptr;
196 }
197 /* Validate certificate type. */
198 const tsi_peer_property* cert_type_prop =
199 tsi_peer_get_property_by_name(peer, TSI_CERTIFICATE_TYPE_PEER_PROPERTY);
200 if (cert_type_prop == nullptr ||
201 strncmp(cert_type_prop->value.data, TSI_ALTS_CERTIFICATE_TYPE,
202 cert_type_prop->value.length) != 0) {
203 gpr_log(GPR_ERROR, "Invalid or missing certificate type property.");
204 return nullptr;
205 }
206 /* Check if security level exists. */
207 const tsi_peer_property* security_level_prop =
208 tsi_peer_get_property_by_name(peer, TSI_SECURITY_LEVEL_PEER_PROPERTY);
209 if (security_level_prop == nullptr) {
210 gpr_log(GPR_ERROR, "Missing security level property.");
211 return nullptr;
212 }
213 /* Validate RPC protocol versions. */
214 const tsi_peer_property* rpc_versions_prop =
215 tsi_peer_get_property_by_name(peer, TSI_ALTS_RPC_VERSIONS);
216 if (rpc_versions_prop == nullptr) {
217 gpr_log(GPR_ERROR, "Missing rpc protocol versions property.");
218 return nullptr;
219 }
220 grpc_gcp_rpc_protocol_versions local_versions, peer_versions;
221 grpc_alts_set_rpc_protocol_versions(&local_versions);
222 grpc_slice slice = grpc_slice_from_copied_buffer(
223 rpc_versions_prop->value.data, rpc_versions_prop->value.length);
224 bool decode_result =
225 grpc_gcp_rpc_protocol_versions_decode(slice, &peer_versions);
226 grpc_slice_unref_internal(slice);
227 if (!decode_result) {
228 gpr_log(GPR_ERROR, "Invalid peer rpc protocol versions.");
229 return nullptr;
230 }
231 /* TODO: Pass highest common rpc protocol version to grpc caller. */
232 bool check_result = grpc_gcp_rpc_protocol_versions_check(
233 &local_versions, &peer_versions, nullptr);
234 if (!check_result) {
235 gpr_log(GPR_ERROR, "Mismatch of local and peer rpc protocol versions.");
236 return nullptr;
237 }
238 /* Validate ALTS Context. */
239 const tsi_peer_property* alts_context_prop =
240 tsi_peer_get_property_by_name(peer, TSI_ALTS_CONTEXT);
241 if (alts_context_prop == nullptr) {
242 gpr_log(GPR_ERROR, "Missing alts context property.");
243 return nullptr;
244 }
245 /* Create auth context. */
246 auto ctx = grpc_core::MakeRefCounted<grpc_auth_context>(nullptr);
247 grpc_auth_context_add_cstring_property(
248 ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
249 GRPC_ALTS_TRANSPORT_SECURITY_TYPE);
250 size_t i = 0;
251 for (i = 0; i < peer->property_count; i++) {
252 const tsi_peer_property* tsi_prop = &peer->properties[i];
253 /* Add service account to auth context. */
254 if (strcmp(tsi_prop->name, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 0) {
255 grpc_auth_context_add_property(
256 ctx.get(), TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY,
257 tsi_prop->value.data, tsi_prop->value.length);
258 GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
259 ctx.get(), TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 1);
260 }
261 /* Add alts context to auth context. */
262 if (strcmp(tsi_prop->name, TSI_ALTS_CONTEXT) == 0) {
263 grpc_auth_context_add_property(ctx.get(), TSI_ALTS_CONTEXT,
264 tsi_prop->value.data,
265 tsi_prop->value.length);
266 }
267 /* Add security level to auth context. */
268 if (strcmp(tsi_prop->name, TSI_SECURITY_LEVEL_PEER_PROPERTY) == 0) {
269 grpc_auth_context_add_property(
270 ctx.get(), GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME,
271 tsi_prop->value.data, tsi_prop->value.length);
272 }
273 }
274 if (!grpc_auth_context_peer_is_authenticated(ctx.get())) {
275 gpr_log(GPR_ERROR, "Invalid unauthenticated peer.");
276 ctx.reset(DEBUG_LOCATION, "test");
277 return nullptr;
278 }
279 return ctx;
280 }
281
282 } // namespace internal
283 } // namespace grpc_core
284
285 grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_alts_channel_security_connector_create(grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,const char * target_name)286 grpc_alts_channel_security_connector_create(
287 grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
288 grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
289 const char* target_name) {
290 if (channel_creds == nullptr || target_name == nullptr) {
291 gpr_log(
292 GPR_ERROR,
293 "Invalid arguments to grpc_alts_channel_security_connector_create()");
294 return nullptr;
295 }
296 return grpc_core::MakeRefCounted<grpc_alts_channel_security_connector>(
297 std::move(channel_creds), std::move(request_metadata_creds), target_name);
298 }
299
300 grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_alts_server_security_connector_create(grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)301 grpc_alts_server_security_connector_create(
302 grpc_core::RefCountedPtr<grpc_server_credentials> server_creds) {
303 if (server_creds == nullptr) {
304 gpr_log(
305 GPR_ERROR,
306 "Invalid arguments to grpc_alts_server_security_connector_create()");
307 return nullptr;
308 }
309 return grpc_core::MakeRefCounted<grpc_alts_server_security_connector>(
310 std::move(server_creds));
311 }
312