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/support/alloc.h>
20 #include <grpc/support/log.h>
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"
31 constexpr size_t kMaxSliceLength = 256;
32 constexpr size_t kMaxSlices = 10;
33 constexpr size_t kSealRepeatTimes = 5;
34 constexpr size_t kTagLength = 16;
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;
44 /* Test input variables for protect/unprotect operations. */
45 struct alts_grpc_record_protocol_test_var {
48 grpc_slice_buffer original_sb;
49 grpc_slice_buffer duplicate_sb;
50 grpc_slice_buffer protected_sb;
51 grpc_slice_buffer unprotected_sb;
54 /* --- Test utility functions. --- */
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);
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;
74 index -= GRPC_SLICE_LENGTH(sb->slices[i]);
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) {
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)) {
101 static void alter_random_byte(grpc_slice_buffer* sb) {
102 GPR_ASSERT(sb != nullptr);
103 if (sb->length == 0) {
107 gsec_test_bias_random_uint32(static_cast<uint32_t>(sb->length));
108 uint8_t* ptr = pointer_to_nth_byte(sb, offset);
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;
119 gsec_test_random_array(&key, key_length);
120 gsec_aead_crypter* crypter = nullptr;
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);
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);
160 static alts_grpc_record_protocol_test_fixture*
161 test_fixture_integrity_only_rekey_create() {
162 return test_fixture_integrity_only_create(true, false);
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);
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;
177 gsec_test_random_array(&key, key_length);
178 gsec_aead_crypter* crypter = nullptr;
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);
213 static alts_grpc_record_protocol_test_fixture*
214 test_fixture_privacy_integrity_no_rekey_create() {
215 return test_fixture_privacy_integrity_create(false);
218 static alts_grpc_record_protocol_test_fixture*
219 test_fixture_privacy_integrity_rekey_create() {
220 return test_fixture_privacy_integrity_create(true);
223 static void alts_grpc_record_protocol_test_fixture_destroy(
224 alts_grpc_record_protocol_test_fixture* fixture) {
225 if (fixture == nullptr) {
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();
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]));
258 static void alts_grpc_record_protocol_test_var_destroy(
259 alts_grpc_record_protocol_test_var* var) {
260 if (var == nullptr) {
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);
270 /* --- alts grpc record protocol tests. --- */
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);
289 are_slice_buffers_equal(&var->unprotected_sb, &var->duplicate_sb));
290 alts_grpc_record_protocol_test_var_destroy(var);
292 grpc_core::ExecCtx::Get()->Flush();
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);
313 are_slice_buffers_equal(&var->unprotected_sb, &var->duplicate_sb));
314 alts_grpc_record_protocol_test_var_destroy(var);
316 grpc_core::ExecCtx::Get()->Flush();
319 static void unsync_seal_unseal(alts_grpc_record_protocol* sender,
320 alts_grpc_record_protocol* receiver) {
321 grpc_core::ExecCtx exec_ctx;
323 alts_grpc_record_protocol_test_var* var =
324 alts_grpc_record_protocol_test_var_create();
326 status = alts_grpc_record_protocol_protect(sender, &var->original_sb,
328 GPR_ASSERT(status == TSI_OK);
329 grpc_slice_buffer_reset_and_unref_internal(&var->protected_sb);
331 status = alts_grpc_record_protocol_protect(sender, &var->duplicate_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();
342 static void corrupted_data(alts_grpc_record_protocol* sender,
343 alts_grpc_record_protocol* receiver) {
344 grpc_core::ExecCtx exec_ctx;
346 alts_grpc_record_protocol_test_var* var =
347 alts_grpc_record_protocol_test_var_create();
349 status = alts_grpc_record_protocol_protect(sender, &var->original_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();
361 static void input_check(alts_grpc_record_protocol* rp) {
362 grpc_core::ExecCtx exec_ctx;
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,
374 GPR_ASSERT(status == TSI_OK);
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);
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();
394 /* --- Test cases. --- */
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);
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);
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);
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);
420 static void alts_grpc_record_protocol_input_check_tests(
421 alts_grpc_record_protocol_test_fixture* fixture) {
422 input_check(fixture->client_protect);
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);
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);
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);
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);
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);
448 int main(int argc, char** argv) {
449 grpc::testing::TestEnvironment env(argc, argv);
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);