blob: d598c4956d15883f34884e5dfd0b4e3fd7423460 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2012 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 "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h"
6
7#include <map>
8#include <memory>
9#include <vector>
10
11#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h"
12#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
13#include "net/third_party/quiche/src/quic/core/quic_packets.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050014#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
15#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
16#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
17#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
bnc4e9283d2019-12-17 07:08:57 -080018#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
dmcardle904ef182019-12-13 08:34:33 -080019#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
dmcardle8f7df532020-01-07 13:28:57 -080020#include "net/third_party/quiche/src/common/test_tools/quiche_test_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050021
22namespace quic {
23namespace test {
24namespace {
25
26char* AsChars(unsigned char* data) {
27 return reinterpret_cast<char*>(data);
28}
29
30class TestCryptoVisitor : public CryptoFramerVisitorInterface {
31 public:
32 TestCryptoVisitor() : error_count_(0) {}
33
34 void OnError(CryptoFramer* framer) override {
35 QUIC_DLOG(ERROR) << "CryptoFramer Error: " << framer->error();
36 ++error_count_;
37 }
38
39 void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
40 messages_.push_back(message);
41 }
42
43 // Counters from the visitor callbacks.
44 int error_count_;
45
46 std::vector<CryptoHandshakeMessage> messages_;
47};
48
49TEST(CryptoFramerTest, ConstructHandshakeMessage) {
50 CryptoHandshakeMessage message;
51 message.set_tag(0xFFAA7733);
52 message.SetStringPiece(0x12345678, "abcdef");
53 message.SetStringPiece(0x12345679, "ghijk");
54 message.SetStringPiece(0x1234567A, "lmnopqr");
55
56 unsigned char packet[] = {
57 // tag
58 0x33, 0x77, 0xAA, 0xFF,
59 // num entries
60 0x03, 0x00,
61 // padding
62 0x00, 0x00,
63 // tag 1
64 0x78, 0x56, 0x34, 0x12,
65 // end offset 1
66 0x06, 0x00, 0x00, 0x00,
67 // tag 2
68 0x79, 0x56, 0x34, 0x12,
69 // end offset 2
70 0x0b, 0x00, 0x00, 0x00,
71 // tag 3
72 0x7A, 0x56, 0x34, 0x12,
73 // end offset 3
74 0x12, 0x00, 0x00, 0x00,
75 // value 1
76 'a', 'b', 'c', 'd', 'e', 'f',
77 // value 2
78 'g', 'h', 'i', 'j', 'k',
79 // value 3
80 'l', 'm', 'n', 'o', 'p', 'q', 'r',
81 };
82
83 CryptoFramer framer;
QUICHE team3fe6a8b2019-03-14 09:10:38 -070084 std::unique_ptr<QuicData> data = framer.ConstructHandshakeMessage(message);
QUICHE teama6ef0a62019-03-07 20:34:33 -050085 ASSERT_TRUE(data != nullptr);
dmcardle8f7df532020-01-07 13:28:57 -080086 quiche::test::CompareCharArraysWithHexError(
87 "constructed packet", data->data(), data->length(), AsChars(packet),
88 QUICHE_ARRAYSIZE(packet));
QUICHE teama6ef0a62019-03-07 20:34:33 -050089}
90
91TEST(CryptoFramerTest, ConstructHandshakeMessageWithTwoKeys) {
92 CryptoHandshakeMessage message;
93 message.set_tag(0xFFAA7733);
94 message.SetStringPiece(0x12345678, "abcdef");
95 message.SetStringPiece(0x12345679, "ghijk");
96
97 unsigned char packet[] = {
98 // tag
99 0x33, 0x77, 0xAA, 0xFF,
100 // num entries
101 0x02, 0x00,
102 // padding
103 0x00, 0x00,
104 // tag 1
105 0x78, 0x56, 0x34, 0x12,
106 // end offset 1
107 0x06, 0x00, 0x00, 0x00,
108 // tag 2
109 0x79, 0x56, 0x34, 0x12,
110 // end offset 2
111 0x0b, 0x00, 0x00, 0x00,
112 // value 1
113 'a', 'b', 'c', 'd', 'e', 'f',
114 // value 2
115 'g', 'h', 'i', 'j', 'k',
116 };
117
118 CryptoFramer framer;
QUICHE team3fe6a8b2019-03-14 09:10:38 -0700119 std::unique_ptr<QuicData> data = framer.ConstructHandshakeMessage(message);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500120 ASSERT_TRUE(data != nullptr);
121
dmcardle8f7df532020-01-07 13:28:57 -0800122 quiche::test::CompareCharArraysWithHexError(
123 "constructed packet", data->data(), data->length(), AsChars(packet),
124 QUICHE_ARRAYSIZE(packet));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500125}
126
127TEST(CryptoFramerTest, ConstructHandshakeMessageZeroLength) {
128 CryptoHandshakeMessage message;
129 message.set_tag(0xFFAA7733);
130 message.SetStringPiece(0x12345678, "");
131
132 unsigned char packet[] = {
133 // tag
134 0x33, 0x77, 0xAA, 0xFF,
135 // num entries
136 0x01, 0x00,
137 // padding
138 0x00, 0x00,
139 // tag 1
140 0x78, 0x56, 0x34, 0x12,
141 // end offset 1
142 0x00, 0x00, 0x00, 0x00,
143 };
144
145 CryptoFramer framer;
QUICHE team3fe6a8b2019-03-14 09:10:38 -0700146 std::unique_ptr<QuicData> data = framer.ConstructHandshakeMessage(message);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500147 ASSERT_TRUE(data != nullptr);
148
dmcardle8f7df532020-01-07 13:28:57 -0800149 quiche::test::CompareCharArraysWithHexError(
150 "constructed packet", data->data(), data->length(), AsChars(packet),
151 QUICHE_ARRAYSIZE(packet));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500152}
153
154TEST(CryptoFramerTest, ConstructHandshakeMessageTooManyEntries) {
155 CryptoHandshakeMessage message;
156 message.set_tag(0xFFAA7733);
157 for (uint32_t key = 1; key <= kMaxEntries + 1; ++key) {
158 message.SetStringPiece(key, "abcdef");
159 }
160
161 CryptoFramer framer;
QUICHE team3fe6a8b2019-03-14 09:10:38 -0700162 std::unique_ptr<QuicData> data = framer.ConstructHandshakeMessage(message);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500163 EXPECT_TRUE(data == nullptr);
164}
165
166TEST(CryptoFramerTest, ConstructHandshakeMessageMinimumSize) {
167 CryptoHandshakeMessage message;
168 message.set_tag(0xFFAA7733);
169 message.SetStringPiece(0x01020304, "test");
170 message.set_minimum_size(64);
171
172 unsigned char packet[] = {
173 // tag
174 0x33, 0x77, 0xAA, 0xFF,
175 // num entries
176 0x02, 0x00,
177 // padding
178 0x00, 0x00,
179 // tag 1
180 'P', 'A', 'D', 0,
181 // end offset 1
182 0x24, 0x00, 0x00, 0x00,
183 // tag 2
184 0x04, 0x03, 0x02, 0x01,
185 // end offset 2
186 0x28, 0x00, 0x00, 0x00,
187 // 36 bytes of padding.
188 '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',
189 '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',
190 '-', '-', '-', '-', '-', '-',
191 // value 2
192 't', 'e', 's', 't',
193 };
194
195 CryptoFramer framer;
QUICHE team3fe6a8b2019-03-14 09:10:38 -0700196 std::unique_ptr<QuicData> data = framer.ConstructHandshakeMessage(message);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500197 ASSERT_TRUE(data != nullptr);
198
dmcardle8f7df532020-01-07 13:28:57 -0800199 quiche::test::CompareCharArraysWithHexError(
200 "constructed packet", data->data(), data->length(), AsChars(packet),
201 QUICHE_ARRAYSIZE(packet));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500202}
203
204TEST(CryptoFramerTest, ConstructHandshakeMessageMinimumSizePadLast) {
205 CryptoHandshakeMessage message;
206 message.set_tag(0xFFAA7733);
207 message.SetStringPiece(1, "");
208 message.set_minimum_size(64);
209
210 unsigned char packet[] = {
211 // tag
212 0x33, 0x77, 0xAA, 0xFF,
213 // num entries
214 0x02, 0x00,
215 // padding
216 0x00, 0x00,
217 // tag 1
218 0x01, 0x00, 0x00, 0x00,
219 // end offset 1
220 0x00, 0x00, 0x00, 0x00,
221 // tag 2
222 'P', 'A', 'D', 0,
223 // end offset 2
224 0x28, 0x00, 0x00, 0x00,
225 // 40 bytes of padding.
226 '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',
227 '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',
228 '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',
229 };
230
231 CryptoFramer framer;
QUICHE team3fe6a8b2019-03-14 09:10:38 -0700232 std::unique_ptr<QuicData> data = framer.ConstructHandshakeMessage(message);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500233 ASSERT_TRUE(data != nullptr);
234
dmcardle8f7df532020-01-07 13:28:57 -0800235 quiche::test::CompareCharArraysWithHexError(
236 "constructed packet", data->data(), data->length(), AsChars(packet),
237 QUICHE_ARRAYSIZE(packet));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500238}
239
240TEST(CryptoFramerTest, ProcessInput) {
241 test::TestCryptoVisitor visitor;
242 CryptoFramer framer;
243 framer.set_visitor(&visitor);
244
245 unsigned char input[] = {
246 // tag
247 0x33, 0x77, 0xAA, 0xFF,
248 // num entries
249 0x02, 0x00,
250 // padding
251 0x00, 0x00,
252 // tag 1
253 0x78, 0x56, 0x34, 0x12,
254 // end offset 1
255 0x06, 0x00, 0x00, 0x00,
256 // tag 2
257 0x79, 0x56, 0x34, 0x12,
258 // end offset 2
259 0x0b, 0x00, 0x00, 0x00,
260 // value 1
261 'a', 'b', 'c', 'd', 'e', 'f',
262 // value 2
263 'g', 'h', 'i', 'j', 'k',
264 };
265
266 EXPECT_TRUE(framer.ProcessInput(
bnc4e9283d2019-12-17 07:08:57 -0800267 quiche::QuicheStringPiece(AsChars(input), QUICHE_ARRAYSIZE(input))));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500268 EXPECT_EQ(0u, framer.InputBytesRemaining());
269 EXPECT_EQ(0, visitor.error_count_);
270 ASSERT_EQ(1u, visitor.messages_.size());
271 const CryptoHandshakeMessage& message = visitor.messages_[0];
272 EXPECT_EQ(0xFFAA7733, message.tag());
273 EXPECT_EQ(2u, message.tag_value_map().size());
274 EXPECT_EQ("abcdef", crypto_test_utils::GetValueForTag(message, 0x12345678));
275 EXPECT_EQ("ghijk", crypto_test_utils::GetValueForTag(message, 0x12345679));
276}
277
278TEST(CryptoFramerTest, ProcessInputWithThreeKeys) {
279 test::TestCryptoVisitor visitor;
280 CryptoFramer framer;
281 framer.set_visitor(&visitor);
282
283 unsigned char input[] = {
284 // tag
285 0x33, 0x77, 0xAA, 0xFF,
286 // num entries
287 0x03, 0x00,
288 // padding
289 0x00, 0x00,
290 // tag 1
291 0x78, 0x56, 0x34, 0x12,
292 // end offset 1
293 0x06, 0x00, 0x00, 0x00,
294 // tag 2
295 0x79, 0x56, 0x34, 0x12,
296 // end offset 2
297 0x0b, 0x00, 0x00, 0x00,
298 // tag 3
299 0x7A, 0x56, 0x34, 0x12,
300 // end offset 3
301 0x12, 0x00, 0x00, 0x00,
302 // value 1
303 'a', 'b', 'c', 'd', 'e', 'f',
304 // value 2
305 'g', 'h', 'i', 'j', 'k',
306 // value 3
307 'l', 'm', 'n', 'o', 'p', 'q', 'r',
308 };
309
310 EXPECT_TRUE(framer.ProcessInput(
bnc4e9283d2019-12-17 07:08:57 -0800311 quiche::QuicheStringPiece(AsChars(input), QUICHE_ARRAYSIZE(input))));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500312 EXPECT_EQ(0u, framer.InputBytesRemaining());
313 EXPECT_EQ(0, visitor.error_count_);
314 ASSERT_EQ(1u, visitor.messages_.size());
315 const CryptoHandshakeMessage& message = visitor.messages_[0];
316 EXPECT_EQ(0xFFAA7733, message.tag());
317 EXPECT_EQ(3u, message.tag_value_map().size());
318 EXPECT_EQ("abcdef", crypto_test_utils::GetValueForTag(message, 0x12345678));
319 EXPECT_EQ("ghijk", crypto_test_utils::GetValueForTag(message, 0x12345679));
320 EXPECT_EQ("lmnopqr", crypto_test_utils::GetValueForTag(message, 0x1234567A));
321}
322
323TEST(CryptoFramerTest, ProcessInputIncrementally) {
324 test::TestCryptoVisitor visitor;
325 CryptoFramer framer;
326 framer.set_visitor(&visitor);
327
328 unsigned char input[] = {
329 // tag
330 0x33, 0x77, 0xAA, 0xFF,
331 // num entries
332 0x02, 0x00,
333 // padding
334 0x00, 0x00,
335 // tag 1
336 0x78, 0x56, 0x34, 0x12,
337 // end offset 1
338 0x06, 0x00, 0x00, 0x00,
339 // tag 2
340 0x79, 0x56, 0x34, 0x12,
341 // end offset 2
342 0x0b, 0x00, 0x00, 0x00,
343 // value 1
344 'a', 'b', 'c', 'd', 'e', 'f',
345 // value 2
346 'g', 'h', 'i', 'j', 'k',
347 };
348
bnc4e9283d2019-12-17 07:08:57 -0800349 for (size_t i = 0; i < QUICHE_ARRAYSIZE(input); i++) {
dmcardle904ef182019-12-13 08:34:33 -0800350 EXPECT_TRUE(
351 framer.ProcessInput(quiche::QuicheStringPiece(AsChars(input) + i, 1)));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500352 }
353 EXPECT_EQ(0u, framer.InputBytesRemaining());
354 ASSERT_EQ(1u, visitor.messages_.size());
355 const CryptoHandshakeMessage& message = visitor.messages_[0];
356 EXPECT_EQ(0xFFAA7733, message.tag());
357 EXPECT_EQ(2u, message.tag_value_map().size());
358 EXPECT_EQ("abcdef", crypto_test_utils::GetValueForTag(message, 0x12345678));
359 EXPECT_EQ("ghijk", crypto_test_utils::GetValueForTag(message, 0x12345679));
360}
361
362TEST(CryptoFramerTest, ProcessInputTagsOutOfOrder) {
363 test::TestCryptoVisitor visitor;
364 CryptoFramer framer;
365 framer.set_visitor(&visitor);
366
367 unsigned char input[] = {
368 // tag
369 0x33, 0x77, 0xAA, 0xFF,
370 // num entries
371 0x02, 0x00,
372 // padding
373 0x00, 0x00,
374 // tag 1
375 0x78, 0x56, 0x34, 0x13,
376 // end offset 1
377 0x01, 0x00, 0x00, 0x00,
378 // tag 2
379 0x79, 0x56, 0x34, 0x12,
380 // end offset 2
381 0x02, 0x00, 0x00, 0x00,
382 };
383
384 EXPECT_FALSE(framer.ProcessInput(
bnc4e9283d2019-12-17 07:08:57 -0800385 quiche::QuicheStringPiece(AsChars(input), QUICHE_ARRAYSIZE(input))));
bnc162322c2019-12-05 10:30:04 -0800386 EXPECT_THAT(framer.error(), IsError(QUIC_CRYPTO_TAGS_OUT_OF_ORDER));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500387 EXPECT_EQ(1, visitor.error_count_);
388}
389
390TEST(CryptoFramerTest, ProcessEndOffsetsOutOfOrder) {
391 test::TestCryptoVisitor visitor;
392 CryptoFramer framer;
393 framer.set_visitor(&visitor);
394
395 unsigned char input[] = {
396 // tag
397 0x33, 0x77, 0xAA, 0xFF,
398 // num entries
399 0x02, 0x00,
400 // padding
401 0x00, 0x00,
402 // tag 1
403 0x79, 0x56, 0x34, 0x12,
404 // end offset 1
405 0x01, 0x00, 0x00, 0x00,
406 // tag 2
407 0x78, 0x56, 0x34, 0x13,
408 // end offset 2
409 0x00, 0x00, 0x00, 0x00,
410 };
411
412 EXPECT_FALSE(framer.ProcessInput(
bnc4e9283d2019-12-17 07:08:57 -0800413 quiche::QuicheStringPiece(AsChars(input), QUICHE_ARRAYSIZE(input))));
bnc162322c2019-12-05 10:30:04 -0800414 EXPECT_THAT(framer.error(), IsError(QUIC_CRYPTO_TAGS_OUT_OF_ORDER));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500415 EXPECT_EQ(1, visitor.error_count_);
416}
417
418TEST(CryptoFramerTest, ProcessInputTooManyEntries) {
419 test::TestCryptoVisitor visitor;
420 CryptoFramer framer;
421 framer.set_visitor(&visitor);
422
423 unsigned char input[] = {
424 // tag
425 0x33, 0x77, 0xAA, 0xFF,
426 // num entries
427 0xA0, 0x00,
428 // padding
429 0x00, 0x00,
430 };
431
432 EXPECT_FALSE(framer.ProcessInput(
bnc4e9283d2019-12-17 07:08:57 -0800433 quiche::QuicheStringPiece(AsChars(input), QUICHE_ARRAYSIZE(input))));
bnc162322c2019-12-05 10:30:04 -0800434 EXPECT_THAT(framer.error(), IsError(QUIC_CRYPTO_TOO_MANY_ENTRIES));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500435 EXPECT_EQ(1, visitor.error_count_);
436}
437
438TEST(CryptoFramerTest, ProcessInputZeroLength) {
439 test::TestCryptoVisitor visitor;
440 CryptoFramer framer;
441 framer.set_visitor(&visitor);
442
443 unsigned char input[] = {
444 // tag
445 0x33, 0x77, 0xAA, 0xFF,
446 // num entries
447 0x02, 0x00,
448 // padding
449 0x00, 0x00,
450 // tag 1
451 0x78, 0x56, 0x34, 0x12,
452 // end offset 1
453 0x00, 0x00, 0x00, 0x00,
454 // tag 2
455 0x79, 0x56, 0x34, 0x12,
456 // end offset 2
457 0x05, 0x00, 0x00, 0x00,
458 };
459
460 EXPECT_TRUE(framer.ProcessInput(
bnc4e9283d2019-12-17 07:08:57 -0800461 quiche::QuicheStringPiece(AsChars(input), QUICHE_ARRAYSIZE(input))));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500462 EXPECT_EQ(0, visitor.error_count_);
463}
464
465} // namespace
466} // namespace test
467} // namespace quic