/* * * 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/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h" #include #include #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( 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; }