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