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. */
ensure_iovec_buf_size(alts_grpc_record_protocol * rp,const grpc_slice_buffer * sb)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
alts_grpc_record_protocol_convert_slice_buffer_to_iovec(alts_grpc_record_protocol * rp,const grpc_slice_buffer * sb)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
alts_grpc_record_protocol_copy_slice_buffer(const grpc_slice_buffer * src,unsigned char * dst)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
alts_grpc_record_protocol_get_header_iovec(alts_grpc_record_protocol * rp)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
alts_grpc_record_protocol_init(alts_grpc_record_protocol * rp,gsec_aead_crypter * crypter,size_t overflow_size,bool is_client,bool is_integrity_only,bool is_protect)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. --- */
alts_grpc_record_protocol_protect(alts_grpc_record_protocol * self,grpc_slice_buffer * unprotected_slices,grpc_slice_buffer * protected_slices)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
alts_grpc_record_protocol_unprotect(alts_grpc_record_protocol * self,grpc_slice_buffer * protected_slices,grpc_slice_buffer * unprotected_slices)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
alts_grpc_record_protocol_destroy(alts_grpc_record_protocol * self)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. */
alts_grpc_record_protocol_max_unprotected_data_size(const alts_grpc_record_protocol * self,size_t max_protected_frame_size)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