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_record_protocol_common.h" 22 23 #include <string.h> 24 25 #include <grpc/support/alloc.h> 26 #include <grpc/support/log.h> 27 28 #include "src/core/lib/gpr/useful.h" 29 #include "src/core/lib/iomgr/exec_ctx.h" 30 #include "src/core/lib/slice/slice_internal.h" 31 32 const size_t kInitialIovecBufferSize = 8; 33 34 /* Makes sure iovec_buf in alts_grpc_record_protocol is large enough. */ 35 static void ensure_iovec_buf_size(alts_grpc_record_protocol* rp, 36 const grpc_slice_buffer* sb) { 37 GPR_ASSERT(rp != nullptr && sb != nullptr); 38 if (sb->count <= rp->iovec_buf_length) { 39 return; 40 } 41 /* At least double the iovec buffer size. */ 42 rp->iovec_buf_length = GPR_MAX(sb->count, 2 * rp->iovec_buf_length); 43 rp->iovec_buf = static_cast<iovec_t*>( 44 gpr_realloc(rp->iovec_buf, rp->iovec_buf_length * sizeof(iovec_t))); 45 } 46 47 /* --- Implementation of methods defined in tsi_grpc_record_protocol_common.h. 48 * --- */ 49 50 void alts_grpc_record_protocol_convert_slice_buffer_to_iovec( 51 alts_grpc_record_protocol* rp, const grpc_slice_buffer* sb) { 52 GPR_ASSERT(rp != nullptr && sb != nullptr); 53 ensure_iovec_buf_size(rp, sb); 54 for (size_t i = 0; i < sb->count; i++) { 55 rp->iovec_buf[i].iov_base = GRPC_SLICE_START_PTR(sb->slices[i]); 56 rp->iovec_buf[i].iov_len = GRPC_SLICE_LENGTH(sb->slices[i]); 57 } 58 } 59 60 void alts_grpc_record_protocol_copy_slice_buffer(const grpc_slice_buffer* src, 61 unsigned char* dst) { 62 GPR_ASSERT(src != nullptr && dst != nullptr); 63 for (size_t i = 0; i < src->count; i++) { 64 size_t slice_length = GRPC_SLICE_LENGTH(src->slices[i]); 65 memcpy(dst, GRPC_SLICE_START_PTR(src->slices[i]), slice_length); 66 dst += slice_length; 67 } 68 } 69 70 iovec_t alts_grpc_record_protocol_get_header_iovec( 71 alts_grpc_record_protocol* rp) { 72 iovec_t header_iovec = {nullptr, 0}; 73 if (rp == nullptr) { 74 return header_iovec; 75 } 76 header_iovec.iov_len = rp->header_length; 77 if (rp->header_sb.count == 1) { 78 header_iovec.iov_base = GRPC_SLICE_START_PTR(rp->header_sb.slices[0]); 79 } else { 80 /* Frame header is in multiple slices, copies the header bytes from slice 81 * buffer to a single flat buffer. */ 82 alts_grpc_record_protocol_copy_slice_buffer(&rp->header_sb, rp->header_buf); 83 header_iovec.iov_base = rp->header_buf; 84 } 85 return header_iovec; 86 } 87 88 tsi_result alts_grpc_record_protocol_init(alts_grpc_record_protocol* rp, 89 gsec_aead_crypter* crypter, 90 size_t overflow_size, bool is_client, 91 bool is_integrity_only, 92 bool is_protect) { 93 if (rp == nullptr || crypter == nullptr) { 94 gpr_log(GPR_ERROR, 95 "Invalid nullptr arguments to alts_grpc_record_protocol init."); 96 return TSI_INVALID_ARGUMENT; 97 } 98 /* Creates alts_iovec_record_protocol. */ 99 char* error_details = nullptr; 100 grpc_status_code status = alts_iovec_record_protocol_create( 101 crypter, overflow_size, is_client, is_integrity_only, is_protect, 102 &rp->iovec_rp, &error_details); 103 if (status != GRPC_STATUS_OK) { 104 gpr_log(GPR_ERROR, "Failed to create alts_iovec_record_protocol, %s.", 105 error_details); 106 gpr_free(error_details); 107 return TSI_INTERNAL_ERROR; 108 } 109 /* Allocates header slice buffer. */ 110 grpc_slice_buffer_init(&rp->header_sb); 111 /* Allocates header buffer. */ 112 rp->header_length = alts_iovec_record_protocol_get_header_length(); 113 rp->header_buf = static_cast<unsigned char*>(gpr_malloc(rp->header_length)); 114 rp->tag_length = alts_iovec_record_protocol_get_tag_length(rp->iovec_rp); 115 /* Allocates iovec buffer. */ 116 rp->iovec_buf_length = kInitialIovecBufferSize; 117 rp->iovec_buf = 118 static_cast<iovec_t*>(gpr_malloc(rp->iovec_buf_length * sizeof(iovec_t))); 119 return TSI_OK; 120 } 121 122 /* --- Implementation of methods defined in tsi_grpc_record_protocol.h. --- */ 123 tsi_result alts_grpc_record_protocol_protect( 124 alts_grpc_record_protocol* self, grpc_slice_buffer* unprotected_slices, 125 grpc_slice_buffer* protected_slices) { 126 if (grpc_core::ExecCtx::Get() == nullptr || self == nullptr || 127 self->vtable == nullptr || unprotected_slices == nullptr || 128 protected_slices == nullptr) { 129 return TSI_INVALID_ARGUMENT; 130 } 131 if (self->vtable->protect == nullptr) { 132 return TSI_UNIMPLEMENTED; 133 } 134 return self->vtable->protect(self, unprotected_slices, protected_slices); 135 } 136 137 tsi_result alts_grpc_record_protocol_unprotect( 138 alts_grpc_record_protocol* self, grpc_slice_buffer* protected_slices, 139 grpc_slice_buffer* unprotected_slices) { 140 if (grpc_core::ExecCtx::Get() == nullptr || self == nullptr || 141 self->vtable == nullptr || protected_slices == nullptr || 142 unprotected_slices == nullptr) { 143 return TSI_INVALID_ARGUMENT; 144 } 145 if (self->vtable->unprotect == nullptr) { 146 return TSI_UNIMPLEMENTED; 147 } 148 return self->vtable->unprotect(self, protected_slices, unprotected_slices); 149 } 150 151 void alts_grpc_record_protocol_destroy(alts_grpc_record_protocol* self) { 152 if (self == nullptr) { 153 return; 154 } 155 if (self->vtable->destruct != nullptr) { 156 self->vtable->destruct(self); 157 } 158 alts_iovec_record_protocol_destroy(self->iovec_rp); 159 grpc_slice_buffer_destroy_internal(&self->header_sb); 160 gpr_free(self->header_buf); 161 gpr_free(self->iovec_buf); 162 gpr_free(self); 163 } 164 165 /* Integrity-only and privacy-integrity share the same implementation. No need 166 * to call vtable. */ 167 size_t alts_grpc_record_protocol_max_unprotected_data_size( 168 const alts_grpc_record_protocol* self, size_t max_protected_frame_size) { 169 if (self == nullptr) { 170 return 0; 171 } 172 return alts_iovec_record_protocol_max_unprotected_data_size( 173 self->iovec_rp, max_protected_frame_size); 174 } 175