blob: 1605b264c632a5f2fb29e64866f12ce51de0890f [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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 "net/third_party/quiche/src/quic/core/chlo_extractor.h"
6
7#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h"
nharper55fa6132019-05-07 19:37:21 -07008#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -05009#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
10#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
nharper55fa6132019-05-07 19:37:21 -070011#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050012#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
13#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
haoyuewang6a6a0ff2020-06-23 16:32:26 -070014#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050015#include "net/third_party/quiche/src/quic/core/quic_framer.h"
16#include "net/third_party/quiche/src/quic/core/quic_utils.h"
dmcardlecf0bfcf2019-12-13 08:08:21 -080017#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
18#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050019
20namespace quic {
21
22namespace {
23
24class ChloFramerVisitor : public QuicFramerVisitorInterface,
25 public CryptoFramerVisitorInterface {
26 public:
27 ChloFramerVisitor(QuicFramer* framer,
28 const QuicTagVector& create_session_tag_indicators,
29 ChloExtractor::Delegate* delegate);
30
31 ~ChloFramerVisitor() override = default;
32
33 // QuicFramerVisitorInterface implementation
dschinazi17d42422019-06-18 16:35:07 -070034 void OnError(QuicFramer* /*framer*/) override {}
fayang8aba1ff2019-06-21 12:00:54 -070035 bool OnProtocolVersionMismatch(ParsedQuicVersion version) override;
QUICHE teama6ef0a62019-03-07 20:34:33 -050036 void OnPacket() override {}
dschinazi17d42422019-06-18 16:35:07 -070037 void OnPublicResetPacket(const QuicPublicResetPacket& /*packet*/) override {}
QUICHE teama6ef0a62019-03-07 20:34:33 -050038 void OnVersionNegotiationPacket(
dschinazi17d42422019-06-18 16:35:07 -070039 const QuicVersionNegotiationPacket& /*packet*/) override {}
40 void OnRetryPacket(QuicConnectionId /*original_connection_id*/,
41 QuicConnectionId /*new_connection_id*/,
dschinazi278efae2020-01-28 17:03:09 -080042 quiche::QuicheStringPiece /*retry_token*/,
43 quiche::QuicheStringPiece /*retry_integrity_tag*/,
44 quiche::QuicheStringPiece /*retry_without_tag*/) override {
45 }
QUICHE teama6ef0a62019-03-07 20:34:33 -050046 bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override;
47 bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override;
dschinazi17d42422019-06-18 16:35:07 -070048 void OnDecryptedPacket(EncryptionLevel /*level*/) override {}
QUICHE teama6ef0a62019-03-07 20:34:33 -050049 bool OnPacketHeader(const QuicPacketHeader& header) override;
50 void OnCoalescedPacket(const QuicEncryptedPacket& packet) override;
dschinazi4b5a68a2019-08-15 15:45:36 -070051 void OnUndecryptablePacket(const QuicEncryptedPacket& packet,
52 EncryptionLevel decryption_level,
53 bool has_decryption_key) override;
QUICHE teama6ef0a62019-03-07 20:34:33 -050054 bool OnStreamFrame(const QuicStreamFrame& frame) override;
55 bool OnCryptoFrame(const QuicCryptoFrame& frame) override;
56 bool OnAckFrameStart(QuicPacketNumber largest_acked,
57 QuicTime::Delta ack_delay_time) override;
58 bool OnAckRange(QuicPacketNumber start, QuicPacketNumber end) override;
59 bool OnAckTimestamp(QuicPacketNumber packet_number,
60 QuicTime timestamp) override;
61 bool OnAckFrameEnd(QuicPacketNumber start) override;
62 bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override;
63 bool OnPingFrame(const QuicPingFrame& frame) override;
64 bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override;
65 bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override;
QUICHE teama6ef0a62019-03-07 20:34:33 -050066 bool OnNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame) override;
67 bool OnRetireConnectionIdFrame(
68 const QuicRetireConnectionIdFrame& frame) override;
69 bool OnNewTokenFrame(const QuicNewTokenFrame& frame) override;
70 bool OnStopSendingFrame(const QuicStopSendingFrame& frame) override;
71 bool OnPathChallengeFrame(const QuicPathChallengeFrame& frame) override;
72 bool OnPathResponseFrame(const QuicPathResponseFrame& frame) override;
73 bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override;
fkastenholz3c4eabf2019-04-22 07:49:59 -070074 bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override;
75 bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override;
QUICHE teama6ef0a62019-03-07 20:34:33 -050076 bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
77 bool OnBlockedFrame(const QuicBlockedFrame& frame) override;
78 bool OnPaddingFrame(const QuicPaddingFrame& frame) override;
79 bool OnMessageFrame(const QuicMessageFrame& frame) override;
fayang01062942020-01-22 07:23:23 -080080 bool OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& frame) override;
haoyuewang6a6a0ff2020-06-23 16:32:26 -070081 bool OnAckFrequencyFrame(const QuicAckFrequencyFrame& farme) override;
QUICHE teama6ef0a62019-03-07 20:34:33 -050082 void OnPacketComplete() override {}
83 bool IsValidStatelessResetToken(QuicUint128 token) const override;
84 void OnAuthenticatedIetfStatelessResetPacket(
dschinazi17d42422019-06-18 16:35:07 -070085 const QuicIetfStatelessResetPacket& /*packet*/) override {}
QUICHE teama6ef0a62019-03-07 20:34:33 -050086
87 // CryptoFramerVisitorInterface implementation.
88 void OnError(CryptoFramer* framer) override;
89 void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
90
91 // Shared implementation between OnStreamFrame and OnCryptoFrame.
dmcardlecf0bfcf2019-12-13 08:08:21 -080092 bool OnHandshakeData(quiche::QuicheStringPiece data);
QUICHE teama6ef0a62019-03-07 20:34:33 -050093
94 bool found_chlo() { return found_chlo_; }
95 bool chlo_contains_tags() { return chlo_contains_tags_; }
96
97 private:
98 QuicFramer* framer_;
99 const QuicTagVector& create_session_tag_indicators_;
100 ChloExtractor::Delegate* delegate_;
101 bool found_chlo_;
102 bool chlo_contains_tags_;
103 QuicConnectionId connection_id_;
104};
105
106ChloFramerVisitor::ChloFramerVisitor(
107 QuicFramer* framer,
108 const QuicTagVector& create_session_tag_indicators,
109 ChloExtractor::Delegate* delegate)
110 : framer_(framer),
111 create_session_tag_indicators_(create_session_tag_indicators),
112 delegate_(delegate),
113 found_chlo_(false),
114 chlo_contains_tags_(false),
115 connection_id_(EmptyQuicConnectionId()) {}
116
fayang8aba1ff2019-06-21 12:00:54 -0700117bool ChloFramerVisitor::OnProtocolVersionMismatch(ParsedQuicVersion version) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500118 if (!framer_->IsSupportedVersion(version)) {
119 return false;
120 }
121 framer_->set_version(version);
122 return true;
123}
124
125bool ChloFramerVisitor::OnUnauthenticatedPublicHeader(
126 const QuicPacketHeader& header) {
127 connection_id_ = header.destination_connection_id;
nharper55fa6132019-05-07 19:37:21 -0700128 // QuicFramer creates a NullEncrypter and NullDecrypter at level
nharper4a5a76c2019-09-13 13:44:37 -0700129 // ENCRYPTION_INITIAL. While those are the correct ones to use with some
130 // versions of QUIC, others use the IETF-style initial crypters, so those need
131 // to be created and installed.
132 framer_->SetInitialObfuscators(header.destination_connection_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500133 return true;
134}
135bool ChloFramerVisitor::OnUnauthenticatedHeader(
dschinazi17d42422019-06-18 16:35:07 -0700136 const QuicPacketHeader& /*header*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500137 return true;
138}
dschinazi17d42422019-06-18 16:35:07 -0700139bool ChloFramerVisitor::OnPacketHeader(const QuicPacketHeader& /*header*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500140 return true;
141}
dschinazi4b5a68a2019-08-15 15:45:36 -0700142
dschinazi17d42422019-06-18 16:35:07 -0700143void ChloFramerVisitor::OnCoalescedPacket(
144 const QuicEncryptedPacket& /*packet*/) {}
dschinazi4b5a68a2019-08-15 15:45:36 -0700145
146void ChloFramerVisitor::OnUndecryptablePacket(
147 const QuicEncryptedPacket& /*packet*/,
148 EncryptionLevel /*decryption_level*/,
149 bool /*has_decryption_key*/) {}
150
QUICHE teama6ef0a62019-03-07 20:34:33 -0500151bool ChloFramerVisitor::OnStreamFrame(const QuicStreamFrame& frame) {
QUICHE teamea740082019-03-11 17:58:43 -0700152 if (QuicVersionUsesCryptoFrames(framer_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500153 // CHLO will be sent in CRYPTO frames in v47 and above.
154 return false;
155 }
dmcardlecf0bfcf2019-12-13 08:08:21 -0800156 quiche::QuicheStringPiece data(frame.data_buffer, frame.data_length);
nharper46833c32019-05-15 21:33:05 -0700157 if (QuicUtils::IsCryptoStreamId(framer_->transport_version(),
158 frame.stream_id) &&
dmcardlecf0bfcf2019-12-13 08:08:21 -0800159 frame.offset == 0 && quiche::QuicheTextUtils::StartsWith(data, "CHLO")) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500160 return OnHandshakeData(data);
161 }
162 return true;
163}
164
165bool ChloFramerVisitor::OnCryptoFrame(const QuicCryptoFrame& frame) {
QUICHE teamea740082019-03-11 17:58:43 -0700166 if (!QuicVersionUsesCryptoFrames(framer_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500167 // CHLO will be in stream frames before v47.
168 return false;
169 }
dmcardlecf0bfcf2019-12-13 08:08:21 -0800170 quiche::QuicheStringPiece data(frame.data_buffer, frame.data_length);
171 if (frame.offset == 0 && quiche::QuicheTextUtils::StartsWith(data, "CHLO")) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500172 return OnHandshakeData(data);
173 }
174 return true;
175}
176
dmcardlecf0bfcf2019-12-13 08:08:21 -0800177bool ChloFramerVisitor::OnHandshakeData(quiche::QuicheStringPiece data) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500178 CryptoFramer crypto_framer;
179 crypto_framer.set_visitor(this);
180 if (!crypto_framer.ProcessInput(data)) {
181 return false;
182 }
183 // Interrogate the crypto framer and see if there are any
184 // intersecting tags between what we saw in the maybe-CHLO and the
185 // indicator set.
186 for (const QuicTag tag : create_session_tag_indicators_) {
187 if (crypto_framer.HasTag(tag)) {
188 chlo_contains_tags_ = true;
189 }
190 }
191 if (chlo_contains_tags_ && delegate_) {
192 // Unfortunately, because this is a partial CHLO,
193 // OnHandshakeMessage was never called, so the ALPN was never
194 // extracted. Fake it up a bit and send it to the delegate so that
195 // the correct dispatch can happen.
196 crypto_framer.ForceHandshake();
197 }
198
199 return true;
200}
201
202bool ChloFramerVisitor::OnAckFrameStart(QuicPacketNumber /*largest_acked*/,
203 QuicTime::Delta /*ack_delay_time*/) {
204 return true;
205}
206
207bool ChloFramerVisitor::OnAckRange(QuicPacketNumber /*start*/,
208 QuicPacketNumber /*end*/) {
209 return true;
210}
211
212bool ChloFramerVisitor::OnAckTimestamp(QuicPacketNumber /*packet_number*/,
213 QuicTime /*timestamp*/) {
214 return true;
215}
216
217bool ChloFramerVisitor::OnAckFrameEnd(QuicPacketNumber /*start*/) {
218 return true;
219}
220
dschinazi17d42422019-06-18 16:35:07 -0700221bool ChloFramerVisitor::OnStopWaitingFrame(
222 const QuicStopWaitingFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500223 return true;
224}
225
dschinazi17d42422019-06-18 16:35:07 -0700226bool ChloFramerVisitor::OnPingFrame(const QuicPingFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500227 return true;
228}
229
dschinazi17d42422019-06-18 16:35:07 -0700230bool ChloFramerVisitor::OnRstStreamFrame(const QuicRstStreamFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500231 return true;
232}
233
234bool ChloFramerVisitor::OnConnectionCloseFrame(
dschinazi17d42422019-06-18 16:35:07 -0700235 const QuicConnectionCloseFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500236 return true;
237}
238
dschinazi17d42422019-06-18 16:35:07 -0700239bool ChloFramerVisitor::OnStopSendingFrame(
240 const QuicStopSendingFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500241 return true;
242}
243
244bool ChloFramerVisitor::OnPathChallengeFrame(
dschinazi17d42422019-06-18 16:35:07 -0700245 const QuicPathChallengeFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500246 return true;
247}
248
249bool ChloFramerVisitor::OnPathResponseFrame(
dschinazi17d42422019-06-18 16:35:07 -0700250 const QuicPathResponseFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500251 return true;
252}
253
dschinazi17d42422019-06-18 16:35:07 -0700254bool ChloFramerVisitor::OnGoAwayFrame(const QuicGoAwayFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500255 return true;
256}
257
258bool ChloFramerVisitor::OnWindowUpdateFrame(
dschinazi17d42422019-06-18 16:35:07 -0700259 const QuicWindowUpdateFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500260 return true;
261}
262
dschinazi17d42422019-06-18 16:35:07 -0700263bool ChloFramerVisitor::OnBlockedFrame(const QuicBlockedFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500264 return true;
265}
266
267bool ChloFramerVisitor::OnNewConnectionIdFrame(
dschinazi17d42422019-06-18 16:35:07 -0700268 const QuicNewConnectionIdFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500269 return true;
270}
271
272bool ChloFramerVisitor::OnRetireConnectionIdFrame(
dschinazi17d42422019-06-18 16:35:07 -0700273 const QuicRetireConnectionIdFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500274 return true;
275}
276
dschinazi17d42422019-06-18 16:35:07 -0700277bool ChloFramerVisitor::OnNewTokenFrame(const QuicNewTokenFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500278 return true;
279}
280
dschinazi17d42422019-06-18 16:35:07 -0700281bool ChloFramerVisitor::OnPaddingFrame(const QuicPaddingFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500282 return true;
283}
284
dschinazi17d42422019-06-18 16:35:07 -0700285bool ChloFramerVisitor::OnMessageFrame(const QuicMessageFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500286 return true;
287}
288
fayang01062942020-01-22 07:23:23 -0800289bool ChloFramerVisitor::OnHandshakeDoneFrame(
290 const QuicHandshakeDoneFrame& /*frame*/) {
291 return true;
292}
293
haoyuewang6a6a0ff2020-06-23 16:32:26 -0700294bool ChloFramerVisitor::OnAckFrequencyFrame(
295 const QuicAckFrequencyFrame& /*frame*/) {
296 return true;
297}
298
dschinazi17d42422019-06-18 16:35:07 -0700299bool ChloFramerVisitor::IsValidStatelessResetToken(
300 QuicUint128 /*token*/) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500301 return false;
302}
303
dschinazi17d42422019-06-18 16:35:07 -0700304bool ChloFramerVisitor::OnMaxStreamsFrame(
305 const QuicMaxStreamsFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500306 return true;
307}
308
fkastenholz3c4eabf2019-04-22 07:49:59 -0700309bool ChloFramerVisitor::OnStreamsBlockedFrame(
dschinazi17d42422019-06-18 16:35:07 -0700310 const QuicStreamsBlockedFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500311 return true;
312}
313
dschinazi17d42422019-06-18 16:35:07 -0700314void ChloFramerVisitor::OnError(CryptoFramer* /*framer*/) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500315
316void ChloFramerVisitor::OnHandshakeMessage(
317 const CryptoHandshakeMessage& message) {
318 if (delegate_ != nullptr) {
319 delegate_->OnChlo(framer_->transport_version(), connection_id_, message);
320 }
321 found_chlo_ = true;
322}
323
324} // namespace
325
326// static
327bool ChloExtractor::Extract(const QuicEncryptedPacket& packet,
dschinazi4fd8cb12019-09-09 16:31:06 -0700328 ParsedQuicVersion version,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500329 const QuicTagVector& create_session_tag_indicators,
330 Delegate* delegate,
331 uint8_t connection_id_length) {
dschinazi4fd8cb12019-09-09 16:31:06 -0700332 QUIC_DVLOG(1) << "Extracting CHLO using version " << version;
333 QuicFramer framer({version}, QuicTime::Zero(), Perspective::IS_SERVER,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500334 connection_id_length);
335 ChloFramerVisitor visitor(&framer, create_session_tag_indicators, delegate);
336 framer.set_visitor(&visitor);
337 if (!framer.ProcessPacket(packet)) {
338 return false;
339 }
340 return visitor.found_chlo() || visitor.chlo_contains_tags();
341}
342
343} // namespace quic