blob: 38e97bd15feee08653adfa69ca4abe6922db73d1 [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"
14#include "net/third_party/quiche/src/quic/core/quic_framer.h"
15#include "net/third_party/quiche/src/quic/core/quic_utils.h"
16#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
17#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
18
19namespace quic {
20
21namespace {
22
23class ChloFramerVisitor : public QuicFramerVisitorInterface,
24 public CryptoFramerVisitorInterface {
25 public:
26 ChloFramerVisitor(QuicFramer* framer,
27 const QuicTagVector& create_session_tag_indicators,
28 ChloExtractor::Delegate* delegate);
29
30 ~ChloFramerVisitor() override = default;
31
32 // QuicFramerVisitorInterface implementation
dschinazi17d42422019-06-18 16:35:07 -070033 void OnError(QuicFramer* /*framer*/) override {}
fayang8aba1ff2019-06-21 12:00:54 -070034 bool OnProtocolVersionMismatch(ParsedQuicVersion version) override;
QUICHE teama6ef0a62019-03-07 20:34:33 -050035 void OnPacket() override {}
dschinazi17d42422019-06-18 16:35:07 -070036 void OnPublicResetPacket(const QuicPublicResetPacket& /*packet*/) override {}
QUICHE teama6ef0a62019-03-07 20:34:33 -050037 void OnVersionNegotiationPacket(
dschinazi17d42422019-06-18 16:35:07 -070038 const QuicVersionNegotiationPacket& /*packet*/) override {}
39 void OnRetryPacket(QuicConnectionId /*original_connection_id*/,
40 QuicConnectionId /*new_connection_id*/,
41 QuicStringPiece /*retry_token*/) override {}
QUICHE teama6ef0a62019-03-07 20:34:33 -050042 bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override;
43 bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override;
dschinazi17d42422019-06-18 16:35:07 -070044 void OnDecryptedPacket(EncryptionLevel /*level*/) override {}
QUICHE teama6ef0a62019-03-07 20:34:33 -050045 bool OnPacketHeader(const QuicPacketHeader& header) override;
46 void OnCoalescedPacket(const QuicEncryptedPacket& packet) override;
dschinazi4b5a68a2019-08-15 15:45:36 -070047 void OnUndecryptablePacket(const QuicEncryptedPacket& packet,
48 EncryptionLevel decryption_level,
49 bool has_decryption_key) override;
QUICHE teama6ef0a62019-03-07 20:34:33 -050050 bool OnStreamFrame(const QuicStreamFrame& frame) override;
51 bool OnCryptoFrame(const QuicCryptoFrame& frame) override;
52 bool OnAckFrameStart(QuicPacketNumber largest_acked,
53 QuicTime::Delta ack_delay_time) override;
54 bool OnAckRange(QuicPacketNumber start, QuicPacketNumber end) override;
55 bool OnAckTimestamp(QuicPacketNumber packet_number,
56 QuicTime timestamp) override;
57 bool OnAckFrameEnd(QuicPacketNumber start) override;
58 bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override;
59 bool OnPingFrame(const QuicPingFrame& frame) override;
60 bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override;
61 bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override;
QUICHE teama6ef0a62019-03-07 20:34:33 -050062 bool OnNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame) override;
63 bool OnRetireConnectionIdFrame(
64 const QuicRetireConnectionIdFrame& frame) override;
65 bool OnNewTokenFrame(const QuicNewTokenFrame& frame) override;
66 bool OnStopSendingFrame(const QuicStopSendingFrame& frame) override;
67 bool OnPathChallengeFrame(const QuicPathChallengeFrame& frame) override;
68 bool OnPathResponseFrame(const QuicPathResponseFrame& frame) override;
69 bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override;
fkastenholz3c4eabf2019-04-22 07:49:59 -070070 bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override;
71 bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override;
QUICHE teama6ef0a62019-03-07 20:34:33 -050072 bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
73 bool OnBlockedFrame(const QuicBlockedFrame& frame) override;
74 bool OnPaddingFrame(const QuicPaddingFrame& frame) override;
75 bool OnMessageFrame(const QuicMessageFrame& frame) override;
76 void OnPacketComplete() override {}
77 bool IsValidStatelessResetToken(QuicUint128 token) const override;
78 void OnAuthenticatedIetfStatelessResetPacket(
dschinazi17d42422019-06-18 16:35:07 -070079 const QuicIetfStatelessResetPacket& /*packet*/) override {}
QUICHE teama6ef0a62019-03-07 20:34:33 -050080
81 // CryptoFramerVisitorInterface implementation.
82 void OnError(CryptoFramer* framer) override;
83 void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
84
85 // Shared implementation between OnStreamFrame and OnCryptoFrame.
86 bool OnHandshakeData(QuicStringPiece data);
87
88 bool found_chlo() { return found_chlo_; }
89 bool chlo_contains_tags() { return chlo_contains_tags_; }
90
91 private:
92 QuicFramer* framer_;
93 const QuicTagVector& create_session_tag_indicators_;
94 ChloExtractor::Delegate* delegate_;
95 bool found_chlo_;
96 bool chlo_contains_tags_;
97 QuicConnectionId connection_id_;
98};
99
100ChloFramerVisitor::ChloFramerVisitor(
101 QuicFramer* framer,
102 const QuicTagVector& create_session_tag_indicators,
103 ChloExtractor::Delegate* delegate)
104 : framer_(framer),
105 create_session_tag_indicators_(create_session_tag_indicators),
106 delegate_(delegate),
107 found_chlo_(false),
108 chlo_contains_tags_(false),
109 connection_id_(EmptyQuicConnectionId()) {}
110
fayang8aba1ff2019-06-21 12:00:54 -0700111bool ChloFramerVisitor::OnProtocolVersionMismatch(ParsedQuicVersion version) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500112 if (!framer_->IsSupportedVersion(version)) {
113 return false;
114 }
115 framer_->set_version(version);
116 return true;
117}
118
119bool ChloFramerVisitor::OnUnauthenticatedPublicHeader(
120 const QuicPacketHeader& header) {
121 connection_id_ = header.destination_connection_id;
nharper55fa6132019-05-07 19:37:21 -0700122 // QuicFramer creates a NullEncrypter and NullDecrypter at level
123 // ENCRYPTION_INITIAL, which are the correct ones to use with the QUIC Crypto
124 // handshake. When the TLS handshake is used, the IETF-style initial crypters
125 // are used instead, so those need to be created and installed.
126 if (header.version.handshake_protocol == PROTOCOL_TLS1_3) {
127 CrypterPair crypters;
128 CryptoUtils::CreateTlsInitialCrypters(
129 Perspective::IS_SERVER, header.version.transport_version,
130 header.destination_connection_id, &crypters);
131 framer_->SetEncrypter(ENCRYPTION_INITIAL, std::move(crypters.encrypter));
132 if (framer_->version().KnowsWhichDecrypterToUse()) {
133 framer_->InstallDecrypter(ENCRYPTION_INITIAL,
134 std::move(crypters.decrypter));
135 } else {
136 framer_->SetDecrypter(ENCRYPTION_INITIAL, std::move(crypters.decrypter));
137 }
138 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500139 return true;
140}
141bool ChloFramerVisitor::OnUnauthenticatedHeader(
dschinazi17d42422019-06-18 16:35:07 -0700142 const QuicPacketHeader& /*header*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500143 return true;
144}
dschinazi17d42422019-06-18 16:35:07 -0700145bool ChloFramerVisitor::OnPacketHeader(const QuicPacketHeader& /*header*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500146 return true;
147}
dschinazi4b5a68a2019-08-15 15:45:36 -0700148
dschinazi17d42422019-06-18 16:35:07 -0700149void ChloFramerVisitor::OnCoalescedPacket(
150 const QuicEncryptedPacket& /*packet*/) {}
dschinazi4b5a68a2019-08-15 15:45:36 -0700151
152void ChloFramerVisitor::OnUndecryptablePacket(
153 const QuicEncryptedPacket& /*packet*/,
154 EncryptionLevel /*decryption_level*/,
155 bool /*has_decryption_key*/) {}
156
QUICHE teama6ef0a62019-03-07 20:34:33 -0500157bool ChloFramerVisitor::OnStreamFrame(const QuicStreamFrame& frame) {
QUICHE teamea740082019-03-11 17:58:43 -0700158 if (QuicVersionUsesCryptoFrames(framer_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500159 // CHLO will be sent in CRYPTO frames in v47 and above.
160 return false;
161 }
162 QuicStringPiece data(frame.data_buffer, frame.data_length);
nharper46833c32019-05-15 21:33:05 -0700163 if (QuicUtils::IsCryptoStreamId(framer_->transport_version(),
164 frame.stream_id) &&
QUICHE teama6ef0a62019-03-07 20:34:33 -0500165 frame.offset == 0 && QuicTextUtils::StartsWith(data, "CHLO")) {
166 return OnHandshakeData(data);
167 }
168 return true;
169}
170
171bool ChloFramerVisitor::OnCryptoFrame(const QuicCryptoFrame& frame) {
QUICHE teamea740082019-03-11 17:58:43 -0700172 if (!QuicVersionUsesCryptoFrames(framer_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500173 // CHLO will be in stream frames before v47.
174 return false;
175 }
176 QuicStringPiece data(frame.data_buffer, frame.data_length);
177 if (frame.offset == 0 && QuicTextUtils::StartsWith(data, "CHLO")) {
178 return OnHandshakeData(data);
179 }
180 return true;
181}
182
183bool ChloFramerVisitor::OnHandshakeData(QuicStringPiece data) {
184 CryptoFramer crypto_framer;
185 crypto_framer.set_visitor(this);
186 if (!crypto_framer.ProcessInput(data)) {
187 return false;
188 }
189 // Interrogate the crypto framer and see if there are any
190 // intersecting tags between what we saw in the maybe-CHLO and the
191 // indicator set.
192 for (const QuicTag tag : create_session_tag_indicators_) {
193 if (crypto_framer.HasTag(tag)) {
194 chlo_contains_tags_ = true;
195 }
196 }
197 if (chlo_contains_tags_ && delegate_) {
198 // Unfortunately, because this is a partial CHLO,
199 // OnHandshakeMessage was never called, so the ALPN was never
200 // extracted. Fake it up a bit and send it to the delegate so that
201 // the correct dispatch can happen.
202 crypto_framer.ForceHandshake();
203 }
204
205 return true;
206}
207
208bool ChloFramerVisitor::OnAckFrameStart(QuicPacketNumber /*largest_acked*/,
209 QuicTime::Delta /*ack_delay_time*/) {
210 return true;
211}
212
213bool ChloFramerVisitor::OnAckRange(QuicPacketNumber /*start*/,
214 QuicPacketNumber /*end*/) {
215 return true;
216}
217
218bool ChloFramerVisitor::OnAckTimestamp(QuicPacketNumber /*packet_number*/,
219 QuicTime /*timestamp*/) {
220 return true;
221}
222
223bool ChloFramerVisitor::OnAckFrameEnd(QuicPacketNumber /*start*/) {
224 return true;
225}
226
dschinazi17d42422019-06-18 16:35:07 -0700227bool ChloFramerVisitor::OnStopWaitingFrame(
228 const QuicStopWaitingFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500229 return true;
230}
231
dschinazi17d42422019-06-18 16:35:07 -0700232bool ChloFramerVisitor::OnPingFrame(const QuicPingFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500233 return true;
234}
235
dschinazi17d42422019-06-18 16:35:07 -0700236bool ChloFramerVisitor::OnRstStreamFrame(const QuicRstStreamFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500237 return true;
238}
239
240bool ChloFramerVisitor::OnConnectionCloseFrame(
dschinazi17d42422019-06-18 16:35:07 -0700241 const QuicConnectionCloseFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500242 return true;
243}
244
dschinazi17d42422019-06-18 16:35:07 -0700245bool ChloFramerVisitor::OnStopSendingFrame(
246 const QuicStopSendingFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500247 return true;
248}
249
250bool ChloFramerVisitor::OnPathChallengeFrame(
dschinazi17d42422019-06-18 16:35:07 -0700251 const QuicPathChallengeFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500252 return true;
253}
254
255bool ChloFramerVisitor::OnPathResponseFrame(
dschinazi17d42422019-06-18 16:35:07 -0700256 const QuicPathResponseFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500257 return true;
258}
259
dschinazi17d42422019-06-18 16:35:07 -0700260bool ChloFramerVisitor::OnGoAwayFrame(const QuicGoAwayFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500261 return true;
262}
263
264bool ChloFramerVisitor::OnWindowUpdateFrame(
dschinazi17d42422019-06-18 16:35:07 -0700265 const QuicWindowUpdateFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500266 return true;
267}
268
dschinazi17d42422019-06-18 16:35:07 -0700269bool ChloFramerVisitor::OnBlockedFrame(const QuicBlockedFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500270 return true;
271}
272
273bool ChloFramerVisitor::OnNewConnectionIdFrame(
dschinazi17d42422019-06-18 16:35:07 -0700274 const QuicNewConnectionIdFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500275 return true;
276}
277
278bool ChloFramerVisitor::OnRetireConnectionIdFrame(
dschinazi17d42422019-06-18 16:35:07 -0700279 const QuicRetireConnectionIdFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500280 return true;
281}
282
dschinazi17d42422019-06-18 16:35:07 -0700283bool ChloFramerVisitor::OnNewTokenFrame(const QuicNewTokenFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500284 return true;
285}
286
dschinazi17d42422019-06-18 16:35:07 -0700287bool ChloFramerVisitor::OnPaddingFrame(const QuicPaddingFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500288 return true;
289}
290
dschinazi17d42422019-06-18 16:35:07 -0700291bool ChloFramerVisitor::OnMessageFrame(const QuicMessageFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500292 return true;
293}
294
dschinazi17d42422019-06-18 16:35:07 -0700295bool ChloFramerVisitor::IsValidStatelessResetToken(
296 QuicUint128 /*token*/) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500297 return false;
298}
299
dschinazi17d42422019-06-18 16:35:07 -0700300bool ChloFramerVisitor::OnMaxStreamsFrame(
301 const QuicMaxStreamsFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500302 return true;
303}
304
fkastenholz3c4eabf2019-04-22 07:49:59 -0700305bool ChloFramerVisitor::OnStreamsBlockedFrame(
dschinazi17d42422019-06-18 16:35:07 -0700306 const QuicStreamsBlockedFrame& /*frame*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500307 return true;
308}
309
dschinazi17d42422019-06-18 16:35:07 -0700310void ChloFramerVisitor::OnError(CryptoFramer* /*framer*/) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500311
312void ChloFramerVisitor::OnHandshakeMessage(
313 const CryptoHandshakeMessage& message) {
314 if (delegate_ != nullptr) {
315 delegate_->OnChlo(framer_->transport_version(), connection_id_, message);
316 }
317 found_chlo_ = true;
318}
319
320} // namespace
321
322// static
323bool ChloExtractor::Extract(const QuicEncryptedPacket& packet,
324 const ParsedQuicVersionVector& versions,
325 const QuicTagVector& create_session_tag_indicators,
326 Delegate* delegate,
327 uint8_t connection_id_length) {
dschinazie9db63c2019-07-17 16:19:42 -0700328 QUIC_DVLOG(1) << "Extracting CHLO using versions "
329 << ParsedQuicVersionVectorToString(versions);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500330 QuicFramer framer(versions, QuicTime::Zero(), Perspective::IS_SERVER,
331 connection_id_length);
332 ChloFramerVisitor visitor(&framer, create_session_tag_indicators, delegate);
333 framer.set_visitor(&visitor);
334 if (!framer.ProcessPacket(packet)) {
335 return false;
336 }
337 return visitor.found_chlo() || visitor.chlo_contains_tags();
338}
339
340} // namespace quic