blob: d8a32bcfe9f66883ec0f48f83a6a112ad0c3e458 [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 "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
8#include "net/third_party/quiche/src/quic/core/quic_data_reader.h"
9#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
10#include "net/third_party/quiche/src/quic/core/quic_packets.h"
11#include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h"
12#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
13#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
14#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
15#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
16#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
17
18namespace quic {
19
20namespace {
21
22const size_t kQuicTagSize = sizeof(QuicTag);
23const size_t kCryptoEndOffsetSize = sizeof(uint32_t);
24const size_t kNumEntriesSize = sizeof(uint16_t);
25
26// OneShotVisitor is a framer visitor that records a single handshake message.
27class OneShotVisitor : public CryptoFramerVisitorInterface {
28 public:
29 OneShotVisitor() : error_(false) {}
30
31 void OnError(CryptoFramer* framer) override { error_ = true; }
32
33 void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
34 out_ = QuicMakeUnique<CryptoHandshakeMessage>(message);
35 }
36
37 bool error() const { return error_; }
38
39 std::unique_ptr<CryptoHandshakeMessage> release() { return std::move(out_); }
40
41 private:
42 std::unique_ptr<CryptoHandshakeMessage> out_;
43 bool error_;
44};
45
46} // namespace
47
48CryptoFramer::CryptoFramer()
49 : visitor_(nullptr),
50 error_detail_(""),
51 num_entries_(0),
52 values_len_(0),
53 process_truncated_messages_(false) {
54 Clear();
55}
56
57CryptoFramer::~CryptoFramer() {}
58
59// static
60std::unique_ptr<CryptoHandshakeMessage> CryptoFramer::ParseMessage(
61 QuicStringPiece in) {
62 OneShotVisitor visitor;
63 CryptoFramer framer;
64
65 framer.set_visitor(&visitor);
66 if (!framer.ProcessInput(in) || visitor.error() ||
67 framer.InputBytesRemaining()) {
68 return nullptr;
69 }
70
71 return visitor.release();
72}
73
74QuicErrorCode CryptoFramer::error() const {
75 return error_;
76}
77
vasilvvc48c8712019-03-11 13:38:16 -070078const std::string& CryptoFramer::error_detail() const {
QUICHE teama6ef0a62019-03-07 20:34:33 -050079 return error_detail_;
80}
81
82bool CryptoFramer::ProcessInput(QuicStringPiece input, EncryptionLevel level) {
83 return ProcessInput(input);
84}
85
86bool CryptoFramer::ProcessInput(QuicStringPiece input) {
87 DCHECK_EQ(QUIC_NO_ERROR, error_);
88 if (error_ != QUIC_NO_ERROR) {
89 return false;
90 }
91 error_ = Process(input);
92 if (error_ != QUIC_NO_ERROR) {
93 DCHECK(!error_detail_.empty());
94 visitor_->OnError(this);
95 return false;
96 }
97
98 return true;
99}
100
101size_t CryptoFramer::InputBytesRemaining() const {
102 return buffer_.length();
103}
104
105bool CryptoFramer::HasTag(QuicTag tag) const {
106 if (state_ != STATE_READING_VALUES) {
107 return false;
108 }
109 for (const auto& it : tags_and_lengths_) {
110 if (it.first == tag) {
111 return true;
112 }
113 }
114 return false;
115}
116
117void CryptoFramer::ForceHandshake() {
118 QuicDataReader reader(buffer_.data(), buffer_.length(), HOST_BYTE_ORDER);
119 for (const std::pair<QuicTag, size_t>& item : tags_and_lengths_) {
120 QuicStringPiece value;
121 if (reader.BytesRemaining() < item.second) {
122 break;
123 }
124 reader.ReadStringPiece(&value, item.second);
125 message_.SetStringPiece(item.first, value);
126 }
127 visitor_->OnHandshakeMessage(message_);
128}
129
130// static
131QuicData* CryptoFramer::ConstructHandshakeMessage(
132 const CryptoHandshakeMessage& message) {
133 size_t num_entries = message.tag_value_map().size();
134 size_t pad_length = 0;
135 bool need_pad_tag = false;
136 bool need_pad_value = false;
137
138 size_t len = message.size();
139 if (len < message.minimum_size()) {
140 need_pad_tag = true;
141 need_pad_value = true;
142 num_entries++;
143
144 size_t delta = message.minimum_size() - len;
145 const size_t overhead = kQuicTagSize + kCryptoEndOffsetSize;
146 if (delta > overhead) {
147 pad_length = delta - overhead;
148 }
149 len += overhead + pad_length;
150 }
151
152 if (num_entries > kMaxEntries) {
153 return nullptr;
154 }
155
156 std::unique_ptr<char[]> buffer(new char[len]);
157 QuicDataWriter writer(len, buffer.get(), HOST_BYTE_ORDER);
158 if (!writer.WriteTag(message.tag())) {
159 DCHECK(false) << "Failed to write message tag.";
160 return nullptr;
161 }
162 if (!writer.WriteUInt16(static_cast<uint16_t>(num_entries))) {
163 DCHECK(false) << "Failed to write size.";
164 return nullptr;
165 }
166 if (!writer.WriteUInt16(0)) {
167 DCHECK(false) << "Failed to write padding.";
168 return nullptr;
169 }
170
171 uint32_t end_offset = 0;
172 // Tags and offsets
173 for (auto it = message.tag_value_map().begin();
174 it != message.tag_value_map().end(); ++it) {
175 if (it->first == kPAD && need_pad_tag) {
176 // Existing PAD tags are only checked when padding needs to be added
177 // because parts of the code may need to reserialize received messages
178 // and those messages may, legitimately include padding.
179 DCHECK(false) << "Message needed padding but already contained a PAD tag";
180 return nullptr;
181 }
182
183 if (it->first > kPAD && need_pad_tag) {
184 need_pad_tag = false;
185 if (!WritePadTag(&writer, pad_length, &end_offset)) {
186 return nullptr;
187 }
188 }
189
190 if (!writer.WriteTag(it->first)) {
191 DCHECK(false) << "Failed to write tag.";
192 return nullptr;
193 }
194 end_offset += it->second.length();
195 if (!writer.WriteUInt32(end_offset)) {
196 DCHECK(false) << "Failed to write end offset.";
197 return nullptr;
198 }
199 }
200
201 if (need_pad_tag) {
202 if (!WritePadTag(&writer, pad_length, &end_offset)) {
203 return nullptr;
204 }
205 }
206
207 // Values
208 for (auto it = message.tag_value_map().begin();
209 it != message.tag_value_map().end(); ++it) {
210 if (it->first > kPAD && need_pad_value) {
211 need_pad_value = false;
212 if (!writer.WriteRepeatedByte('-', pad_length)) {
213 DCHECK(false) << "Failed to write padding.";
214 return nullptr;
215 }
216 }
217
218 if (!writer.WriteBytes(it->second.data(), it->second.length())) {
219 DCHECK(false) << "Failed to write value.";
220 return nullptr;
221 }
222 }
223
224 if (need_pad_value) {
225 if (!writer.WriteRepeatedByte('-', pad_length)) {
226 DCHECK(false) << "Failed to write padding.";
227 return nullptr;
228 }
229 }
230
231 return new QuicData(buffer.release(), len, true);
232}
233
234void CryptoFramer::Clear() {
235 message_.Clear();
236 tags_and_lengths_.clear();
237 error_ = QUIC_NO_ERROR;
238 error_detail_ = "";
239 state_ = STATE_READING_TAG;
240}
241
242QuicErrorCode CryptoFramer::Process(QuicStringPiece input) {
243 // Add this data to the buffer.
244 buffer_.append(input.data(), input.length());
245 QuicDataReader reader(buffer_.data(), buffer_.length(), HOST_BYTE_ORDER);
246
247 switch (state_) {
248 case STATE_READING_TAG:
249 if (reader.BytesRemaining() < kQuicTagSize) {
250 break;
251 }
252 QuicTag message_tag;
253 reader.ReadTag(&message_tag);
254 message_.set_tag(message_tag);
255 state_ = STATE_READING_NUM_ENTRIES;
256 QUIC_FALLTHROUGH_INTENDED;
257 case STATE_READING_NUM_ENTRIES:
258 if (reader.BytesRemaining() < kNumEntriesSize + sizeof(uint16_t)) {
259 break;
260 }
261 reader.ReadUInt16(&num_entries_);
262 if (num_entries_ > kMaxEntries) {
263 error_detail_ = QuicStrCat(num_entries_, " entries");
264 return QUIC_CRYPTO_TOO_MANY_ENTRIES;
265 }
266 uint16_t padding;
267 reader.ReadUInt16(&padding);
268
269 tags_and_lengths_.reserve(num_entries_);
270 state_ = STATE_READING_TAGS_AND_LENGTHS;
271 values_len_ = 0;
272 QUIC_FALLTHROUGH_INTENDED;
273 case STATE_READING_TAGS_AND_LENGTHS: {
274 if (reader.BytesRemaining() <
275 num_entries_ * (kQuicTagSize + kCryptoEndOffsetSize)) {
276 break;
277 }
278
279 uint32_t last_end_offset = 0;
280 for (unsigned i = 0; i < num_entries_; ++i) {
281 QuicTag tag;
282 reader.ReadTag(&tag);
283 if (i > 0 && tag <= tags_and_lengths_[i - 1].first) {
284 if (tag == tags_and_lengths_[i - 1].first) {
285 error_detail_ = QuicStrCat("Duplicate tag:", tag);
286 return QUIC_CRYPTO_DUPLICATE_TAG;
287 }
288 error_detail_ = QuicStrCat("Tag ", tag, " out of order");
289 return QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
290 }
291
292 uint32_t end_offset;
293 reader.ReadUInt32(&end_offset);
294
295 if (end_offset < last_end_offset) {
296 error_detail_ =
297 QuicStrCat("End offset: ", end_offset, " vs ", last_end_offset);
298 return QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
299 }
300 tags_and_lengths_.push_back(std::make_pair(
301 tag, static_cast<size_t>(end_offset - last_end_offset)));
302 last_end_offset = end_offset;
303 }
304 values_len_ = last_end_offset;
305 state_ = STATE_READING_VALUES;
306 QUIC_FALLTHROUGH_INTENDED;
307 }
308 case STATE_READING_VALUES:
309 if (reader.BytesRemaining() < values_len_) {
310 if (!process_truncated_messages_) {
311 break;
312 }
313 QUIC_LOG(ERROR) << "Trunacted message. Missing "
314 << values_len_ - reader.BytesRemaining() << " bytes.";
315 }
316 for (const std::pair<QuicTag, size_t>& item : tags_and_lengths_) {
317 QuicStringPiece value;
318 if (!reader.ReadStringPiece(&value, item.second)) {
319 DCHECK(process_truncated_messages_);
320 // Store an empty value.
321 message_.SetStringPiece(item.first, "");
322 continue;
323 }
324 message_.SetStringPiece(item.first, value);
325 }
326 visitor_->OnHandshakeMessage(message_);
327 Clear();
328 state_ = STATE_READING_TAG;
329 break;
330 }
331 // Save any remaining data.
vasilvvc48c8712019-03-11 13:38:16 -0700332 buffer_ = std::string(reader.PeekRemainingPayload());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500333 return QUIC_NO_ERROR;
334}
335
336// static
337bool CryptoFramer::WritePadTag(QuicDataWriter* writer,
338 size_t pad_length,
339 uint32_t* end_offset) {
340 if (!writer->WriteTag(kPAD)) {
341 DCHECK(false) << "Failed to write tag.";
342 return false;
343 }
344 *end_offset += pad_length;
345 if (!writer->WriteUInt32(*end_offset)) {
346 DCHECK(false) << "Failed to write end offset.";
347 return false;
348 }
349 return true;
350}
351
352} // namespace quic