| // Copyright (c) 2022 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "quiche/quic/load_balancer/load_balancer_config.h" | 
 |  | 
 | #include <cstdint> | 
 |  | 
 | #include "absl/types/span.h" | 
 | #include "quiche/quic/platform/api/quic_expect_bug.h" | 
 | #include "quiche/quic/platform/api/quic_test.h" | 
 | #include "quiche/quic/test_tools/quic_test_utils.h" | 
 |  | 
 | namespace quic { | 
 |  | 
 | namespace test { | 
 |  | 
 | namespace { | 
 |  | 
 | constexpr char raw_key[] = { | 
 |     0xfd, 0xf7, 0x26, 0xa9, 0x89, 0x3e, 0xc0, 0x5c, | 
 |     0x06, 0x32, 0xd3, 0x95, 0x66, 0x80, 0xba, 0xf0, | 
 | }; | 
 |  | 
 | class LoadBalancerConfigTest : public QuicTest {}; | 
 |  | 
 | TEST_F(LoadBalancerConfigTest, InvalidParams) { | 
 |   // Bogus config_id. | 
 |   EXPECT_QUIC_BUG( | 
 |       EXPECT_FALSE(LoadBalancerConfig::CreateUnencrypted(3, 4, 10).has_value()), | 
 |       "Invalid LoadBalancerConfig Config ID 3 Server ID Length 4 " | 
 |       "Nonce Length 10"); | 
 |   // Bad Server ID lengths. | 
 |   EXPECT_QUIC_BUG(EXPECT_FALSE(LoadBalancerConfig::Create( | 
 |                                    2, 0, 10, absl::string_view(raw_key, 16)) | 
 |                                    .has_value()), | 
 |                   "Invalid LoadBalancerConfig Config ID 2 Server ID Length 0 " | 
 |                   "Nonce Length 10"); | 
 |   EXPECT_QUIC_BUG( | 
 |       EXPECT_FALSE(LoadBalancerConfig::CreateUnencrypted(2, 16, 4).has_value()), | 
 |       "Invalid LoadBalancerConfig Config ID 2 Server ID Length 16 " | 
 |       "Nonce Length 4"); | 
 |   // Bad Nonce lengths. | 
 |   EXPECT_QUIC_BUG( | 
 |       EXPECT_FALSE(LoadBalancerConfig::CreateUnencrypted(2, 4, 2).has_value()), | 
 |       "Invalid LoadBalancerConfig Config ID 2 Server ID Length 4 " | 
 |       "Nonce Length 2"); | 
 |   EXPECT_QUIC_BUG( | 
 |       EXPECT_FALSE(LoadBalancerConfig::CreateUnencrypted(2, 1, 17).has_value()), | 
 |       "Invalid LoadBalancerConfig Config ID 2 Server ID Length 1 " | 
 |       "Nonce Length 17"); | 
 |   // Bad key lengths. | 
 |   EXPECT_QUIC_BUG( | 
 |       EXPECT_FALSE(LoadBalancerConfig::Create(2, 3, 4, "").has_value()), | 
 |       "Invalid LoadBalancerConfig Key Length: 0"); | 
 |   EXPECT_QUIC_BUG(EXPECT_FALSE(LoadBalancerConfig::Create( | 
 |                                    2, 3, 4, absl::string_view(raw_key, 10)) | 
 |                                    .has_value()), | 
 |                   "Invalid LoadBalancerConfig Key Length: 10"); | 
 |   EXPECT_QUIC_BUG(EXPECT_FALSE(LoadBalancerConfig::Create( | 
 |                                    0, 3, 4, absl::string_view(raw_key, 17)) | 
 |                                    .has_value()), | 
 |                   "Invalid LoadBalancerConfig Key Length: 17"); | 
 | } | 
 |  | 
 | TEST_F(LoadBalancerConfigTest, ValidParams) { | 
 |   // Test valid configurations and accessors | 
 |   auto config = LoadBalancerConfig::CreateUnencrypted(0, 3, 4); | 
 |   EXPECT_TRUE(config.has_value()); | 
 |   EXPECT_EQ(config->config_id(), 0); | 
 |   EXPECT_EQ(config->server_id_len(), 3); | 
 |   EXPECT_EQ(config->nonce_len(), 4); | 
 |   EXPECT_EQ(config->plaintext_len(), 7); | 
 |   EXPECT_EQ(config->total_len(), 8); | 
 |   EXPECT_FALSE(config->IsEncrypted()); | 
 |   auto config2 = | 
 |       LoadBalancerConfig::Create(2, 6, 7, absl::string_view(raw_key, 16)); | 
 |   EXPECT_TRUE(config.has_value()); | 
 |   EXPECT_EQ(config2->config_id(), 2); | 
 |   EXPECT_EQ(config2->server_id_len(), 6); | 
 |   EXPECT_EQ(config2->nonce_len(), 7); | 
 |   EXPECT_EQ(config2->plaintext_len(), 13); | 
 |   EXPECT_EQ(config2->total_len(), 14); | 
 |   EXPECT_TRUE(config2->IsEncrypted()); | 
 | } | 
 |  | 
 | // Compare EncryptionPass() results to the example in | 
 | // draft-ietf-quic-load-balancers-14, Section 4.3.2. | 
 | TEST_F(LoadBalancerConfigTest, TestEncryptionPassExample) { | 
 |   auto config = | 
 |       LoadBalancerConfig::Create(0, 3, 4, absl::string_view(raw_key, 16)); | 
 |   EXPECT_TRUE(config.has_value()); | 
 |   EXPECT_TRUE(config->IsEncrypted()); | 
 |   std::array<uint8_t, 7> bytes = { | 
 |       0x31, 0x44, 0x1a, 0x9c, 0x69, 0xc2, 0x75, | 
 |   }; | 
 |   // Input is too short. | 
 |   EXPECT_FALSE(config->EncryptionPass(absl::Span<uint8_t>(bytes.data(), 6), 0)); | 
 |   EXPECT_TRUE(config->EncryptionPass(absl::Span<uint8_t>(bytes), 1)); | 
 |   EXPECT_TRUE((bytes == std::array<uint8_t, 7>( | 
 |                             {0x31, 0x44, 0x1a, 0x92, 0x52, 0xaa, 0xef}))); | 
 |   EXPECT_TRUE(config->EncryptionPass(absl::Span<uint8_t>(bytes), 2)); | 
 |   EXPECT_TRUE((bytes == std::array<uint8_t, 7>( | 
 |                             {0xe6, 0xa1, 0x3a, 0xb2, 0x52, 0xaa, 0xef}))); | 
 |   EXPECT_TRUE(config->EncryptionPass(absl::Span<uint8_t>(bytes), 3)); | 
 |   EXPECT_TRUE((bytes == std::array<uint8_t, 7>( | 
 |                             {0xe6, 0xa1, 0x3a, 0xbc, 0xe1, 0xe0, 0xd2}))); | 
 |   EXPECT_TRUE(config->EncryptionPass(absl::Span<uint8_t>(bytes), 4)); | 
 |   EXPECT_TRUE((bytes == std::array<uint8_t, 7>( | 
 |                             {0x32, 0xc3, 0x63, 0xfc, 0xe1, 0xe0, 0xd2}))); | 
 | } | 
 |  | 
 | TEST_F(LoadBalancerConfigTest, EncryptionPassPlaintext) { | 
 |   auto config = LoadBalancerConfig::CreateUnencrypted(0, 3, 4); | 
 |   std::array<uint8_t, 7> bytes = {0x31, 0x44, 0x1a, 0x9c, 0x69, 0xc2, 0x75}; | 
 |   EXPECT_FALSE(config->EncryptionPass(absl::Span<uint8_t>(bytes), 1)); | 
 | } | 
 |  | 
 | TEST_F(LoadBalancerConfigTest, InvalidBlockEncryption) { | 
 |   uint8_t pt[kLoadBalancerBlockSize], ct[kLoadBalancerBlockSize]; | 
 |   auto pt_config = LoadBalancerConfig::CreateUnencrypted(0, 8, 8); | 
 |   EXPECT_FALSE(pt_config->BlockEncrypt(pt, ct)); | 
 |   EXPECT_FALSE(pt_config->BlockDecrypt(ct, pt)); | 
 |   EXPECT_FALSE(pt_config->EncryptionPass(absl::Span<uint8_t>(pt), 0)); | 
 |   auto small_cid_config = | 
 |       LoadBalancerConfig::Create(0, 3, 4, absl::string_view(raw_key, 16)); | 
 |   EXPECT_TRUE(small_cid_config->BlockEncrypt(pt, ct)); | 
 |   EXPECT_FALSE(small_cid_config->BlockDecrypt(ct, pt)); | 
 |   auto block_config = | 
 |       LoadBalancerConfig::Create(0, 8, 8, absl::string_view(raw_key, 16)); | 
 |   EXPECT_TRUE(block_config->BlockEncrypt(pt, ct)); | 
 |   EXPECT_TRUE(block_config->BlockDecrypt(ct, pt)); | 
 | } | 
 |  | 
 | // Block decrypt test from the Test Vector in | 
 | // draft-ietf-quic-load-balancers-14, Appendix B. | 
 | TEST_F(LoadBalancerConfigTest, BlockEncryptionExample) { | 
 |   const uint8_t ptext[] = {0xed, 0x79, 0x3a, 0x51, 0xd4, 0x9b, 0x8f, 0x5f, | 
 |                            0xee, 0x08, 0x0d, 0xbf, 0x48, 0xc0, 0xd1, 0xe5}; | 
 |   const uint8_t ctext[] = {0x4d, 0xd2, 0xd0, 0x5a, 0x7b, 0x0d, 0xe9, 0xb2, | 
 |                            0xb9, 0x90, 0x7a, 0xfb, 0x5e, 0xcf, 0x8c, 0xc3}; | 
 |   const char key[] = {0x8f, 0x95, 0xf0, 0x92, 0x45, 0x76, 0x5f, 0x80, | 
 |                       0x25, 0x69, 0x34, 0xe5, 0x0c, 0x66, 0x20, 0x7f}; | 
 |   uint8_t result[sizeof(ptext)]; | 
 |   auto config = LoadBalancerConfig::Create(0, 8, 8, absl::string_view(key, 16)); | 
 |   EXPECT_TRUE(config->BlockEncrypt(ptext, result)); | 
 |   EXPECT_EQ(memcmp(result, ctext, sizeof(ctext)), 0); | 
 |   EXPECT_TRUE(config->BlockDecrypt(ctext, result)); | 
 |   EXPECT_EQ(memcmp(result, ptext, sizeof(ptext)), 0); | 
 | } | 
 |  | 
 | TEST_F(LoadBalancerConfigTest, ConfigIsCopyable) { | 
 |   const uint8_t ptext[] = {0xed, 0x79, 0x3a, 0x51, 0xd4, 0x9b, 0x8f, 0x5f, | 
 |                            0xee, 0x08, 0x0d, 0xbf, 0x48, 0xc0, 0xd1, 0xe5}; | 
 |   const uint8_t ctext[] = {0x4d, 0xd2, 0xd0, 0x5a, 0x7b, 0x0d, 0xe9, 0xb2, | 
 |                            0xb9, 0x90, 0x7a, 0xfb, 0x5e, 0xcf, 0x8c, 0xc3}; | 
 |   const char key[] = {0x8f, 0x95, 0xf0, 0x92, 0x45, 0x76, 0x5f, 0x80, | 
 |                       0x25, 0x69, 0x34, 0xe5, 0x0c, 0x66, 0x20, 0x7f}; | 
 |   uint8_t result[sizeof(ptext)]; | 
 |   auto config = LoadBalancerConfig::Create(0, 8, 8, absl::string_view(key, 16)); | 
 |   auto config2 = config; | 
 |   EXPECT_TRUE(config->BlockEncrypt(ptext, result)); | 
 |   EXPECT_EQ(memcmp(result, ctext, sizeof(ctext)), 0); | 
 |   EXPECT_TRUE(config2->BlockEncrypt(ptext, result)); | 
 |   EXPECT_EQ(memcmp(result, ctext, sizeof(ctext)), 0); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | }  // namespace test | 
 |  | 
 | }  // namespace quic |