xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/chlo_extractor_test.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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