Home | History | Annotate | Download | only in zero_copy_frame_protector
      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/slice_buffer.h>
     20 #include <grpc/support/alloc.h>
     21 #include <grpc/support/log.h>
     22 
     23 #include "src/core/lib/iomgr/exec_ctx.h"
     24 #include "src/core/lib/slice/slice_internal.h"
     25 #include "src/core/tsi/alts/crypt/gsec.h"
     26 #include "src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h"
     27 #include "src/core/tsi/transport_security_grpc.h"
     28 #include "test/core/tsi/alts/crypt/gsec_test_util.h"
     29 
     30 /* TODO: tests zero_copy_grpc_protector under TSI test library, which
     31  * has more comprehensive tests.  */
     32 
     33 constexpr size_t kSealRepeatTimes = 50;
     34 constexpr size_t kSmallBufferSize = 16;
     35 constexpr size_t kLargeBufferSize = 16384;
     36 constexpr size_t kChannelMaxSize = 2048;
     37 constexpr size_t kChannelMinSize = 128;
     38 
     39 /* Test fixtures for each test cases.  */
     40 struct alts_zero_copy_grpc_protector_test_fixture {
     41   tsi_zero_copy_grpc_protector* client;
     42   tsi_zero_copy_grpc_protector* server;
     43 };
     44 
     45 /* Test input variables for protect/unprotect operations.  */
     46 struct alts_zero_copy_grpc_protector_test_var {
     47   grpc_slice_buffer original_sb;
     48   grpc_slice_buffer duplicate_sb;
     49   grpc_slice_buffer staging_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                                        grpc_slice_buffer* dup_sb,
     58                                        size_t length) {
     59   GPR_ASSERT(sb != nullptr);
     60   GPR_ASSERT(dup_sb != nullptr);
     61   GPR_ASSERT(length > 0);
     62   grpc_slice slice = GRPC_SLICE_MALLOC(length);
     63   gsec_test_random_bytes(GRPC_SLICE_START_PTR(slice), length);
     64   grpc_slice_buffer_add(sb, grpc_slice_ref(slice));
     65   grpc_slice_buffer_add(dup_sb, slice);
     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 && second_ptr != nullptr);
     94     if ((*first_ptr) != (*second_ptr)) {
     95       return false;
     96     }
     97   }
     98   return true;
     99 }
    100 
    101 static alts_zero_copy_grpc_protector_test_fixture*
    102 alts_zero_copy_grpc_protector_test_fixture_create(bool rekey,
    103                                                   bool integrity_only,
    104                                                   bool enable_extra_copy) {
    105   alts_zero_copy_grpc_protector_test_fixture* fixture =
    106       static_cast<alts_zero_copy_grpc_protector_test_fixture*>(
    107           gpr_zalloc(sizeof(alts_zero_copy_grpc_protector_test_fixture)));
    108   grpc_core::ExecCtx exec_ctx;
    109   size_t key_length = rekey ? kAes128GcmRekeyKeyLength : kAes128GcmKeyLength;
    110   uint8_t* key;
    111   size_t max_protected_frame_size = 1024;
    112   gsec_test_random_array(&key, key_length);
    113   GPR_ASSERT(alts_zero_copy_grpc_protector_create(
    114                  key, key_length, rekey, /*is_client=*/true, integrity_only,
    115                  enable_extra_copy, &max_protected_frame_size,
    116                  &fixture->client) == TSI_OK);
    117   GPR_ASSERT(alts_zero_copy_grpc_protector_create(
    118                  key, key_length, rekey, /*is_client=*/false, integrity_only,
    119                  enable_extra_copy, &max_protected_frame_size,
    120                  &fixture->server) == TSI_OK);
    121   gpr_free(key);
    122   grpc_core::ExecCtx::Get()->Flush();
    123   return fixture;
    124 }
    125 
    126 static void alts_zero_copy_grpc_protector_test_fixture_destroy(
    127     alts_zero_copy_grpc_protector_test_fixture* fixture) {
    128   if (fixture == nullptr) {
    129     return;
    130   }
    131   grpc_core::ExecCtx exec_ctx;
    132   tsi_zero_copy_grpc_protector_destroy(fixture->client);
    133   tsi_zero_copy_grpc_protector_destroy(fixture->server);
    134   grpc_core::ExecCtx::Get()->Flush();
    135   gpr_free(fixture);
    136 }
    137 
    138 static alts_zero_copy_grpc_protector_test_var*
    139 alts_zero_copy_grpc_protector_test_var_create() {
    140   alts_zero_copy_grpc_protector_test_var* var =
    141       static_cast<alts_zero_copy_grpc_protector_test_var*>(
    142           gpr_zalloc(sizeof(alts_zero_copy_grpc_protector_test_var)));
    143   grpc_slice_buffer_init(&var->original_sb);
    144   grpc_slice_buffer_init(&var->duplicate_sb);
    145   grpc_slice_buffer_init(&var->staging_sb);
    146   grpc_slice_buffer_init(&var->protected_sb);
    147   grpc_slice_buffer_init(&var->unprotected_sb);
    148   return var;
    149 }
    150 
    151 static void alts_zero_copy_grpc_protector_test_var_destroy(
    152     alts_zero_copy_grpc_protector_test_var* var) {
    153   if (var == nullptr) {
    154     return;
    155   }
    156   grpc_slice_buffer_destroy_internal(&var->original_sb);
    157   grpc_slice_buffer_destroy_internal(&var->duplicate_sb);
    158   grpc_slice_buffer_destroy_internal(&var->staging_sb);
    159   grpc_slice_buffer_destroy_internal(&var->protected_sb);
    160   grpc_slice_buffer_destroy_internal(&var->unprotected_sb);
    161   gpr_free(var);
    162 }
    163 
    164 /* --- ALTS zero-copy protector tests. --- */
    165 
    166 static void seal_unseal_small_buffer(tsi_zero_copy_grpc_protector* sender,
    167                                      tsi_zero_copy_grpc_protector* receiver) {
    168   grpc_core::ExecCtx exec_ctx;
    169   for (size_t i = 0; i < kSealRepeatTimes; i++) {
    170     alts_zero_copy_grpc_protector_test_var* var =
    171         alts_zero_copy_grpc_protector_test_var_create();
    172     /* Creates a random small slice buffer and calls protect().  */
    173     create_random_slice_buffer(&var->original_sb, &var->duplicate_sb,
    174                                kSmallBufferSize);
    175     GPR_ASSERT(tsi_zero_copy_grpc_protector_protect(
    176                    sender, &var->original_sb, &var->protected_sb) == TSI_OK);
    177     /* Splits protected slice buffer into two: first one is staging_sb, and
    178      * second one is is protected_sb.  */
    179     uint32_t staging_sb_size =
    180         gsec_test_bias_random_uint32(
    181             static_cast<uint32_t>(var->protected_sb.length - 1)) +
    182         1;
    183     grpc_slice_buffer_move_first(&var->protected_sb, staging_sb_size,
    184                                  &var->staging_sb);
    185     /* Unprotects one by one.  */
    186     GPR_ASSERT(tsi_zero_copy_grpc_protector_unprotect(
    187                    receiver, &var->staging_sb, &var->unprotected_sb) == TSI_OK);
    188     GPR_ASSERT(var->unprotected_sb.length == 0);
    189     GPR_ASSERT(tsi_zero_copy_grpc_protector_unprotect(
    190                    receiver, &var->protected_sb, &var->unprotected_sb) ==
    191                TSI_OK);
    192     GPR_ASSERT(
    193         are_slice_buffers_equal(&var->unprotected_sb, &var->duplicate_sb));
    194     alts_zero_copy_grpc_protector_test_var_destroy(var);
    195   }
    196   grpc_core::ExecCtx::Get()->Flush();
    197 }
    198 
    199 static void seal_unseal_large_buffer(tsi_zero_copy_grpc_protector* sender,
    200                                      tsi_zero_copy_grpc_protector* receiver) {
    201   grpc_core::ExecCtx exec_ctx;
    202   for (size_t i = 0; i < kSealRepeatTimes; i++) {
    203     alts_zero_copy_grpc_protector_test_var* var =
    204         alts_zero_copy_grpc_protector_test_var_create();
    205     /* Creates a random large slice buffer and calls protect().  */
    206     create_random_slice_buffer(&var->original_sb, &var->duplicate_sb,
    207                                kLargeBufferSize);
    208     GPR_ASSERT(tsi_zero_copy_grpc_protector_protect(
    209                    sender, &var->original_sb, &var->protected_sb) == TSI_OK);
    210     /* Splits protected slice buffer into multiple pieces. Receiver unprotects
    211      * each slice buffer one by one.  */
    212     uint32_t channel_size = gsec_test_bias_random_uint32(static_cast<uint32_t>(
    213                                 kChannelMaxSize + 1 - kChannelMinSize)) +
    214                             static_cast<uint32_t>(kChannelMinSize);
    215     while (var->protected_sb.length > channel_size) {
    216       grpc_slice_buffer_reset_and_unref_internal(&var->staging_sb);
    217       grpc_slice_buffer_move_first(&var->protected_sb, channel_size,
    218                                    &var->staging_sb);
    219       GPR_ASSERT(tsi_zero_copy_grpc_protector_unprotect(
    220                      receiver, &var->staging_sb, &var->unprotected_sb) ==
    221                  TSI_OK);
    222     }
    223     GPR_ASSERT(tsi_zero_copy_grpc_protector_unprotect(
    224                    receiver, &var->protected_sb, &var->unprotected_sb) ==
    225                TSI_OK);
    226     GPR_ASSERT(
    227         are_slice_buffers_equal(&var->unprotected_sb, &var->duplicate_sb));
    228     alts_zero_copy_grpc_protector_test_var_destroy(var);
    229   }
    230   grpc_core::ExecCtx::Get()->Flush();
    231 }
    232 
    233 /* --- Test cases. --- */
    234 
    235 static void alts_zero_copy_protector_seal_unseal_small_buffer_tests(
    236     bool enable_extra_copy) {
    237   alts_zero_copy_grpc_protector_test_fixture* fixture =
    238       alts_zero_copy_grpc_protector_test_fixture_create(
    239           /*rekey=*/false, /*integrity_only=*/true, enable_extra_copy);
    240   seal_unseal_small_buffer(fixture->client, fixture->server);
    241   seal_unseal_small_buffer(fixture->server, fixture->client);
    242   alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
    243 
    244   fixture = alts_zero_copy_grpc_protector_test_fixture_create(
    245       /*rekey=*/false, /*integrity_only=*/false, enable_extra_copy);
    246   seal_unseal_small_buffer(fixture->client, fixture->server);
    247   seal_unseal_small_buffer(fixture->server, fixture->client);
    248   alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
    249 
    250   fixture = alts_zero_copy_grpc_protector_test_fixture_create(
    251       /*rekey=*/true, /*integrity_only=*/true, enable_extra_copy);
    252   seal_unseal_small_buffer(fixture->client, fixture->server);
    253   seal_unseal_small_buffer(fixture->server, fixture->client);
    254   alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
    255 
    256   fixture = alts_zero_copy_grpc_protector_test_fixture_create(
    257       /*rekey=*/true, /*integrity_only=*/false, enable_extra_copy);
    258   seal_unseal_small_buffer(fixture->client, fixture->server);
    259   seal_unseal_small_buffer(fixture->server, fixture->client);
    260   alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
    261 }
    262 
    263 static void alts_zero_copy_protector_seal_unseal_large_buffer_tests(
    264     bool enable_extra_copy) {
    265   alts_zero_copy_grpc_protector_test_fixture* fixture =
    266       alts_zero_copy_grpc_protector_test_fixture_create(
    267           /*rekey=*/false, /*integrity_only=*/true, enable_extra_copy);
    268   seal_unseal_large_buffer(fixture->client, fixture->server);
    269   seal_unseal_large_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=*/false, /*integrity_only=*/false, enable_extra_copy);
    274   seal_unseal_large_buffer(fixture->client, fixture->server);
    275   seal_unseal_large_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=*/true, enable_extra_copy);
    280   seal_unseal_large_buffer(fixture->client, fixture->server);
    281   seal_unseal_large_buffer(fixture->server, fixture->client);
    282   alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
    283 
    284   fixture = alts_zero_copy_grpc_protector_test_fixture_create(
    285       /*rekey=*/true, /*integrity_only=*/false, enable_extra_copy);
    286   seal_unseal_large_buffer(fixture->client, fixture->server);
    287   seal_unseal_large_buffer(fixture->server, fixture->client);
    288   alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
    289 }
    290 
    291 int main(int argc, char** argv) {
    292   alts_zero_copy_protector_seal_unseal_small_buffer_tests(
    293       /*enable_extra_copy=*/false);
    294   alts_zero_copy_protector_seal_unseal_small_buffer_tests(
    295       /*enable_extra_copy=*/true);
    296   alts_zero_copy_protector_seal_unseal_large_buffer_tests(
    297       /*enable_extra_copy=*/false);
    298   alts_zero_copy_protector_seal_unseal_large_buffer_tests(
    299       /*enable_extra_copy=*/true);
    300   return 0;
    301 }
    302