crypto_framer.cc revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
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_handshake.h"
8#include "net/quic/quic_data_reader.h"
9#include "net/quic/quic_data_writer.h"
10
11using base::StringPiece;
12using std::make_pair;
13using std::pair;
14using std::vector;
15
16namespace net {
17
18namespace {
19
20const size_t kQuicTagSize = sizeof(uint32);
21const size_t kCryptoEndOffsetSize = sizeof(uint32);
22const size_t kNumEntriesSize = sizeof(uint16);
23const size_t kValueLenSize = sizeof(uint16);
24
25// OneShotVisitor is a framer visitor that records a single handshake message.
26class OneShotVisitor : public CryptoFramerVisitorInterface {
27 public:
28  explicit OneShotVisitor(CryptoHandshakeMessage* out)
29      : out_(out),
30        error_(false) {
31  }
32
33  virtual void OnError(CryptoFramer* framer) OVERRIDE { error_ = true; }
34
35  virtual void OnHandshakeMessage(
36      const CryptoHandshakeMessage& message) OVERRIDE {
37    *out_ = message;
38  }
39
40  bool error() const { return error_; }
41
42 private:
43  CryptoHandshakeMessage* const out_;
44  bool error_;
45};
46
47}  // namespace
48
49CryptoFramer::CryptoFramer()
50    : visitor_(NULL),
51      num_entries_(0),
52      values_len_(0) {
53  Clear();
54}
55
56CryptoFramer::~CryptoFramer() {}
57
58// static
59CryptoHandshakeMessage* CryptoFramer::ParseMessage(StringPiece in) {
60  scoped_ptr<CryptoHandshakeMessage> msg(new CryptoHandshakeMessage);
61  OneShotVisitor visitor(msg.get());
62  CryptoFramer framer;
63
64  framer.set_visitor(&visitor);
65  if (!framer.ProcessInput(in) || visitor.error() ||
66      framer.InputBytesRemaining()) {
67    return NULL;
68  }
69
70  return msg.release();
71}
72
73bool CryptoFramer::ProcessInput(StringPiece input) {
74  DCHECK_EQ(QUIC_NO_ERROR, error_);
75  if (error_ != QUIC_NO_ERROR) {
76    return false;
77  }
78  // Add this data to the buffer.
79  buffer_.append(input.data(), input.length());
80  QuicDataReader reader(buffer_.data(), buffer_.length());
81
82  switch (state_) {
83    case STATE_READING_TAG:
84      if (reader.BytesRemaining() < kQuicTagSize) {
85        break;
86      }
87      QuicTag message_tag;
88      reader.ReadUInt32(&message_tag);
89      message_.set_tag(message_tag);
90      state_ = STATE_READING_NUM_ENTRIES;
91    case STATE_READING_NUM_ENTRIES:
92      if (reader.BytesRemaining() < kNumEntriesSize + sizeof(uint16)) {
93        break;
94      }
95      reader.ReadUInt16(&num_entries_);
96      if (num_entries_ > kMaxEntries) {
97        error_ = QUIC_CRYPTO_TOO_MANY_ENTRIES;
98        return false;
99      }
100      uint16 padding;
101      reader.ReadUInt16(&padding);
102
103      tags_and_lengths_.reserve(num_entries_);
104      state_ = STATE_READING_TAGS_AND_LENGTHS;
105      values_len_ = 0;
106    case STATE_READING_TAGS_AND_LENGTHS: {
107      if (reader.BytesRemaining() <
108              num_entries_ * (kQuicTagSize + kCryptoEndOffsetSize)) {
109        break;
110      }
111
112      uint32 last_end_offset = 0;
113      for (unsigned i = 0; i < num_entries_; ++i) {
114        QuicTag tag;
115        reader.ReadUInt32(&tag);
116        if (i > 0 && tag <= tags_and_lengths_[i-1].first) {
117          if (tag == tags_and_lengths_[i-1].first) {
118            error_ = QUIC_CRYPTO_DUPLICATE_TAG;
119          } else {
120            error_ = QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
121          }
122          return false;
123        }
124
125        uint32 end_offset;
126        reader.ReadUInt32(&end_offset);
127
128        if (end_offset < last_end_offset) {
129          error_ = QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
130          return false;
131        }
132        tags_and_lengths_.push_back(
133            make_pair(tag, static_cast<size_t>(end_offset - last_end_offset)));
134        last_end_offset = end_offset;
135      }
136      values_len_ = last_end_offset;
137      state_ = STATE_READING_VALUES;
138    }
139    case STATE_READING_VALUES:
140      if (reader.BytesRemaining() < values_len_) {
141        break;
142      }
143      for (vector<pair<QuicTag, size_t> >::const_iterator
144           it = tags_and_lengths_.begin(); it != tags_and_lengths_.end();
145           it++) {
146        StringPiece value;
147        reader.ReadStringPiece(&value, it->second);
148        message_.SetStringPiece(it->first, value);
149      }
150      visitor_->OnHandshakeMessage(message_);
151      Clear();
152      state_ = STATE_READING_TAG;
153      break;
154  }
155  // Save any remaining data.
156  buffer_ = reader.PeekRemainingPayload().as_string();
157  return true;
158}
159
160// static
161QuicData* CryptoFramer::ConstructHandshakeMessage(
162    const CryptoHandshakeMessage& message) {
163  if (message.tag_value_map().size() > kMaxEntries) {
164    return NULL;
165  }
166  size_t len = kQuicTagSize;    // message tag
167  len += sizeof(uint16);        // number of map entries
168  len += sizeof(uint16);        // padding.
169  QuicTagValueMap::const_iterator it = message.tag_value_map().begin();
170  while (it != message.tag_value_map().end()) {
171    len += kQuicTagSize;          // tag
172    len += kCryptoEndOffsetSize;  // end offset
173    len += it->second.length();   // value
174    ++it;
175  }
176
177  QuicDataWriter writer(len);
178  if (!writer.WriteUInt32(message.tag())) {
179    DCHECK(false) << "Failed to write message tag.";
180    return NULL;
181  }
182  if (!writer.WriteUInt16(message.tag_value_map().size())) {
183    DCHECK(false) << "Failed to write size.";
184    return NULL;
185  }
186  if (!writer.WriteUInt16(0)) {
187    DCHECK(false) << "Failed to write padding.";
188    return NULL;
189  }
190
191  uint32 end_offset = 0;
192  // Tags and offsets
193  for (it = message.tag_value_map().begin();
194       it != message.tag_value_map().end(); ++it) {
195    if (!writer.WriteUInt32(it->first)) {
196      DCHECK(false) << "Failed to write tag.";
197      return NULL;
198    }
199    end_offset += it->second.length();
200    if (!writer.WriteUInt32(end_offset)) {
201      DCHECK(false) << "Failed to write end offset.";
202      return NULL;
203    }
204  }
205
206  // Values
207  for (it = message.tag_value_map().begin();
208       it != message.tag_value_map().end(); ++it) {
209    if (!writer.WriteBytes(it->second.data(), it->second.length())) {
210      DCHECK(false) << "Failed to write value.";
211      return NULL;
212    }
213  }
214  return new QuicData(writer.take(), len, true);
215}
216
217void CryptoFramer::Clear() {
218  message_.Clear();
219  tags_and_lengths_.clear();
220  error_ = QUIC_NO_ERROR;
221  state_ = STATE_READING_TAG;
222}
223
224}  // namespace net
225