3 * Copyright 2018 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <grpc/support/port_platform.h>
21 #include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
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>
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"
42 /* Main struct for ALTS TSI handshaker. */
43 struct alts_tsi_handshaker {
45 alts_handshaker_client* client;
46 grpc_slice target_name;
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;
57 /* Main struct for ALTS TSI handshaker result. */
58 typedef struct alts_tsi_handshaker_result {
59 tsi_handshaker_result base;
62 unsigned char* unused_bytes;
63 size_t unused_bytes_size;
64 grpc_slice rpc_versions;
66 } alts_tsi_handshaker_result;
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;
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);
81 gpr_log(GPR_ERROR, "Failed to construct tsi peer");
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]);
89 tsi_peer_destruct(peer);
90 gpr_log(GPR_ERROR, "Failed to set tsi peer property");
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]);
99 tsi_peer_destruct(peer);
100 gpr_log(GPR_ERROR, "Failed to set tsi peer property");
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]);
109 tsi_peer_destruct(peer);
110 gpr_log(GPR_ERROR, "Failed to set tsi peer property");
112 GPR_ASSERT(++index == kTsiAltsNumOfPeerProperties);
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) {
121 "Invalid arguments to create_zero_copy_grpc_protector()");
122 return TSI_INVALID_ARGUMENT;
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);
133 gpr_log(GPR_ERROR, "Failed to create zero-copy grpc 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) {
143 "Invalid arguments to handshaker_result_create_frame_protector()");
144 return TSI_INVALID_ARGUMENT;
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);
154 gpr_log(GPR_ERROR, "Failed to create frame protector");
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) {
164 "Invalid arguments to handshaker_result_get_unused_bytes()");
165 return TSI_INVALID_ARGUMENT;
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;
175 static void handshaker_result_destroy(tsi_handshaker_result* self) {
176 if (self == nullptr) {
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);
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};
195 tsi_result alts_tsi_handshaker_result_create(grpc_gcp_HandshakerResp* resp,
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;
202 const grpc_gcp_HandshakerResult* hresult =
203 grpc_gcp_HandshakerResp_result(resp);
204 const grpc_gcp_Identity* identity =
205 grpc_gcp_HandshakerResult_peer_identity(hresult);
206 if (identity == nullptr) {
207 gpr_log(GPR_ERROR, "Invalid identity");
208 return TSI_FAILED_PRECONDITION;
210 upb_strview service_account = grpc_gcp_Identity_service_account(identity);
211 if (service_account.size == 0) {
212 gpr_log(GPR_ERROR, "Invalid service account");
213 return TSI_FAILED_PRECONDITION;
215 upb_strview key_data = grpc_gcp_HandshakerResult_key_data(hresult);
216 if (key_data.size < kAltsAes128GcmRekeyKeyLength) {
217 gpr_log(GPR_ERROR, "Bad key length");
218 return TSI_FAILED_PRECONDITION;
220 const grpc_gcp_RpcProtocolVersions* peer_rpc_version =
221 grpc_gcp_HandshakerResult_peer_rpc_versions(hresult);
222 if (peer_rpc_version == nullptr) {
223 gpr_log(GPR_ERROR, "Peer does not set RPC protocol versions.");
224 return TSI_FAILED_PRECONDITION;
226 alts_tsi_handshaker_result* result =
227 static_cast<alts_tsi_handshaker_result*>(gpr_zalloc(sizeof(*result)));
229 static_cast<char*>(gpr_zalloc(kAltsAes128GcmRekeyKeyLength));
230 memcpy(result->key_data, key_data.data, kAltsAes128GcmRekeyKeyLength);
231 result->peer_identity =
232 static_cast<char*>(gpr_zalloc(service_account.size + 1));
233 memcpy(result->peer_identity, service_account.data, service_account.size);
235 bool serialized = grpc_gcp_rpc_protocol_versions_encode(
236 peer_rpc_version, arena.ptr(), &result->rpc_versions);
238 gpr_log(GPR_ERROR, "Failed to serialize peer's RPC protocol versions.");
239 return TSI_FAILED_PRECONDITION;
241 result->is_client = is_client;
242 result->base.vtable = &result_vtable;
243 *self = &result->base;
247 /* gRPC provided callback used when gRPC thread model is applied. */
248 static void on_handshaker_service_resp_recv(void* arg, grpc_error* error) {
249 alts_handshaker_client* client = static_cast<alts_handshaker_client*>(arg);
250 if (client == nullptr) {
251 gpr_log(GPR_ERROR, "ALTS handshaker client is nullptr");
255 if (error != GRPC_ERROR_NONE) {
257 "ALTS handshaker on_handshaker_service_resp_recv error: %s",
258 grpc_error_string(error));
261 alts_handshaker_client_handle_response(client, success);
264 /* gRPC provided callback used when dedicatd CQ and thread are used.
265 * It serves to safely bring the control back to application. */
266 static void on_handshaker_service_resp_recv_dedicated(void* arg,
268 alts_shared_resource_dedicated* resource =
269 grpc_alts_get_shared_resource_dedicated();
270 grpc_cq_end_op(resource->cq, arg, GRPC_ERROR_NONE,
271 [](void* done_arg, grpc_cq_completion* storage) {}, nullptr,
275 static tsi_result handshaker_next(
276 tsi_handshaker* self, const unsigned char* received_bytes,
277 size_t received_bytes_size, const unsigned char** bytes_to_send,
278 size_t* bytes_to_send_size, tsi_handshaker_result** result,
279 tsi_handshaker_on_next_done_cb cb, void* user_data) {
280 if (self == nullptr || cb == nullptr) {
281 gpr_log(GPR_ERROR, "Invalid arguments to handshaker_next()");
282 return TSI_INVALID_ARGUMENT;
284 if (self->handshake_shutdown) {
285 gpr_log(GPR_ERROR, "TSI handshake shutdown");
286 return TSI_HANDSHAKE_SHUTDOWN;
288 alts_tsi_handshaker* handshaker =
289 reinterpret_cast<alts_tsi_handshaker*>(self);
290 tsi_result ok = TSI_OK;
291 if (!handshaker->has_created_handshaker_client) {
292 if (handshaker->channel == nullptr) {
293 grpc_alts_shared_resource_dedicated_start(
294 handshaker->handshaker_service_url);
295 handshaker->interested_parties =
296 grpc_alts_get_shared_resource_dedicated()->interested_parties;
297 GPR_ASSERT(handshaker->interested_parties != nullptr);
299 grpc_iomgr_cb_func grpc_cb = handshaker->channel == nullptr
300 ? on_handshaker_service_resp_recv_dedicated
301 : on_handshaker_service_resp_recv;
302 grpc_channel* channel =
303 handshaker->channel == nullptr
304 ? grpc_alts_get_shared_resource_dedicated()->channel
305 : handshaker->channel;
306 handshaker->client = alts_grpc_handshaker_client_create(
307 handshaker, channel, handshaker->handshaker_service_url,
308 handshaker->interested_parties, handshaker->options,
309 handshaker->target_name, grpc_cb, cb, user_data,
310 handshaker->client_vtable_for_testing, handshaker->is_client);
311 if (handshaker->client == nullptr) {
312 gpr_log(GPR_ERROR, "Failed to create ALTS handshaker client");
313 return TSI_FAILED_PRECONDITION;
315 handshaker->has_created_handshaker_client = true;
317 if (handshaker->channel == nullptr &&
318 handshaker->client_vtable_for_testing == nullptr) {
319 GPR_ASSERT(grpc_cq_begin_op(grpc_alts_get_shared_resource_dedicated()->cq,
320 handshaker->client));
322 grpc_slice slice = (received_bytes == nullptr || received_bytes_size == 0)
324 : grpc_slice_from_copied_buffer(
325 reinterpret_cast<const char*>(received_bytes),
326 received_bytes_size);
327 if (!handshaker->has_sent_start_message) {
328 ok = handshaker->is_client
329 ? alts_handshaker_client_start_client(handshaker->client)
330 : alts_handshaker_client_start_server(handshaker->client, &slice);
331 handshaker->has_sent_start_message = true;
333 ok = alts_handshaker_client_next(handshaker->client, &slice);
335 grpc_slice_unref_internal(slice);
337 gpr_log(GPR_ERROR, "Failed to schedule ALTS handshaker requests");
344 * This API will be invoked by a non-gRPC application, and an ExecCtx needs
345 * to be explicitly created in order to invoke ALTS handshaker client API's
346 * that assumes the caller is inside gRPC core.
348 static tsi_result handshaker_next_dedicated(
349 tsi_handshaker* self, const unsigned char* received_bytes,
350 size_t received_bytes_size, const unsigned char** bytes_to_send,
351 size_t* bytes_to_send_size, tsi_handshaker_result** result,
352 tsi_handshaker_on_next_done_cb cb, void* user_data) {
353 grpc_core::ExecCtx exec_ctx;
354 return handshaker_next(self, received_bytes, received_bytes_size,
355 bytes_to_send, bytes_to_send_size, result, cb,
359 static void handshaker_shutdown(tsi_handshaker* self) {
360 GPR_ASSERT(self != nullptr);
361 if (self->handshake_shutdown) {
364 alts_tsi_handshaker* handshaker =
365 reinterpret_cast<alts_tsi_handshaker*>(self);
366 alts_handshaker_client_shutdown(handshaker->client);
369 static void handshaker_destroy(tsi_handshaker* self) {
370 if (self == nullptr) {
373 alts_tsi_handshaker* handshaker =
374 reinterpret_cast<alts_tsi_handshaker*>(self);
375 alts_handshaker_client_destroy(handshaker->client);
376 grpc_slice_unref_internal(handshaker->target_name);
377 grpc_alts_credentials_options_destroy(handshaker->options);
378 if (handshaker->channel != nullptr) {
379 grpc_channel_destroy(handshaker->channel);
381 gpr_free(handshaker->handshaker_service_url);
382 gpr_free(handshaker);
385 static const tsi_handshaker_vtable handshaker_vtable = {
388 nullptr, handshaker_destroy,
389 handshaker_next, handshaker_shutdown};
391 static const tsi_handshaker_vtable handshaker_vtable_dedicated = {
398 handshaker_next_dedicated,
399 handshaker_shutdown};
401 bool alts_tsi_handshaker_has_shutdown(alts_tsi_handshaker* handshaker) {
402 GPR_ASSERT(handshaker != nullptr);
403 return handshaker->base.handshake_shutdown;
406 tsi_result alts_tsi_handshaker_create(
407 const grpc_alts_credentials_options* options, const char* target_name,
408 const char* handshaker_service_url, bool is_client,
409 grpc_pollset_set* interested_parties, tsi_handshaker** self) {
410 if (handshaker_service_url == nullptr || self == nullptr ||
411 options == nullptr || (is_client && target_name == nullptr)) {
412 gpr_log(GPR_ERROR, "Invalid arguments to alts_tsi_handshaker_create()");
413 return TSI_INVALID_ARGUMENT;
415 alts_tsi_handshaker* handshaker =
416 static_cast<alts_tsi_handshaker*>(gpr_zalloc(sizeof(*handshaker)));
417 bool use_dedicated_cq = interested_parties == nullptr;
418 handshaker->client = nullptr;
419 handshaker->is_client = is_client;
420 handshaker->has_sent_start_message = false;
421 handshaker->target_name = target_name == nullptr
423 : grpc_slice_from_static_string(target_name);
424 handshaker->interested_parties = interested_parties;
425 handshaker->has_created_handshaker_client = false;
426 handshaker->handshaker_service_url = gpr_strdup(handshaker_service_url);
427 handshaker->options = grpc_alts_credentials_options_copy(options);
428 handshaker->base.vtable =
429 use_dedicated_cq ? &handshaker_vtable_dedicated : &handshaker_vtable;
430 handshaker->channel =
433 : grpc_insecure_channel_create(handshaker->handshaker_service_url,
435 *self = &handshaker->base;
439 void alts_tsi_handshaker_result_set_unused_bytes(tsi_handshaker_result* self,
440 grpc_slice* recv_bytes,
441 size_t bytes_consumed) {
442 GPR_ASSERT(recv_bytes != nullptr && self != nullptr);
443 if (GRPC_SLICE_LENGTH(*recv_bytes) == bytes_consumed) {
446 alts_tsi_handshaker_result* result =
447 reinterpret_cast<alts_tsi_handshaker_result*>(self);
448 result->unused_bytes_size = GRPC_SLICE_LENGTH(*recv_bytes) - bytes_consumed;
449 result->unused_bytes =
450 static_cast<unsigned char*>(gpr_zalloc(result->unused_bytes_size));
451 memcpy(result->unused_bytes,
452 GRPC_SLICE_START_PTR(*recv_bytes) + bytes_consumed,
453 result->unused_bytes_size);
456 namespace grpc_core {
459 bool alts_tsi_handshaker_get_has_sent_start_message_for_testing(
460 alts_tsi_handshaker* handshaker) {
461 GPR_ASSERT(handshaker != nullptr);
462 return handshaker->has_sent_start_message;
465 void alts_tsi_handshaker_set_client_vtable_for_testing(
466 alts_tsi_handshaker* handshaker, alts_handshaker_client_vtable* vtable) {
467 GPR_ASSERT(handshaker != nullptr);
468 handshaker->client_vtable_for_testing = vtable;
471 bool alts_tsi_handshaker_get_is_client_for_testing(
472 alts_tsi_handshaker* handshaker) {
473 GPR_ASSERT(handshaker != nullptr);
474 return handshaker->is_client;
477 alts_handshaker_client* alts_tsi_handshaker_get_client_for_testing(
478 alts_tsi_handshaker* handshaker) {
479 return handshaker->client;
482 } // namespace internal
483 } // namespace grpc_core