• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_handshaker_client.h"
22 
23 #include <grpc/byte_buffer.h>
24 #include <grpc/support/alloc.h>
25 #include <grpc/support/log.h>
26 
27 #include "src/core/lib/slice/slice_internal.h"
28 #include "src/core/tsi/alts/handshaker/alts_handshaker_service_api.h"
29 
30 const int kHandshakerClientOpNum = 4;
31 
32 typedef struct alts_grpc_handshaker_client {
33   alts_handshaker_client base;
34   grpc_call* call;
35   alts_grpc_caller grpc_caller;
36 } alts_grpc_handshaker_client;
37 
grpc_start_batch(grpc_call * call,const grpc_op * ops,size_t nops,void * tag)38 static grpc_call_error grpc_start_batch(grpc_call* call, const grpc_op* ops,
39                                         size_t nops, void* tag) {
40   return grpc_call_start_batch(call, ops, nops, tag, nullptr);
41 }
42 
43 /**
44  * Populate grpc operation data with the fields of ALTS TSI event and make a
45  * grpc call.
46  */
make_grpc_call(alts_handshaker_client * client,alts_tsi_event * event,bool is_start)47 static tsi_result make_grpc_call(alts_handshaker_client* client,
48                                  alts_tsi_event* event, bool is_start) {
49   GPR_ASSERT(client != nullptr && event != nullptr);
50   alts_grpc_handshaker_client* grpc_client =
51       reinterpret_cast<alts_grpc_handshaker_client*>(client);
52   grpc_op ops[kHandshakerClientOpNum];
53   memset(ops, 0, sizeof(ops));
54   grpc_op* op = ops;
55   if (is_start) {
56     op->op = GRPC_OP_SEND_INITIAL_METADATA;
57     op->data.send_initial_metadata.count = 0;
58     op++;
59     GPR_ASSERT(op - ops <= kHandshakerClientOpNum);
60     op->op = GRPC_OP_RECV_INITIAL_METADATA;
61     op->data.recv_initial_metadata.recv_initial_metadata =
62         &event->initial_metadata;
63     op++;
64     GPR_ASSERT(op - ops <= kHandshakerClientOpNum);
65   }
66   op->op = GRPC_OP_SEND_MESSAGE;
67   op->data.send_message.send_message = event->send_buffer;
68   op++;
69   GPR_ASSERT(op - ops <= kHandshakerClientOpNum);
70   op->op = GRPC_OP_RECV_MESSAGE;
71   op->data.recv_message.recv_message = &event->recv_buffer;
72   op++;
73   GPR_ASSERT(op - ops <= kHandshakerClientOpNum);
74   GPR_ASSERT(grpc_client->grpc_caller != nullptr);
75   if (grpc_client->grpc_caller(grpc_client->call, ops,
76                                static_cast<size_t>(op - ops),
77                                (void*)event) != GRPC_CALL_OK) {
78     gpr_log(GPR_ERROR, "Start batch operation failed");
79     return TSI_INTERNAL_ERROR;
80   }
81   return TSI_OK;
82 }
83 
84 /* Create and populate a client_start handshaker request, then serialize it. */
get_serialized_start_client(alts_tsi_event * event)85 static grpc_byte_buffer* get_serialized_start_client(alts_tsi_event* event) {
86   bool ok = true;
87   grpc_gcp_handshaker_req* req =
88       grpc_gcp_handshaker_req_create(CLIENT_START_REQ);
89   ok &= grpc_gcp_handshaker_req_set_handshake_protocol(
90       req, grpc_gcp_HandshakeProtocol_ALTS);
91   ok &= grpc_gcp_handshaker_req_add_application_protocol(
92       req, ALTS_APPLICATION_PROTOCOL);
93   ok &= grpc_gcp_handshaker_req_add_record_protocol(req, ALTS_RECORD_PROTOCOL);
94   grpc_gcp_rpc_protocol_versions* versions = &event->options->rpc_versions;
95   ok &= grpc_gcp_handshaker_req_set_rpc_versions(
96       req, versions->max_rpc_version.major, versions->max_rpc_version.minor,
97       versions->min_rpc_version.major, versions->min_rpc_version.minor);
98   char* target_name = grpc_slice_to_c_string(event->target_name);
99   ok &= grpc_gcp_handshaker_req_set_target_name(req, target_name);
100   target_service_account* ptr =
101       (reinterpret_cast<grpc_alts_credentials_client_options*>(event->options))
102           ->target_account_list_head;
103   while (ptr != nullptr) {
104     grpc_gcp_handshaker_req_add_target_identity_service_account(req, ptr->data);
105     ptr = ptr->next;
106   }
107   grpc_slice slice;
108   ok &= grpc_gcp_handshaker_req_encode(req, &slice);
109   grpc_byte_buffer* buffer = nullptr;
110   if (ok) {
111     buffer = grpc_raw_byte_buffer_create(&slice, 1 /* number of slices */);
112   }
113   grpc_slice_unref_internal(slice);
114   gpr_free(target_name);
115   grpc_gcp_handshaker_req_destroy(req);
116   return buffer;
117 }
118 
handshaker_client_start_client(alts_handshaker_client * client,alts_tsi_event * event)119 static tsi_result handshaker_client_start_client(alts_handshaker_client* client,
120                                                  alts_tsi_event* event) {
121   if (client == nullptr || event == nullptr) {
122     gpr_log(GPR_ERROR, "Invalid arguments to handshaker_client_start_client()");
123     return TSI_INVALID_ARGUMENT;
124   }
125   grpc_byte_buffer* buffer = get_serialized_start_client(event);
126   if (buffer == nullptr) {
127     gpr_log(GPR_ERROR, "get_serialized_start_client() failed");
128     return TSI_INTERNAL_ERROR;
129   }
130   event->send_buffer = buffer;
131   tsi_result result = make_grpc_call(client, event, true /* is_start */);
132   if (result != TSI_OK) {
133     gpr_log(GPR_ERROR, "make_grpc_call() failed");
134   }
135   return result;
136 }
137 
138 /* Create and populate a start_server handshaker request, then serialize it. */
get_serialized_start_server(alts_tsi_event * event,grpc_slice * bytes_received)139 static grpc_byte_buffer* get_serialized_start_server(
140     alts_tsi_event* event, grpc_slice* bytes_received) {
141   GPR_ASSERT(bytes_received != nullptr);
142   grpc_gcp_handshaker_req* req =
143       grpc_gcp_handshaker_req_create(SERVER_START_REQ);
144   bool ok = grpc_gcp_handshaker_req_add_application_protocol(
145       req, ALTS_APPLICATION_PROTOCOL);
146   ok &= grpc_gcp_handshaker_req_param_add_record_protocol(
147       req, grpc_gcp_HandshakeProtocol_ALTS, ALTS_RECORD_PROTOCOL);
148   ok &= grpc_gcp_handshaker_req_set_in_bytes(
149       req, reinterpret_cast<const char*> GRPC_SLICE_START_PTR(*bytes_received),
150       GRPC_SLICE_LENGTH(*bytes_received));
151   grpc_gcp_rpc_protocol_versions* versions = &event->options->rpc_versions;
152   ok &= grpc_gcp_handshaker_req_set_rpc_versions(
153       req, versions->max_rpc_version.major, versions->max_rpc_version.minor,
154       versions->min_rpc_version.major, versions->min_rpc_version.minor);
155   grpc_slice req_slice;
156   ok &= grpc_gcp_handshaker_req_encode(req, &req_slice);
157   grpc_byte_buffer* buffer = nullptr;
158   if (ok) {
159     buffer = grpc_raw_byte_buffer_create(&req_slice, 1 /* number of slices */);
160   }
161   grpc_slice_unref_internal(req_slice);
162   grpc_gcp_handshaker_req_destroy(req);
163   return buffer;
164 }
165 
handshaker_client_start_server(alts_handshaker_client * client,alts_tsi_event * event,grpc_slice * bytes_received)166 static tsi_result handshaker_client_start_server(alts_handshaker_client* client,
167                                                  alts_tsi_event* event,
168                                                  grpc_slice* bytes_received) {
169   if (client == nullptr || event == nullptr || bytes_received == nullptr) {
170     gpr_log(GPR_ERROR, "Invalid arguments to handshaker_client_start_server()");
171     return TSI_INVALID_ARGUMENT;
172   }
173   grpc_byte_buffer* buffer = get_serialized_start_server(event, bytes_received);
174   if (buffer == nullptr) {
175     gpr_log(GPR_ERROR, "get_serialized_start_server() failed");
176     return TSI_INTERNAL_ERROR;
177   }
178   event->send_buffer = buffer;
179   tsi_result result = make_grpc_call(client, event, true /* is_start */);
180   if (result != TSI_OK) {
181     gpr_log(GPR_ERROR, "make_grpc_call() failed");
182   }
183   return result;
184 }
185 
186 /* Create and populate a next handshaker request, then serialize it. */
get_serialized_next(grpc_slice * bytes_received)187 static grpc_byte_buffer* get_serialized_next(grpc_slice* bytes_received) {
188   GPR_ASSERT(bytes_received != nullptr);
189   grpc_gcp_handshaker_req* req = grpc_gcp_handshaker_req_create(NEXT_REQ);
190   bool ok = grpc_gcp_handshaker_req_set_in_bytes(
191       req, reinterpret_cast<const char*> GRPC_SLICE_START_PTR(*bytes_received),
192       GRPC_SLICE_LENGTH(*bytes_received));
193   grpc_slice req_slice;
194   ok &= grpc_gcp_handshaker_req_encode(req, &req_slice);
195   grpc_byte_buffer* buffer = nullptr;
196   if (ok) {
197     buffer = grpc_raw_byte_buffer_create(&req_slice, 1 /* number of slices */);
198   }
199   grpc_slice_unref_internal(req_slice);
200   grpc_gcp_handshaker_req_destroy(req);
201   return buffer;
202 }
203 
handshaker_client_next(alts_handshaker_client * client,alts_tsi_event * event,grpc_slice * bytes_received)204 static tsi_result handshaker_client_next(alts_handshaker_client* client,
205                                          alts_tsi_event* event,
206                                          grpc_slice* bytes_received) {
207   if (client == nullptr || event == nullptr || bytes_received == nullptr) {
208     gpr_log(GPR_ERROR, "Invalid arguments to handshaker_client_next()");
209     return TSI_INVALID_ARGUMENT;
210   }
211   grpc_byte_buffer* buffer = get_serialized_next(bytes_received);
212   if (buffer == nullptr) {
213     gpr_log(GPR_ERROR, "get_serialized_next() failed");
214     return TSI_INTERNAL_ERROR;
215   }
216   event->send_buffer = buffer;
217   tsi_result result = make_grpc_call(client, event, false /* is_start */);
218   if (result != TSI_OK) {
219     gpr_log(GPR_ERROR, "make_grpc_call() failed");
220   }
221   return result;
222 }
223 
handshaker_client_shutdown(alts_handshaker_client * client)224 static void handshaker_client_shutdown(alts_handshaker_client* client) {
225   GPR_ASSERT(client != nullptr);
226   alts_grpc_handshaker_client* grpc_client =
227       reinterpret_cast<alts_grpc_handshaker_client*>(client);
228   GPR_ASSERT(grpc_call_cancel(grpc_client->call, nullptr) == GRPC_CALL_OK);
229 }
230 
handshaker_client_destruct(alts_handshaker_client * client)231 static void handshaker_client_destruct(alts_handshaker_client* client) {
232   if (client == nullptr) {
233     return;
234   }
235   alts_grpc_handshaker_client* grpc_client =
236       reinterpret_cast<alts_grpc_handshaker_client*>(client);
237   grpc_call_unref(grpc_client->call);
238 }
239 
240 static const alts_handshaker_client_vtable vtable = {
241     handshaker_client_start_client, handshaker_client_start_server,
242     handshaker_client_next, handshaker_client_shutdown,
243     handshaker_client_destruct};
244 
alts_grpc_handshaker_client_create(grpc_channel * channel,grpc_completion_queue * queue,const char * handshaker_service_url)245 alts_handshaker_client* alts_grpc_handshaker_client_create(
246     grpc_channel* channel, grpc_completion_queue* queue,
247     const char* handshaker_service_url) {
248   if (channel == nullptr || queue == nullptr ||
249       handshaker_service_url == nullptr) {
250     gpr_log(GPR_ERROR, "Invalid arguments to alts_handshaker_client_create()");
251     return nullptr;
252   }
253   alts_grpc_handshaker_client* client =
254       static_cast<alts_grpc_handshaker_client*>(gpr_zalloc(sizeof(*client)));
255   client->grpc_caller = grpc_start_batch;
256   grpc_slice slice = grpc_slice_from_copied_string(handshaker_service_url);
257   client->call = grpc_channel_create_call(
258       channel, nullptr, GRPC_PROPAGATE_DEFAULTS, queue,
259       grpc_slice_from_static_string(ALTS_SERVICE_METHOD), &slice,
260       gpr_inf_future(GPR_CLOCK_REALTIME), nullptr);
261   client->base.vtable = &vtable;
262   grpc_slice_unref_internal(slice);
263   return &client->base;
264 }
265 
266 namespace grpc_core {
267 namespace internal {
268 
alts_handshaker_client_set_grpc_caller_for_testing(alts_handshaker_client * client,alts_grpc_caller caller)269 void alts_handshaker_client_set_grpc_caller_for_testing(
270     alts_handshaker_client* client, alts_grpc_caller caller) {
271   GPR_ASSERT(client != nullptr && caller != nullptr);
272   alts_grpc_handshaker_client* grpc_client =
273       reinterpret_cast<alts_grpc_handshaker_client*>(client);
274   grpc_client->grpc_caller = caller;
275 }
276 
277 }  // namespace internal
278 }  // namespace grpc_core
279 
alts_handshaker_client_start_client(alts_handshaker_client * client,alts_tsi_event * event)280 tsi_result alts_handshaker_client_start_client(alts_handshaker_client* client,
281                                                alts_tsi_event* event) {
282   if (client != nullptr && client->vtable != nullptr &&
283       client->vtable->client_start != nullptr) {
284     return client->vtable->client_start(client, event);
285   }
286   gpr_log(GPR_ERROR,
287           "client or client->vtable has not been initialized properly");
288   return TSI_INVALID_ARGUMENT;
289 }
290 
alts_handshaker_client_start_server(alts_handshaker_client * client,alts_tsi_event * event,grpc_slice * bytes_received)291 tsi_result alts_handshaker_client_start_server(alts_handshaker_client* client,
292                                                alts_tsi_event* event,
293                                                grpc_slice* bytes_received) {
294   if (client != nullptr && client->vtable != nullptr &&
295       client->vtable->server_start != nullptr) {
296     return client->vtable->server_start(client, event, bytes_received);
297   }
298   gpr_log(GPR_ERROR,
299           "client or client->vtable has not been initialized properly");
300   return TSI_INVALID_ARGUMENT;
301 }
302 
alts_handshaker_client_next(alts_handshaker_client * client,alts_tsi_event * event,grpc_slice * bytes_received)303 tsi_result alts_handshaker_client_next(alts_handshaker_client* client,
304                                        alts_tsi_event* event,
305                                        grpc_slice* bytes_received) {
306   if (client != nullptr && client->vtable != nullptr &&
307       client->vtable->next != nullptr) {
308     return client->vtable->next(client, event, bytes_received);
309   }
310   gpr_log(GPR_ERROR,
311           "client or client->vtable has not been initialized properly");
312   return TSI_INVALID_ARGUMENT;
313 }
314 
alts_handshaker_client_shutdown(alts_handshaker_client * client)315 void alts_handshaker_client_shutdown(alts_handshaker_client* client) {
316   if (client != nullptr && client->vtable != nullptr &&
317       client->vtable->shutdown != nullptr) {
318     client->vtable->shutdown(client);
319   }
320 }
321 
alts_handshaker_client_destroy(alts_handshaker_client * client)322 void alts_handshaker_client_destroy(alts_handshaker_client* client) {
323   if (client != nullptr) {
324     if (client->vtable != nullptr && client->vtable->destruct != nullptr) {
325       client->vtable->destruct(client);
326     }
327     gpr_free(client);
328   }
329 }
330