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/tsi/alts/handshaker/alts_tsi_handshaker.h"
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include <grpc/support/alloc.h>
28 #include <grpc/support/log.h>
29 #include <grpc/support/string_util.h>
30 #include <grpc/support/sync.h>
31 #include <grpc/support/thd_id.h>
32 
33 #include "src/core/lib/gprpp/thd.h"
34 #include "src/core/lib/iomgr/closure.h"
35 #include "src/core/lib/slice/slice_internal.h"
36 #include "src/core/tsi/alts/frame_protector/alts_frame_protector.h"
37 #include "src/core/tsi/alts/handshaker/alts_handshaker_client.h"
38 #include "src/core/tsi/alts/handshaker/alts_shared_resource.h"
39 #include "src/core/tsi/alts/handshaker/alts_tsi_utils.h"
40 #include "src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h"
41 
42 /* Main struct for ALTS TSI handshaker. */
43 struct alts_tsi_handshaker {
44   tsi_handshaker base;
45   alts_handshaker_client* client;
46   grpc_slice target_name;
47   bool is_client;
48   bool has_sent_start_message;
49   bool has_created_handshaker_client;
50   char* handshaker_service_url;
51   grpc_pollset_set* interested_parties;
52   grpc_alts_credentials_options* options;
53   alts_handshaker_client_vtable* client_vtable_for_testing;
54   grpc_channel* channel;
55 };
56 
57 /* Main struct for ALTS TSI handshaker result. */
58 typedef struct alts_tsi_handshaker_result {
59   tsi_handshaker_result base;
60   char* peer_identity;
61   char* key_data;
62   unsigned char* unused_bytes;
63   size_t unused_bytes_size;
64   grpc_slice rpc_versions;
65   bool is_client;
66 } alts_tsi_handshaker_result;
67 
handshaker_result_extract_peer(const tsi_handshaker_result * self,tsi_peer * peer)68 static tsi_result handshaker_result_extract_peer(
69     const tsi_handshaker_result* self, tsi_peer* peer) {
70   if (self == nullptr || peer == nullptr) {
71     gpr_log(GPR_ERROR, "Invalid argument to handshaker_result_extract_peer()");
72     return TSI_INVALID_ARGUMENT;
73   }
74   alts_tsi_handshaker_result* result =
75       reinterpret_cast<alts_tsi_handshaker_result*>(
76           const_cast<tsi_handshaker_result*>(self));
77   GPR_ASSERT(kTsiAltsNumOfPeerProperties == 3);
78   tsi_result ok = tsi_construct_peer(kTsiAltsNumOfPeerProperties, peer);
79   int index = 0;
80   if (ok != TSI_OK) {
81     gpr_log(GPR_ERROR, "Failed to construct tsi peer");
82     return ok;
83   }
84   GPR_ASSERT(&peer->properties[index] != nullptr);
85   ok = tsi_construct_string_peer_property_from_cstring(
86       TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_ALTS_CERTIFICATE_TYPE,
87       &peer->properties[index]);
88   if (ok != TSI_OK) {
89     tsi_peer_destruct(peer);
90     gpr_log(GPR_ERROR, "Failed to set tsi peer property");
91     return ok;
92   }
93   index++;
94   GPR_ASSERT(&peer->properties[index] != nullptr);
95   ok = tsi_construct_string_peer_property_from_cstring(
96       TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY, result->peer_identity,
97       &peer->properties[index]);
98   if (ok != TSI_OK) {
99     tsi_peer_destruct(peer);
100     gpr_log(GPR_ERROR, "Failed to set tsi peer property");
101   }
102   index++;
103   GPR_ASSERT(&peer->properties[index] != nullptr);
104   ok = tsi_construct_string_peer_property(
105       TSI_ALTS_RPC_VERSIONS,
106       reinterpret_cast<char*>(GRPC_SLICE_START_PTR(result->rpc_versions)),
107       GRPC_SLICE_LENGTH(result->rpc_versions), &peer->properties[2]);
108   if (ok != TSI_OK) {
109     tsi_peer_destruct(peer);
110     gpr_log(GPR_ERROR, "Failed to set tsi peer property");
111   }
112   GPR_ASSERT(++index == kTsiAltsNumOfPeerProperties);
113   return ok;
114 }
115 
handshaker_result_create_zero_copy_grpc_protector(const tsi_handshaker_result * self,size_t * max_output_protected_frame_size,tsi_zero_copy_grpc_protector ** protector)116 static tsi_result handshaker_result_create_zero_copy_grpc_protector(
117     const tsi_handshaker_result* self, size_t* max_output_protected_frame_size,
118     tsi_zero_copy_grpc_protector** protector) {
119   if (self == nullptr || protector == nullptr) {
120     gpr_log(GPR_ERROR,
121             "Invalid arguments to create_zero_copy_grpc_protector()");
122     return TSI_INVALID_ARGUMENT;
123   }
124   alts_tsi_handshaker_result* result =
125       reinterpret_cast<alts_tsi_handshaker_result*>(
126           const_cast<tsi_handshaker_result*>(self));
127   tsi_result ok = alts_zero_copy_grpc_protector_create(
128       reinterpret_cast<const uint8_t*>(result->key_data),
129       kAltsAes128GcmRekeyKeyLength, /*is_rekey=*/true, result->is_client,
130       /*is_integrity_only=*/false, /*enable_extra_copy=*/false,
131       max_output_protected_frame_size, protector);
132   if (ok != TSI_OK) {
133     gpr_log(GPR_ERROR, "Failed to create zero-copy grpc protector");
134   }
135   return ok;
136 }
137 
handshaker_result_create_frame_protector(const tsi_handshaker_result * self,size_t * max_output_protected_frame_size,tsi_frame_protector ** protector)138 static tsi_result handshaker_result_create_frame_protector(
139     const tsi_handshaker_result* self, size_t* max_output_protected_frame_size,
140     tsi_frame_protector** protector) {
141   if (self == nullptr || protector == nullptr) {
142     gpr_log(GPR_ERROR,
143             "Invalid arguments to handshaker_result_create_frame_protector()");
144     return TSI_INVALID_ARGUMENT;
145   }
146   alts_tsi_handshaker_result* result =
147       reinterpret_cast<alts_tsi_handshaker_result*>(
148           const_cast<tsi_handshaker_result*>(self));
149   tsi_result ok = alts_create_frame_protector(
150       reinterpret_cast<const uint8_t*>(result->key_data),
151       kAltsAes128GcmRekeyKeyLength, result->is_client, /*is_rekey=*/true,
152       max_output_protected_frame_size, protector);
153   if (ok != TSI_OK) {
154     gpr_log(GPR_ERROR, "Failed to create frame protector");
155   }
156   return ok;
157 }
158 
handshaker_result_get_unused_bytes(const tsi_handshaker_result * self,const unsigned char ** bytes,size_t * bytes_size)159 static tsi_result handshaker_result_get_unused_bytes(
160     const tsi_handshaker_result* self, const unsigned char** bytes,
161     size_t* bytes_size) {
162   if (self == nullptr || bytes == nullptr || bytes_size == nullptr) {
163     gpr_log(GPR_ERROR,
164             "Invalid arguments to handshaker_result_get_unused_bytes()");
165     return TSI_INVALID_ARGUMENT;
166   }
167   alts_tsi_handshaker_result* result =
168       reinterpret_cast<alts_tsi_handshaker_result*>(
169           const_cast<tsi_handshaker_result*>(self));
170   *bytes = result->unused_bytes;
171   *bytes_size = result->unused_bytes_size;
172   return TSI_OK;
173 }
174 
handshaker_result_destroy(tsi_handshaker_result * self)175 static void handshaker_result_destroy(tsi_handshaker_result* self) {
176   if (self == nullptr) {
177     return;
178   }
179   alts_tsi_handshaker_result* result =
180       reinterpret_cast<alts_tsi_handshaker_result*>(
181           const_cast<tsi_handshaker_result*>(self));
182   gpr_free(result->peer_identity);
183   gpr_free(result->key_data);
184   gpr_free(result->unused_bytes);
185   grpc_slice_unref_internal(result->rpc_versions);
186   gpr_free(result);
187 }
188 
189 static const tsi_handshaker_result_vtable result_vtable = {
190     handshaker_result_extract_peer,
191     handshaker_result_create_zero_copy_grpc_protector,
192     handshaker_result_create_frame_protector,
193     handshaker_result_get_unused_bytes, handshaker_result_destroy};
194 
alts_tsi_handshaker_result_create(grpc_gcp_handshaker_resp * resp,bool is_client,tsi_handshaker_result ** self)195 tsi_result alts_tsi_handshaker_result_create(grpc_gcp_handshaker_resp* resp,
196                                              bool is_client,
197                                              tsi_handshaker_result** self) {
198   if (self == nullptr || resp == nullptr) {
199     gpr_log(GPR_ERROR, "Invalid arguments to create_handshaker_result()");
200     return TSI_INVALID_ARGUMENT;
201   }
202   grpc_slice* key = static_cast<grpc_slice*>(resp->result.key_data.arg);
203   GPR_ASSERT(key != nullptr);
204   grpc_slice* identity =
205       static_cast<grpc_slice*>(resp->result.peer_identity.service_account.arg);
206   if (identity == nullptr) {
207     gpr_log(GPR_ERROR, "Invalid service account");
208     return TSI_FAILED_PRECONDITION;
209   }
210   if (GRPC_SLICE_LENGTH(*key) < kAltsAes128GcmRekeyKeyLength) {
211     gpr_log(GPR_ERROR, "Bad key length");
212     return TSI_FAILED_PRECONDITION;
213   }
214   alts_tsi_handshaker_result* result =
215       static_cast<alts_tsi_handshaker_result*>(gpr_zalloc(sizeof(*result)));
216   result->key_data =
217       static_cast<char*>(gpr_zalloc(kAltsAes128GcmRekeyKeyLength));
218   memcpy(result->key_data, GRPC_SLICE_START_PTR(*key),
219          kAltsAes128GcmRekeyKeyLength);
220   result->peer_identity = grpc_slice_to_c_string(*identity);
221   if (!resp->result.has_peer_rpc_versions) {
222     gpr_log(GPR_ERROR, "Peer does not set RPC protocol versions.");
223     return TSI_FAILED_PRECONDITION;
224   }
225   if (!grpc_gcp_rpc_protocol_versions_encode(&resp->result.peer_rpc_versions,
226                                              &result->rpc_versions)) {
227     gpr_log(GPR_ERROR, "Failed to serialize peer's RPC protocol versions.");
228     return TSI_FAILED_PRECONDITION;
229   }
230   result->is_client = is_client;
231   result->base.vtable = &result_vtable;
232   *self = &result->base;
233   return TSI_OK;
234 }
235 
236 /* gRPC provided callback used when gRPC thread model is applied. */
on_handshaker_service_resp_recv(void * arg,grpc_error * error)237 static void on_handshaker_service_resp_recv(void* arg, grpc_error* error) {
238   alts_handshaker_client* client = static_cast<alts_handshaker_client*>(arg);
239   if (client == nullptr) {
240     gpr_log(GPR_ERROR, "ALTS handshaker client is nullptr");
241     return;
242   }
243   alts_handshaker_client_handle_response(client, true);
244 }
245 
246 /* gRPC provided callback used when dedicatd CQ and thread are used.
247  * It serves to safely bring the control back to application. */
on_handshaker_service_resp_recv_dedicated(void * arg,grpc_error * error)248 static void on_handshaker_service_resp_recv_dedicated(void* arg,
249                                                       grpc_error* error) {
250   alts_shared_resource_dedicated* resource =
251       grpc_alts_get_shared_resource_dedicated();
252   grpc_cq_end_op(resource->cq, arg, GRPC_ERROR_NONE,
253                  [](void* done_arg, grpc_cq_completion* storage) {}, nullptr,
254                  &resource->storage);
255 }
256 
handshaker_next(tsi_handshaker * self,const unsigned char * received_bytes,size_t received_bytes_size,const unsigned char ** bytes_to_send,size_t * bytes_to_send_size,tsi_handshaker_result ** result,tsi_handshaker_on_next_done_cb cb,void * user_data)257 static tsi_result handshaker_next(
258     tsi_handshaker* self, const unsigned char* received_bytes,
259     size_t received_bytes_size, const unsigned char** bytes_to_send,
260     size_t* bytes_to_send_size, tsi_handshaker_result** result,
261     tsi_handshaker_on_next_done_cb cb, void* user_data) {
262   if (self == nullptr || cb == nullptr) {
263     gpr_log(GPR_ERROR, "Invalid arguments to handshaker_next()");
264     return TSI_INVALID_ARGUMENT;
265   }
266   if (self->handshake_shutdown) {
267     gpr_log(GPR_ERROR, "TSI handshake shutdown");
268     return TSI_HANDSHAKE_SHUTDOWN;
269   }
270   alts_tsi_handshaker* handshaker =
271       reinterpret_cast<alts_tsi_handshaker*>(self);
272   tsi_result ok = TSI_OK;
273   if (!handshaker->has_created_handshaker_client) {
274     if (handshaker->channel == nullptr) {
275       grpc_alts_shared_resource_dedicated_start(
276           handshaker->handshaker_service_url);
277       handshaker->interested_parties =
278           grpc_alts_get_shared_resource_dedicated()->interested_parties;
279       GPR_ASSERT(handshaker->interested_parties != nullptr);
280     }
281     grpc_iomgr_cb_func grpc_cb = handshaker->channel == nullptr
282                                      ? on_handshaker_service_resp_recv_dedicated
283                                      : on_handshaker_service_resp_recv;
284     grpc_channel* channel =
285         handshaker->channel == nullptr
286             ? grpc_alts_get_shared_resource_dedicated()->channel
287             : handshaker->channel;
288     handshaker->client = alts_grpc_handshaker_client_create(
289         handshaker, channel, handshaker->handshaker_service_url,
290         handshaker->interested_parties, handshaker->options,
291         handshaker->target_name, grpc_cb, cb, user_data,
292         handshaker->client_vtable_for_testing, handshaker->is_client);
293     if (handshaker->client == nullptr) {
294       gpr_log(GPR_ERROR, "Failed to create ALTS handshaker client");
295       return TSI_FAILED_PRECONDITION;
296     }
297     handshaker->has_created_handshaker_client = true;
298   }
299   if (handshaker->channel == nullptr &&
300       handshaker->client_vtable_for_testing == nullptr) {
301     GPR_ASSERT(grpc_cq_begin_op(grpc_alts_get_shared_resource_dedicated()->cq,
302                                 handshaker->client));
303   }
304   grpc_slice slice = (received_bytes == nullptr || received_bytes_size == 0)
305                          ? grpc_empty_slice()
306                          : grpc_slice_from_copied_buffer(
307                                reinterpret_cast<const char*>(received_bytes),
308                                received_bytes_size);
309   if (!handshaker->has_sent_start_message) {
310     ok = handshaker->is_client
311              ? alts_handshaker_client_start_client(handshaker->client)
312              : alts_handshaker_client_start_server(handshaker->client, &slice);
313     handshaker->has_sent_start_message = true;
314   } else {
315     ok = alts_handshaker_client_next(handshaker->client, &slice);
316   }
317   grpc_slice_unref_internal(slice);
318   if (ok != TSI_OK) {
319     gpr_log(GPR_ERROR, "Failed to schedule ALTS handshaker requests");
320     return ok;
321   }
322   return TSI_ASYNC;
323 }
324 
325 /*
326  * This API will be invoked by a non-gRPC application, and an ExecCtx needs
327  * to be explicitly created in order to invoke ALTS handshaker client API's
328  * that assumes the caller is inside gRPC core.
329  */
handshaker_next_dedicated(tsi_handshaker * self,const unsigned char * received_bytes,size_t received_bytes_size,const unsigned char ** bytes_to_send,size_t * bytes_to_send_size,tsi_handshaker_result ** result,tsi_handshaker_on_next_done_cb cb,void * user_data)330 static tsi_result handshaker_next_dedicated(
331     tsi_handshaker* self, const unsigned char* received_bytes,
332     size_t received_bytes_size, const unsigned char** bytes_to_send,
333     size_t* bytes_to_send_size, tsi_handshaker_result** result,
334     tsi_handshaker_on_next_done_cb cb, void* user_data) {
335   grpc_core::ExecCtx exec_ctx;
336   return handshaker_next(self, received_bytes, received_bytes_size,
337                          bytes_to_send, bytes_to_send_size, result, cb,
338                          user_data);
339 }
340 
handshaker_shutdown(tsi_handshaker * self)341 static void handshaker_shutdown(tsi_handshaker* self) {
342   GPR_ASSERT(self != nullptr);
343   if (self->handshake_shutdown) {
344     return;
345   }
346   alts_tsi_handshaker* handshaker =
347       reinterpret_cast<alts_tsi_handshaker*>(self);
348   alts_handshaker_client_shutdown(handshaker->client);
349 }
350 
handshaker_destroy(tsi_handshaker * self)351 static void handshaker_destroy(tsi_handshaker* self) {
352   if (self == nullptr) {
353     return;
354   }
355   alts_tsi_handshaker* handshaker =
356       reinterpret_cast<alts_tsi_handshaker*>(self);
357   alts_handshaker_client_destroy(handshaker->client);
358   grpc_slice_unref_internal(handshaker->target_name);
359   grpc_alts_credentials_options_destroy(handshaker->options);
360   if (handshaker->channel != nullptr) {
361     grpc_channel_destroy(handshaker->channel);
362   }
363   gpr_free(handshaker->handshaker_service_url);
364   gpr_free(handshaker);
365 }
366 
367 static const tsi_handshaker_vtable handshaker_vtable = {
368     nullptr,         nullptr,
369     nullptr,         nullptr,
370     nullptr,         handshaker_destroy,
371     handshaker_next, handshaker_shutdown};
372 
373 static const tsi_handshaker_vtable handshaker_vtable_dedicated = {
374     nullptr,
375     nullptr,
376     nullptr,
377     nullptr,
378     nullptr,
379     handshaker_destroy,
380     handshaker_next_dedicated,
381     handshaker_shutdown};
382 
alts_tsi_handshaker_has_shutdown(alts_tsi_handshaker * handshaker)383 bool alts_tsi_handshaker_has_shutdown(alts_tsi_handshaker* handshaker) {
384   GPR_ASSERT(handshaker != nullptr);
385   return handshaker->base.handshake_shutdown;
386 }
387 
alts_tsi_handshaker_create(const grpc_alts_credentials_options * options,const char * target_name,const char * handshaker_service_url,bool is_client,grpc_pollset_set * interested_parties,tsi_handshaker ** self)388 tsi_result alts_tsi_handshaker_create(
389     const grpc_alts_credentials_options* options, const char* target_name,
390     const char* handshaker_service_url, bool is_client,
391     grpc_pollset_set* interested_parties, tsi_handshaker** self) {
392   if (handshaker_service_url == nullptr || self == nullptr ||
393       options == nullptr || (is_client && target_name == nullptr)) {
394     gpr_log(GPR_ERROR, "Invalid arguments to alts_tsi_handshaker_create()");
395     return TSI_INVALID_ARGUMENT;
396   }
397   alts_tsi_handshaker* handshaker =
398       static_cast<alts_tsi_handshaker*>(gpr_zalloc(sizeof(*handshaker)));
399   bool use_dedicated_cq = interested_parties == nullptr;
400   handshaker->client = nullptr;
401   handshaker->is_client = is_client;
402   handshaker->has_sent_start_message = false;
403   handshaker->target_name = target_name == nullptr
404                                 ? grpc_empty_slice()
405                                 : grpc_slice_from_static_string(target_name);
406   handshaker->interested_parties = interested_parties;
407   handshaker->has_created_handshaker_client = false;
408   handshaker->handshaker_service_url = gpr_strdup(handshaker_service_url);
409   handshaker->options = grpc_alts_credentials_options_copy(options);
410   handshaker->base.vtable =
411       use_dedicated_cq ? &handshaker_vtable_dedicated : &handshaker_vtable;
412   handshaker->channel =
413       use_dedicated_cq
414           ? nullptr
415           : grpc_insecure_channel_create(handshaker->handshaker_service_url,
416                                          nullptr, nullptr);
417   *self = &handshaker->base;
418   return TSI_OK;
419 }
420 
alts_tsi_handshaker_result_set_unused_bytes(tsi_handshaker_result * self,grpc_slice * recv_bytes,size_t bytes_consumed)421 void alts_tsi_handshaker_result_set_unused_bytes(tsi_handshaker_result* self,
422                                                  grpc_slice* recv_bytes,
423                                                  size_t bytes_consumed) {
424   GPR_ASSERT(recv_bytes != nullptr && self != nullptr);
425   if (GRPC_SLICE_LENGTH(*recv_bytes) == bytes_consumed) {
426     return;
427   }
428   alts_tsi_handshaker_result* result =
429       reinterpret_cast<alts_tsi_handshaker_result*>(self);
430   result->unused_bytes_size = GRPC_SLICE_LENGTH(*recv_bytes) - bytes_consumed;
431   result->unused_bytes =
432       static_cast<unsigned char*>(gpr_zalloc(result->unused_bytes_size));
433   memcpy(result->unused_bytes,
434          GRPC_SLICE_START_PTR(*recv_bytes) + bytes_consumed,
435          result->unused_bytes_size);
436 }
437 
438 namespace grpc_core {
439 namespace internal {
440 
alts_tsi_handshaker_get_has_sent_start_message_for_testing(alts_tsi_handshaker * handshaker)441 bool alts_tsi_handshaker_get_has_sent_start_message_for_testing(
442     alts_tsi_handshaker* handshaker) {
443   GPR_ASSERT(handshaker != nullptr);
444   return handshaker->has_sent_start_message;
445 }
446 
alts_tsi_handshaker_set_client_vtable_for_testing(alts_tsi_handshaker * handshaker,alts_handshaker_client_vtable * vtable)447 void alts_tsi_handshaker_set_client_vtable_for_testing(
448     alts_tsi_handshaker* handshaker, alts_handshaker_client_vtable* vtable) {
449   GPR_ASSERT(handshaker != nullptr);
450   handshaker->client_vtable_for_testing = vtable;
451 }
452 
alts_tsi_handshaker_get_is_client_for_testing(alts_tsi_handshaker * handshaker)453 bool alts_tsi_handshaker_get_is_client_for_testing(
454     alts_tsi_handshaker* handshaker) {
455   GPR_ASSERT(handshaker != nullptr);
456   return handshaker->is_client;
457 }
458 
alts_tsi_handshaker_get_client_for_testing(alts_tsi_handshaker * handshaker)459 alts_handshaker_client* alts_tsi_handshaker_get_client_for_testing(
460     alts_tsi_handshaker* handshaker) {
461   return handshaker->client;
462 }
463 
464 }  // namespace internal
465 }  // namespace grpc_core
466