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/sync.h> 30 #include <grpc/support/thd_id.h> 31 32 #include "src/core/lib/gpr/host_port.h" 33 #include "src/core/lib/gprpp/thd.h" 34 #include "src/core/lib/slice/slice_internal.h" 35 #include "src/core/tsi/alts/frame_protector/alts_frame_protector.h" 36 #include "src/core/tsi/alts/handshaker/alts_handshaker_client.h" 37 #include "src/core/tsi/alts/handshaker/alts_tsi_utils.h" 38 #include "src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h" 39 #include "src/core/tsi/alts_transport_security.h" 40 41 #define TSI_ALTS_INITIAL_BUFFER_SIZE 256 42 43 static alts_shared_resource* kSharedResource = alts_get_shared_resource(); 44 45 /* Main struct for ALTS TSI handshaker. */ 46 typedef struct alts_tsi_handshaker { 47 tsi_handshaker base; 48 alts_handshaker_client* client; 49 grpc_slice recv_bytes; 50 grpc_slice target_name; 51 unsigned char* buffer; 52 size_t buffer_size; 53 bool is_client; 54 bool has_sent_start_message; 55 grpc_alts_credentials_options* options; 56 } alts_tsi_handshaker; 57 58 /* Main struct for ALTS TSI handshaker result. */ 59 typedef struct alts_tsi_handshaker_result { 60 tsi_handshaker_result base; 61 char* peer_identity; 62 char* key_data; 63 unsigned char* unused_bytes; 64 size_t unused_bytes_size; 65 grpc_slice rpc_versions; 66 bool is_client; 67 } alts_tsi_handshaker_result; 68 69 static tsi_result handshaker_result_extract_peer( 70 const tsi_handshaker_result* self, tsi_peer* peer) { 71 if (self == nullptr || peer == nullptr) { 72 gpr_log(GPR_ERROR, "Invalid argument to handshaker_result_extract_peer()"); 73 return TSI_INVALID_ARGUMENT; 74 } 75 alts_tsi_handshaker_result* result = 76 reinterpret_cast<alts_tsi_handshaker_result*>( 77 const_cast<tsi_handshaker_result*>(self)); 78 GPR_ASSERT(kTsiAltsNumOfPeerProperties == 3); 79 tsi_result ok = tsi_construct_peer(kTsiAltsNumOfPeerProperties, peer); 80 int index = 0; 81 if (ok != TSI_OK) { 82 gpr_log(GPR_ERROR, "Failed to construct tsi peer"); 83 return ok; 84 } 85 GPR_ASSERT(&peer->properties[index] != nullptr); 86 ok = tsi_construct_string_peer_property_from_cstring( 87 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_ALTS_CERTIFICATE_TYPE, 88 &peer->properties[index]); 89 if (ok != TSI_OK) { 90 tsi_peer_destruct(peer); 91 gpr_log(GPR_ERROR, "Failed to set tsi peer property"); 92 return ok; 93 } 94 index++; 95 GPR_ASSERT(&peer->properties[index] != nullptr); 96 ok = tsi_construct_string_peer_property_from_cstring( 97 TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY, result->peer_identity, 98 &peer->properties[index]); 99 if (ok != TSI_OK) { 100 tsi_peer_destruct(peer); 101 gpr_log(GPR_ERROR, "Failed to set tsi peer property"); 102 } 103 index++; 104 GPR_ASSERT(&peer->properties[index] != nullptr); 105 ok = tsi_construct_string_peer_property( 106 TSI_ALTS_RPC_VERSIONS, 107 reinterpret_cast<char*>(GRPC_SLICE_START_PTR(result->rpc_versions)), 108 GRPC_SLICE_LENGTH(result->rpc_versions), &peer->properties[2]); 109 if (ok != TSI_OK) { 110 tsi_peer_destruct(peer); 111 gpr_log(GPR_ERROR, "Failed to set tsi peer property"); 112 } 113 GPR_ASSERT(++index == kTsiAltsNumOfPeerProperties); 114 return ok; 115 } 116 117 static tsi_result handshaker_result_create_zero_copy_grpc_protector( 118 const tsi_handshaker_result* self, size_t* max_output_protected_frame_size, 119 tsi_zero_copy_grpc_protector** protector) { 120 if (self == nullptr || protector == nullptr) { 121 gpr_log(GPR_ERROR, 122 "Invalid arguments to create_zero_copy_grpc_protector()"); 123 return TSI_INVALID_ARGUMENT; 124 } 125 alts_tsi_handshaker_result* result = 126 reinterpret_cast<alts_tsi_handshaker_result*>( 127 const_cast<tsi_handshaker_result*>(self)); 128 tsi_result ok = alts_zero_copy_grpc_protector_create( 129 reinterpret_cast<const uint8_t*>(result->key_data), 130 kAltsAes128GcmRekeyKeyLength, /*is_rekey=*/true, result->is_client, 131 /*is_integrity_only=*/false, /*enable_extra_copy=*/false, 132 max_output_protected_frame_size, protector); 133 if (ok != TSI_OK) { 134 gpr_log(GPR_ERROR, "Failed to create zero-copy grpc protector"); 135 } 136 return ok; 137 } 138 139 static tsi_result handshaker_result_create_frame_protector( 140 const tsi_handshaker_result* self, size_t* max_output_protected_frame_size, 141 tsi_frame_protector** protector) { 142 if (self == nullptr || protector == nullptr) { 143 gpr_log(GPR_ERROR, 144 "Invalid arguments to handshaker_result_create_frame_protector()"); 145 return TSI_INVALID_ARGUMENT; 146 } 147 alts_tsi_handshaker_result* result = 148 reinterpret_cast<alts_tsi_handshaker_result*>( 149 const_cast<tsi_handshaker_result*>(self)); 150 tsi_result ok = alts_create_frame_protector( 151 reinterpret_cast<const uint8_t*>(result->key_data), 152 kAltsAes128GcmRekeyKeyLength, result->is_client, /*is_rekey=*/true, 153 max_output_protected_frame_size, protector); 154 if (ok != TSI_OK) { 155 gpr_log(GPR_ERROR, "Failed to create frame protector"); 156 } 157 return ok; 158 } 159 160 static tsi_result handshaker_result_get_unused_bytes( 161 const tsi_handshaker_result* self, const unsigned char** bytes, 162 size_t* bytes_size) { 163 if (self == nullptr || bytes == nullptr || bytes_size == nullptr) { 164 gpr_log(GPR_ERROR, 165 "Invalid arguments to handshaker_result_get_unused_bytes()"); 166 return TSI_INVALID_ARGUMENT; 167 } 168 alts_tsi_handshaker_result* result = 169 reinterpret_cast<alts_tsi_handshaker_result*>( 170 const_cast<tsi_handshaker_result*>(self)); 171 *bytes = result->unused_bytes; 172 *bytes_size = result->unused_bytes_size; 173 return TSI_OK; 174 } 175 176 static void handshaker_result_destroy(tsi_handshaker_result* self) { 177 if (self == nullptr) { 178 return; 179 } 180 alts_tsi_handshaker_result* result = 181 reinterpret_cast<alts_tsi_handshaker_result*>( 182 const_cast<tsi_handshaker_result*>(self)); 183 gpr_free(result->peer_identity); 184 gpr_free(result->key_data); 185 gpr_free(result->unused_bytes); 186 grpc_slice_unref_internal(result->rpc_versions); 187 gpr_free(result); 188 } 189 190 static const tsi_handshaker_result_vtable result_vtable = { 191 handshaker_result_extract_peer, 192 handshaker_result_create_zero_copy_grpc_protector, 193 handshaker_result_create_frame_protector, 194 handshaker_result_get_unused_bytes, handshaker_result_destroy}; 195 196 static tsi_result create_handshaker_result(grpc_gcp_handshaker_resp* resp, 197 bool is_client, 198 tsi_handshaker_result** self) { 199 if (self == nullptr || resp == nullptr) { 200 gpr_log(GPR_ERROR, "Invalid arguments to create_handshaker_result()"); 201 return TSI_INVALID_ARGUMENT; 202 } 203 grpc_slice* key = static_cast<grpc_slice*>(resp->result.key_data.arg); 204 GPR_ASSERT(key != nullptr); 205 grpc_slice* identity = 206 static_cast<grpc_slice*>(resp->result.peer_identity.service_account.arg); 207 if (identity == nullptr) { 208 gpr_log(GPR_ERROR, "Invalid service account"); 209 return TSI_FAILED_PRECONDITION; 210 } 211 if (GRPC_SLICE_LENGTH(*key) < kAltsAes128GcmRekeyKeyLength) { 212 gpr_log(GPR_ERROR, "Bad key length"); 213 return TSI_FAILED_PRECONDITION; 214 } 215 alts_tsi_handshaker_result* result = 216 static_cast<alts_tsi_handshaker_result*>(gpr_zalloc(sizeof(*result))); 217 result->key_data = 218 static_cast<char*>(gpr_zalloc(kAltsAes128GcmRekeyKeyLength)); 219 memcpy(result->key_data, GRPC_SLICE_START_PTR(*key), 220 kAltsAes128GcmRekeyKeyLength); 221 result->peer_identity = grpc_slice_to_c_string(*identity); 222 if (!resp->result.has_peer_rpc_versions) { 223 gpr_log(GPR_ERROR, "Peer does not set RPC protocol versions."); 224 return TSI_FAILED_PRECONDITION; 225 } 226 if (!grpc_gcp_rpc_protocol_versions_encode(&resp->result.peer_rpc_versions, 227 &result->rpc_versions)) { 228 gpr_log(GPR_ERROR, "Failed to serialize peer's RPC protocol versions."); 229 return TSI_FAILED_PRECONDITION; 230 } 231 result->is_client = is_client; 232 result->base.vtable = &result_vtable; 233 *self = &result->base; 234 return TSI_OK; 235 } 236 237 static tsi_result handshaker_next( 238 tsi_handshaker* self, const unsigned char* received_bytes, 239 size_t received_bytes_size, const unsigned char** bytes_to_send, 240 size_t* bytes_to_send_size, tsi_handshaker_result** result, 241 tsi_handshaker_on_next_done_cb cb, void* user_data) { 242 if (self == nullptr || cb == nullptr) { 243 gpr_log(GPR_ERROR, "Invalid arguments to handshaker_next()"); 244 return TSI_INVALID_ARGUMENT; 245 } 246 if (self->handshake_shutdown) { 247 gpr_log(GPR_ERROR, "TSI handshake shutdown"); 248 return TSI_HANDSHAKE_SHUTDOWN; 249 } 250 alts_tsi_handshaker* handshaker = 251 reinterpret_cast<alts_tsi_handshaker*>(self); 252 tsi_result ok = TSI_OK; 253 alts_tsi_event* event = nullptr; 254 ok = alts_tsi_event_create(handshaker, cb, user_data, handshaker->options, 255 handshaker->target_name, &event); 256 if (ok != TSI_OK) { 257 gpr_log(GPR_ERROR, "Failed to create ALTS TSI event"); 258 return ok; 259 } 260 grpc_slice slice = (received_bytes == nullptr || received_bytes_size == 0) 261 ? grpc_empty_slice() 262 : grpc_slice_from_copied_buffer( 263 reinterpret_cast<const char*>(received_bytes), 264 received_bytes_size); 265 if (!handshaker->has_sent_start_message) { 266 ok = handshaker->is_client 267 ? alts_handshaker_client_start_client(handshaker->client, event) 268 : alts_handshaker_client_start_server(handshaker->client, event, 269 &slice); 270 handshaker->has_sent_start_message = true; 271 } else { 272 if (!GRPC_SLICE_IS_EMPTY(handshaker->recv_bytes)) { 273 grpc_slice_unref_internal(handshaker->recv_bytes); 274 } 275 handshaker->recv_bytes = grpc_slice_ref(slice); 276 ok = alts_handshaker_client_next(handshaker->client, event, &slice); 277 } 278 grpc_slice_unref_internal(slice); 279 if (ok != TSI_OK) { 280 gpr_log(GPR_ERROR, "Failed to schedule ALTS handshaker requests"); 281 return ok; 282 } 283 return TSI_ASYNC; 284 } 285 286 static void handshaker_shutdown(tsi_handshaker* self) { 287 GPR_ASSERT(self != nullptr); 288 if (self->handshake_shutdown) { 289 return; 290 } 291 alts_tsi_handshaker* handshaker = 292 reinterpret_cast<alts_tsi_handshaker*>(self); 293 alts_handshaker_client_shutdown(handshaker->client); 294 } 295 296 static void handshaker_destroy(tsi_handshaker* self) { 297 if (self == nullptr) { 298 return; 299 } 300 alts_tsi_handshaker* handshaker = 301 reinterpret_cast<alts_tsi_handshaker*>(self); 302 alts_handshaker_client_destroy(handshaker->client); 303 grpc_slice_unref_internal(handshaker->recv_bytes); 304 grpc_slice_unref_internal(handshaker->target_name); 305 grpc_alts_credentials_options_destroy(handshaker->options); 306 gpr_free(handshaker->buffer); 307 gpr_free(handshaker); 308 } 309 310 static const tsi_handshaker_vtable handshaker_vtable = { 311 nullptr, nullptr, 312 nullptr, nullptr, 313 nullptr, handshaker_destroy, 314 handshaker_next, handshaker_shutdown}; 315 316 static void thread_worker(void* arg) { 317 while (true) { 318 grpc_event event = grpc_completion_queue_next( 319 kSharedResource->cq, gpr_inf_future(GPR_CLOCK_REALTIME), nullptr); 320 GPR_ASSERT(event.type != GRPC_QUEUE_TIMEOUT); 321 if (event.type == GRPC_QUEUE_SHUTDOWN) { 322 /* signal alts_tsi_shutdown() to destroy completion queue. */ 323 grpc_tsi_alts_signal_for_cq_destroy(); 324 break; 325 } 326 /* event.type == GRPC_OP_COMPLETE. */ 327 alts_tsi_event* alts_event = static_cast<alts_tsi_event*>(event.tag); 328 alts_tsi_event_dispatch_to_handshaker(alts_event, event.success); 329 alts_tsi_event_destroy(alts_event); 330 } 331 } 332 333 static void init_shared_resources(const char* handshaker_service_url) { 334 GPR_ASSERT(handshaker_service_url != nullptr); 335 gpr_mu_lock(&kSharedResource->mu); 336 if (kSharedResource->channel == nullptr) { 337 gpr_cv_init(&kSharedResource->cv); 338 kSharedResource->channel = 339 grpc_insecure_channel_create(handshaker_service_url, nullptr, nullptr); 340 kSharedResource->cq = grpc_completion_queue_create_for_next(nullptr); 341 kSharedResource->thread = 342 grpc_core::Thread("alts_tsi_handshaker", &thread_worker, nullptr); 343 kSharedResource->thread.Start(); 344 } 345 gpr_mu_unlock(&kSharedResource->mu); 346 } 347 348 tsi_result alts_tsi_handshaker_create( 349 const grpc_alts_credentials_options* options, const char* target_name, 350 const char* handshaker_service_url, bool is_client, tsi_handshaker** self) { 351 if (handshaker_service_url == nullptr || self == nullptr || 352 options == nullptr || (is_client && target_name == nullptr)) { 353 gpr_log(GPR_ERROR, "Invalid arguments to alts_tsi_handshaker_create()"); 354 return TSI_INVALID_ARGUMENT; 355 } 356 init_shared_resources(handshaker_service_url); 357 alts_handshaker_client* client = alts_grpc_handshaker_client_create( 358 kSharedResource->channel, kSharedResource->cq, handshaker_service_url); 359 if (client == nullptr) { 360 gpr_log(GPR_ERROR, "Failed to create ALTS handshaker client"); 361 return TSI_FAILED_PRECONDITION; 362 } 363 alts_tsi_handshaker* handshaker = 364 static_cast<alts_tsi_handshaker*>(gpr_zalloc(sizeof(*handshaker))); 365 handshaker->client = client; 366 handshaker->buffer_size = TSI_ALTS_INITIAL_BUFFER_SIZE; 367 handshaker->buffer = 368 static_cast<unsigned char*>(gpr_zalloc(handshaker->buffer_size)); 369 handshaker->is_client = is_client; 370 handshaker->has_sent_start_message = false; 371 handshaker->target_name = target_name == nullptr 372 ? grpc_empty_slice() 373 : grpc_slice_from_static_string(target_name); 374 handshaker->options = grpc_alts_credentials_options_copy(options); 375 handshaker->base.vtable = &handshaker_vtable; 376 *self = &handshaker->base; 377 return TSI_OK; 378 } 379 380 static bool is_handshake_finished_properly(grpc_gcp_handshaker_resp* resp) { 381 GPR_ASSERT(resp != nullptr); 382 if (resp->has_result) { 383 return true; 384 } 385 return false; 386 } 387 388 static void set_unused_bytes(tsi_handshaker_result* self, 389 grpc_slice* recv_bytes, size_t bytes_consumed) { 390 GPR_ASSERT(recv_bytes != nullptr && self != nullptr); 391 if (GRPC_SLICE_LENGTH(*recv_bytes) == bytes_consumed) { 392 return; 393 } 394 alts_tsi_handshaker_result* result = 395 reinterpret_cast<alts_tsi_handshaker_result*>(self); 396 result->unused_bytes_size = GRPC_SLICE_LENGTH(*recv_bytes) - bytes_consumed; 397 result->unused_bytes = 398 static_cast<unsigned char*>(gpr_zalloc(result->unused_bytes_size)); 399 memcpy(result->unused_bytes, 400 GRPC_SLICE_START_PTR(*recv_bytes) + bytes_consumed, 401 result->unused_bytes_size); 402 } 403 404 void alts_tsi_handshaker_handle_response(alts_tsi_handshaker* handshaker, 405 grpc_byte_buffer* recv_buffer, 406 grpc_status_code status, 407 grpc_slice* details, 408 tsi_handshaker_on_next_done_cb cb, 409 void* user_data, bool is_ok) { 410 /* Invalid input check. */ 411 if (cb == nullptr) { 412 gpr_log(GPR_ERROR, 413 "cb is nullptr in alts_tsi_handshaker_handle_response()"); 414 return; 415 } 416 if (handshaker == nullptr || recv_buffer == nullptr) { 417 gpr_log(GPR_ERROR, 418 "Invalid arguments to alts_tsi_handshaker_handle_response()"); 419 cb(TSI_INTERNAL_ERROR, user_data, nullptr, 0, nullptr); 420 return; 421 } 422 if (handshaker->base.handshake_shutdown) { 423 gpr_log(GPR_ERROR, "TSI handshake shutdown"); 424 cb(TSI_HANDSHAKE_SHUTDOWN, user_data, nullptr, 0, nullptr); 425 return; 426 } 427 /* Failed grpc call check. */ 428 if (!is_ok || status != GRPC_STATUS_OK) { 429 gpr_log(GPR_ERROR, "grpc call made to handshaker service failed"); 430 if (details != nullptr) { 431 char* error_details = grpc_slice_to_c_string(*details); 432 gpr_log(GPR_ERROR, "error details:%s", error_details); 433 gpr_free(error_details); 434 } 435 cb(TSI_INTERNAL_ERROR, user_data, nullptr, 0, nullptr); 436 return; 437 } 438 grpc_gcp_handshaker_resp* resp = 439 alts_tsi_utils_deserialize_response(recv_buffer); 440 /* Invalid handshaker response check. */ 441 if (resp == nullptr) { 442 gpr_log(GPR_ERROR, "alts_tsi_utils_deserialize_response() failed"); 443 cb(TSI_DATA_CORRUPTED, user_data, nullptr, 0, nullptr); 444 return; 445 } 446 grpc_slice* slice = static_cast<grpc_slice*>(resp->out_frames.arg); 447 unsigned char* bytes_to_send = nullptr; 448 size_t bytes_to_send_size = 0; 449 if (slice != nullptr) { 450 bytes_to_send_size = GRPC_SLICE_LENGTH(*slice); 451 while (bytes_to_send_size > handshaker->buffer_size) { 452 handshaker->buffer_size *= 2; 453 handshaker->buffer = static_cast<unsigned char*>( 454 gpr_realloc(handshaker->buffer, handshaker->buffer_size)); 455 } 456 memcpy(handshaker->buffer, GRPC_SLICE_START_PTR(*slice), 457 bytes_to_send_size); 458 bytes_to_send = handshaker->buffer; 459 } 460 tsi_handshaker_result* result = nullptr; 461 if (is_handshake_finished_properly(resp)) { 462 create_handshaker_result(resp, handshaker->is_client, &result); 463 set_unused_bytes(result, &handshaker->recv_bytes, resp->bytes_consumed); 464 } 465 grpc_status_code code = static_cast<grpc_status_code>(resp->status.code); 466 if (code != GRPC_STATUS_OK) { 467 grpc_slice* details = static_cast<grpc_slice*>(resp->status.details.arg); 468 if (details != nullptr) { 469 char* error_details = grpc_slice_to_c_string(*details); 470 gpr_log(GPR_ERROR, "Error from handshaker service:%s", error_details); 471 gpr_free(error_details); 472 } 473 } 474 grpc_gcp_handshaker_resp_destroy(resp); 475 cb(alts_tsi_utils_convert_to_tsi_result(code), user_data, bytes_to_send, 476 bytes_to_send_size, result); 477 } 478 479 namespace grpc_core { 480 namespace internal { 481 482 bool alts_tsi_handshaker_get_has_sent_start_message_for_testing( 483 alts_tsi_handshaker* handshaker) { 484 GPR_ASSERT(handshaker != nullptr); 485 return handshaker->has_sent_start_message; 486 } 487 488 bool alts_tsi_handshaker_get_is_client_for_testing( 489 alts_tsi_handshaker* handshaker) { 490 GPR_ASSERT(handshaker != nullptr); 491 return handshaker->is_client; 492 } 493 494 void alts_tsi_handshaker_set_recv_bytes_for_testing( 495 alts_tsi_handshaker* handshaker, grpc_slice* slice) { 496 GPR_ASSERT(handshaker != nullptr && slice != nullptr); 497 handshaker->recv_bytes = grpc_slice_ref(*slice); 498 } 499 500 grpc_slice alts_tsi_handshaker_get_recv_bytes_for_testing( 501 alts_tsi_handshaker* handshaker) { 502 GPR_ASSERT(handshaker != nullptr); 503 return handshaker->recv_bytes; 504 } 505 506 void alts_tsi_handshaker_set_client_for_testing( 507 alts_tsi_handshaker* handshaker, alts_handshaker_client* client) { 508 GPR_ASSERT(handshaker != nullptr && client != nullptr); 509 alts_handshaker_client_destroy(handshaker->client); 510 handshaker->client = client; 511 } 512 513 alts_handshaker_client* alts_tsi_handshaker_get_client_for_testing( 514 alts_tsi_handshaker* handshaker) { 515 return handshaker->client; 516 } 517 518 } // namespace internal 519 } // namespace grpc_core 520