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 "src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h"
20 
21 #include <gtest/gtest.h>
22 
23 #include "absl/types/span.h"
24 
25 #include <grpc/slice_buffer.h>
26 #include <grpc/support/alloc.h>
27 #include <grpc/support/log.h>
28 
29 #include "src/core/tsi/alts/crypt/gsec.h"
30 #include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h"
31 #include "src/core/tsi/transport_security_grpc.h"
32 #include "test/core/tsi/alts/crypt/gsec_test_util.h"
33 #include "test/core/util/test_config.h"
34 
35 // TODO(unknown): tests zero_copy_grpc_protector under TSI test library, which
36 // has more comprehensive tests.
37 
38 constexpr size_t kSealRepeatTimes = 50;
39 constexpr size_t kSmallBufferSize = 16;
40 constexpr size_t kLargeBufferSize = 16384;
41 constexpr size_t kChannelMaxSize = 2048;
42 constexpr size_t kChannelMinSize = 128;
43 
44 // Test fixtures for each test cases.
45 struct alts_zero_copy_grpc_protector_test_fixture {
46   tsi_zero_copy_grpc_protector* client;
47   tsi_zero_copy_grpc_protector* server;
48 };
49 
50 // Test input variables for protect/unprotect operations.
51 struct alts_zero_copy_grpc_protector_test_var {
52   grpc_slice_buffer original_sb;
53   grpc_slice_buffer duplicate_sb;
54   grpc_slice_buffer staging_sb;
55   grpc_slice_buffer protected_sb;
56   grpc_slice_buffer unprotected_sb;
57 };
58 
59 // --- Test utility functions. ---
60 
create_random_slice_buffer(grpc_slice_buffer * sb,grpc_slice_buffer * dup_sb,size_t length)61 static void create_random_slice_buffer(grpc_slice_buffer* sb,
62                                        grpc_slice_buffer* dup_sb,
63                                        size_t length) {
64   ASSERT_NE(sb, nullptr);
65   ASSERT_NE(dup_sb, nullptr);
66   ASSERT_GT(length, 0);
67   grpc_slice slice = GRPC_SLICE_MALLOC(length);
68   gsec_test_random_bytes(GRPC_SLICE_START_PTR(slice), length);
69   grpc_slice_buffer_add(sb, grpc_slice_ref(slice));
70   grpc_slice_buffer_add(dup_sb, slice);
71 }
72 
pointer_to_nth_byte(grpc_slice_buffer * sb,size_t index)73 static uint8_t* pointer_to_nth_byte(grpc_slice_buffer* sb, size_t index) {
74   EXPECT_NE(sb, nullptr);
75   EXPECT_LT(index, sb->length);
76   for (size_t i = 0; i < sb->count; i++) {
77     if (index < GRPC_SLICE_LENGTH(sb->slices[i])) {
78       return GRPC_SLICE_START_PTR(sb->slices[i]) + index;
79     } else {
80       index -= GRPC_SLICE_LENGTH(sb->slices[i]);
81     }
82   }
83   return nullptr;
84 }
85 
86 // Checks if two slice buffer contents are the same. It is not super efficient,
87 // but OK for testing.
are_slice_buffers_equal(grpc_slice_buffer * first,grpc_slice_buffer * second)88 static bool are_slice_buffers_equal(grpc_slice_buffer* first,
89                                     grpc_slice_buffer* second) {
90   EXPECT_NE(first, nullptr);
91   EXPECT_NE(second, nullptr);
92   if (first->length != second->length) {
93     return false;
94   }
95   for (size_t i = 0; i < first->length; i++) {
96     uint8_t* first_ptr = pointer_to_nth_byte(first, i);
97     uint8_t* second_ptr = pointer_to_nth_byte(second, i);
98     EXPECT_TRUE(first_ptr != nullptr && second_ptr != nullptr);
99     if ((*first_ptr) != (*second_ptr)) {
100       return false;
101     }
102   }
103   return true;
104 }
105 
106 static alts_zero_copy_grpc_protector_test_fixture*
alts_zero_copy_grpc_protector_test_fixture_create(bool rekey,bool integrity_only,bool enable_extra_copy)107 alts_zero_copy_grpc_protector_test_fixture_create(bool rekey,
108                                                   bool integrity_only,
109                                                   bool enable_extra_copy) {
110   alts_zero_copy_grpc_protector_test_fixture* fixture =
111       static_cast<alts_zero_copy_grpc_protector_test_fixture*>(
112           gpr_zalloc(sizeof(alts_zero_copy_grpc_protector_test_fixture)));
113   size_t key_length = rekey ? kAes128GcmRekeyKeyLength : kAes128GcmKeyLength;
114   uint8_t* key;
115   size_t max_protected_frame_size = 1024;
116   size_t actual_max_protected_frame_size;
117   gsec_test_random_array(&key, key_length);
118   EXPECT_EQ(alts_zero_copy_grpc_protector_create(
119                 grpc_core::GsecKeyFactory(absl::MakeConstSpan(key, key_length),
120                                           rekey),
121                 /*is_client=*/true, integrity_only, enable_extra_copy,
122                 &max_protected_frame_size, &fixture->client),
123             TSI_OK);
124   EXPECT_EQ(tsi_zero_copy_grpc_protector_max_frame_size(
125                 fixture->client, &actual_max_protected_frame_size),
126             TSI_OK);
127   EXPECT_EQ(actual_max_protected_frame_size, max_protected_frame_size);
128   EXPECT_EQ(alts_zero_copy_grpc_protector_create(
129                 grpc_core::GsecKeyFactory(absl::MakeConstSpan(key, key_length),
130                                           rekey),
131                 /*is_client=*/false, integrity_only, enable_extra_copy,
132                 &max_protected_frame_size, &fixture->server),
133             TSI_OK);
134   EXPECT_EQ(tsi_zero_copy_grpc_protector_max_frame_size(
135                 fixture->server, &actual_max_protected_frame_size),
136             TSI_OK);
137   EXPECT_EQ(actual_max_protected_frame_size, max_protected_frame_size);
138   gpr_free(key);
139   return fixture;
140 }
141 
alts_zero_copy_grpc_protector_test_fixture_destroy(alts_zero_copy_grpc_protector_test_fixture * fixture)142 static void alts_zero_copy_grpc_protector_test_fixture_destroy(
143     alts_zero_copy_grpc_protector_test_fixture* fixture) {
144   if (fixture == nullptr) {
145     return;
146   }
147   tsi_zero_copy_grpc_protector_destroy(fixture->client);
148   tsi_zero_copy_grpc_protector_destroy(fixture->server);
149   gpr_free(fixture);
150 }
151 
152 static alts_zero_copy_grpc_protector_test_var*
alts_zero_copy_grpc_protector_test_var_create()153 alts_zero_copy_grpc_protector_test_var_create() {
154   alts_zero_copy_grpc_protector_test_var* var =
155       static_cast<alts_zero_copy_grpc_protector_test_var*>(
156           gpr_zalloc(sizeof(alts_zero_copy_grpc_protector_test_var)));
157   grpc_slice_buffer_init(&var->original_sb);
158   grpc_slice_buffer_init(&var->duplicate_sb);
159   grpc_slice_buffer_init(&var->staging_sb);
160   grpc_slice_buffer_init(&var->protected_sb);
161   grpc_slice_buffer_init(&var->unprotected_sb);
162   return var;
163 }
164 
alts_zero_copy_grpc_protector_test_var_destroy(alts_zero_copy_grpc_protector_test_var * var)165 static void alts_zero_copy_grpc_protector_test_var_destroy(
166     alts_zero_copy_grpc_protector_test_var* var) {
167   if (var == nullptr) {
168     return;
169   }
170   grpc_slice_buffer_destroy(&var->original_sb);
171   grpc_slice_buffer_destroy(&var->duplicate_sb);
172   grpc_slice_buffer_destroy(&var->staging_sb);
173   grpc_slice_buffer_destroy(&var->protected_sb);
174   grpc_slice_buffer_destroy(&var->unprotected_sb);
175   gpr_free(var);
176 }
177 
178 // --- ALTS zero-copy protector tests. ---
179 
seal_unseal_small_buffer(tsi_zero_copy_grpc_protector * sender,tsi_zero_copy_grpc_protector * receiver)180 static void seal_unseal_small_buffer(tsi_zero_copy_grpc_protector* sender,
181                                      tsi_zero_copy_grpc_protector* receiver) {
182   for (size_t i = 0; i < kSealRepeatTimes; i++) {
183     int min_progress_size;
184     alts_zero_copy_grpc_protector_test_var* var =
185         alts_zero_copy_grpc_protector_test_var_create();
186     // Creates a random small slice buffer and calls protect().
187     create_random_slice_buffer(&var->original_sb, &var->duplicate_sb,
188                                kSmallBufferSize);
189     ASSERT_EQ(tsi_zero_copy_grpc_protector_protect(sender, &var->original_sb,
190                                                    &var->protected_sb),
191               TSI_OK);
192     // Splits protected slice buffer into two: first one is staging_sb, and
193     // second one is protected_sb.
194     uint32_t staging_sb_size =
195         gsec_test_bias_random_uint32(
196             static_cast<uint32_t>(var->protected_sb.length - 1)) +
197         1;
198     grpc_slice_buffer_move_first(&var->protected_sb, staging_sb_size,
199                                  &var->staging_sb);
200     // Unprotects one by one.
201     ASSERT_EQ(tsi_zero_copy_grpc_protector_unprotect(receiver, &var->staging_sb,
202                                                      &var->unprotected_sb,
203                                                      &min_progress_size),
204               TSI_OK);
205     if (staging_sb_size >= kZeroCopyFrameLengthFieldSize) {
206       ASSERT_EQ(min_progress_size, static_cast<int>(var->protected_sb.length));
207     } else {
208       ASSERT_EQ(min_progress_size, 1);
209     }
210     ASSERT_EQ(var->unprotected_sb.length, 0);
211     ASSERT_EQ(tsi_zero_copy_grpc_protector_unprotect(
212                   receiver, &var->protected_sb, &var->unprotected_sb,
213                   &min_progress_size),
214               TSI_OK);
215     ASSERT_TRUE(
216         are_slice_buffers_equal(&var->unprotected_sb, &var->duplicate_sb));
217     ASSERT_EQ(min_progress_size, 1);
218     alts_zero_copy_grpc_protector_test_var_destroy(var);
219   }
220 }
221 
seal_unseal_large_buffer(tsi_zero_copy_grpc_protector * sender,tsi_zero_copy_grpc_protector * receiver)222 static void seal_unseal_large_buffer(tsi_zero_copy_grpc_protector* sender,
223                                      tsi_zero_copy_grpc_protector* receiver) {
224   for (size_t i = 0; i < kSealRepeatTimes; i++) {
225     alts_zero_copy_grpc_protector_test_var* var =
226         alts_zero_copy_grpc_protector_test_var_create();
227     // Creates a random large slice buffer and calls protect().
228     create_random_slice_buffer(&var->original_sb, &var->duplicate_sb,
229                                kLargeBufferSize);
230     ASSERT_EQ(tsi_zero_copy_grpc_protector_protect(sender, &var->original_sb,
231                                                    &var->protected_sb),
232               TSI_OK);
233     // Splits protected slice buffer into multiple pieces. Receiver unprotects
234     // each slice buffer one by one.
235     uint32_t channel_size = gsec_test_bias_random_uint32(static_cast<uint32_t>(
236                                 kChannelMaxSize + 1 - kChannelMinSize)) +
237                             static_cast<uint32_t>(kChannelMinSize);
238     while (var->protected_sb.length > channel_size) {
239       grpc_slice_buffer_reset_and_unref(&var->staging_sb);
240       grpc_slice_buffer_move_first(&var->protected_sb, channel_size,
241                                    &var->staging_sb);
242       ASSERT_EQ(tsi_zero_copy_grpc_protector_unprotect(
243                     receiver, &var->staging_sb, &var->unprotected_sb, nullptr),
244                 TSI_OK);
245     }
246     ASSERT_EQ(tsi_zero_copy_grpc_protector_unprotect(
247                   receiver, &var->protected_sb, &var->unprotected_sb, nullptr),
248               TSI_OK);
249     ASSERT_TRUE(
250         are_slice_buffers_equal(&var->unprotected_sb, &var->duplicate_sb));
251     alts_zero_copy_grpc_protector_test_var_destroy(var);
252   }
253 }
254 
255 // --- Test cases. ---
256 
alts_zero_copy_protector_seal_unseal_small_buffer_tests(bool enable_extra_copy)257 static void alts_zero_copy_protector_seal_unseal_small_buffer_tests(
258     bool enable_extra_copy) {
259   alts_zero_copy_grpc_protector_test_fixture* fixture =
260       alts_zero_copy_grpc_protector_test_fixture_create(
261           /*rekey=*/false, /*integrity_only=*/true, enable_extra_copy);
262   seal_unseal_small_buffer(fixture->client, fixture->server);
263   seal_unseal_small_buffer(fixture->server, fixture->client);
264   alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
265 
266   fixture = alts_zero_copy_grpc_protector_test_fixture_create(
267       /*rekey=*/false, /*integrity_only=*/false, enable_extra_copy);
268   seal_unseal_small_buffer(fixture->client, fixture->server);
269   seal_unseal_small_buffer(fixture->server, fixture->client);
270   alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
271 
272   fixture = alts_zero_copy_grpc_protector_test_fixture_create(
273       /*rekey=*/true, /*integrity_only=*/true, enable_extra_copy);
274   seal_unseal_small_buffer(fixture->client, fixture->server);
275   seal_unseal_small_buffer(fixture->server, fixture->client);
276   alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
277 
278   fixture = alts_zero_copy_grpc_protector_test_fixture_create(
279       /*rekey=*/true, /*integrity_only=*/false, enable_extra_copy);
280   seal_unseal_small_buffer(fixture->client, fixture->server);
281   seal_unseal_small_buffer(fixture->server, fixture->client);
282   alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
283 }
284 
alts_zero_copy_protector_seal_unseal_large_buffer_tests(bool enable_extra_copy)285 static void alts_zero_copy_protector_seal_unseal_large_buffer_tests(
286     bool enable_extra_copy) {
287   alts_zero_copy_grpc_protector_test_fixture* fixture =
288       alts_zero_copy_grpc_protector_test_fixture_create(
289           /*rekey=*/false, /*integrity_only=*/true, enable_extra_copy);
290   seal_unseal_large_buffer(fixture->client, fixture->server);
291   seal_unseal_large_buffer(fixture->server, fixture->client);
292   alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
293 
294   fixture = alts_zero_copy_grpc_protector_test_fixture_create(
295       /*rekey=*/false, /*integrity_only=*/false, enable_extra_copy);
296   seal_unseal_large_buffer(fixture->client, fixture->server);
297   seal_unseal_large_buffer(fixture->server, fixture->client);
298   alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
299 
300   fixture = alts_zero_copy_grpc_protector_test_fixture_create(
301       /*rekey=*/true, /*integrity_only=*/true, enable_extra_copy);
302   seal_unseal_large_buffer(fixture->client, fixture->server);
303   seal_unseal_large_buffer(fixture->server, fixture->client);
304   alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
305 
306   fixture = alts_zero_copy_grpc_protector_test_fixture_create(
307       /*rekey=*/true, /*integrity_only=*/false, enable_extra_copy);
308   seal_unseal_large_buffer(fixture->client, fixture->server);
309   seal_unseal_large_buffer(fixture->server, fixture->client);
310   alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
311 }
312 
TEST(AltsZeroCopyGrpcProtectorTest,MainTest)313 TEST(AltsZeroCopyGrpcProtectorTest, MainTest) {
314   grpc_init();
315   alts_zero_copy_protector_seal_unseal_small_buffer_tests(
316       /*enable_extra_copy=*/false);
317   alts_zero_copy_protector_seal_unseal_small_buffer_tests(
318       /*enable_extra_copy=*/true);
319   alts_zero_copy_protector_seal_unseal_large_buffer_tests(
320       /*enable_extra_copy=*/false);
321   alts_zero_copy_protector_seal_unseal_large_buffer_tests(
322       /*enable_extra_copy=*/true);
323   grpc_shutdown();
324 }
325 
main(int argc,char ** argv)326 int main(int argc, char** argv) {
327   grpc::testing::TestEnvironment env(&argc, argv);
328   ::testing::InitGoogleTest(&argc, argv);
329   grpc::testing::TestGrpcScope grpc_scope;
330   return RUN_ALL_TESTS();
331 }
332