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