1 // Copyright (c) 2022 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "quiche/quic/load_balancer/load_balancer_config.h"
6 
7 #include <array>
8 #include <cstdint>
9 #include <cstring>
10 
11 #include "absl/strings/string_view.h"
12 #include "absl/types/span.h"
13 #include "quiche/quic/core/quic_connection_id.h"
14 #include "quiche/quic/load_balancer/load_balancer_server_id.h"
15 #include "quiche/quic/platform/api/quic_expect_bug.h"
16 #include "quiche/quic/platform/api/quic_test.h"
17 
18 namespace quic {
19 
20 namespace test {
21 
22 class LoadBalancerConfigPeer {
23  public:
InitializeFourPass(LoadBalancerConfig & config,const uint8_t * input,uint8_t * left,uint8_t * right,uint8_t * half_len)24   static bool InitializeFourPass(LoadBalancerConfig& config,
25                                  const uint8_t* input, uint8_t* left,
26                                  uint8_t* right, uint8_t* half_len) {
27     return config.InitializeFourPass(input, left, right, half_len);
28   }
29 
EncryptionPass(LoadBalancerConfig & config,uint8_t index,uint8_t half_len,bool is_length_odd,uint8_t * left,uint8_t * right)30   static void EncryptionPass(LoadBalancerConfig& config, uint8_t index,
31                              uint8_t half_len, bool is_length_odd,
32                              uint8_t* left, uint8_t* right) {
33     config.EncryptionPass(index, half_len, is_length_odd, left, right);
34   }
35 };
36 
37 namespace {
38 
39 constexpr char raw_key[] = {
40     0xfd, 0xf7, 0x26, 0xa9, 0x89, 0x3e, 0xc0, 0x5c,
41     0x06, 0x32, 0xd3, 0x95, 0x66, 0x80, 0xba, 0xf0,
42 };
43 
44 class LoadBalancerConfigTest : public QuicTest {};
45 
TEST_F(LoadBalancerConfigTest,InvalidParams)46 TEST_F(LoadBalancerConfigTest, InvalidParams) {
47   // Bogus config_id.
48   EXPECT_QUIC_BUG(
49       EXPECT_FALSE(LoadBalancerConfig::CreateUnencrypted(7, 4, 10).has_value()),
50       "Invalid LoadBalancerConfig Config ID 7 Server ID Length 4 "
51       "Nonce Length 10");
52   // Bad Server ID lengths.
53   EXPECT_QUIC_BUG(EXPECT_FALSE(LoadBalancerConfig::Create(
54                                    2, 0, 10, absl::string_view(raw_key, 16))
55                                    .has_value()),
56                   "Invalid LoadBalancerConfig Config ID 2 Server ID Length 0 "
57                   "Nonce Length 10");
58   EXPECT_QUIC_BUG(
59       EXPECT_FALSE(LoadBalancerConfig::CreateUnencrypted(6, 16, 4).has_value()),
60       "Invalid LoadBalancerConfig Config ID 6 Server ID Length 16 "
61       "Nonce Length 4");
62   // Bad Nonce lengths.
63   EXPECT_QUIC_BUG(
64       EXPECT_FALSE(LoadBalancerConfig::CreateUnencrypted(6, 4, 2).has_value()),
65       "Invalid LoadBalancerConfig Config ID 6 Server ID Length 4 "
66       "Nonce Length 2");
67   EXPECT_QUIC_BUG(
68       EXPECT_FALSE(LoadBalancerConfig::CreateUnencrypted(6, 1, 17).has_value()),
69       "Invalid LoadBalancerConfig Config ID 6 Server ID Length 1 "
70       "Nonce Length 17");
71   // Bad key lengths.
72   EXPECT_QUIC_BUG(
73       EXPECT_FALSE(LoadBalancerConfig::Create(2, 3, 4, "").has_value()),
74       "Invalid LoadBalancerConfig Key Length: 0");
75   EXPECT_QUIC_BUG(EXPECT_FALSE(LoadBalancerConfig::Create(
76                                    2, 3, 4, absl::string_view(raw_key, 10))
77                                    .has_value()),
78                   "Invalid LoadBalancerConfig Key Length: 10");
79   EXPECT_QUIC_BUG(EXPECT_FALSE(LoadBalancerConfig::Create(
80                                    0, 3, 4, absl::string_view(raw_key, 17))
81                                    .has_value()),
82                   "Invalid LoadBalancerConfig Key Length: 17");
83 }
84 
TEST_F(LoadBalancerConfigTest,ValidParams)85 TEST_F(LoadBalancerConfigTest, ValidParams) {
86   // Test valid configurations and accessors
87   auto config = LoadBalancerConfig::CreateUnencrypted(0, 3, 4);
88   EXPECT_TRUE(config.has_value());
89   EXPECT_EQ(config->config_id(), 0);
90   EXPECT_EQ(config->server_id_len(), 3);
91   EXPECT_EQ(config->nonce_len(), 4);
92   EXPECT_EQ(config->plaintext_len(), 7);
93   EXPECT_EQ(config->total_len(), 8);
94   EXPECT_FALSE(config->IsEncrypted());
95   auto config2 =
96       LoadBalancerConfig::Create(2, 6, 7, absl::string_view(raw_key, 16));
97   EXPECT_TRUE(config.has_value());
98   EXPECT_EQ(config2->config_id(), 2);
99   EXPECT_EQ(config2->server_id_len(), 6);
100   EXPECT_EQ(config2->nonce_len(), 7);
101   EXPECT_EQ(config2->plaintext_len(), 13);
102   EXPECT_EQ(config2->total_len(), 14);
103   EXPECT_TRUE(config2->IsEncrypted());
104 }
105 
106 // Compare EncryptionPass() results to the example in
107 // draft-ietf-quic-load-balancers-19, Section 4.3.2.
TEST_F(LoadBalancerConfigTest,TestEncryptionPassExample)108 TEST_F(LoadBalancerConfigTest, TestEncryptionPassExample) {
109   auto config =
110       LoadBalancerConfig::Create(0, 3, 4, absl::string_view(raw_key, 16));
111   EXPECT_TRUE(config.has_value());
112   EXPECT_TRUE(config->IsEncrypted());
113   uint8_t input[] = {0x07, 0x31, 0x44, 0x1a, 0x9c, 0x69, 0xc2, 0x75};
114   std::array<uint8_t, kLoadBalancerBlockSize> left, right;
115   uint8_t half_len;
116 
117   bool is_length_odd = LoadBalancerConfigPeer::InitializeFourPass(
118       *config, input + 1, left.data(), right.data(), &half_len);
119   EXPECT_TRUE(is_length_odd);
120   std::array<std::array<uint8_t, kLoadBalancerBlockSize>,
121              kNumLoadBalancerCryptoPasses + 1>
122       expected_left = {{
123           {0x31, 0x44, 0x1a, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124            0x00, 0x00, 0x00, 0x07, 0x00},
125           {0x31, 0x44, 0x1a, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126            0x00, 0x00, 0x00, 0x07, 0x01},
127           {0xd4, 0xa0, 0x48, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
128            0x00, 0x00, 0x00, 0x07, 0x01},
129           {0xd4, 0xa0, 0x48, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130            0x00, 0x00, 0x00, 0x07, 0x03},
131           {0x67, 0x94, 0x7d, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132            0x00, 0x00, 0x00, 0x07, 0x03},
133       }};
134   std::array<std::array<uint8_t, kLoadBalancerBlockSize>,
135              kNumLoadBalancerCryptoPasses + 1>
136       expected_right = {{
137           {0x0c, 0x69, 0xc2, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138            0x00, 0x00, 0x00, 0x07, 0x00},
139           {0x0e, 0x3c, 0x1f, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
140            0x00, 0x00, 0x00, 0x07, 0x00},
141           {0x0e, 0x3c, 0x1f, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142            0x00, 0x00, 0x00, 0x07, 0x02},
143           {0x09, 0xbe, 0x05, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144            0x00, 0x00, 0x00, 0x07, 0x02},
145           {0x09, 0xbe, 0x05, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146            0x00, 0x00, 0x00, 0x07, 0x04},
147       }};
148 
149   EXPECT_EQ(left, expected_left[0]);
150   EXPECT_EQ(right, expected_right[0]);
151   for (int i = 1; i <= kNumLoadBalancerCryptoPasses; ++i) {
152     LoadBalancerConfigPeer::EncryptionPass(*config, i, half_len, is_length_odd,
153                                            left.data(), right.data());
154     EXPECT_EQ(left, expected_left[i]);
155     EXPECT_EQ(right, expected_right[i]);
156   }
157 }
158 
159 // Check that the encryption pass code can decode its own ciphertext. Various
160 // pointer errors could cause the code to overwrite bits that contain
161 // important information.
TEST_F(LoadBalancerConfigTest,EncryptionPassesAreReversible)162 TEST_F(LoadBalancerConfigTest, EncryptionPassesAreReversible) {
163   auto config =
164       LoadBalancerConfig::Create(0, 3, 4, absl::string_view(raw_key, 16));
165   std::array<uint8_t, kLoadBalancerBlockSize> start_left = {
166       0x31, 0x44, 0x1a, 0x90, 0x00, 0x00, 0x00, 0x00,
167       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
168   };
169   std::array<uint8_t, kLoadBalancerBlockSize> start_right = {
170       0x0c, 0x69, 0xc2, 0x75, 0x00, 0x00, 0x00, 0x00,
171       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
172   };
173   std::array<uint8_t, kLoadBalancerBlockSize> left = start_left,
174                                               right = start_right;
175   // Work left->right and right->left passes.
176   LoadBalancerConfigPeer::EncryptionPass(*config, 1, 4, true, left.data(),
177                                          right.data());
178   LoadBalancerConfigPeer::EncryptionPass(*config, 2, 4, true, left.data(),
179                                          right.data());
180   LoadBalancerConfigPeer::EncryptionPass(*config, 2, 4, true, left.data(),
181                                          right.data());
182   LoadBalancerConfigPeer::EncryptionPass(*config, 1, 4, true, left.data(),
183                                          right.data());
184   // Since index is manually written into the second byte only on input, it is
185   // not reversible.
186   left[15] = 0;
187   right[15] = 0;
188   EXPECT_EQ(left, start_left);
189   EXPECT_EQ(right, start_right);
190 }
191 
192 // Tests for Encrypt() and Decrypt() are in LoadBalancerEncoderTest and
193 // LoadBalancerDecoderTest, respectively.
194 
TEST_F(LoadBalancerConfigTest,InvalidBlockEncryption)195 TEST_F(LoadBalancerConfigTest, InvalidBlockEncryption) {
196   uint8_t pt[kLoadBalancerBlockSize + 1], ct[kLoadBalancerBlockSize];
197   auto pt_config = LoadBalancerConfig::CreateUnencrypted(0, 8, 8);
198   ASSERT_TRUE(pt_config.has_value());
199   EXPECT_FALSE(pt_config->BlockEncrypt(pt, ct));
200   EXPECT_FALSE(pt_config->BlockDecrypt(ct, pt));
201   EXPECT_TRUE(pt_config->FourPassEncrypt(absl::Span<uint8_t>(pt, sizeof(pt)))
202                   .IsEmpty());
203   LoadBalancerServerId answer;
204   EXPECT_FALSE(pt_config->FourPassDecrypt(
205       absl::Span<uint8_t>(pt, sizeof(pt) - 1), answer));
206   auto small_cid_config =
207       LoadBalancerConfig::Create(0, 3, 4, absl::string_view(raw_key, 16));
208   ASSERT_TRUE(small_cid_config.has_value());
209   EXPECT_TRUE(small_cid_config->BlockEncrypt(pt, ct));
210   EXPECT_FALSE(small_cid_config->BlockDecrypt(ct, pt));
211   auto block_config =
212       LoadBalancerConfig::Create(0, 8, 8, absl::string_view(raw_key, 16));
213   ASSERT_TRUE(block_config.has_value());
214   EXPECT_TRUE(block_config->BlockEncrypt(pt, ct));
215   EXPECT_TRUE(block_config->BlockDecrypt(ct, pt));
216 }
217 
218 // Block decrypt test from the Test Vector in
219 // draft-ietf-quic-load-balancers-19, Appendix B.
TEST_F(LoadBalancerConfigTest,BlockEncryptionExample)220 TEST_F(LoadBalancerConfigTest, BlockEncryptionExample) {
221   const uint8_t ptext[] = {0xed, 0x79, 0x3a, 0x51, 0xd4, 0x9b, 0x8f, 0x5f,
222                            0xee, 0x08, 0x0d, 0xbf, 0x48, 0xc0, 0xd1, 0xe5};
223   const uint8_t ctext[] = {0x4d, 0xd2, 0xd0, 0x5a, 0x7b, 0x0d, 0xe9, 0xb2,
224                            0xb9, 0x90, 0x7a, 0xfb, 0x5e, 0xcf, 0x8c, 0xc3};
225   const char key[] = {0x8f, 0x95, 0xf0, 0x92, 0x45, 0x76, 0x5f, 0x80,
226                       0x25, 0x69, 0x34, 0xe5, 0x0c, 0x66, 0x20, 0x7f};
227   uint8_t result[sizeof(ptext)];
228   auto config = LoadBalancerConfig::Create(0, 8, 8, absl::string_view(key, 16));
229   EXPECT_TRUE(config->BlockEncrypt(ptext, result));
230   EXPECT_EQ(memcmp(result, ctext, sizeof(ctext)), 0);
231   EXPECT_TRUE(config->BlockDecrypt(ctext, result));
232   EXPECT_EQ(memcmp(result, ptext, sizeof(ptext)), 0);
233 }
234 
TEST_F(LoadBalancerConfigTest,ConfigIsCopyable)235 TEST_F(LoadBalancerConfigTest, ConfigIsCopyable) {
236   const uint8_t ptext[] = {0xed, 0x79, 0x3a, 0x51, 0xd4, 0x9b, 0x8f, 0x5f,
237                            0xee, 0x08, 0x0d, 0xbf, 0x48, 0xc0, 0xd1, 0xe5};
238   const uint8_t ctext[] = {0x4d, 0xd2, 0xd0, 0x5a, 0x7b, 0x0d, 0xe9, 0xb2,
239                            0xb9, 0x90, 0x7a, 0xfb, 0x5e, 0xcf, 0x8c, 0xc3};
240   const char key[] = {0x8f, 0x95, 0xf0, 0x92, 0x45, 0x76, 0x5f, 0x80,
241                       0x25, 0x69, 0x34, 0xe5, 0x0c, 0x66, 0x20, 0x7f};
242   uint8_t result[sizeof(ptext)];
243   auto config = LoadBalancerConfig::Create(0, 8, 8, absl::string_view(key, 16));
244   auto config2 = config;
245   EXPECT_TRUE(config->BlockEncrypt(ptext, result));
246   EXPECT_EQ(memcmp(result, ctext, sizeof(ctext)), 0);
247   EXPECT_TRUE(config2->BlockEncrypt(ptext, result));
248   EXPECT_EQ(memcmp(result, ctext, sizeof(ctext)), 0);
249 }
250 
TEST_F(LoadBalancerConfigTest,FourPassInputTooShort)251 TEST_F(LoadBalancerConfigTest, FourPassInputTooShort) {
252   auto config =
253       LoadBalancerConfig::Create(0, 3, 4, absl::string_view(raw_key, 16));
254   uint8_t input[] = {0x0d, 0xd2, 0xd0, 0x5a, 0x7b, 0x0d, 0xe9};
255   LoadBalancerServerId answer;
256   bool decrypt_result;
257   EXPECT_QUIC_BUG(
258       decrypt_result = config->FourPassDecrypt(
259           absl::Span<const uint8_t>(input, sizeof(input) - 1), answer),
260       "Called FourPassDecrypt with a short Connection ID");
261   EXPECT_FALSE(decrypt_result);
262   QuicConnectionId encrypt_result;
263   EXPECT_QUIC_BUG(encrypt_result = config->FourPassEncrypt(
264                       absl::Span<uint8_t>(input, sizeof(input))),
265                   "Called FourPassEncrypt with a short Connection ID");
266   EXPECT_TRUE(encrypt_result.IsEmpty());
267 }
268 
269 }  // namespace
270 
271 }  // namespace test
272 
273 }  // namespace quic
274