OLD | NEW |
| (Empty) |
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 "net/quic/crypto/crypto_framer.h" | |
6 | |
7 #include <memory> | |
8 | |
9 #include "base/strings/stringprintf.h" | |
10 #include "net/quic/crypto/crypto_protocol.h" | |
11 #include "net/quic/quic_data_reader.h" | |
12 #include "net/quic/quic_data_writer.h" | |
13 | |
14 using base::StringPiece; | |
15 using std::pair; | |
16 using std::vector; | |
17 | |
18 namespace net { | |
19 | |
20 namespace { | |
21 | |
22 const size_t kQuicTagSize = sizeof(uint32_t); | |
23 const size_t kCryptoEndOffsetSize = sizeof(uint32_t); | |
24 const size_t kNumEntriesSize = sizeof(uint16_t); | |
25 | |
26 // OneShotVisitor is a framer visitor that records a single handshake message. | |
27 class 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_.reset(new CryptoHandshakeMessage(message)); | |
35 } | |
36 | |
37 bool error() const { return error_; } | |
38 | |
39 CryptoHandshakeMessage* release() { return out_.release(); } | |
40 | |
41 private: | |
42 std::unique_ptr<CryptoHandshakeMessage> out_; | |
43 bool error_; | |
44 }; | |
45 | |
46 } // namespace | |
47 | |
48 CryptoFramer::CryptoFramer() | |
49 : visitor_(nullptr), error_detail_(""), num_entries_(0), values_len_(0) { | |
50 Clear(); | |
51 } | |
52 | |
53 CryptoFramer::~CryptoFramer() {} | |
54 | |
55 // static | |
56 CryptoHandshakeMessage* CryptoFramer::ParseMessage(StringPiece in) { | |
57 OneShotVisitor visitor; | |
58 CryptoFramer framer; | |
59 | |
60 framer.set_visitor(&visitor); | |
61 if (!framer.ProcessInput(in) || visitor.error() || | |
62 framer.InputBytesRemaining()) { | |
63 return nullptr; | |
64 } | |
65 | |
66 return visitor.release(); | |
67 } | |
68 | |
69 bool CryptoFramer::ProcessInput(StringPiece input) { | |
70 DCHECK_EQ(QUIC_NO_ERROR, error_); | |
71 if (error_ != QUIC_NO_ERROR) { | |
72 return false; | |
73 } | |
74 error_ = Process(input); | |
75 if (error_ != QUIC_NO_ERROR) { | |
76 DCHECK(!error_detail_.empty()); | |
77 visitor_->OnError(this); | |
78 return false; | |
79 } | |
80 | |
81 return true; | |
82 } | |
83 | |
84 // static | |
85 QuicData* CryptoFramer::ConstructHandshakeMessage( | |
86 const CryptoHandshakeMessage& message) { | |
87 size_t num_entries = message.tag_value_map().size(); | |
88 size_t pad_length = 0; | |
89 bool need_pad_tag = false; | |
90 bool need_pad_value = false; | |
91 | |
92 size_t len = message.size(); | |
93 if (len < message.minimum_size()) { | |
94 need_pad_tag = true; | |
95 need_pad_value = true; | |
96 num_entries++; | |
97 | |
98 size_t delta = message.minimum_size() - len; | |
99 const size_t overhead = kQuicTagSize + kCryptoEndOffsetSize; | |
100 if (delta > overhead) { | |
101 pad_length = delta - overhead; | |
102 } | |
103 len += overhead + pad_length; | |
104 } | |
105 | |
106 if (num_entries > kMaxEntries) { | |
107 return nullptr; | |
108 } | |
109 | |
110 std::unique_ptr<char[]> buffer(new char[len]); | |
111 QuicDataWriter writer(len, buffer.get()); | |
112 if (!writer.WriteUInt32(message.tag())) { | |
113 DCHECK(false) << "Failed to write message tag."; | |
114 return nullptr; | |
115 } | |
116 if (!writer.WriteUInt16(static_cast<uint16_t>(num_entries))) { | |
117 DCHECK(false) << "Failed to write size."; | |
118 return nullptr; | |
119 } | |
120 if (!writer.WriteUInt16(0)) { | |
121 DCHECK(false) << "Failed to write padding."; | |
122 return nullptr; | |
123 } | |
124 | |
125 uint32_t end_offset = 0; | |
126 // Tags and offsets | |
127 for (QuicTagValueMap::const_iterator it = message.tag_value_map().begin(); | |
128 it != message.tag_value_map().end(); ++it) { | |
129 if (it->first == kPAD && need_pad_tag) { | |
130 // Existing PAD tags are only checked when padding needs to be added | |
131 // because parts of the code may need to reserialize received messages | |
132 // and those messages may, legitimately include padding. | |
133 DCHECK(false) << "Message needed padding but already contained a PAD tag"; | |
134 return nullptr; | |
135 } | |
136 | |
137 if (it->first > kPAD && need_pad_tag) { | |
138 need_pad_tag = false; | |
139 if (!WritePadTag(&writer, pad_length, &end_offset)) { | |
140 return nullptr; | |
141 } | |
142 } | |
143 | |
144 if (!writer.WriteUInt32(it->first)) { | |
145 DCHECK(false) << "Failed to write tag."; | |
146 return nullptr; | |
147 } | |
148 end_offset += it->second.length(); | |
149 if (!writer.WriteUInt32(end_offset)) { | |
150 DCHECK(false) << "Failed to write end offset."; | |
151 return nullptr; | |
152 } | |
153 } | |
154 | |
155 if (need_pad_tag) { | |
156 if (!WritePadTag(&writer, pad_length, &end_offset)) { | |
157 return nullptr; | |
158 } | |
159 } | |
160 | |
161 // Values | |
162 for (QuicTagValueMap::const_iterator it = message.tag_value_map().begin(); | |
163 it != message.tag_value_map().end(); ++it) { | |
164 if (it->first > kPAD && need_pad_value) { | |
165 need_pad_value = false; | |
166 if (!writer.WriteRepeatedByte('-', pad_length)) { | |
167 DCHECK(false) << "Failed to write padding."; | |
168 return nullptr; | |
169 } | |
170 } | |
171 | |
172 if (!writer.WriteBytes(it->second.data(), it->second.length())) { | |
173 DCHECK(false) << "Failed to write value."; | |
174 return nullptr; | |
175 } | |
176 } | |
177 | |
178 if (need_pad_value) { | |
179 if (!writer.WriteRepeatedByte('-', pad_length)) { | |
180 DCHECK(false) << "Failed to write padding."; | |
181 return nullptr; | |
182 } | |
183 } | |
184 | |
185 return new QuicData(buffer.release(), len, true); | |
186 } | |
187 | |
188 void CryptoFramer::Clear() { | |
189 message_.Clear(); | |
190 tags_and_lengths_.clear(); | |
191 error_ = QUIC_NO_ERROR; | |
192 error_detail_ = ""; | |
193 state_ = STATE_READING_TAG; | |
194 } | |
195 | |
196 QuicErrorCode CryptoFramer::Process(StringPiece input) { | |
197 // Add this data to the buffer. | |
198 buffer_.append(input.data(), input.length()); | |
199 QuicDataReader reader(buffer_.data(), buffer_.length()); | |
200 | |
201 switch (state_) { | |
202 case STATE_READING_TAG: | |
203 if (reader.BytesRemaining() < kQuicTagSize) { | |
204 break; | |
205 } | |
206 QuicTag message_tag; | |
207 reader.ReadUInt32(&message_tag); | |
208 message_.set_tag(message_tag); | |
209 state_ = STATE_READING_NUM_ENTRIES; | |
210 case STATE_READING_NUM_ENTRIES: | |
211 if (reader.BytesRemaining() < kNumEntriesSize + sizeof(uint16_t)) { | |
212 break; | |
213 } | |
214 reader.ReadUInt16(&num_entries_); | |
215 if (num_entries_ > kMaxEntries) { | |
216 error_detail_ = base::StringPrintf("%u entries", num_entries_); | |
217 return QUIC_CRYPTO_TOO_MANY_ENTRIES; | |
218 } | |
219 uint16_t padding; | |
220 reader.ReadUInt16(&padding); | |
221 | |
222 tags_and_lengths_.reserve(num_entries_); | |
223 state_ = STATE_READING_TAGS_AND_LENGTHS; | |
224 values_len_ = 0; | |
225 case STATE_READING_TAGS_AND_LENGTHS: { | |
226 if (reader.BytesRemaining() < | |
227 num_entries_ * (kQuicTagSize + kCryptoEndOffsetSize)) { | |
228 break; | |
229 } | |
230 | |
231 uint32_t last_end_offset = 0; | |
232 for (unsigned i = 0; i < num_entries_; ++i) { | |
233 QuicTag tag; | |
234 reader.ReadUInt32(&tag); | |
235 if (i > 0 && tag <= tags_and_lengths_[i - 1].first) { | |
236 if (tag == tags_and_lengths_[i - 1].first) { | |
237 error_detail_ = base::StringPrintf("Duplicate tag:%u", tag); | |
238 return QUIC_CRYPTO_DUPLICATE_TAG; | |
239 } | |
240 error_detail_ = base::StringPrintf("Tag %u out of order", tag); | |
241 return QUIC_CRYPTO_TAGS_OUT_OF_ORDER; | |
242 } | |
243 | |
244 uint32_t end_offset; | |
245 reader.ReadUInt32(&end_offset); | |
246 | |
247 if (end_offset < last_end_offset) { | |
248 error_detail_ = base::StringPrintf("End offset: %u vs %u", end_offset, | |
249 last_end_offset); | |
250 return QUIC_CRYPTO_TAGS_OUT_OF_ORDER; | |
251 } | |
252 tags_and_lengths_.push_back(std::make_pair( | |
253 tag, static_cast<size_t>(end_offset - last_end_offset))); | |
254 last_end_offset = end_offset; | |
255 } | |
256 values_len_ = last_end_offset; | |
257 state_ = STATE_READING_VALUES; | |
258 } | |
259 case STATE_READING_VALUES: | |
260 if (reader.BytesRemaining() < values_len_) { | |
261 break; | |
262 } | |
263 for (const pair<QuicTag, size_t>& item : tags_and_lengths_) { | |
264 StringPiece value; | |
265 reader.ReadStringPiece(&value, item.second); | |
266 message_.SetStringPiece(item.first, value); | |
267 } | |
268 visitor_->OnHandshakeMessage(message_); | |
269 Clear(); | |
270 state_ = STATE_READING_TAG; | |
271 break; | |
272 } | |
273 // Save any remaining data. | |
274 buffer_ = reader.PeekRemainingPayload().as_string(); | |
275 return QUIC_NO_ERROR; | |
276 } | |
277 | |
278 // static | |
279 bool CryptoFramer::WritePadTag(QuicDataWriter* writer, | |
280 size_t pad_length, | |
281 uint32_t* end_offset) { | |
282 if (!writer->WriteUInt32(kPAD)) { | |
283 DCHECK(false) << "Failed to write tag."; | |
284 return false; | |
285 } | |
286 *end_offset += pad_length; | |
287 if (!writer->WriteUInt32(*end_offset)) { | |
288 DCHECK(false) << "Failed to write end offset."; | |
289 return false; | |
290 } | |
291 return true; | |
292 } | |
293 | |
294 } // namespace net | |
OLD | NEW |