Home | History | Annotate | Download | only in zero_copy_frame_protector
      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/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h"
     22 
     23 #include <grpc/support/alloc.h>
     24 #include <grpc/support/log.h>
     25 
     26 #include <string.h>
     27 
     28 #include "src/core/lib/slice/slice_internal.h"
     29 #include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h"
     30 #include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h"
     31 
     32 /* Main struct for alts_grpc_integrity_only_record_protocol.  */
     33 typedef struct alts_grpc_integrity_only_record_protocol {
     34   alts_grpc_record_protocol base;
     35   bool enable_extra_copy;
     36   grpc_slice_buffer data_sb;
     37   unsigned char* tag_buf;
     38 } alts_grpc_integrity_only_record_protocol;
     39 
     40 /* --- alts_grpc_record_protocol methods implementation. --- */
     41 
     42 static tsi_result alts_grpc_integrity_only_extra_copy_protect(
     43     alts_grpc_record_protocol* rp, grpc_slice_buffer* unprotected_slices,
     44     grpc_slice_buffer* protected_slices) {
     45   /* Allocates memory for protected frame and copies data.  */
     46   size_t data_length = unprotected_slices->length;
     47   size_t protected_frame_size =
     48       unprotected_slices->length + rp->header_length + rp->tag_length;
     49   grpc_slice protected_slice = GRPC_SLICE_MALLOC(protected_frame_size);
     50   uint8_t* data = GRPC_SLICE_START_PTR(protected_slice) + rp->header_length;
     51   for (size_t i = 0; i < unprotected_slices->count; i++) {
     52     memcpy(data, GRPC_SLICE_START_PTR(unprotected_slices->slices[i]),
     53            GRPC_SLICE_LENGTH(unprotected_slices->slices[i]));
     54     data += GRPC_SLICE_LENGTH(unprotected_slices->slices[i]);
     55   }
     56   /* Calls alts_iovec_record_protocol protect.  */
     57   char* error_details = nullptr;
     58   iovec_t header_iovec = {GRPC_SLICE_START_PTR(protected_slice),
     59                           rp->header_length};
     60   iovec_t tag_iovec = {
     61       GRPC_SLICE_START_PTR(protected_slice) + rp->header_length + data_length,
     62       rp->tag_length};
     63   rp->iovec_buf[0].iov_base =
     64       GRPC_SLICE_START_PTR(protected_slice) + rp->header_length;
     65   rp->iovec_buf[0].iov_len = data_length;
     66   grpc_status_code status = alts_iovec_record_protocol_integrity_only_protect(
     67       rp->iovec_rp, rp->iovec_buf, 1, header_iovec, tag_iovec, &error_details);
     68   if (status != GRPC_STATUS_OK) {
     69     gpr_log(GPR_ERROR, "Failed to protect, %s", error_details);
     70     gpr_free(error_details);
     71     return TSI_INTERNAL_ERROR;
     72   }
     73   grpc_slice_buffer_add(protected_slices, protected_slice);
     74   grpc_slice_buffer_reset_and_unref_internal(unprotected_slices);
     75   return TSI_OK;
     76 }
     77 
     78 static tsi_result alts_grpc_integrity_only_protect(
     79     alts_grpc_record_protocol* rp, grpc_slice_buffer* unprotected_slices,
     80     grpc_slice_buffer* protected_slices) {
     81   /* Input sanity check.  */
     82   if (rp == nullptr || unprotected_slices == nullptr ||
     83       protected_slices == nullptr) {
     84     gpr_log(GPR_ERROR,
     85             "Invalid nullptr arguments to alts_grpc_record_protocol protect.");
     86     return TSI_INVALID_ARGUMENT;
     87   }
     88   alts_grpc_integrity_only_record_protocol* integrity_only_record_protocol =
     89       reinterpret_cast<alts_grpc_integrity_only_record_protocol*>(rp);
     90   if (integrity_only_record_protocol->enable_extra_copy) {
     91     return alts_grpc_integrity_only_extra_copy_protect(rp, unprotected_slices,
     92                                                        protected_slices);
     93   }
     94   /* Allocates memory for header and tag slices.  */
     95   grpc_slice header_slice = GRPC_SLICE_MALLOC(rp->header_length);
     96   grpc_slice tag_slice = GRPC_SLICE_MALLOC(rp->tag_length);
     97   /* Calls alts_iovec_record_protocol protect.  */
     98   char* error_details = nullptr;
     99   iovec_t header_iovec = {GRPC_SLICE_START_PTR(header_slice),
    100                           GRPC_SLICE_LENGTH(header_slice)};
    101   iovec_t tag_iovec = {GRPC_SLICE_START_PTR(tag_slice),
    102                        GRPC_SLICE_LENGTH(tag_slice)};
    103   alts_grpc_record_protocol_convert_slice_buffer_to_iovec(rp,
    104                                                           unprotected_slices);
    105   grpc_status_code status = alts_iovec_record_protocol_integrity_only_protect(
    106       rp->iovec_rp, rp->iovec_buf, unprotected_slices->count, header_iovec,
    107       tag_iovec, &error_details);
    108   if (status != GRPC_STATUS_OK) {
    109     gpr_log(GPR_ERROR, "Failed to protect, %s", error_details);
    110     gpr_free(error_details);
    111     return TSI_INTERNAL_ERROR;
    112   }
    113   /* Appends result to protected_slices.  */
    114   grpc_slice_buffer_add(protected_slices, header_slice);
    115   grpc_slice_buffer_move_into(unprotected_slices, protected_slices);
    116   grpc_slice_buffer_add(protected_slices, tag_slice);
    117   return TSI_OK;
    118 }
    119 
    120 static tsi_result alts_grpc_integrity_only_unprotect(
    121     alts_grpc_record_protocol* rp, grpc_slice_buffer* protected_slices,
    122     grpc_slice_buffer* unprotected_slices) {
    123   /* Input sanity check.  */
    124   if (rp == nullptr || protected_slices == nullptr ||
    125       unprotected_slices == nullptr) {
    126     gpr_log(
    127         GPR_ERROR,
    128         "Invalid nullptr arguments to alts_grpc_record_protocol unprotect.");
    129     return TSI_INVALID_ARGUMENT;
    130   }
    131   if (protected_slices->length < rp->header_length + rp->tag_length) {
    132     gpr_log(GPR_ERROR, "Protected slices do not have sufficient data.");
    133     return TSI_INVALID_ARGUMENT;
    134   }
    135   /* In this method, rp points to alts_grpc_record_protocol struct
    136    * and integrity_only_record_protocol points to
    137    * alts_grpc_integrity_only_record_protocol struct.  */
    138   alts_grpc_integrity_only_record_protocol* integrity_only_record_protocol =
    139       reinterpret_cast<alts_grpc_integrity_only_record_protocol*>(rp);
    140   /* Strips frame header from protected slices.  */
    141   grpc_slice_buffer_reset_and_unref_internal(&rp->header_sb);
    142   grpc_slice_buffer_move_first(protected_slices, rp->header_length,
    143                                &rp->header_sb);
    144   GPR_ASSERT(rp->header_sb.length == rp->header_length);
    145   iovec_t header_iovec = alts_grpc_record_protocol_get_header_iovec(rp);
    146   /* Moves protected slices data to data_sb and leaves the remaining tag.  */
    147   grpc_slice_buffer_reset_and_unref_internal(
    148       &integrity_only_record_protocol->data_sb);
    149   grpc_slice_buffer_move_first(protected_slices,
    150                                protected_slices->length - rp->tag_length,
    151                                &integrity_only_record_protocol->data_sb);
    152   GPR_ASSERT(protected_slices->length == rp->tag_length);
    153   iovec_t tag_iovec = {nullptr, rp->tag_length};
    154   if (protected_slices->count == 1) {
    155     tag_iovec.iov_base = GRPC_SLICE_START_PTR(protected_slices->slices[0]);
    156   } else {
    157     /* Frame tag is in multiple slices, copies the tag bytes from slice
    158      * buffer to a single flat buffer.  */
    159     alts_grpc_record_protocol_copy_slice_buffer(
    160         protected_slices, integrity_only_record_protocol->tag_buf);
    161     tag_iovec.iov_base = integrity_only_record_protocol->tag_buf;
    162   }
    163   /* Calls alts_iovec_record_protocol unprotect.  */
    164   char* error_details = nullptr;
    165   alts_grpc_record_protocol_convert_slice_buffer_to_iovec(
    166       rp, &integrity_only_record_protocol->data_sb);
    167   grpc_status_code status = alts_iovec_record_protocol_integrity_only_unprotect(
    168       rp->iovec_rp, rp->iovec_buf,
    169       integrity_only_record_protocol->data_sb.count, header_iovec, tag_iovec,
    170       &error_details);
    171   if (status != GRPC_STATUS_OK) {
    172     gpr_log(GPR_ERROR, "Failed to unprotect, %s", error_details);
    173     gpr_free(error_details);
    174     return TSI_INTERNAL_ERROR;
    175   }
    176   grpc_slice_buffer_reset_and_unref_internal(&rp->header_sb);
    177   grpc_slice_buffer_reset_and_unref_internal(protected_slices);
    178   grpc_slice_buffer_move_into(&integrity_only_record_protocol->data_sb,
    179                               unprotected_slices);
    180   return TSI_OK;
    181 }
    182 
    183 static void alts_grpc_integrity_only_destruct(alts_grpc_record_protocol* rp) {
    184   if (rp == nullptr) {
    185     return;
    186   }
    187   alts_grpc_integrity_only_record_protocol* integrity_only_rp =
    188       reinterpret_cast<alts_grpc_integrity_only_record_protocol*>(rp);
    189   grpc_slice_buffer_destroy_internal(&integrity_only_rp->data_sb);
    190   gpr_free(integrity_only_rp->tag_buf);
    191 }
    192 
    193 static const alts_grpc_record_protocol_vtable
    194     alts_grpc_integrity_only_record_protocol_vtable = {
    195         alts_grpc_integrity_only_protect, alts_grpc_integrity_only_unprotect,
    196         alts_grpc_integrity_only_destruct};
    197 
    198 tsi_result alts_grpc_integrity_only_record_protocol_create(
    199     gsec_aead_crypter* crypter, size_t overflow_size, bool is_client,
    200     bool is_protect, bool enable_extra_copy, alts_grpc_record_protocol** rp) {
    201   if (crypter == nullptr || rp == nullptr) {
    202     gpr_log(GPR_ERROR,
    203             "Invalid nullptr arguments to alts_grpc_record_protocol create.");
    204     return TSI_INVALID_ARGUMENT;
    205   }
    206   alts_grpc_integrity_only_record_protocol* impl =
    207       static_cast<alts_grpc_integrity_only_record_protocol*>(
    208           gpr_zalloc(sizeof(alts_grpc_integrity_only_record_protocol)));
    209   /* Calls alts_grpc_record_protocol init.  */
    210   tsi_result result = alts_grpc_record_protocol_init(
    211       &impl->base, crypter, overflow_size, is_client,
    212       /*is_integrity_only=*/true, is_protect);
    213   if (result != TSI_OK) {
    214     gpr_free(impl);
    215     return result;
    216   }
    217   impl->enable_extra_copy = enable_extra_copy;
    218   /* Initializes slice buffer for data_sb.  */
    219   grpc_slice_buffer_init(&impl->data_sb);
    220   /* Allocates tag buffer.  */
    221   impl->tag_buf =
    222       static_cast<unsigned char*>(gpr_malloc(impl->base.tag_length));
    223   impl->base.vtable = &alts_grpc_integrity_only_record_protocol_vtable;
    224   *rp = &impl->base;
    225   return TSI_OK;
    226 }
    227