3 * Copyright 2018 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <grpc/slice_buffer.h>
20 #include <grpc/support/alloc.h>
21 #include <grpc/support/log.h>
23 #include "src/core/lib/iomgr/exec_ctx.h"
24 #include "src/core/lib/slice/slice_internal.h"
25 #include "src/core/tsi/alts/crypt/gsec.h"
26 #include "src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h"
27 #include "src/core/tsi/transport_security_grpc.h"
28 #include "test/core/tsi/alts/crypt/gsec_test_util.h"
29 #include "test/core/util/test_config.h"
31 /* TODO: tests zero_copy_grpc_protector under TSI test library, which
32 * has more comprehensive tests. */
34 constexpr size_t kSealRepeatTimes = 50;
35 constexpr size_t kSmallBufferSize = 16;
36 constexpr size_t kLargeBufferSize = 16384;
37 constexpr size_t kChannelMaxSize = 2048;
38 constexpr size_t kChannelMinSize = 128;
40 /* Test fixtures for each test cases. */
41 struct alts_zero_copy_grpc_protector_test_fixture {
42 tsi_zero_copy_grpc_protector* client;
43 tsi_zero_copy_grpc_protector* server;
46 /* Test input variables for protect/unprotect operations. */
47 struct alts_zero_copy_grpc_protector_test_var {
48 grpc_slice_buffer original_sb;
49 grpc_slice_buffer duplicate_sb;
50 grpc_slice_buffer staging_sb;
51 grpc_slice_buffer protected_sb;
52 grpc_slice_buffer unprotected_sb;
55 /* --- Test utility functions. --- */
57 static void create_random_slice_buffer(grpc_slice_buffer* sb,
58 grpc_slice_buffer* dup_sb,
60 GPR_ASSERT(sb != nullptr);
61 GPR_ASSERT(dup_sb != nullptr);
62 GPR_ASSERT(length > 0);
63 grpc_slice slice = GRPC_SLICE_MALLOC(length);
64 gsec_test_random_bytes(GRPC_SLICE_START_PTR(slice), length);
65 grpc_slice_buffer_add(sb, grpc_slice_ref(slice));
66 grpc_slice_buffer_add(dup_sb, slice);
69 static uint8_t* pointer_to_nth_byte(grpc_slice_buffer* sb, size_t index) {
70 GPR_ASSERT(sb != nullptr);
71 GPR_ASSERT(index < sb->length);
72 for (size_t i = 0; i < sb->count; i++) {
73 if (index < GRPC_SLICE_LENGTH(sb->slices[i])) {
74 return GRPC_SLICE_START_PTR(sb->slices[i]) + index;
76 index -= GRPC_SLICE_LENGTH(sb->slices[i]);
82 /* Checks if two slice buffer contents are the same. It is not super efficient,
83 * but OK for testing. */
84 static bool are_slice_buffers_equal(grpc_slice_buffer* first,
85 grpc_slice_buffer* second) {
86 GPR_ASSERT(first != nullptr);
87 GPR_ASSERT(second != nullptr);
88 if (first->length != second->length) {
91 for (size_t i = 0; i < first->length; i++) {
92 uint8_t* first_ptr = pointer_to_nth_byte(first, i);
93 uint8_t* second_ptr = pointer_to_nth_byte(second, i);
94 GPR_ASSERT(first_ptr != nullptr && second_ptr != nullptr);
95 if ((*first_ptr) != (*second_ptr)) {
102 static alts_zero_copy_grpc_protector_test_fixture*
103 alts_zero_copy_grpc_protector_test_fixture_create(bool rekey,
105 bool enable_extra_copy) {
106 alts_zero_copy_grpc_protector_test_fixture* fixture =
107 static_cast<alts_zero_copy_grpc_protector_test_fixture*>(
108 gpr_zalloc(sizeof(alts_zero_copy_grpc_protector_test_fixture)));
109 grpc_core::ExecCtx exec_ctx;
110 size_t key_length = rekey ? kAes128GcmRekeyKeyLength : kAes128GcmKeyLength;
112 size_t max_protected_frame_size = 1024;
113 size_t actual_max_protected_frame_size;
114 gsec_test_random_array(&key, key_length);
115 GPR_ASSERT(alts_zero_copy_grpc_protector_create(
116 key, key_length, rekey, /*is_client=*/true, integrity_only,
117 enable_extra_copy, &max_protected_frame_size,
118 &fixture->client) == TSI_OK);
119 GPR_ASSERT(tsi_zero_copy_grpc_protector_max_frame_size(
120 fixture->client, &actual_max_protected_frame_size) == TSI_OK);
121 GPR_ASSERT(actual_max_protected_frame_size == max_protected_frame_size);
122 GPR_ASSERT(alts_zero_copy_grpc_protector_create(
123 key, key_length, rekey, /*is_client=*/false, integrity_only,
124 enable_extra_copy, &max_protected_frame_size,
125 &fixture->server) == TSI_OK);
126 GPR_ASSERT(tsi_zero_copy_grpc_protector_max_frame_size(
127 fixture->server, &actual_max_protected_frame_size) == TSI_OK);
128 GPR_ASSERT(actual_max_protected_frame_size == max_protected_frame_size);
130 grpc_core::ExecCtx::Get()->Flush();
134 static void alts_zero_copy_grpc_protector_test_fixture_destroy(
135 alts_zero_copy_grpc_protector_test_fixture* fixture) {
136 if (fixture == nullptr) {
139 grpc_core::ExecCtx exec_ctx;
140 tsi_zero_copy_grpc_protector_destroy(fixture->client);
141 tsi_zero_copy_grpc_protector_destroy(fixture->server);
142 grpc_core::ExecCtx::Get()->Flush();
146 static alts_zero_copy_grpc_protector_test_var*
147 alts_zero_copy_grpc_protector_test_var_create() {
148 alts_zero_copy_grpc_protector_test_var* var =
149 static_cast<alts_zero_copy_grpc_protector_test_var*>(
150 gpr_zalloc(sizeof(alts_zero_copy_grpc_protector_test_var)));
151 grpc_slice_buffer_init(&var->original_sb);
152 grpc_slice_buffer_init(&var->duplicate_sb);
153 grpc_slice_buffer_init(&var->staging_sb);
154 grpc_slice_buffer_init(&var->protected_sb);
155 grpc_slice_buffer_init(&var->unprotected_sb);
159 static void alts_zero_copy_grpc_protector_test_var_destroy(
160 alts_zero_copy_grpc_protector_test_var* var) {
161 if (var == nullptr) {
164 grpc_slice_buffer_destroy_internal(&var->original_sb);
165 grpc_slice_buffer_destroy_internal(&var->duplicate_sb);
166 grpc_slice_buffer_destroy_internal(&var->staging_sb);
167 grpc_slice_buffer_destroy_internal(&var->protected_sb);
168 grpc_slice_buffer_destroy_internal(&var->unprotected_sb);
172 /* --- ALTS zero-copy protector tests. --- */
174 static void seal_unseal_small_buffer(tsi_zero_copy_grpc_protector* sender,
175 tsi_zero_copy_grpc_protector* receiver) {
176 grpc_core::ExecCtx exec_ctx;
177 for (size_t i = 0; i < kSealRepeatTimes; i++) {
178 alts_zero_copy_grpc_protector_test_var* var =
179 alts_zero_copy_grpc_protector_test_var_create();
180 /* Creates a random small slice buffer and calls protect(). */
181 create_random_slice_buffer(&var->original_sb, &var->duplicate_sb,
183 GPR_ASSERT(tsi_zero_copy_grpc_protector_protect(
184 sender, &var->original_sb, &var->protected_sb) == TSI_OK);
185 /* Splits protected slice buffer into two: first one is staging_sb, and
186 * second one is protected_sb. */
187 uint32_t staging_sb_size =
188 gsec_test_bias_random_uint32(
189 static_cast<uint32_t>(var->protected_sb.length - 1)) +
191 grpc_slice_buffer_move_first(&var->protected_sb, staging_sb_size,
193 /* Unprotects one by one. */
194 GPR_ASSERT(tsi_zero_copy_grpc_protector_unprotect(
195 receiver, &var->staging_sb, &var->unprotected_sb) == TSI_OK);
196 GPR_ASSERT(var->unprotected_sb.length == 0);
197 GPR_ASSERT(tsi_zero_copy_grpc_protector_unprotect(
198 receiver, &var->protected_sb, &var->unprotected_sb) ==
201 are_slice_buffers_equal(&var->unprotected_sb, &var->duplicate_sb));
202 alts_zero_copy_grpc_protector_test_var_destroy(var);
204 grpc_core::ExecCtx::Get()->Flush();
207 static void seal_unseal_large_buffer(tsi_zero_copy_grpc_protector* sender,
208 tsi_zero_copy_grpc_protector* receiver) {
209 grpc_core::ExecCtx exec_ctx;
210 for (size_t i = 0; i < kSealRepeatTimes; i++) {
211 alts_zero_copy_grpc_protector_test_var* var =
212 alts_zero_copy_grpc_protector_test_var_create();
213 /* Creates a random large slice buffer and calls protect(). */
214 create_random_slice_buffer(&var->original_sb, &var->duplicate_sb,
216 GPR_ASSERT(tsi_zero_copy_grpc_protector_protect(
217 sender, &var->original_sb, &var->protected_sb) == TSI_OK);
218 /* Splits protected slice buffer into multiple pieces. Receiver unprotects
219 * each slice buffer one by one. */
220 uint32_t channel_size = gsec_test_bias_random_uint32(static_cast<uint32_t>(
221 kChannelMaxSize + 1 - kChannelMinSize)) +
222 static_cast<uint32_t>(kChannelMinSize);
223 while (var->protected_sb.length > channel_size) {
224 grpc_slice_buffer_reset_and_unref_internal(&var->staging_sb);
225 grpc_slice_buffer_move_first(&var->protected_sb, channel_size,
227 GPR_ASSERT(tsi_zero_copy_grpc_protector_unprotect(
228 receiver, &var->staging_sb, &var->unprotected_sb) ==
231 GPR_ASSERT(tsi_zero_copy_grpc_protector_unprotect(
232 receiver, &var->protected_sb, &var->unprotected_sb) ==
235 are_slice_buffers_equal(&var->unprotected_sb, &var->duplicate_sb));
236 alts_zero_copy_grpc_protector_test_var_destroy(var);
238 grpc_core::ExecCtx::Get()->Flush();
241 /* --- Test cases. --- */
243 static void alts_zero_copy_protector_seal_unseal_small_buffer_tests(
244 bool enable_extra_copy) {
245 alts_zero_copy_grpc_protector_test_fixture* fixture =
246 alts_zero_copy_grpc_protector_test_fixture_create(
247 /*rekey=*/false, /*integrity_only=*/true, enable_extra_copy);
248 seal_unseal_small_buffer(fixture->client, fixture->server);
249 seal_unseal_small_buffer(fixture->server, fixture->client);
250 alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
252 fixture = alts_zero_copy_grpc_protector_test_fixture_create(
253 /*rekey=*/false, /*integrity_only=*/false, enable_extra_copy);
254 seal_unseal_small_buffer(fixture->client, fixture->server);
255 seal_unseal_small_buffer(fixture->server, fixture->client);
256 alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
258 fixture = alts_zero_copy_grpc_protector_test_fixture_create(
259 /*rekey=*/true, /*integrity_only=*/true, enable_extra_copy);
260 seal_unseal_small_buffer(fixture->client, fixture->server);
261 seal_unseal_small_buffer(fixture->server, fixture->client);
262 alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
264 fixture = alts_zero_copy_grpc_protector_test_fixture_create(
265 /*rekey=*/true, /*integrity_only=*/false, enable_extra_copy);
266 seal_unseal_small_buffer(fixture->client, fixture->server);
267 seal_unseal_small_buffer(fixture->server, fixture->client);
268 alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
271 static void alts_zero_copy_protector_seal_unseal_large_buffer_tests(
272 bool enable_extra_copy) {
273 alts_zero_copy_grpc_protector_test_fixture* fixture =
274 alts_zero_copy_grpc_protector_test_fixture_create(
275 /*rekey=*/false, /*integrity_only=*/true, enable_extra_copy);
276 seal_unseal_large_buffer(fixture->client, fixture->server);
277 seal_unseal_large_buffer(fixture->server, fixture->client);
278 alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
280 fixture = alts_zero_copy_grpc_protector_test_fixture_create(
281 /*rekey=*/false, /*integrity_only=*/false, enable_extra_copy);
282 seal_unseal_large_buffer(fixture->client, fixture->server);
283 seal_unseal_large_buffer(fixture->server, fixture->client);
284 alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
286 fixture = alts_zero_copy_grpc_protector_test_fixture_create(
287 /*rekey=*/true, /*integrity_only=*/true, enable_extra_copy);
288 seal_unseal_large_buffer(fixture->client, fixture->server);
289 seal_unseal_large_buffer(fixture->server, fixture->client);
290 alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
292 fixture = alts_zero_copy_grpc_protector_test_fixture_create(
293 /*rekey=*/true, /*integrity_only=*/false, enable_extra_copy);
294 seal_unseal_large_buffer(fixture->client, fixture->server);
295 seal_unseal_large_buffer(fixture->server, fixture->client);
296 alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
299 int main(int argc, char** argv) {
300 grpc::testing::TestEnvironment env(argc, argv);
302 alts_zero_copy_protector_seal_unseal_small_buffer_tests(
303 /*enable_extra_copy=*/false);
304 alts_zero_copy_protector_seal_unseal_small_buffer_tests(
305 /*enable_extra_copy=*/true);
306 alts_zero_copy_protector_seal_unseal_large_buffer_tests(
307 /*enable_extra_copy=*/false);
308 alts_zero_copy_protector_seal_unseal_large_buffer_tests(
309 /*enable_extra_copy=*/true);