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