| /* |
| * |
| * 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 <grpc/support/port_platform.h> |
| |
| #include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h" |
| |
| #include <grpc/support/alloc.h> |
| #include <grpc/support/log.h> |
| |
| #include "src/core/lib/slice/slice_internal.h" |
| #include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h" |
| #include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h" |
| |
| /* Privacy-integrity alts_grpc_record_protocol object uses the same struct |
| * defined in alts_grpc_record_protocol_common.h. */ |
| |
| /* --- alts_grpc_record_protocol methods implementation. --- */ |
| |
| static tsi_result alts_grpc_privacy_integrity_protect( |
| alts_grpc_record_protocol* rp, grpc_slice_buffer* unprotected_slices, |
| grpc_slice_buffer* protected_slices) { |
| /* Input sanity check. */ |
| if (rp == nullptr || unprotected_slices == nullptr || |
| protected_slices == nullptr) { |
| gpr_log(GPR_ERROR, |
| "Invalid nullptr arguments to alts_grpc_record_protocol protect."); |
| return TSI_INVALID_ARGUMENT; |
| } |
| /* Allocates memory for output frame. In privacy-integrity protect, the |
| * protected frame is stored in a newly allocated buffer. */ |
| size_t protected_frame_size = |
| unprotected_slices->length + rp->header_length + |
| alts_iovec_record_protocol_get_tag_length(rp->iovec_rp); |
| grpc_slice protected_slice = GRPC_SLICE_MALLOC(protected_frame_size); |
| iovec_t protected_iovec = {GRPC_SLICE_START_PTR(protected_slice), |
| GRPC_SLICE_LENGTH(protected_slice)}; |
| /* Calls alts_iovec_record_protocol protect. */ |
| char* error_details = nullptr; |
| alts_grpc_record_protocol_convert_slice_buffer_to_iovec(rp, |
| unprotected_slices); |
| grpc_status_code status = |
| alts_iovec_record_protocol_privacy_integrity_protect( |
| rp->iovec_rp, rp->iovec_buf, unprotected_slices->count, |
| protected_iovec, &error_details); |
| if (status != GRPC_STATUS_OK) { |
| gpr_log(GPR_ERROR, "Failed to protect, %s", error_details); |
| gpr_free(error_details); |
| grpc_slice_unref_internal(protected_slice); |
| return TSI_INTERNAL_ERROR; |
| } |
| grpc_slice_buffer_add(protected_slices, protected_slice); |
| grpc_slice_buffer_reset_and_unref_internal(unprotected_slices); |
| return TSI_OK; |
| } |
| |
| static tsi_result alts_grpc_privacy_integrity_unprotect( |
| alts_grpc_record_protocol* rp, grpc_slice_buffer* protected_slices, |
| grpc_slice_buffer* unprotected_slices) { |
| /* Input sanity check. */ |
| if (rp == nullptr || protected_slices == nullptr || |
| unprotected_slices == nullptr) { |
| gpr_log( |
| GPR_ERROR, |
| "Invalid nullptr arguments to alts_grpc_record_protocol unprotect."); |
| return TSI_INVALID_ARGUMENT; |
| } |
| /* Allocates memory for output frame. In privacy-integrity unprotect, the |
| * unprotected data are stored in a newly allocated buffer. */ |
| if (protected_slices->length < rp->header_length + rp->tag_length) { |
| gpr_log(GPR_ERROR, "Protected slices do not have sufficient data."); |
| return TSI_INVALID_ARGUMENT; |
| } |
| size_t unprotected_frame_size = |
| protected_slices->length - rp->header_length - rp->tag_length; |
| grpc_slice unprotected_slice = GRPC_SLICE_MALLOC(unprotected_frame_size); |
| iovec_t unprotected_iovec = {GRPC_SLICE_START_PTR(unprotected_slice), |
| GRPC_SLICE_LENGTH(unprotected_slice)}; |
| /* Strips frame header from protected slices. */ |
| grpc_slice_buffer_reset_and_unref_internal(&rp->header_sb); |
| grpc_slice_buffer_move_first(protected_slices, rp->header_length, |
| &rp->header_sb); |
| iovec_t header_iovec = alts_grpc_record_protocol_get_header_iovec(rp); |
| /* Calls alts_iovec_record_protocol unprotect. */ |
| char* error_details = nullptr; |
| alts_grpc_record_protocol_convert_slice_buffer_to_iovec(rp, protected_slices); |
| grpc_status_code status = |
| alts_iovec_record_protocol_privacy_integrity_unprotect( |
| rp->iovec_rp, header_iovec, rp->iovec_buf, protected_slices->count, |
| unprotected_iovec, &error_details); |
| if (status != GRPC_STATUS_OK) { |
| gpr_log(GPR_ERROR, "Failed to unprotect, %s", error_details); |
| gpr_free(error_details); |
| grpc_slice_unref_internal(unprotected_slice); |
| return TSI_INTERNAL_ERROR; |
| } |
| grpc_slice_buffer_reset_and_unref_internal(&rp->header_sb); |
| grpc_slice_buffer_reset_and_unref_internal(protected_slices); |
| grpc_slice_buffer_add(unprotected_slices, unprotected_slice); |
| return TSI_OK; |
| } |
| |
| static const alts_grpc_record_protocol_vtable |
| alts_grpc_privacy_integrity_record_protocol_vtable = { |
| alts_grpc_privacy_integrity_protect, |
| alts_grpc_privacy_integrity_unprotect, nullptr}; |
| |
| tsi_result alts_grpc_privacy_integrity_record_protocol_create( |
| gsec_aead_crypter* crypter, size_t overflow_size, bool is_client, |
| bool is_protect, alts_grpc_record_protocol** rp) { |
| if (crypter == nullptr || rp == nullptr) { |
| gpr_log(GPR_ERROR, |
| "Invalid nullptr arguments to alts_grpc_record_protocol create."); |
| return TSI_INVALID_ARGUMENT; |
| } |
| auto* impl = static_cast<alts_grpc_record_protocol*>( |
| gpr_zalloc(sizeof(alts_grpc_record_protocol))); |
| /* Calls alts_grpc_record_protocol init. */ |
| tsi_result result = |
| alts_grpc_record_protocol_init(impl, crypter, overflow_size, is_client, |
| /*is_integrity_only=*/false, is_protect); |
| if (result != TSI_OK) { |
| gpr_free(impl); |
| return result; |
| } |
| impl->vtable = &alts_grpc_privacy_integrity_record_protocol_vtable; |
| *rp = impl; |
| return TSI_OK; |
| } |