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 "test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.h"
     20 
     21 const size_t kHandshakeProtocolNum = 3;
     22 
     23 grpc_gcp_handshaker_req* grpc_gcp_handshaker_decoded_req_create(
     24     grpc_gcp_handshaker_req_type type) {
     25   grpc_gcp_handshaker_req* req =
     26       static_cast<grpc_gcp_handshaker_req*>(gpr_zalloc(sizeof(*req)));
     27   switch (type) {
     28     case CLIENT_START_REQ:
     29       req->has_client_start = true;
     30       req->client_start.target_identities.funcs.decode =
     31           decode_repeated_identity_cb;
     32       req->client_start.application_protocols.funcs.decode =
     33           decode_repeated_string_cb;
     34       req->client_start.record_protocols.funcs.decode =
     35           decode_repeated_string_cb;
     36       req->client_start.local_identity.hostname.funcs.decode =
     37           decode_string_or_bytes_cb;
     38       req->client_start.local_identity.service_account.funcs.decode =
     39           decode_string_or_bytes_cb;
     40       req->client_start.local_endpoint.ip_address.funcs.decode =
     41           decode_string_or_bytes_cb;
     42       req->client_start.remote_endpoint.ip_address.funcs.decode =
     43           decode_string_or_bytes_cb;
     44       req->client_start.target_name.funcs.decode = decode_string_or_bytes_cb;
     45       break;
     46     case SERVER_START_REQ:
     47       req->has_server_start = true;
     48       req->server_start.application_protocols.funcs.decode =
     49           &decode_repeated_string_cb;
     50       for (size_t i = 0; i < kHandshakeProtocolNum; i++) {
     51         req->server_start.handshake_parameters[i]
     52             .value.local_identities.funcs.decode = &decode_repeated_identity_cb;
     53         req->server_start.handshake_parameters[i]
     54             .value.record_protocols.funcs.decode = &decode_repeated_string_cb;
     55       }
     56       req->server_start.in_bytes.funcs.decode = decode_string_or_bytes_cb;
     57       req->server_start.local_endpoint.ip_address.funcs.decode =
     58           decode_string_or_bytes_cb;
     59       req->server_start.remote_endpoint.ip_address.funcs.decode =
     60           decode_string_or_bytes_cb;
     61       break;
     62     case NEXT_REQ:
     63       req->has_next = true;
     64       break;
     65   }
     66   return req;
     67 }
     68 
     69 bool grpc_gcp_handshaker_resp_set_application_protocol(
     70     grpc_gcp_handshaker_resp* resp, const char* application_protocol) {
     71   if (resp == nullptr || application_protocol == nullptr) {
     72     gpr_log(GPR_ERROR,
     73             "Invalid nullptr arguments to "
     74             "handshaker_resp_set_application_protocol().");
     75     return false;
     76   }
     77   resp->has_result = true;
     78   grpc_slice* slice =
     79       create_slice(application_protocol, strlen(application_protocol));
     80   resp->result.application_protocol.arg = slice;
     81   resp->result.application_protocol.funcs.encode = encode_string_or_bytes_cb;
     82   return true;
     83 }
     84 
     85 bool grpc_gcp_handshaker_resp_set_record_protocol(
     86     grpc_gcp_handshaker_resp* resp, const char* record_protocol) {
     87   if (resp == nullptr || record_protocol == nullptr) {
     88     gpr_log(GPR_ERROR,
     89             "Invalid nullptr arguments to "
     90             "handshaker_resp_set_record_protocol().");
     91     return false;
     92   }
     93   resp->has_result = true;
     94   grpc_slice* slice = create_slice(record_protocol, strlen(record_protocol));
     95   resp->result.record_protocol.arg = slice;
     96   resp->result.record_protocol.funcs.encode = encode_string_or_bytes_cb;
     97   return true;
     98 }
     99 
    100 bool grpc_gcp_handshaker_resp_set_key_data(grpc_gcp_handshaker_resp* resp,
    101                                            const char* key_data, size_t size) {
    102   if (resp == nullptr || key_data == nullptr) {
    103     gpr_log(GPR_ERROR,
    104             "Invalid nullptr arguments to handshaker_resp_set_key_data().");
    105     return false;
    106   }
    107   resp->has_result = true;
    108   grpc_slice* slice = create_slice(key_data, size);
    109   resp->result.key_data.arg = slice;
    110   resp->result.key_data.funcs.encode = encode_string_or_bytes_cb;
    111   return true;
    112 }
    113 
    114 static void set_identity_hostname(grpc_gcp_identity* identity,
    115                                   const char* hostname) {
    116   grpc_slice* slice = create_slice(hostname, strlen(hostname));
    117   identity->hostname.arg = slice;
    118   identity->hostname.funcs.encode = encode_string_or_bytes_cb;
    119 }
    120 
    121 static void set_identity_service_account(grpc_gcp_identity* identity,
    122                                          const char* service_account) {
    123   grpc_slice* slice = create_slice(service_account, strlen(service_account));
    124   identity->service_account.arg = slice;
    125   identity->service_account.funcs.encode = encode_string_or_bytes_cb;
    126 }
    127 
    128 bool grpc_gcp_handshaker_resp_set_local_identity_hostname(
    129     grpc_gcp_handshaker_resp* resp, const char* hostname) {
    130   if (resp == nullptr || hostname == nullptr) {
    131     gpr_log(GPR_ERROR,
    132             "Invalid nullptr arguments to "
    133             "grpc_gcp_handshaker_resp_set_local_identity_hostname().");
    134     return false;
    135   }
    136   resp->has_result = true;
    137   resp->result.has_local_identity = true;
    138   set_identity_hostname(&resp->result.local_identity, hostname);
    139   return true;
    140 }
    141 
    142 bool grpc_gcp_handshaker_resp_set_local_identity_service_account(
    143     grpc_gcp_handshaker_resp* resp, const char* service_account) {
    144   if (resp == nullptr || service_account == nullptr) {
    145     gpr_log(GPR_ERROR,
    146             "Invalid nullptr arguments to "
    147             "grpc_gcp_handshaker_resp_set_local_identity_service_account().");
    148     return false;
    149   }
    150   resp->has_result = true;
    151   resp->result.has_local_identity = true;
    152   set_identity_service_account(&resp->result.local_identity, service_account);
    153   return true;
    154 }
    155 
    156 bool grpc_gcp_handshaker_resp_set_peer_identity_hostname(
    157     grpc_gcp_handshaker_resp* resp, const char* hostname) {
    158   if (resp == nullptr || hostname == nullptr) {
    159     gpr_log(GPR_ERROR,
    160             "Invalid nullptr arguments to "
    161             "grpc_gcp_handshaker_resp_set_peer_identity_hostname().");
    162     return false;
    163   }
    164   resp->has_result = true;
    165   resp->result.has_peer_identity = true;
    166   set_identity_hostname(&resp->result.peer_identity, hostname);
    167   return true;
    168 }
    169 
    170 bool grpc_gcp_handshaker_resp_set_peer_identity_service_account(
    171     grpc_gcp_handshaker_resp* resp, const char* service_account) {
    172   if (resp == nullptr || service_account == nullptr) {
    173     gpr_log(GPR_ERROR,
    174             "Invalid nullptr arguments to "
    175             "grpc_gcp_handshaker_resp_set_peer_identity_service_account().");
    176     return false;
    177   }
    178   resp->has_result = true;
    179   resp->result.has_peer_identity = true;
    180   set_identity_service_account(&resp->result.peer_identity, service_account);
    181   return true;
    182 }
    183 
    184 bool grpc_gcp_handshaker_resp_set_channel_open(grpc_gcp_handshaker_resp* resp,
    185                                                bool keep_channel_open) {
    186   if (resp == nullptr) {
    187     gpr_log(GPR_ERROR,
    188             "Invalid nullptr argument to "
    189             "grpc_gcp_handshaker_resp_set_channel_open().");
    190     return false;
    191   }
    192   resp->has_result = true;
    193   resp->result.has_keep_channel_open = true;
    194   resp->result.keep_channel_open = keep_channel_open;
    195   return true;
    196 }
    197 
    198 bool grpc_gcp_handshaker_resp_set_code(grpc_gcp_handshaker_resp* resp,
    199                                        uint32_t code) {
    200   if (resp == nullptr) {
    201     gpr_log(GPR_ERROR,
    202             "Invalid nullptr argument to grpc_gcp_handshaker_resp_set_code().");
    203     return false;
    204   }
    205   resp->has_status = true;
    206   resp->status.has_code = true;
    207   resp->status.code = code;
    208   return true;
    209 }
    210 
    211 bool grpc_gcp_handshaker_resp_set_details(grpc_gcp_handshaker_resp* resp,
    212                                           const char* details) {
    213   if (resp == nullptr || details == nullptr) {
    214     gpr_log(
    215         GPR_ERROR,
    216         "Invalid nullptr arguments to grpc_gcp_handshaker_resp_set_details().");
    217     return false;
    218   }
    219   resp->has_status = true;
    220   grpc_slice* slice = create_slice(details, strlen(details));
    221   resp->status.details.arg = slice;
    222   resp->status.details.funcs.encode = encode_string_or_bytes_cb;
    223   return true;
    224 }
    225 
    226 bool grpc_gcp_handshaker_resp_set_out_frames(grpc_gcp_handshaker_resp* resp,
    227                                              const char* out_frames,
    228                                              size_t size) {
    229   if (resp == nullptr || out_frames == nullptr) {
    230     gpr_log(GPR_ERROR,
    231             "Invalid nullptr arguments to "
    232             "grpc_gcp_handshaker_resp_set_out_frames().");
    233     return false;
    234   }
    235   grpc_slice* slice = create_slice(out_frames, size);
    236   resp->out_frames.arg = slice;
    237   resp->out_frames.funcs.encode = encode_string_or_bytes_cb;
    238   return true;
    239 }
    240 
    241 bool grpc_gcp_handshaker_resp_set_bytes_consumed(grpc_gcp_handshaker_resp* resp,
    242                                                  int32_t bytes_consumed) {
    243   if (resp == nullptr) {
    244     gpr_log(GPR_ERROR,
    245             "Invalid nullptr argument to "
    246             "grpc_gcp_handshaker_resp_set_bytes_consumed().");
    247     return false;
    248   }
    249   resp->has_bytes_consumed = true;
    250   resp->bytes_consumed = bytes_consumed;
    251   return true;
    252 }
    253 
    254 bool grpc_gcp_handshaker_resp_set_peer_rpc_versions(
    255     grpc_gcp_handshaker_resp* resp, uint32_t max_major, uint32_t max_minor,
    256     uint32_t min_major, uint32_t min_minor) {
    257   if (resp == nullptr) {
    258     gpr_log(GPR_ERROR,
    259             "Invalid nullptr argument to "
    260             "grpc_gcp_handshaker_resp_set_peer_rpc_versions().");
    261     return false;
    262   }
    263   resp->has_result = true;
    264   resp->result.has_peer_rpc_versions = true;
    265   grpc_gcp_rpc_protocol_versions* versions = &resp->result.peer_rpc_versions;
    266   versions->has_max_rpc_version = true;
    267   versions->has_min_rpc_version = true;
    268   versions->max_rpc_version.has_major = true;
    269   versions->max_rpc_version.has_minor = true;
    270   versions->min_rpc_version.has_major = true;
    271   versions->min_rpc_version.has_minor = true;
    272   versions->max_rpc_version.major = max_major;
    273   versions->max_rpc_version.minor = max_minor;
    274   versions->min_rpc_version.major = min_major;
    275   versions->min_rpc_version.minor = min_minor;
    276   return true;
    277 }
    278 
    279 bool grpc_gcp_handshaker_resp_encode(grpc_gcp_handshaker_resp* resp,
    280                                      grpc_slice* slice) {
    281   if (resp == nullptr || slice == nullptr) {
    282     gpr_log(GPR_ERROR,
    283             "Invalid nullptr arguments to grpc_gcp_handshaker_resp_encode().");
    284     return false;
    285   }
    286   pb_ostream_t size_stream;
    287   memset(&size_stream, 0, sizeof(pb_ostream_t));
    288   if (!pb_encode(&size_stream, grpc_gcp_HandshakerResp_fields, resp)) {
    289     gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&size_stream));
    290     return false;
    291   }
    292   size_t encoded_length = size_stream.bytes_written;
    293   *slice = grpc_slice_malloc(encoded_length);
    294   pb_ostream_t output_stream =
    295       pb_ostream_from_buffer(GRPC_SLICE_START_PTR(*slice), encoded_length);
    296   if (!pb_encode(&output_stream, grpc_gcp_HandshakerResp_fields, resp)) {
    297     gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&size_stream));
    298     return false;
    299   }
    300   return true;
    301 }
    302 
    303 bool grpc_gcp_handshaker_req_decode(grpc_slice slice,
    304                                     grpc_gcp_handshaker_req* req) {
    305   if (req == nullptr) {
    306     gpr_log(GPR_ERROR,
    307             "Invalid nullptr argument to grpc_gcp_handshaker_req_decode().");
    308     return false;
    309   }
    310   pb_istream_t stream = pb_istream_from_buffer(GRPC_SLICE_START_PTR(slice),
    311                                                GRPC_SLICE_LENGTH(slice));
    312   req->next.in_bytes.funcs.decode = decode_string_or_bytes_cb;
    313   if (!pb_decode(&stream, grpc_gcp_HandshakerReq_fields, req)) {
    314     gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream));
    315     return false;
    316   }
    317   return true;
    318 }
    319 
    320 /* Check equality of a pair of grpc_slice fields. */
    321 static bool slice_equals(grpc_slice* l_slice, grpc_slice* r_slice) {
    322   if (l_slice == nullptr && r_slice == nullptr) {
    323     return true;
    324   }
    325   if (l_slice != nullptr && r_slice != nullptr) {
    326     return grpc_slice_eq(*l_slice, *r_slice);
    327   }
    328   return false;
    329 }
    330 
    331 /* Check equality of a pair of grpc_gcp_identity fields. */
    332 static bool handshaker_identity_equals(const grpc_gcp_identity* l_id,
    333                                        const grpc_gcp_identity* r_id) {
    334   if (!((l_id->hostname.arg != nullptr) != (r_id->hostname.arg != nullptr))) {
    335     if (l_id->hostname.arg != nullptr) {
    336       return slice_equals(static_cast<grpc_slice*>(l_id->hostname.arg),
    337                           static_cast<grpc_slice*>(r_id->hostname.arg));
    338     }
    339   } else {
    340     return false;
    341   }
    342   if (!((l_id->service_account.arg != nullptr) !=
    343         (r_id->service_account.arg != nullptr))) {
    344     if (l_id->service_account.arg != nullptr) {
    345       return slice_equals(static_cast<grpc_slice*>(l_id->service_account.arg),
    346                           static_cast<grpc_slice*>(r_id->service_account.arg));
    347     }
    348   } else {
    349     return false;
    350   }
    351   return true;
    352 }
    353 
    354 static bool handshaker_rpc_versions_equals(
    355     const grpc_gcp_rpc_protocol_versions* l_version,
    356     const grpc_gcp_rpc_protocol_versions* r_version) {
    357   bool result = true;
    358   result &=
    359       (l_version->max_rpc_version.major == r_version->max_rpc_version.major);
    360   result &=
    361       (l_version->max_rpc_version.minor == r_version->max_rpc_version.minor);
    362   result &=
    363       (l_version->min_rpc_version.major == r_version->min_rpc_version.major);
    364   result &=
    365       (l_version->min_rpc_version.minor == r_version->min_rpc_version.minor);
    366   return result;
    367 }
    368 
    369 /* Check equality of a pair of grpc_gcp_endpoint fields. */
    370 static bool handshaker_endpoint_equals(const grpc_gcp_endpoint* l_end,
    371                                        const grpc_gcp_endpoint* r_end) {
    372   bool result = true;
    373   result &= (l_end->port == r_end->port);
    374   result &= (l_end->protocol == r_end->protocol);
    375   if (!((l_end->ip_address.arg != nullptr) !=
    376         (r_end->ip_address.arg != nullptr))) {
    377     if (l_end->ip_address.arg != nullptr) {
    378       result &= slice_equals(static_cast<grpc_slice*>(l_end->ip_address.arg),
    379                              static_cast<grpc_slice*>(r_end->ip_address.arg));
    380     }
    381   } else {
    382     return false;
    383   }
    384   return result;
    385 }
    386 /**
    387  * Check if a specific repeated field (i.e., target) is contained in a repeated
    388  * field list (i.e., head).
    389  */
    390 static bool repeated_field_list_contains_identity(
    391     const repeated_field* head, const repeated_field* target) {
    392   repeated_field* field = const_cast<repeated_field*>(head);
    393   while (field != nullptr) {
    394     if (handshaker_identity_equals(
    395             static_cast<const grpc_gcp_identity*>(field->data),
    396             static_cast<const grpc_gcp_identity*>(target->data))) {
    397       return true;
    398     }
    399     field = field->next;
    400   }
    401   return false;
    402 }
    403 
    404 static bool repeated_field_list_contains_string(const repeated_field* head,
    405                                                 const repeated_field* target) {
    406   repeated_field* field = const_cast<repeated_field*>(head);
    407   while (field != nullptr) {
    408     if (slice_equals((grpc_slice*)field->data, (grpc_slice*)target->data)) {
    409       return true;
    410     }
    411     field = field->next;
    412   }
    413   return false;
    414 }
    415 
    416 /* Return a length of repeated field list. */
    417 static size_t repeated_field_list_get_length(const repeated_field* head) {
    418   repeated_field* field = const_cast<repeated_field*>(head);
    419   size_t len = 0;
    420   while (field != nullptr) {
    421     len++;
    422     field = field->next;
    423   }
    424   return len;
    425 }
    426 
    427 /**
    428  * Check if a pair of repeated field lists contain the same set of repeated
    429  * fields.
    430  */
    431 static bool repeated_field_list_equals_identity(const repeated_field* l_head,
    432                                                 const repeated_field* r_head) {
    433   if (repeated_field_list_get_length(l_head) !=
    434       repeated_field_list_get_length(r_head)) {
    435     return false;
    436   }
    437   repeated_field* field = const_cast<repeated_field*>(l_head);
    438   repeated_field* head = const_cast<repeated_field*>(r_head);
    439   while (field != nullptr) {
    440     if (!repeated_field_list_contains_identity(head, field)) {
    441       return false;
    442     }
    443     field = field->next;
    444   }
    445   return true;
    446 }
    447 
    448 static bool repeated_field_list_equals_string(const repeated_field* l_head,
    449                                               const repeated_field* r_head) {
    450   if (repeated_field_list_get_length(l_head) !=
    451       repeated_field_list_get_length(r_head)) {
    452     return false;
    453   }
    454   repeated_field* field = const_cast<repeated_field*>(l_head);
    455   repeated_field* head = const_cast<repeated_field*>(r_head);
    456   while (field != nullptr) {
    457     if (!repeated_field_list_contains_string(head, field)) {
    458       return false;
    459     }
    460     field = field->next;
    461   }
    462   return true;
    463 }
    464 
    465 /* Check equality of a pair of ALTS client_start handshake requests. */
    466 bool grpc_gcp_handshaker_client_start_req_equals(
    467     grpc_gcp_start_client_handshake_req* l_req,
    468     grpc_gcp_start_client_handshake_req* r_req) {
    469   bool result = true;
    470   /* Compare handshake_security_protocol. */
    471   result &=
    472       l_req->handshake_security_protocol == r_req->handshake_security_protocol;
    473   /* Compare application_protocols, record_protocols, and target_identities. */
    474   result &= repeated_field_list_equals_string(
    475       static_cast<const repeated_field*>(l_req->application_protocols.arg),
    476       static_cast<const repeated_field*>(r_req->application_protocols.arg));
    477   result &= repeated_field_list_equals_string(
    478       static_cast<const repeated_field*>(l_req->record_protocols.arg),
    479       static_cast<const repeated_field*>(r_req->record_protocols.arg));
    480   result &= repeated_field_list_equals_identity(
    481       static_cast<const repeated_field*>(l_req->target_identities.arg),
    482       static_cast<const repeated_field*>(r_req->target_identities.arg));
    483   if ((l_req->has_local_identity ^ r_req->has_local_identity) |
    484       (l_req->has_local_endpoint ^ r_req->has_local_endpoint) |
    485       ((l_req->has_remote_endpoint ^ r_req->has_remote_endpoint)) |
    486       (l_req->has_rpc_versions ^ r_req->has_rpc_versions)) {
    487     return false;
    488   }
    489   /* Compare local_identity, local_endpoint, and remote_endpoint. */
    490   if (l_req->has_local_identity) {
    491     result &= handshaker_identity_equals(&l_req->local_identity,
    492                                          &r_req->local_identity);
    493   }
    494   if (l_req->has_local_endpoint) {
    495     result &= handshaker_endpoint_equals(&l_req->local_endpoint,
    496                                          &r_req->local_endpoint);
    497   }
    498   if (l_req->has_remote_endpoint) {
    499     result &= handshaker_endpoint_equals(&l_req->remote_endpoint,
    500                                          &r_req->remote_endpoint);
    501   }
    502   if (l_req->has_rpc_versions) {
    503     result &= handshaker_rpc_versions_equals(&l_req->rpc_versions,
    504                                              &r_req->rpc_versions);
    505   }
    506   return result;
    507 }
    508 
    509 /* Check equality of a pair of ALTS server_start handshake requests. */
    510 bool grpc_gcp_handshaker_server_start_req_equals(
    511     grpc_gcp_start_server_handshake_req* l_req,
    512     grpc_gcp_start_server_handshake_req* r_req) {
    513   bool result = true;
    514   /* Compare application_protocols. */
    515   result &= repeated_field_list_equals_string(
    516       static_cast<const repeated_field*>(l_req->application_protocols.arg),
    517       static_cast<const repeated_field*>(r_req->application_protocols.arg));
    518   /* Compare handshake_parameters. */
    519   size_t i = 0, j = 0;
    520   result &=
    521       (l_req->handshake_parameters_count == r_req->handshake_parameters_count);
    522   for (i = 0; i < l_req->handshake_parameters_count; i++) {
    523     bool found = false;
    524     for (j = 0; j < r_req->handshake_parameters_count; j++) {
    525       if (l_req->handshake_parameters[i].key ==
    526           r_req->handshake_parameters[j].key) {
    527         found = true;
    528         result &= repeated_field_list_equals_string(
    529             static_cast<const repeated_field*>(
    530                 l_req->handshake_parameters[i].value.record_protocols.arg),
    531             static_cast<const repeated_field*>(
    532                 r_req->handshake_parameters[j].value.record_protocols.arg));
    533         result &= repeated_field_list_equals_identity(
    534             static_cast<const repeated_field*>(
    535                 l_req->handshake_parameters[i].value.local_identities.arg),
    536             static_cast<const repeated_field*>(
    537                 r_req->handshake_parameters[j].value.local_identities.arg));
    538       }
    539     }
    540     if (!found) {
    541       return false;
    542     }
    543   }
    544   /* Compare in_bytes, local_endpoint, remote_endpoint. */
    545   result &= slice_equals(static_cast<grpc_slice*>(l_req->in_bytes.arg),
    546                          static_cast<grpc_slice*>(r_req->in_bytes.arg));
    547   if ((l_req->has_local_endpoint ^ r_req->has_local_endpoint) |
    548       (l_req->has_remote_endpoint ^ r_req->has_remote_endpoint) |
    549       (l_req->has_rpc_versions ^ r_req->has_rpc_versions))
    550     return false;
    551   if (l_req->has_local_endpoint) {
    552     result &= handshaker_endpoint_equals(&l_req->local_endpoint,
    553                                          &r_req->local_endpoint);
    554   }
    555   if (l_req->has_remote_endpoint) {
    556     result &= handshaker_endpoint_equals(&l_req->remote_endpoint,
    557                                          &r_req->remote_endpoint);
    558   }
    559   if (l_req->has_rpc_versions) {
    560     result &= handshaker_rpc_versions_equals(&l_req->rpc_versions,
    561                                              &r_req->rpc_versions);
    562   }
    563   return result;
    564 }
    565 
    566 /* Check equality of a pair of ALTS handshake requests. */
    567 bool grpc_gcp_handshaker_req_equals(grpc_gcp_handshaker_req* l_req,
    568                                     grpc_gcp_handshaker_req* r_req) {
    569   if (l_req->has_next && r_req->has_next) {
    570     return slice_equals(static_cast<grpc_slice*>(l_req->next.in_bytes.arg),
    571                         static_cast<grpc_slice*>(r_req->next.in_bytes.arg));
    572   } else if (l_req->has_client_start && r_req->has_client_start) {
    573     return grpc_gcp_handshaker_client_start_req_equals(&l_req->client_start,
    574                                                        &r_req->client_start);
    575   } else if (l_req->has_server_start && r_req->has_server_start) {
    576     return grpc_gcp_handshaker_server_start_req_equals(&l_req->server_start,
    577                                                        &r_req->server_start);
    578   }
    579   return false;
    580 }
    581 
    582 /* Check equality of a pair of ALTS handshake results. */
    583 bool grpc_gcp_handshaker_resp_result_equals(
    584     grpc_gcp_handshaker_result* l_result,
    585     grpc_gcp_handshaker_result* r_result) {
    586   bool result = true;
    587   /* Compare application_protocol, record_protocol, and key_data. */
    588   result &= slice_equals(
    589       static_cast<grpc_slice*>(l_result->application_protocol.arg),
    590       static_cast<grpc_slice*>(r_result->application_protocol.arg));
    591   result &=
    592       slice_equals(static_cast<grpc_slice*>(l_result->record_protocol.arg),
    593                    static_cast<grpc_slice*>(r_result->record_protocol.arg));
    594   result &= slice_equals(static_cast<grpc_slice*>(l_result->key_data.arg),
    595                          static_cast<grpc_slice*>(r_result->key_data.arg));
    596   /* Compare local_identity, peer_identity, and keep_channel_open. */
    597   if ((l_result->has_local_identity ^ r_result->has_local_identity) |
    598       (l_result->has_peer_identity ^ r_result->has_peer_identity) |
    599       (l_result->has_peer_rpc_versions ^ r_result->has_peer_rpc_versions)) {
    600     return false;
    601   }
    602   if (l_result->has_local_identity) {
    603     result &= handshaker_identity_equals(&l_result->local_identity,
    604                                          &r_result->local_identity);
    605   }
    606   if (l_result->has_peer_identity) {
    607     result &= handshaker_identity_equals(&l_result->peer_identity,
    608                                          &r_result->peer_identity);
    609   }
    610   if (l_result->has_peer_rpc_versions) {
    611     result &= handshaker_rpc_versions_equals(&l_result->peer_rpc_versions,
    612                                              &r_result->peer_rpc_versions);
    613   }
    614   result &= (l_result->keep_channel_open == r_result->keep_channel_open);
    615   return result;
    616 }
    617 
    618 /* Check equality of a pair of ALTS handshake responses. */
    619 bool grpc_gcp_handshaker_resp_equals(grpc_gcp_handshaker_resp* l_resp,
    620                                      grpc_gcp_handshaker_resp* r_resp) {
    621   bool result = true;
    622   /* Compare out_frames and bytes_consumed. */
    623   result &= slice_equals(static_cast<grpc_slice*>(l_resp->out_frames.arg),
    624                          static_cast<grpc_slice*>(r_resp->out_frames.arg));
    625   result &= (l_resp->bytes_consumed == r_resp->bytes_consumed);
    626   /* Compare result and status. */
    627   if ((l_resp->has_result ^ r_resp->has_result) |
    628       (l_resp->has_status ^ r_resp->has_status)) {
    629     return false;
    630   }
    631   if (l_resp->has_result) {
    632     result &= grpc_gcp_handshaker_resp_result_equals(&l_resp->result,
    633                                                      &r_resp->result);
    634   }
    635   if (l_resp->has_status) {
    636     result &= (l_resp->status.code == r_resp->status.code);
    637     result &=
    638         slice_equals(static_cast<grpc_slice*>(l_resp->status.details.arg),
    639                      static_cast<grpc_slice*>(r_resp->status.details.arg));
    640   }
    641   return result;
    642 }
    643