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