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.
5 #include "net/quic/crypto/crypto_framer.h"
7 #include "net/quic/crypto/crypto_protocol.h"
8 #include "net/quic/quic_data_reader.h"
9 #include "net/quic/quic_data_writer.h"
11 using base::StringPiece;
20 const size_t kQuicTagSize = sizeof(uint32);
21 const size_t kCryptoEndOffsetSize = sizeof(uint32);
22 const size_t kNumEntriesSize = sizeof(uint16);
24 // OneShotVisitor is a framer visitor that records a single handshake message.
25 class OneShotVisitor : public CryptoFramerVisitorInterface {
27 OneShotVisitor() : error_(false) {}
29 void OnError(CryptoFramer* framer) override { error_ = true; }
31 void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
32 out_.reset(new CryptoHandshakeMessage(message));
35 bool error() const { return error_; }
37 CryptoHandshakeMessage* release() { return out_.release(); }
40 scoped_ptr<CryptoHandshakeMessage> out_;
46 CryptoFramer::CryptoFramer()
53 CryptoFramer::~CryptoFramer() {}
56 CryptoHandshakeMessage* CryptoFramer::ParseMessage(StringPiece in) {
57 OneShotVisitor visitor;
60 framer.set_visitor(&visitor);
61 if (!framer.ProcessInput(in) || visitor.error() ||
62 framer.InputBytesRemaining()) {
66 return visitor.release();
69 bool CryptoFramer::ProcessInput(StringPiece input) {
70 DCHECK_EQ(QUIC_NO_ERROR, error_);
71 if (error_ != QUIC_NO_ERROR) {
74 error_ = Process(input);
75 if (error_ != QUIC_NO_ERROR) {
76 visitor_->OnError(this);
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;
91 size_t len = message.size();
92 if (len < message.minimum_size()) {
94 need_pad_value = true;
97 size_t delta = message.minimum_size() - len;
98 const size_t overhead = kQuicTagSize + kCryptoEndOffsetSize;
99 if (delta > overhead) {
100 pad_length = delta - overhead;
102 len += overhead + pad_length;
105 if (num_entries > kMaxEntries) {
110 QuicDataWriter writer(len);
111 if (!writer.WriteUInt32(message.tag())) {
112 DCHECK(false) << "Failed to write message tag.";
115 if (!writer.WriteUInt16(num_entries)) {
116 DCHECK(false) << "Failed to write size.";
119 if (!writer.WriteUInt16(0)) {
120 DCHECK(false) << "Failed to write padding.";
124 uint32 end_offset = 0;
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";
136 if (it->first > kPAD && need_pad_tag) {
137 need_pad_tag = false;
138 if (!WritePadTag(&writer, pad_length, &end_offset)) {
143 if (!writer.WriteUInt32(it->first)) {
144 DCHECK(false) << "Failed to write tag.";
147 end_offset += it->second.length();
148 if (!writer.WriteUInt32(end_offset)) {
149 DCHECK(false) << "Failed to write end offset.";
155 if (!WritePadTag(&writer, pad_length, &end_offset)) {
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.";
171 if (!writer.WriteBytes(it->second.data(), it->second.length())) {
172 DCHECK(false) << "Failed to write value.";
177 if (need_pad_value) {
178 if (!writer.WriteRepeatedByte('-', pad_length)) {
179 DCHECK(false) << "Failed to write padding.";
184 return new QuicData(writer.take(), len, true);
187 void CryptoFramer::Clear() {
189 tags_and_lengths_.clear();
190 error_ = QUIC_NO_ERROR;
191 state_ = STATE_READING_TAG;
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());
200 case STATE_READING_TAG:
201 if (reader.BytesRemaining() < kQuicTagSize) {
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)) {
212 reader.ReadUInt16(&num_entries_);
213 if (num_entries_ > kMaxEntries) {
214 return QUIC_CRYPTO_TOO_MANY_ENTRIES;
217 reader.ReadUInt16(&padding);
219 tags_and_lengths_.reserve(num_entries_);
220 state_ = STATE_READING_TAGS_AND_LENGTHS;
222 case STATE_READING_TAGS_AND_LENGTHS: {
223 if (reader.BytesRemaining() <
224 num_entries_ * (kQuicTagSize + kCryptoEndOffsetSize)) {
228 uint32 last_end_offset = 0;
229 for (unsigned i = 0; i < num_entries_; ++i) {
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;
236 return QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
240 reader.ReadUInt32(&end_offset);
242 if (end_offset < last_end_offset) {
243 return QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
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;
249 values_len_ = last_end_offset;
250 state_ = STATE_READING_VALUES;
252 case STATE_READING_VALUES:
253 if (reader.BytesRemaining() < values_len_) {
256 for (vector<pair<QuicTag, size_t> >::const_iterator
257 it = tags_and_lengths_.begin(); it != tags_and_lengths_.end();
260 reader.ReadStringPiece(&value, it->second);
261 message_.SetStringPiece(it->first, value);
263 visitor_->OnHandshakeMessage(message_);
265 state_ = STATE_READING_TAG;
268 // Save any remaining data.
269 buffer_ = reader.PeekRemainingPayload().as_string();
270 return QUIC_NO_ERROR;
274 bool CryptoFramer::WritePadTag(QuicDataWriter* writer,
276 uint32* end_offset) {
277 if (!writer->WriteUInt32(kPAD)) {
278 DCHECK(false) << "Failed to write tag.";
281 *end_offset += pad_length;
282 if (!writer->WriteUInt32(*end_offset)) {
283 DCHECK(false) << "Failed to write end offset.";