Imported Upstream version 1.41.0
[platform/upstream/grpc.git] / test / core / tsi / alts / zero_copy_frame_protector / alts_grpc_record_protocol_test.cc
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_grpc_record_protocol.h"
20
21 #include <grpc/support/alloc.h>
22 #include <grpc/support/log.h>
23
24 #include "src/core/lib/iomgr/exec_ctx.h"
25 #include "src/core/lib/slice/slice_internal.h"
26 #include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h"
27 #include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h"
28 #include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h"
29 #include "test/core/tsi/alts/crypt/gsec_test_util.h"
30 #include "test/core/util/test_config.h"
31
32 constexpr size_t kMaxSliceLength = 256;
33 constexpr size_t kMaxSlices = 10;
34 constexpr size_t kSealRepeatTimes = 5;
35 constexpr size_t kTagLength = 16;
36
37 /* Test fixtures for each test cases.  */
38 struct alts_grpc_record_protocol_test_fixture {
39   alts_grpc_record_protocol* client_protect;
40   alts_grpc_record_protocol* client_unprotect;
41   alts_grpc_record_protocol* server_protect;
42   alts_grpc_record_protocol* server_unprotect;
43 };
44
45 /* Test input variables for protect/unprotect operations.  */
46 struct alts_grpc_record_protocol_test_var {
47   size_t header_length;
48   size_t tag_length;
49   grpc_slice_buffer original_sb;
50   grpc_slice_buffer duplicate_sb;
51   grpc_slice_buffer protected_sb;
52   grpc_slice_buffer unprotected_sb;
53 };
54
55 /* --- Test utility functions. --- */
56
57 static void create_random_slice_buffer(grpc_slice_buffer* sb) {
58   GPR_ASSERT(sb != nullptr);
59   size_t slice_count = gsec_test_bias_random_uint32(kMaxSlices) + 1;
60   for (size_t i = 0; i < slice_count; i++) {
61     size_t slice_length = gsec_test_bias_random_uint32(kMaxSliceLength) + 1;
62     grpc_slice slice = GRPC_SLICE_MALLOC(slice_length);
63     gsec_test_random_bytes(GRPC_SLICE_START_PTR(slice), slice_length);
64     grpc_slice_buffer_add(sb, slice);
65   }
66 }
67
68 static uint8_t* pointer_to_nth_byte(grpc_slice_buffer* sb, size_t index) {
69   GPR_ASSERT(sb != nullptr);
70   GPR_ASSERT(index < sb->length);
71   for (size_t i = 0; i < sb->count; i++) {
72     if (index < GRPC_SLICE_LENGTH(sb->slices[i])) {
73       return GRPC_SLICE_START_PTR(sb->slices[i]) + index;
74     } else {
75       index -= GRPC_SLICE_LENGTH(sb->slices[i]);
76     }
77   }
78   return nullptr;
79 }
80
81 /* Checks if two slice buffer contents are the same. It is not super efficient,
82  * but OK for testing.  */
83 static bool are_slice_buffers_equal(grpc_slice_buffer* first,
84                                     grpc_slice_buffer* second) {
85   GPR_ASSERT(first != nullptr);
86   GPR_ASSERT(second != nullptr);
87   if (first->length != second->length) {
88     return false;
89   }
90   for (size_t i = 0; i < first->length; i++) {
91     uint8_t* first_ptr = pointer_to_nth_byte(first, i);
92     uint8_t* second_ptr = pointer_to_nth_byte(second, i);
93     GPR_ASSERT(first_ptr != nullptr);
94     GPR_ASSERT(second_ptr != nullptr);
95     if ((*first_ptr) != (*second_ptr)) {
96       return false;
97     }
98   }
99   return true;
100 }
101
102 static void alter_random_byte(grpc_slice_buffer* sb) {
103   GPR_ASSERT(sb != nullptr);
104   if (sb->length == 0) {
105     return;
106   }
107   uint32_t offset =
108       gsec_test_bias_random_uint32(static_cast<uint32_t>(sb->length));
109   uint8_t* ptr = pointer_to_nth_byte(sb, offset);
110   (*ptr)++;
111 }
112
113 static alts_grpc_record_protocol_test_fixture*
114 test_fixture_integrity_only_create(bool rekey, bool extra_copy) {
115   alts_grpc_record_protocol_test_fixture* fixture =
116       static_cast<alts_grpc_record_protocol_test_fixture*>(
117           gpr_zalloc(sizeof(alts_grpc_record_protocol_test_fixture)));
118   size_t key_length = rekey ? kAes128GcmRekeyKeyLength : kAes128GcmKeyLength;
119   uint8_t* key;
120   gsec_test_random_array(&key, key_length);
121   gsec_aead_crypter* crypter = nullptr;
122
123   /* Create client record protocol for protect. */
124   GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
125                  key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
126                  &crypter, nullptr) == GRPC_STATUS_OK);
127   GPR_ASSERT(alts_grpc_integrity_only_record_protocol_create(
128                  crypter, 8, /*is_client=*/true, /*is_protect=*/true,
129                  extra_copy, &fixture->client_protect) == TSI_OK);
130   /* Create client record protocol for unprotect.  */
131   GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
132                  key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
133                  &crypter, nullptr) == GRPC_STATUS_OK);
134   GPR_ASSERT(alts_grpc_integrity_only_record_protocol_create(
135                  crypter, 8, /*is_client=*/true, /*is_protect=*/false,
136                  extra_copy, &fixture->client_unprotect) == TSI_OK);
137   /* Create server record protocol for protect.  */
138   GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
139                  key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
140                  &crypter, nullptr) == GRPC_STATUS_OK);
141   GPR_ASSERT(alts_grpc_integrity_only_record_protocol_create(
142                  crypter, 8, /*is_client=*/false, /*is_protect=*/true,
143                  extra_copy, &fixture->server_protect) == TSI_OK);
144   /* Create server record protocol for unprotect.  */
145   GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
146                  key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
147                  &crypter, nullptr) == GRPC_STATUS_OK);
148   GPR_ASSERT(alts_grpc_integrity_only_record_protocol_create(
149                  crypter, 8, /*is_client=*/false, /*is_protect=*/false,
150                  extra_copy, &fixture->server_unprotect) == TSI_OK);
151
152   gpr_free(key);
153   return fixture;
154 }
155
156 static alts_grpc_record_protocol_test_fixture*
157 test_fixture_integrity_only_no_rekey_no_extra_copy_create() {
158   return test_fixture_integrity_only_create(false, false);
159 }
160
161 static alts_grpc_record_protocol_test_fixture*
162 test_fixture_integrity_only_rekey_create() {
163   return test_fixture_integrity_only_create(true, false);
164 }
165
166 static alts_grpc_record_protocol_test_fixture*
167 test_fixture_integrity_only_extra_copy_create() {
168   return test_fixture_integrity_only_create(false, true);
169 }
170
171 static alts_grpc_record_protocol_test_fixture*
172 test_fixture_privacy_integrity_create(bool rekey) {
173   alts_grpc_record_protocol_test_fixture* fixture =
174       static_cast<alts_grpc_record_protocol_test_fixture*>(
175           gpr_zalloc(sizeof(alts_grpc_record_protocol_test_fixture)));
176   size_t key_length = rekey ? kAes128GcmRekeyKeyLength : kAes128GcmKeyLength;
177   uint8_t* key;
178   gsec_test_random_array(&key, key_length);
179   gsec_aead_crypter* crypter = nullptr;
180
181   /* Create client record protocol for protect. */
182   GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
183                  key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
184                  &crypter, nullptr) == GRPC_STATUS_OK);
185   GPR_ASSERT(alts_grpc_privacy_integrity_record_protocol_create(
186                  crypter, 8, /*is_client=*/true, /*is_protect=*/true,
187                  &fixture->client_protect) == TSI_OK);
188   /* Create client record protocol for unprotect.  */
189   GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
190                  key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
191                  &crypter, nullptr) == GRPC_STATUS_OK);
192   GPR_ASSERT(alts_grpc_privacy_integrity_record_protocol_create(
193                  crypter, 8, /*is_client=*/true, /*is_protect=*/false,
194                  &fixture->client_unprotect) == TSI_OK);
195   /* Create server record protocol for protect.  */
196   GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
197                  key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
198                  &crypter, nullptr) == GRPC_STATUS_OK);
199   GPR_ASSERT(alts_grpc_privacy_integrity_record_protocol_create(
200                  crypter, 8, /*is_client=*/false, /*is_protect=*/true,
201                  &fixture->server_protect) == TSI_OK);
202   /* Create server record protocol for unprotect.  */
203   GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
204                  key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
205                  &crypter, nullptr) == GRPC_STATUS_OK);
206   GPR_ASSERT(alts_grpc_privacy_integrity_record_protocol_create(
207                  crypter, 8, /*is_client=*/false, /*is_protect=*/false,
208                  &fixture->server_unprotect) == TSI_OK);
209
210   gpr_free(key);
211   return fixture;
212 }
213
214 static alts_grpc_record_protocol_test_fixture*
215 test_fixture_privacy_integrity_no_rekey_create() {
216   return test_fixture_privacy_integrity_create(false);
217 }
218
219 static alts_grpc_record_protocol_test_fixture*
220 test_fixture_privacy_integrity_rekey_create() {
221   return test_fixture_privacy_integrity_create(true);
222 }
223
224 static void alts_grpc_record_protocol_test_fixture_destroy(
225     alts_grpc_record_protocol_test_fixture* fixture) {
226   if (fixture == nullptr) {
227     return;
228   }
229   grpc_core::ExecCtx exec_ctx;
230   alts_grpc_record_protocol_destroy(fixture->client_protect);
231   alts_grpc_record_protocol_destroy(fixture->client_unprotect);
232   alts_grpc_record_protocol_destroy(fixture->server_protect);
233   alts_grpc_record_protocol_destroy(fixture->server_unprotect);
234   grpc_core::ExecCtx::Get()->Flush();
235   gpr_free(fixture);
236 }
237
238 static alts_grpc_record_protocol_test_var*
239 alts_grpc_record_protocol_test_var_create() {
240   alts_grpc_record_protocol_test_var* var =
241       static_cast<alts_grpc_record_protocol_test_var*>(
242           gpr_zalloc(sizeof(alts_grpc_record_protocol_test_var)));
243   var->header_length = alts_iovec_record_protocol_get_header_length();
244   var->tag_length = kTagLength;
245   /* Initialized slice buffers.  */
246   grpc_slice_buffer_init(&var->original_sb);
247   grpc_slice_buffer_init(&var->duplicate_sb);
248   grpc_slice_buffer_init(&var->protected_sb);
249   grpc_slice_buffer_init(&var->unprotected_sb);
250   /* Randomly sets content of original_sb, and copies into duplicate_sb.  */
251   create_random_slice_buffer(&var->original_sb);
252   for (size_t i = 0; i < var->original_sb.count; i++) {
253     grpc_slice_buffer_add(&var->duplicate_sb,
254                           grpc_slice_ref(var->original_sb.slices[i]));
255   }
256   return var;
257 }
258
259 static void alts_grpc_record_protocol_test_var_destroy(
260     alts_grpc_record_protocol_test_var* var) {
261   if (var == nullptr) {
262     return;
263   }
264   grpc_slice_buffer_destroy_internal(&var->original_sb);
265   grpc_slice_buffer_destroy_internal(&var->duplicate_sb);
266   grpc_slice_buffer_destroy_internal(&var->protected_sb);
267   grpc_slice_buffer_destroy_internal(&var->unprotected_sb);
268   gpr_free(var);
269 }
270
271 /* --- alts grpc record protocol tests. --- */
272
273 static void random_seal_unseal(alts_grpc_record_protocol* sender,
274                                alts_grpc_record_protocol* receiver) {
275   grpc_core::ExecCtx exec_ctx;
276   for (size_t i = 0; i < kSealRepeatTimes; i++) {
277     alts_grpc_record_protocol_test_var* var =
278         alts_grpc_record_protocol_test_var_create();
279     /* Seals and then unseals.  */
280     size_t data_length = var->original_sb.length;
281     tsi_result status = alts_grpc_record_protocol_protect(
282         sender, &var->original_sb, &var->protected_sb);
283     GPR_ASSERT(status == TSI_OK);
284     GPR_ASSERT(var->protected_sb.length ==
285                data_length + var->header_length + var->tag_length);
286     status = alts_grpc_record_protocol_unprotect(receiver, &var->protected_sb,
287                                                  &var->unprotected_sb);
288     GPR_ASSERT(status == TSI_OK);
289     GPR_ASSERT(
290         are_slice_buffers_equal(&var->unprotected_sb, &var->duplicate_sb));
291     alts_grpc_record_protocol_test_var_destroy(var);
292   }
293   grpc_core::ExecCtx::Get()->Flush();
294 }
295
296 static void empty_seal_unseal(alts_grpc_record_protocol* sender,
297                               alts_grpc_record_protocol* receiver) {
298   grpc_core::ExecCtx exec_ctx;
299   for (size_t i = 0; i < kSealRepeatTimes; i++) {
300     alts_grpc_record_protocol_test_var* var =
301         alts_grpc_record_protocol_test_var_create();
302     /* Seals and then unseals empty payload.  */
303     grpc_slice_buffer_reset_and_unref_internal(&var->original_sb);
304     grpc_slice_buffer_reset_and_unref_internal(&var->duplicate_sb);
305     tsi_result status = alts_grpc_record_protocol_protect(
306         sender, &var->original_sb, &var->protected_sb);
307     GPR_ASSERT(status == TSI_OK);
308     GPR_ASSERT(var->protected_sb.length ==
309                var->header_length + var->tag_length);
310     status = alts_grpc_record_protocol_unprotect(receiver, &var->protected_sb,
311                                                  &var->unprotected_sb);
312     GPR_ASSERT(status == TSI_OK);
313     GPR_ASSERT(
314         are_slice_buffers_equal(&var->unprotected_sb, &var->duplicate_sb));
315     alts_grpc_record_protocol_test_var_destroy(var);
316   }
317   grpc_core::ExecCtx::Get()->Flush();
318 }
319
320 static void unsync_seal_unseal(alts_grpc_record_protocol* sender,
321                                alts_grpc_record_protocol* receiver) {
322   grpc_core::ExecCtx exec_ctx;
323   tsi_result status;
324   alts_grpc_record_protocol_test_var* var =
325       alts_grpc_record_protocol_test_var_create();
326   /* Seals once.  */
327   status = alts_grpc_record_protocol_protect(sender, &var->original_sb,
328                                              &var->protected_sb);
329   GPR_ASSERT(status == TSI_OK);
330   grpc_slice_buffer_reset_and_unref_internal(&var->protected_sb);
331   /* Seals again.  */
332   status = alts_grpc_record_protocol_protect(sender, &var->duplicate_sb,
333                                              &var->protected_sb);
334   GPR_ASSERT(status == TSI_OK);
335   /* Unseals the second frame.  */
336   status = alts_grpc_record_protocol_unprotect(receiver, &var->protected_sb,
337                                                &var->unprotected_sb);
338   GPR_ASSERT(status == TSI_INTERNAL_ERROR);
339   alts_grpc_record_protocol_test_var_destroy(var);
340   grpc_core::ExecCtx::Get()->Flush();
341 }
342
343 static void corrupted_data(alts_grpc_record_protocol* sender,
344                            alts_grpc_record_protocol* receiver) {
345   grpc_core::ExecCtx exec_ctx;
346   tsi_result status;
347   alts_grpc_record_protocol_test_var* var =
348       alts_grpc_record_protocol_test_var_create();
349   /* Seals once.  */
350   status = alts_grpc_record_protocol_protect(sender, &var->original_sb,
351                                              &var->protected_sb);
352   GPR_ASSERT(status == TSI_OK);
353   /* Corrupts one byte in protected_sb and tries to unprotect.  */
354   alter_random_byte(&var->protected_sb);
355   status = alts_grpc_record_protocol_unprotect(receiver, &var->protected_sb,
356                                                &var->unprotected_sb);
357   GPR_ASSERT(status == TSI_INTERNAL_ERROR);
358   alts_grpc_record_protocol_test_var_destroy(var);
359   grpc_core::ExecCtx::Get()->Flush();
360 }
361
362 static void input_check(alts_grpc_record_protocol* rp) {
363   grpc_core::ExecCtx exec_ctx;
364   tsi_result status;
365   alts_grpc_record_protocol_test_var* var =
366       alts_grpc_record_protocol_test_var_create();
367   /* Protects with nullptr input.  */
368   status = alts_grpc_record_protocol_protect(rp, nullptr, &var->protected_sb);
369   GPR_ASSERT(status == TSI_INVALID_ARGUMENT);
370   status = alts_grpc_record_protocol_protect(rp, &var->original_sb, nullptr);
371   GPR_ASSERT(status == TSI_INVALID_ARGUMENT);
372   /* Unprotects with nullptr input.  */
373   status = alts_grpc_record_protocol_protect(rp, &var->original_sb,
374                                              &var->protected_sb);
375   GPR_ASSERT(status == TSI_OK);
376   status =
377       alts_grpc_record_protocol_unprotect(rp, nullptr, &var->unprotected_sb);
378   GPR_ASSERT(status == TSI_INVALID_ARGUMENT);
379   status = alts_grpc_record_protocol_unprotect(rp, &var->protected_sb, nullptr);
380   GPR_ASSERT(status == TSI_INVALID_ARGUMENT);
381   /* Unprotects on a temporary slice buffer which length is smaller than header
382    * length plus tag length.  */
383   grpc_slice_buffer temp_sb;
384   grpc_slice_buffer_init(&temp_sb);
385   grpc_slice_buffer_move_first(
386       &var->protected_sb, var->header_length + var->tag_length - 1, &temp_sb);
387   status =
388       alts_grpc_record_protocol_unprotect(rp, &temp_sb, &var->unprotected_sb);
389   GPR_ASSERT(status == TSI_INVALID_ARGUMENT);
390   grpc_slice_buffer_destroy_internal(&temp_sb);
391   alts_grpc_record_protocol_test_var_destroy(var);
392   grpc_core::ExecCtx::Get()->Flush();
393 }
394
395 /* --- Test cases. --- */
396
397 static void alts_grpc_record_protocol_random_seal_unseal_tests(
398     alts_grpc_record_protocol_test_fixture* fixture) {
399   random_seal_unseal(fixture->client_protect, fixture->server_unprotect);
400   random_seal_unseal(fixture->server_protect, fixture->client_unprotect);
401 }
402
403 static void alts_grpc_record_protocol_empty_seal_unseal_tests(
404     alts_grpc_record_protocol_test_fixture* fixture) {
405   empty_seal_unseal(fixture->client_protect, fixture->server_unprotect);
406   empty_seal_unseal(fixture->server_protect, fixture->client_unprotect);
407 }
408
409 static void alts_grpc_record_protocol_unsync_seal_unseal_tests(
410     alts_grpc_record_protocol_test_fixture* fixture) {
411   unsync_seal_unseal(fixture->client_protect, fixture->server_unprotect);
412   unsync_seal_unseal(fixture->server_protect, fixture->client_unprotect);
413 }
414
415 static void alts_grpc_record_protocol_corrupted_data_tests(
416     alts_grpc_record_protocol_test_fixture* fixture) {
417   corrupted_data(fixture->client_protect, fixture->server_unprotect);
418   corrupted_data(fixture->server_protect, fixture->client_unprotect);
419 }
420
421 static void alts_grpc_record_protocol_input_check_tests(
422     alts_grpc_record_protocol_test_fixture* fixture) {
423   input_check(fixture->client_protect);
424 }
425
426 static void alts_grpc_record_protocol_tests(
427     alts_grpc_record_protocol_test_fixture* (*fixture_create)()) {
428   auto* fixture_1 = fixture_create();
429   alts_grpc_record_protocol_random_seal_unseal_tests(fixture_1);
430   alts_grpc_record_protocol_test_fixture_destroy(fixture_1);
431
432   auto* fixture_2 = fixture_create();
433   alts_grpc_record_protocol_empty_seal_unseal_tests(fixture_2);
434   alts_grpc_record_protocol_test_fixture_destroy(fixture_2);
435
436   auto* fixture_3 = fixture_create();
437   alts_grpc_record_protocol_unsync_seal_unseal_tests(fixture_3);
438   alts_grpc_record_protocol_test_fixture_destroy(fixture_3);
439
440   auto* fixture_4 = fixture_create();
441   alts_grpc_record_protocol_corrupted_data_tests(fixture_4);
442   alts_grpc_record_protocol_test_fixture_destroy(fixture_4);
443
444   auto* fixture_5 = fixture_create();
445   alts_grpc_record_protocol_input_check_tests(fixture_5);
446   alts_grpc_record_protocol_test_fixture_destroy(fixture_5);
447 }
448
449 int main(int argc, char** argv) {
450   grpc::testing::TestEnvironment env(argc, argv);
451   grpc_init();
452   alts_grpc_record_protocol_tests(
453       &test_fixture_integrity_only_no_rekey_no_extra_copy_create);
454   alts_grpc_record_protocol_tests(&test_fixture_integrity_only_rekey_create);
455   alts_grpc_record_protocol_tests(
456       &test_fixture_integrity_only_extra_copy_create);
457   alts_grpc_record_protocol_tests(
458       &test_fixture_privacy_integrity_no_rekey_create);
459   alts_grpc_record_protocol_tests(&test_fixture_privacy_integrity_rekey_create);
460   grpc_shutdown();
461   return 0;
462 }