Home | History | Annotate | Download | only in handshaker
      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