1 // Copyright (c) 2016 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/core/chlo_extractor.h"
6
7 #include <memory>
8 #include <string>
9 #include <utility>
10
11 #include "absl/base/macros.h"
12 #include "absl/strings/string_view.h"
13 #include "quiche/quic/core/quic_framer.h"
14 #include "quiche/quic/core/quic_utils.h"
15 #include "quiche/quic/platform/api/quic_test.h"
16 #include "quiche/quic/test_tools/crypto_test_utils.h"
17 #include "quiche/quic/test_tools/first_flight.h"
18 #include "quiche/quic/test_tools/quic_test_utils.h"
19
20 namespace quic {
21 namespace test {
22 namespace {
23
24 class TestDelegate : public ChloExtractor::Delegate {
25 public:
26 TestDelegate() = default;
27 ~TestDelegate() override = default;
28
29 // ChloExtractor::Delegate implementation
OnChlo(QuicTransportVersion version,QuicConnectionId connection_id,const CryptoHandshakeMessage & chlo)30 void OnChlo(QuicTransportVersion version, QuicConnectionId connection_id,
31 const CryptoHandshakeMessage& chlo) override {
32 version_ = version;
33 connection_id_ = connection_id;
34 chlo_ = chlo.DebugString();
35 absl::string_view alpn_value;
36 if (chlo.GetStringPiece(kALPN, &alpn_value)) {
37 alpn_ = std::string(alpn_value);
38 }
39 }
40
connection_id() const41 QuicConnectionId connection_id() const { return connection_id_; }
transport_version() const42 QuicTransportVersion transport_version() const { return version_; }
chlo() const43 const std::string& chlo() const { return chlo_; }
alpn() const44 const std::string& alpn() const { return alpn_; }
45
46 private:
47 QuicConnectionId connection_id_;
48 QuicTransportVersion version_;
49 std::string chlo_;
50 std::string alpn_;
51 };
52
53 class ChloExtractorTest : public QuicTestWithParam<ParsedQuicVersion> {
54 public:
ChloExtractorTest()55 ChloExtractorTest() : version_(GetParam()) {}
56
MakePacket(absl::string_view data,bool munge_offset,bool munge_stream_id)57 void MakePacket(absl::string_view data, bool munge_offset,
58 bool munge_stream_id) {
59 QuicPacketHeader header;
60 header.destination_connection_id = TestConnectionId();
61 header.destination_connection_id_included = CONNECTION_ID_PRESENT;
62 header.version_flag = true;
63 header.version = version_;
64 header.reset_flag = false;
65 header.packet_number_length = PACKET_4BYTE_PACKET_NUMBER;
66 header.packet_number = QuicPacketNumber(1);
67 if (version_.HasLongHeaderLengths()) {
68 header.retry_token_length_length =
69 quiche::VARIABLE_LENGTH_INTEGER_LENGTH_1;
70 header.length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_2;
71 }
72 QuicFrames frames;
73 size_t offset = 0;
74 if (munge_offset) {
75 offset++;
76 }
77 QuicFramer framer(SupportedVersions(version_), QuicTime::Zero(),
78 Perspective::IS_CLIENT, kQuicDefaultConnectionIdLength);
79 framer.SetInitialObfuscators(TestConnectionId());
80 if (!version_.UsesCryptoFrames() || munge_stream_id) {
81 QuicStreamId stream_id =
82 QuicUtils::GetCryptoStreamId(version_.transport_version);
83 if (munge_stream_id) {
84 stream_id++;
85 }
86 frames.push_back(
87 QuicFrame(QuicStreamFrame(stream_id, false, offset, data)));
88 } else {
89 frames.push_back(
90 QuicFrame(new QuicCryptoFrame(ENCRYPTION_INITIAL, offset, data)));
91 }
92 std::unique_ptr<QuicPacket> packet(
93 BuildUnsizedDataPacket(&framer, header, frames));
94 EXPECT_TRUE(packet != nullptr);
95 size_t encrypted_length =
96 framer.EncryptPayload(ENCRYPTION_INITIAL, header.packet_number, *packet,
97 buffer_, ABSL_ARRAYSIZE(buffer_));
98 ASSERT_NE(0u, encrypted_length);
99 packet_ = std::make_unique<QuicEncryptedPacket>(buffer_, encrypted_length);
100 EXPECT_TRUE(packet_ != nullptr);
101 DeleteFrames(&frames);
102 }
103
104 protected:
105 ParsedQuicVersion version_;
106 TestDelegate delegate_;
107 std::unique_ptr<QuicEncryptedPacket> packet_;
108 char buffer_[kMaxOutgoingPacketSize];
109 };
110
111 INSTANTIATE_TEST_SUITE_P(
112 ChloExtractorTests, ChloExtractorTest,
113 ::testing::ValuesIn(AllSupportedVersionsWithQuicCrypto()),
114 ::testing::PrintToStringParamName());
115
TEST_P(ChloExtractorTest,FindsValidChlo)116 TEST_P(ChloExtractorTest, FindsValidChlo) {
117 CryptoHandshakeMessage client_hello;
118 client_hello.set_tag(kCHLO);
119
120 std::string client_hello_str(client_hello.GetSerialized().AsStringPiece());
121
122 MakePacket(client_hello_str, /*munge_offset=*/false,
123 /*munge_stream_id=*/false);
124 EXPECT_TRUE(ChloExtractor::Extract(*packet_, version_, {}, &delegate_,
125 kQuicDefaultConnectionIdLength));
126 EXPECT_EQ(version_.transport_version, delegate_.transport_version());
127 EXPECT_EQ(TestConnectionId(), delegate_.connection_id());
128 EXPECT_EQ(client_hello.DebugString(), delegate_.chlo());
129 }
130
TEST_P(ChloExtractorTest,DoesNotFindValidChloOnWrongStream)131 TEST_P(ChloExtractorTest, DoesNotFindValidChloOnWrongStream) {
132 if (version_.UsesCryptoFrames()) {
133 // When crypto frames are in use we do not use stream frames.
134 return;
135 }
136 CryptoHandshakeMessage client_hello;
137 client_hello.set_tag(kCHLO);
138
139 std::string client_hello_str(client_hello.GetSerialized().AsStringPiece());
140 MakePacket(client_hello_str,
141 /*munge_offset=*/false, /*munge_stream_id=*/true);
142 EXPECT_FALSE(ChloExtractor::Extract(*packet_, version_, {}, &delegate_,
143 kQuicDefaultConnectionIdLength));
144 }
145
TEST_P(ChloExtractorTest,DoesNotFindValidChloOnWrongOffset)146 TEST_P(ChloExtractorTest, DoesNotFindValidChloOnWrongOffset) {
147 CryptoHandshakeMessage client_hello;
148 client_hello.set_tag(kCHLO);
149
150 std::string client_hello_str(client_hello.GetSerialized().AsStringPiece());
151 MakePacket(client_hello_str, /*munge_offset=*/true,
152 /*munge_stream_id=*/false);
153 EXPECT_FALSE(ChloExtractor::Extract(*packet_, version_, {}, &delegate_,
154 kQuicDefaultConnectionIdLength));
155 }
156
TEST_P(ChloExtractorTest,DoesNotFindInvalidChlo)157 TEST_P(ChloExtractorTest, DoesNotFindInvalidChlo) {
158 MakePacket("foo", /*munge_offset=*/false,
159 /*munge_stream_id=*/false);
160 EXPECT_FALSE(ChloExtractor::Extract(*packet_, version_, {}, &delegate_,
161 kQuicDefaultConnectionIdLength));
162 }
163
TEST_P(ChloExtractorTest,FirstFlight)164 TEST_P(ChloExtractorTest, FirstFlight) {
165 std::vector<std::unique_ptr<QuicReceivedPacket>> packets =
166 GetFirstFlightOfPackets(version_);
167 ASSERT_EQ(packets.size(), 1u);
168 EXPECT_TRUE(ChloExtractor::Extract(*packets[0], version_, {}, &delegate_,
169 kQuicDefaultConnectionIdLength));
170 EXPECT_EQ(version_.transport_version, delegate_.transport_version());
171 EXPECT_EQ(TestConnectionId(), delegate_.connection_id());
172 EXPECT_EQ(AlpnForVersion(version_), delegate_.alpn());
173 }
174
175 } // namespace
176 } // namespace test
177 } // namespace quic
178