Upstream version 5.34.104.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   virtual void OnError(CryptoFramer* framer) OVERRIDE { error_ = true; }
30
31   virtual void OnHandshakeMessage(
32       const CryptoHandshakeMessage& message) OVERRIDE {
33     out_.reset(new CryptoHandshakeMessage(message));
34   }
35
36   bool error() const { return error_; }
37
38   CryptoHandshakeMessage* release() { return out_.release(); }
39
40  private:
41   scoped_ptr<CryptoHandshakeMessage> out_;
42   bool error_;
43 };
44
45 }  // namespace
46
47 CryptoFramer::CryptoFramer()
48     : visitor_(NULL),
49       num_entries_(0),
50       values_len_(0) {
51   Clear();
52 }
53
54 CryptoFramer::~CryptoFramer() {}
55
56 // static
57 CryptoHandshakeMessage* CryptoFramer::ParseMessage(StringPiece in) {
58   OneShotVisitor visitor;
59   CryptoFramer framer;
60
61   framer.set_visitor(&visitor);
62   if (!framer.ProcessInput(in) || visitor.error() ||
63       framer.InputBytesRemaining()) {
64     return NULL;
65   }
66
67   return visitor.release();
68 }
69
70 bool CryptoFramer::ProcessInput(StringPiece input) {
71   DCHECK_EQ(QUIC_NO_ERROR, error_);
72   if (error_ != QUIC_NO_ERROR) {
73     return false;
74   }
75   error_ = Process(input);
76   if (error_ != QUIC_NO_ERROR) {
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 NULL;
108   }
109
110
111   QuicDataWriter writer(len);
112   if (!writer.WriteUInt32(message.tag())) {
113     DCHECK(false) << "Failed to write message tag.";
114     return NULL;
115   }
116   if (!writer.WriteUInt16(num_entries)) {
117     DCHECK(false) << "Failed to write size.";
118     return NULL;
119   }
120   if (!writer.WriteUInt16(0)) {
121     DCHECK(false) << "Failed to write padding.";
122     return NULL;
123   }
124
125   uint32 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 NULL;
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 NULL;
141       }
142     }
143
144     if (!writer.WriteUInt32(it->first)) {
145       DCHECK(false) << "Failed to write tag.";
146       return NULL;
147     }
148     end_offset += it->second.length();
149     if (!writer.WriteUInt32(end_offset)) {
150       DCHECK(false) << "Failed to write end offset.";
151       return NULL;
152     }
153   }
154
155   if (need_pad_tag) {
156     if (!WritePadTag(&writer, pad_length, &end_offset)) {
157       return NULL;
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 NULL;
169       }
170     }
171
172     if (!writer.WriteBytes(it->second.data(), it->second.length())) {
173       DCHECK(false) << "Failed to write value.";
174       return NULL;
175     }
176   }
177
178   if (need_pad_value) {
179     if (!writer.WriteRepeatedByte('-', pad_length)) {
180       DCHECK(false) << "Failed to write padding.";
181       return NULL;
182     }
183   }
184
185   return new QuicData(writer.take(), len, true);
186 }
187
188 void CryptoFramer::Clear() {
189   message_.Clear();
190   tags_and_lengths_.clear();
191   error_ = QUIC_NO_ERROR;
192   state_ = STATE_READING_TAG;
193 }
194
195 QuicErrorCode CryptoFramer::Process(StringPiece input) {
196   // Add this data to the buffer.
197   buffer_.append(input.data(), input.length());
198   QuicDataReader reader(buffer_.data(), buffer_.length());
199
200   switch (state_) {
201     case STATE_READING_TAG:
202       if (reader.BytesRemaining() < kQuicTagSize) {
203         break;
204       }
205       QuicTag message_tag;
206       reader.ReadUInt32(&message_tag);
207       message_.set_tag(message_tag);
208       state_ = STATE_READING_NUM_ENTRIES;
209     case STATE_READING_NUM_ENTRIES:
210       if (reader.BytesRemaining() < kNumEntriesSize + sizeof(uint16)) {
211         break;
212       }
213       reader.ReadUInt16(&num_entries_);
214       if (num_entries_ > kMaxEntries) {
215         return QUIC_CRYPTO_TOO_MANY_ENTRIES;
216       }
217       uint16 padding;
218       reader.ReadUInt16(&padding);
219
220       tags_and_lengths_.reserve(num_entries_);
221       state_ = STATE_READING_TAGS_AND_LENGTHS;
222       values_len_ = 0;
223     case STATE_READING_TAGS_AND_LENGTHS: {
224       if (reader.BytesRemaining() <
225               num_entries_ * (kQuicTagSize + kCryptoEndOffsetSize)) {
226         break;
227       }
228
229       uint32 last_end_offset = 0;
230       for (unsigned i = 0; i < num_entries_; ++i) {
231         QuicTag tag;
232         reader.ReadUInt32(&tag);
233         if (i > 0 && tag <= tags_and_lengths_[i-1].first) {
234           if (tag == tags_and_lengths_[i-1].first) {
235             return QUIC_CRYPTO_DUPLICATE_TAG;
236           }
237           return QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
238         }
239
240         uint32 end_offset;
241         reader.ReadUInt32(&end_offset);
242
243         if (end_offset < last_end_offset) {
244           return QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
245         }
246         tags_and_lengths_.push_back(
247             make_pair(tag, static_cast<size_t>(end_offset - last_end_offset)));
248         last_end_offset = end_offset;
249       }
250       values_len_ = last_end_offset;
251       state_ = STATE_READING_VALUES;
252     }
253     case STATE_READING_VALUES:
254       if (reader.BytesRemaining() < values_len_) {
255         break;
256       }
257       for (vector<pair<QuicTag, size_t> >::const_iterator
258            it = tags_and_lengths_.begin(); it != tags_and_lengths_.end();
259            it++) {
260         StringPiece value;
261         reader.ReadStringPiece(&value, it->second);
262         message_.SetStringPiece(it->first, value);
263       }
264       visitor_->OnHandshakeMessage(message_);
265       Clear();
266       state_ = STATE_READING_TAG;
267       break;
268   }
269   // Save any remaining data.
270   buffer_ = reader.PeekRemainingPayload().as_string();
271   return QUIC_NO_ERROR;
272 }
273
274 // static
275 bool CryptoFramer::WritePadTag(QuicDataWriter* writer,
276                                size_t pad_length,
277                                uint32* end_offset) {
278   if (!writer->WriteUInt32(kPAD)) {
279     DCHECK(false) << "Failed to write tag.";
280     return false;
281   }
282   *end_offset += pad_length;
283   if (!writer->WriteUInt32(*end_offset)) {
284     DCHECK(false) << "Failed to write end offset.";
285     return false;
286   }
287   return true;
288 }
289
290 }  // namespace net