/* * * Copyright 2018 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include #include "src/core/tsi/alts/handshaker/alts_handshaker_service_api.h" #include #include #include "src/core/tsi/alts/handshaker/transport_security_common_api.h" /* HandshakerReq */ grpc_gcp_handshaker_req* grpc_gcp_handshaker_req_create( grpc_gcp_handshaker_req_type type) { grpc_gcp_handshaker_req* req = static_cast(gpr_zalloc(sizeof(*req))); switch (type) { case CLIENT_START_REQ: req->has_client_start = true; break; case SERVER_START_REQ: req->has_server_start = true; break; case NEXT_REQ: req->has_next = true; break; } return req; } void grpc_gcp_handshaker_req_destroy(grpc_gcp_handshaker_req* req) { if (req == nullptr) { return; } if (req->has_client_start) { /* Destroy client_start request. */ destroy_repeated_field_list_identity( static_cast(req->client_start.target_identities.arg)); destroy_repeated_field_list_string(static_cast( req->client_start.application_protocols.arg)); destroy_repeated_field_list_string( static_cast(req->client_start.record_protocols.arg)); if (req->client_start.has_local_identity) { destroy_slice(static_cast( req->client_start.local_identity.hostname.arg)); destroy_slice(static_cast( req->client_start.local_identity.service_account.arg)); } if (req->client_start.has_local_endpoint) { destroy_slice(static_cast( req->client_start.local_endpoint.ip_address.arg)); } if (req->client_start.has_remote_endpoint) { destroy_slice(static_cast( req->client_start.remote_endpoint.ip_address.arg)); } destroy_slice(static_cast(req->client_start.target_name.arg)); } else if (req->has_server_start) { /* Destroy server_start request. */ size_t i = 0; for (i = 0; i < req->server_start.handshake_parameters_count; i++) { destroy_repeated_field_list_identity( static_cast(req->server_start.handshake_parameters[i] .value.local_identities.arg)); destroy_repeated_field_list_string( static_cast(req->server_start.handshake_parameters[i] .value.record_protocols.arg)); } destroy_repeated_field_list_string(static_cast( req->server_start.application_protocols.arg)); if (req->server_start.has_local_endpoint) { destroy_slice(static_cast( req->server_start.local_endpoint.ip_address.arg)); } if (req->server_start.has_remote_endpoint) { destroy_slice(static_cast( req->server_start.remote_endpoint.ip_address.arg)); } destroy_slice(static_cast(req->server_start.in_bytes.arg)); } else { /* Destroy next request. */ destroy_slice(static_cast(req->next.in_bytes.arg)); } gpr_free(req); } bool grpc_gcp_handshaker_req_set_handshake_protocol( grpc_gcp_handshaker_req* req, grpc_gcp_handshake_protocol handshake_protocol) { if (req == nullptr || !req->has_client_start) { gpr_log(GPR_ERROR, "Invalid arguments to " "grpc_gcp_handshaker_req_set_handshake_protocol()."); return false; } req->client_start.has_handshake_security_protocol = true; req->client_start.handshake_security_protocol = handshake_protocol; return true; } bool grpc_gcp_handshaker_req_set_target_name(grpc_gcp_handshaker_req* req, const char* target_name) { if (req == nullptr || target_name == nullptr || !req->has_client_start) { gpr_log(GPR_ERROR, "Invalid arguments to " "grpc_gcp_handshaker_req_set_target_name()."); return false; } grpc_slice* slice = create_slice(target_name, strlen(target_name)); req->client_start.target_name.arg = slice; req->client_start.target_name.funcs.encode = encode_string_or_bytes_cb; return true; } bool grpc_gcp_handshaker_req_add_application_protocol( grpc_gcp_handshaker_req* req, const char* application_protocol) { if (req == nullptr || application_protocol == nullptr || req->has_next) { gpr_log(GPR_ERROR, "Invalid arguments to " "grpc_gcp_handshaker_req_add_application_protocol()."); return false; } grpc_slice* slice = create_slice(application_protocol, strlen(application_protocol)); if (req->has_client_start) { add_repeated_field(reinterpret_cast( &req->client_start.application_protocols.arg), slice); req->client_start.application_protocols.funcs.encode = encode_repeated_string_cb; } else { add_repeated_field(reinterpret_cast( &req->server_start.application_protocols.arg), slice); req->server_start.application_protocols.funcs.encode = encode_repeated_string_cb; } return true; } bool grpc_gcp_handshaker_req_add_record_protocol(grpc_gcp_handshaker_req* req, const char* record_protocol) { if (req == nullptr || record_protocol == nullptr || !req->has_client_start) { gpr_log(GPR_ERROR, "Invalid arguments to " "grpc_gcp_handshaker_req_add_record_protocol()."); return false; } grpc_slice* slice = create_slice(record_protocol, strlen(record_protocol)); add_repeated_field(reinterpret_cast( &req->client_start.record_protocols.arg), slice); req->client_start.record_protocols.funcs.encode = encode_repeated_string_cb; return true; } static void set_identity_hostname(grpc_gcp_identity* identity, const char* hostname) { grpc_slice* slice = create_slice(hostname, strlen(hostname)); identity->hostname.arg = slice; identity->hostname.funcs.encode = encode_string_or_bytes_cb; } static void set_identity_service_account(grpc_gcp_identity* identity, const char* service_account) { grpc_slice* slice = create_slice(service_account, strlen(service_account)); identity->service_account.arg = slice; identity->service_account.funcs.encode = encode_string_or_bytes_cb; } bool grpc_gcp_handshaker_req_add_target_identity_hostname( grpc_gcp_handshaker_req* req, const char* hostname) { if (req == nullptr || hostname == nullptr || !req->has_client_start) { gpr_log(GPR_ERROR, "Invalid nullptr arguments to " "grpc_gcp_handshaker_req_add_target_identity_hostname()."); return false; } grpc_gcp_identity* target_identity = static_cast(gpr_zalloc(sizeof(*target_identity))); set_identity_hostname(target_identity, hostname); req->client_start.target_identities.funcs.encode = encode_repeated_identity_cb; add_repeated_field(reinterpret_cast( &req->client_start.target_identities.arg), target_identity); return true; } bool grpc_gcp_handshaker_req_add_target_identity_service_account( grpc_gcp_handshaker_req* req, const char* service_account) { if (req == nullptr || service_account == nullptr || !req->has_client_start) { gpr_log(GPR_ERROR, "Invalid nullptr arguments to " "grpc_gcp_handshaker_req_add_target_identity_service_account()."); return false; } grpc_gcp_identity* target_identity = static_cast(gpr_zalloc(sizeof(*target_identity))); set_identity_service_account(target_identity, service_account); req->client_start.target_identities.funcs.encode = encode_repeated_identity_cb; add_repeated_field(reinterpret_cast( &req->client_start.target_identities.arg), target_identity); return true; } bool grpc_gcp_handshaker_req_set_local_identity_hostname( grpc_gcp_handshaker_req* req, const char* hostname) { if (req == nullptr || hostname == nullptr || !req->has_client_start) { gpr_log(GPR_ERROR, "Invalid nullptr arguments to " "grpc_gcp_handshaker_req_set_local_identity_hostname()."); return false; } req->client_start.has_local_identity = true; set_identity_hostname(&req->client_start.local_identity, hostname); return true; } bool grpc_gcp_handshaker_req_set_local_identity_service_account( grpc_gcp_handshaker_req* req, const char* service_account) { if (req == nullptr || service_account == nullptr || !req->has_client_start) { gpr_log(GPR_ERROR, "Invalid nullptr arguments to " "grpc_gcp_handshaker_req_set_local_identity_service_account()."); return false; } req->client_start.has_local_identity = true; set_identity_service_account(&req->client_start.local_identity, service_account); return true; } static void set_endpoint(grpc_gcp_endpoint* endpoint, const char* ip_address, size_t port, grpc_gcp_network_protocol protocol) { grpc_slice* slice = create_slice(ip_address, strlen(ip_address)); endpoint->ip_address.arg = slice; endpoint->ip_address.funcs.encode = encode_string_or_bytes_cb; endpoint->has_port = true; endpoint->port = static_cast(port); endpoint->has_protocol = true; endpoint->protocol = protocol; } bool grpc_gcp_handshaker_req_set_rpc_versions(grpc_gcp_handshaker_req* req, uint32_t max_major, uint32_t max_minor, uint32_t min_major, uint32_t min_minor) { if (req == nullptr || req->has_next) { gpr_log(GPR_ERROR, "Invalid arguments to " "grpc_gcp_handshaker_req_set_rpc_versions()."); return false; } if (req->has_client_start) { req->client_start.has_rpc_versions = true; grpc_gcp_rpc_protocol_versions_set_max(&req->client_start.rpc_versions, max_major, max_minor); grpc_gcp_rpc_protocol_versions_set_min(&req->client_start.rpc_versions, min_major, min_minor); } else { req->server_start.has_rpc_versions = true; grpc_gcp_rpc_protocol_versions_set_max(&req->server_start.rpc_versions, max_major, max_minor); grpc_gcp_rpc_protocol_versions_set_min(&req->server_start.rpc_versions, min_major, min_minor); } return true; } bool grpc_gcp_handshaker_req_set_local_endpoint( grpc_gcp_handshaker_req* req, const char* ip_address, size_t port, grpc_gcp_network_protocol protocol) { if (req == nullptr || ip_address == nullptr || port > 65535 || req->has_next) { gpr_log(GPR_ERROR, "Invalid arguments to " "grpc_gcp_handshaker_req_set_local_endpoint()."); return false; } if (req->has_client_start) { req->client_start.has_local_endpoint = true; set_endpoint(&req->client_start.local_endpoint, ip_address, port, protocol); } else { req->server_start.has_local_endpoint = true; set_endpoint(&req->server_start.local_endpoint, ip_address, port, protocol); } return true; } bool grpc_gcp_handshaker_req_set_remote_endpoint( grpc_gcp_handshaker_req* req, const char* ip_address, size_t port, grpc_gcp_network_protocol protocol) { if (req == nullptr || ip_address == nullptr || port > 65535 || req->has_next) { gpr_log(GPR_ERROR, "Invalid arguments to " "grpc_gcp_handshaker_req_set_remote_endpoint()."); return false; } if (req->has_client_start) { req->client_start.has_remote_endpoint = true; set_endpoint(&req->client_start.remote_endpoint, ip_address, port, protocol); } else { req->server_start.has_remote_endpoint = true; set_endpoint(&req->server_start.remote_endpoint, ip_address, port, protocol); } return true; } bool grpc_gcp_handshaker_req_set_in_bytes(grpc_gcp_handshaker_req* req, const char* in_bytes, size_t size) { if (req == nullptr || in_bytes == nullptr || req->has_client_start) { gpr_log(GPR_ERROR, "Invalid arguments to " "grpc_gcp_handshaker_req_set_in_bytes()."); return false; } grpc_slice* slice = create_slice(in_bytes, size); if (req->has_next) { req->next.in_bytes.arg = slice; req->next.in_bytes.funcs.encode = &encode_string_or_bytes_cb; } else { req->server_start.in_bytes.arg = slice; req->server_start.in_bytes.funcs.encode = &encode_string_or_bytes_cb; } return true; } static grpc_gcp_server_handshake_parameters* server_start_find_param( grpc_gcp_handshaker_req* req, int32_t key) { size_t i = 0; for (i = 0; i < req->server_start.handshake_parameters_count; i++) { if (req->server_start.handshake_parameters[i].key == key) { return &req->server_start.handshake_parameters[i].value; } } req->server_start .handshake_parameters[req->server_start.handshake_parameters_count] .has_key = true; req->server_start .handshake_parameters[req->server_start.handshake_parameters_count] .has_value = true; req->server_start .handshake_parameters[req->server_start.handshake_parameters_count++] .key = key; return &req->server_start .handshake_parameters [req->server_start.handshake_parameters_count - 1] .value; } bool grpc_gcp_handshaker_req_param_add_record_protocol( grpc_gcp_handshaker_req* req, grpc_gcp_handshake_protocol key, const char* record_protocol) { if (req == nullptr || record_protocol == nullptr || !req->has_server_start) { gpr_log(GPR_ERROR, "Invalid arguments to " "grpc_gcp_handshaker_req_param_add_record_protocol()."); return false; } grpc_gcp_server_handshake_parameters* param = server_start_find_param(req, key); grpc_slice* slice = create_slice(record_protocol, strlen(record_protocol)); add_repeated_field( reinterpret_cast(¶m->record_protocols.arg), slice); param->record_protocols.funcs.encode = &encode_repeated_string_cb; return true; } bool grpc_gcp_handshaker_req_param_add_local_identity_hostname( grpc_gcp_handshaker_req* req, grpc_gcp_handshake_protocol key, const char* hostname) { if (req == nullptr || hostname == nullptr || !req->has_server_start) { gpr_log(GPR_ERROR, "Invalid arguments to " "grpc_gcp_handshaker_req_param_add_local_identity_hostname()."); return false; } grpc_gcp_server_handshake_parameters* param = server_start_find_param(req, key); grpc_gcp_identity* local_identity = static_cast(gpr_zalloc(sizeof(*local_identity))); set_identity_hostname(local_identity, hostname); add_repeated_field( reinterpret_cast(¶m->local_identities.arg), local_identity); param->local_identities.funcs.encode = &encode_repeated_identity_cb; return true; } bool grpc_gcp_handshaker_req_param_add_local_identity_service_account( grpc_gcp_handshaker_req* req, grpc_gcp_handshake_protocol key, const char* service_account) { if (req == nullptr || service_account == nullptr || !req->has_server_start) { gpr_log( GPR_ERROR, "Invalid arguments to " "grpc_gcp_handshaker_req_param_add_local_identity_service_account()."); return false; } grpc_gcp_server_handshake_parameters* param = server_start_find_param(req, key); grpc_gcp_identity* local_identity = static_cast(gpr_zalloc(sizeof(*local_identity))); set_identity_service_account(local_identity, service_account); add_repeated_field( reinterpret_cast(¶m->local_identities.arg), local_identity); param->local_identities.funcs.encode = &encode_repeated_identity_cb; return true; } bool grpc_gcp_handshaker_req_encode(grpc_gcp_handshaker_req* req, grpc_slice* slice) { if (req == nullptr || slice == nullptr) { gpr_log(GPR_ERROR, "Invalid nullptr arguments to grpc_gcp_handshaker_req_encode()."); return false; } pb_ostream_t size_stream; memset(&size_stream, 0, sizeof(pb_ostream_t)); if (!pb_encode(&size_stream, grpc_gcp_HandshakerReq_fields, req)) { gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&size_stream)); return false; } size_t encoded_length = size_stream.bytes_written; *slice = grpc_slice_malloc(encoded_length); pb_ostream_t output_stream = pb_ostream_from_buffer(GRPC_SLICE_START_PTR(*slice), encoded_length); if (!pb_encode(&output_stream, grpc_gcp_HandshakerReq_fields, req) != 0) { gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&output_stream)); return false; } return true; } /* HandshakerResp. */ grpc_gcp_handshaker_resp* grpc_gcp_handshaker_resp_create(void) { grpc_gcp_handshaker_resp* resp = static_cast(gpr_zalloc(sizeof(*resp))); return resp; } void grpc_gcp_handshaker_resp_destroy(grpc_gcp_handshaker_resp* resp) { if (resp != nullptr) { destroy_slice(static_cast(resp->out_frames.arg)); if (resp->has_status) { destroy_slice(static_cast(resp->status.details.arg)); } if (resp->has_result) { destroy_slice( static_cast(resp->result.application_protocol.arg)); destroy_slice(static_cast(resp->result.record_protocol.arg)); destroy_slice(static_cast(resp->result.key_data.arg)); if (resp->result.has_local_identity) { destroy_slice( static_cast(resp->result.local_identity.hostname.arg)); destroy_slice(static_cast( resp->result.local_identity.service_account.arg)); } if (resp->result.has_peer_identity) { destroy_slice( static_cast(resp->result.peer_identity.hostname.arg)); destroy_slice(static_cast( resp->result.peer_identity.service_account.arg)); } } gpr_free(resp); } } bool grpc_gcp_handshaker_resp_decode(grpc_slice encoded_handshaker_resp, grpc_gcp_handshaker_resp* resp) { if (resp == nullptr) { gpr_log(GPR_ERROR, "Invalid nullptr argument to grpc_gcp_handshaker_resp_decode()."); return false; } pb_istream_t stream = pb_istream_from_buffer(GRPC_SLICE_START_PTR(encoded_handshaker_resp), GRPC_SLICE_LENGTH(encoded_handshaker_resp)); resp->out_frames.funcs.decode = decode_string_or_bytes_cb; resp->status.details.funcs.decode = decode_string_or_bytes_cb; resp->result.application_protocol.funcs.decode = decode_string_or_bytes_cb; resp->result.record_protocol.funcs.decode = decode_string_or_bytes_cb; resp->result.key_data.funcs.decode = decode_string_or_bytes_cb; resp->result.peer_identity.hostname.funcs.decode = decode_string_or_bytes_cb; resp->result.peer_identity.service_account.funcs.decode = decode_string_or_bytes_cb; resp->result.local_identity.hostname.funcs.decode = decode_string_or_bytes_cb; resp->result.local_identity.service_account.funcs.decode = decode_string_or_bytes_cb; if (!pb_decode(&stream, grpc_gcp_HandshakerResp_fields, resp)) { gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream)); return false; } return true; }