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 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 */ 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. */ 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 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. */ 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 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. */ 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 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 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 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 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 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 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 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 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 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 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