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 "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h"
21 #include <grpc/support/alloc.h>
22 #include <grpc/support/log.h>
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"
32 constexpr size_t kMaxSliceLength = 256;
33 constexpr size_t kMaxSlices = 10;
34 constexpr size_t kSealRepeatTimes = 5;
35 constexpr size_t kTagLength = 16;
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;
45 /* Test input variables for protect/unprotect operations. */
46 struct alts_grpc_record_protocol_test_var {
49 grpc_slice_buffer original_sb;
50 grpc_slice_buffer duplicate_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 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);
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;
75 index -= GRPC_SLICE_LENGTH(sb->slices[i]);
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) {
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)) {
102 static void alter_random_byte(grpc_slice_buffer* sb) {
103 GPR_ASSERT(sb != nullptr);
104 if (sb->length == 0) {
108 gsec_test_bias_random_uint32(static_cast<uint32_t>(sb->length));
109 uint8_t* ptr = pointer_to_nth_byte(sb, offset);
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;
120 gsec_test_random_array(&key, key_length);
121 gsec_aead_crypter* crypter = nullptr;
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);
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);
161 static alts_grpc_record_protocol_test_fixture*
162 test_fixture_integrity_only_rekey_create() {
163 return test_fixture_integrity_only_create(true, false);
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);
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;
178 gsec_test_random_array(&key, key_length);
179 gsec_aead_crypter* crypter = nullptr;
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);
214 static alts_grpc_record_protocol_test_fixture*
215 test_fixture_privacy_integrity_no_rekey_create() {
216 return test_fixture_privacy_integrity_create(false);
219 static alts_grpc_record_protocol_test_fixture*
220 test_fixture_privacy_integrity_rekey_create() {
221 return test_fixture_privacy_integrity_create(true);
224 static void alts_grpc_record_protocol_test_fixture_destroy(
225 alts_grpc_record_protocol_test_fixture* fixture) {
226 if (fixture == nullptr) {
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();
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]));
259 static void alts_grpc_record_protocol_test_var_destroy(
260 alts_grpc_record_protocol_test_var* var) {
261 if (var == nullptr) {
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);
271 /* --- alts grpc record protocol tests. --- */
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);
290 are_slice_buffers_equal(&var->unprotected_sb, &var->duplicate_sb));
291 alts_grpc_record_protocol_test_var_destroy(var);
293 grpc_core::ExecCtx::Get()->Flush();
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);
314 are_slice_buffers_equal(&var->unprotected_sb, &var->duplicate_sb));
315 alts_grpc_record_protocol_test_var_destroy(var);
317 grpc_core::ExecCtx::Get()->Flush();
320 static void unsync_seal_unseal(alts_grpc_record_protocol* sender,
321 alts_grpc_record_protocol* receiver) {
322 grpc_core::ExecCtx exec_ctx;
324 alts_grpc_record_protocol_test_var* var =
325 alts_grpc_record_protocol_test_var_create();
327 status = alts_grpc_record_protocol_protect(sender, &var->original_sb,
329 GPR_ASSERT(status == TSI_OK);
330 grpc_slice_buffer_reset_and_unref_internal(&var->protected_sb);
332 status = alts_grpc_record_protocol_protect(sender, &var->duplicate_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();
343 static void corrupted_data(alts_grpc_record_protocol* sender,
344 alts_grpc_record_protocol* receiver) {
345 grpc_core::ExecCtx exec_ctx;
347 alts_grpc_record_protocol_test_var* var =
348 alts_grpc_record_protocol_test_var_create();
350 status = alts_grpc_record_protocol_protect(sender, &var->original_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();
362 static void input_check(alts_grpc_record_protocol* rp) {
363 grpc_core::ExecCtx exec_ctx;
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,
375 GPR_ASSERT(status == TSI_OK);
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);
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();
395 /* --- Test cases. --- */
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);
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);
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);
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);
421 static void alts_grpc_record_protocol_input_check_tests(
422 alts_grpc_record_protocol_test_fixture* fixture) {
423 input_check(fixture->client_protect);
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);
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);
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);
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);
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);
449 int main(int argc, char** argv) {
450 grpc::testing::TestEnvironment env(argc, argv);
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);