1 // 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 "quiche/quic/core/crypto/crypto_framer.h"
6
7 #include <string>
8 #include <utility>
9
10 #include "absl/base/attributes.h"
11 #include "absl/strings/str_cat.h"
12 #include "absl/strings/string_view.h"
13 #include "quiche/quic/core/crypto/crypto_protocol.h"
14 #include "quiche/quic/core/quic_data_reader.h"
15 #include "quiche/quic/core/quic_data_writer.h"
16 #include "quiche/quic/core/quic_packets.h"
17 #include "quiche/quic/platform/api/quic_logging.h"
18 #include "quiche/common/quiche_endian.h"
19
20 namespace quic {
21
22 namespace {
23
24 const size_t kQuicTagSize = sizeof(QuicTag);
25 const size_t kCryptoEndOffsetSize = sizeof(uint32_t);
26 const size_t kNumEntriesSize = sizeof(uint16_t);
27
28 // OneShotVisitor is a framer visitor that records a single handshake message.
29 class OneShotVisitor : public CryptoFramerVisitorInterface {
30 public:
OneShotVisitor()31 OneShotVisitor() : error_(false) {}
32
OnError(CryptoFramer *)33 void OnError(CryptoFramer* /*framer*/) override { error_ = true; }
34
OnHandshakeMessage(const CryptoHandshakeMessage & message)35 void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
36 out_ = std::make_unique<CryptoHandshakeMessage>(message);
37 }
38
error() const39 bool error() const { return error_; }
40
release()41 std::unique_ptr<CryptoHandshakeMessage> release() { return std::move(out_); }
42
43 private:
44 std::unique_ptr<CryptoHandshakeMessage> out_;
45 bool error_;
46 };
47
48 } // namespace
49
CryptoFramer()50 CryptoFramer::CryptoFramer()
51 : visitor_(nullptr),
52 error_detail_(""),
53 num_entries_(0),
54 values_len_(0),
55 process_truncated_messages_(false) {
56 Clear();
57 }
58
~CryptoFramer()59 CryptoFramer::~CryptoFramer() {}
60
61 // static
ParseMessage(absl::string_view in)62 std::unique_ptr<CryptoHandshakeMessage> CryptoFramer::ParseMessage(
63 absl::string_view in) {
64 OneShotVisitor visitor;
65 CryptoFramer framer;
66
67 framer.set_visitor(&visitor);
68 if (!framer.ProcessInput(in) || visitor.error() ||
69 framer.InputBytesRemaining()) {
70 return nullptr;
71 }
72
73 return visitor.release();
74 }
75
error() const76 QuicErrorCode CryptoFramer::error() const { return error_; }
77
error_detail() const78 const std::string& CryptoFramer::error_detail() const { return error_detail_; }
79
ProcessInput(absl::string_view input,EncryptionLevel)80 bool CryptoFramer::ProcessInput(absl::string_view input,
81 EncryptionLevel /*level*/) {
82 return ProcessInput(input);
83 }
84
ProcessInput(absl::string_view input)85 bool CryptoFramer::ProcessInput(absl::string_view input) {
86 QUICHE_DCHECK_EQ(QUIC_NO_ERROR, error_);
87 if (error_ != QUIC_NO_ERROR) {
88 return false;
89 }
90 error_ = Process(input);
91 if (error_ != QUIC_NO_ERROR) {
92 QUICHE_DCHECK(!error_detail_.empty());
93 visitor_->OnError(this);
94 return false;
95 }
96
97 return true;
98 }
99
InputBytesRemaining() const100 size_t CryptoFramer::InputBytesRemaining() const { return buffer_.length(); }
101
HasTag(QuicTag tag) const102 bool CryptoFramer::HasTag(QuicTag tag) const {
103 if (state_ != STATE_READING_VALUES) {
104 return false;
105 }
106 for (const auto& it : tags_and_lengths_) {
107 if (it.first == tag) {
108 return true;
109 }
110 }
111 return false;
112 }
113
ForceHandshake()114 void CryptoFramer::ForceHandshake() {
115 QuicDataReader reader(buffer_.data(), buffer_.length(),
116 quiche::HOST_BYTE_ORDER);
117 for (const std::pair<QuicTag, size_t>& item : tags_and_lengths_) {
118 absl::string_view value;
119 if (reader.BytesRemaining() < item.second) {
120 break;
121 }
122 reader.ReadStringPiece(&value, item.second);
123 message_.SetStringPiece(item.first, value);
124 }
125 visitor_->OnHandshakeMessage(message_);
126 }
127
128 // static
ConstructHandshakeMessage(const CryptoHandshakeMessage & message)129 std::unique_ptr<QuicData> CryptoFramer::ConstructHandshakeMessage(
130 const CryptoHandshakeMessage& message) {
131 size_t num_entries = message.tag_value_map().size();
132 size_t pad_length = 0;
133 bool need_pad_tag = false;
134 bool need_pad_value = false;
135
136 size_t len = message.size();
137 if (len < message.minimum_size()) {
138 need_pad_tag = true;
139 need_pad_value = true;
140 num_entries++;
141
142 size_t delta = message.minimum_size() - len;
143 const size_t overhead = kQuicTagSize + kCryptoEndOffsetSize;
144 if (delta > overhead) {
145 pad_length = delta - overhead;
146 }
147 len += overhead + pad_length;
148 }
149
150 if (num_entries > kMaxEntries) {
151 return nullptr;
152 }
153
154 std::unique_ptr<char[]> buffer(new char[len]);
155 QuicDataWriter writer(len, buffer.get(), quiche::HOST_BYTE_ORDER);
156 if (!writer.WriteTag(message.tag())) {
157 QUICHE_DCHECK(false) << "Failed to write message tag.";
158 return nullptr;
159 }
160 if (!writer.WriteUInt16(static_cast<uint16_t>(num_entries))) {
161 QUICHE_DCHECK(false) << "Failed to write size.";
162 return nullptr;
163 }
164 if (!writer.WriteUInt16(0)) {
165 QUICHE_DCHECK(false) << "Failed to write padding.";
166 return nullptr;
167 }
168
169 uint32_t end_offset = 0;
170 // Tags and offsets
171 for (auto it = message.tag_value_map().begin();
172 it != message.tag_value_map().end(); ++it) {
173 if (it->first == kPAD && need_pad_tag) {
174 // Existing PAD tags are only checked when padding needs to be added
175 // because parts of the code may need to reserialize received messages
176 // and those messages may, legitimately include padding.
177 QUICHE_DCHECK(false)
178 << "Message needed padding but already contained a PAD tag";
179 return nullptr;
180 }
181
182 if (it->first > kPAD && need_pad_tag) {
183 need_pad_tag = false;
184 if (!WritePadTag(&writer, pad_length, &end_offset)) {
185 return nullptr;
186 }
187 }
188
189 if (!writer.WriteTag(it->first)) {
190 QUICHE_DCHECK(false) << "Failed to write tag.";
191 return nullptr;
192 }
193 end_offset += it->second.length();
194 if (!writer.WriteUInt32(end_offset)) {
195 QUICHE_DCHECK(false) << "Failed to write end offset.";
196 return nullptr;
197 }
198 }
199
200 if (need_pad_tag) {
201 if (!WritePadTag(&writer, pad_length, &end_offset)) {
202 return nullptr;
203 }
204 }
205
206 // Values
207 for (auto it = message.tag_value_map().begin();
208 it != message.tag_value_map().end(); ++it) {
209 if (it->first > kPAD && need_pad_value) {
210 need_pad_value = false;
211 if (!writer.WriteRepeatedByte('-', pad_length)) {
212 QUICHE_DCHECK(false) << "Failed to write padding.";
213 return nullptr;
214 }
215 }
216
217 if (!writer.WriteBytes(it->second.data(), it->second.length())) {
218 QUICHE_DCHECK(false) << "Failed to write value.";
219 return nullptr;
220 }
221 }
222
223 if (need_pad_value) {
224 if (!writer.WriteRepeatedByte('-', pad_length)) {
225 QUICHE_DCHECK(false) << "Failed to write padding.";
226 return nullptr;
227 }
228 }
229
230 return std::make_unique<QuicData>(buffer.release(), len, true);
231 }
232
Clear()233 void CryptoFramer::Clear() {
234 message_.Clear();
235 tags_and_lengths_.clear();
236 error_ = QUIC_NO_ERROR;
237 error_detail_ = "";
238 state_ = STATE_READING_TAG;
239 }
240
Process(absl::string_view input)241 QuicErrorCode CryptoFramer::Process(absl::string_view input) {
242 // Add this data to the buffer.
243 buffer_.append(input.data(), input.length());
244 QuicDataReader reader(buffer_.data(), buffer_.length(),
245 quiche::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 ABSL_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_ = absl::StrCat(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 ABSL_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_ = absl::StrCat("Duplicate tag:", tag);
286 return QUIC_CRYPTO_DUPLICATE_TAG;
287 }
288 error_detail_ = absl::StrCat("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 absl::StrCat("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 ABSL_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 absl::string_view value;
318 if (!reader.ReadStringPiece(&value, item.second)) {
319 QUICHE_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.
332 buffer_ = std::string(reader.PeekRemainingPayload());
333 return QUIC_NO_ERROR;
334 }
335
336 // static
WritePadTag(QuicDataWriter * writer,size_t pad_length,uint32_t * end_offset)337 bool CryptoFramer::WritePadTag(QuicDataWriter* writer, size_t pad_length,
338 uint32_t* end_offset) {
339 if (!writer->WriteTag(kPAD)) {
340 QUICHE_DCHECK(false) << "Failed to write tag.";
341 return false;
342 }
343 *end_offset += pad_length;
344 if (!writer->WriteUInt32(*end_offset)) {
345 QUICHE_DCHECK(false) << "Failed to write end offset.";
346 return false;
347 }
348 return true;
349 }
350
351 } // namespace quic
352