blob: 31c26cfdccf38932042c71f4468789d5e6b9c0ed [file] [log] [blame]
David Ghandehari9e5b5872016-07-28 09:50:04 -07001// 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/quic_data_reader.h"
8#include "net/quic/quic_data_writer.h"
9#include "net/quic/quic_protocol.h"
10
11using base::StringPiece;
12
13namespace net {
14
15namespace {
16
17const size_t kCryptoTagSize = sizeof(uint32);
18const size_t kNumEntriesSize = sizeof(uint16);
19const size_t kValueLenSize = sizeof(uint16);
20
21} // namespace
22
23CryptoFramer::CryptoFramer()
24 : visitor_(NULL),
25 message_tag_(0),
26 num_entries_(0),
27 values_len_(0) {
28 Clear();
29}
30
31CryptoFramer::~CryptoFramer() {}
32
33bool CryptoFramer::ProcessInput(StringPiece input) {
34 DCHECK_EQ(QUIC_NO_ERROR, error_);
35 if (error_ != QUIC_NO_ERROR) {
36 return false;
37 }
38 // Add this data to the buffer.
39 buffer_.append(input.data(), input.length());
40 QuicDataReader reader(buffer_.data(), buffer_.length());
41
42 switch (state_) {
43 case STATE_READING_TAG:
44 if (reader.BytesRemaining() < kCryptoTagSize) {
45 break;
46 }
47 reader.ReadUInt32(&message_tag_);
48 state_ = STATE_READING_NUM_ENTRIES;
49 case STATE_READING_NUM_ENTRIES:
50 if (reader.BytesRemaining() < kNumEntriesSize) {
51 break;
52 }
53 reader.ReadUInt16(&num_entries_);
54 if (num_entries_ > kMaxEntries) {
55 error_ = QUIC_CRYPTO_TOO_MANY_ENTRIES;
56 return false;
57 }
58 state_ = STATE_READING_KEY_TAGS;
59 case STATE_READING_KEY_TAGS:
60 if (reader.BytesRemaining() < num_entries_ * kCryptoTagSize) {
61 break;
62 }
63 for (int i = 0; i < num_entries_; ++i) {
64 CryptoTag tag;
65 reader.ReadUInt32(&tag);
66 if (i > 0 && tag <= tags_.back()) {
67 error_ = QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
68 return false;
69 }
70 tags_.push_back(tag);
71 }
72 state_ = STATE_READING_LENGTHS;
73 case STATE_READING_LENGTHS:
74 if (reader.BytesRemaining() < num_entries_ * kValueLenSize) {
75 break;
76 }
77 values_len_ = 0;
78 for (int i = 0; i < num_entries_; ++i) {
79 uint16 len;
80 reader.ReadUInt16(&len);
81 tag_length_map_[tags_[i]] = len;
82 values_len_ += len;
83 if (len == 0 && i != num_entries_ - 1) {
84 error_ = QUIC_CRYPTO_INVALID_VALUE_LENGTH;
85 return false;
86 }
87 }
88 state_ = STATE_READING_VALUES;
89 case STATE_READING_VALUES:
90 if (reader.BytesRemaining() < values_len_) {
91 break;
92 }
93 for (int i = 0; i < num_entries_; ++i) {
94 StringPiece value;
95 reader.ReadStringPiece(&value, tag_length_map_[tags_[i]]);
96 tag_value_map_[tags_[i]] = value;
97 }
98 CryptoHandshakeMessage message;
99 message.tag = message_tag_;
100 message.tag_value_map.swap(tag_value_map_);
101 visitor_->OnHandshakeMessage(message);
102 Clear();
103 state_ = STATE_READING_TAG;
104 break;
105 }
106 // Save any remaining data.
107 buffer_ = reader.PeekRemainingPayload().as_string();
108 return true;
109}
110
111QuicData* CryptoFramer::ConstructHandshakeMessage(
112 const CryptoHandshakeMessage& message) {
113 if (message.tag_value_map.size() > kMaxEntries) {
114 return NULL;
115 }
116 size_t len = sizeof(uint32); // message tag
117 len += sizeof(uint16); // number of map entries
118 CryptoTagValueMap::const_iterator it = message.tag_value_map.begin();
119 while (it != message.tag_value_map.end()) {
120 len += sizeof(uint32); // tag
121 len += sizeof(uint16); // value len
122 len += it->second.length(); // value
123 if (it->second.length() == 0) {
124 return NULL;
125 }
126 ++it;
127 }
128 if (message.tag_value_map.size() % 2 == 1) {
129 len += sizeof(uint16); // padding
130 }
131
132 QuicDataWriter writer(len);
133 if (!writer.WriteUInt32(message.tag)) {
134 DCHECK(false) << "Failed to write message tag.";
135 return NULL;
136 }
137 if (!writer.WriteUInt16(message.tag_value_map.size())) {
138 DCHECK(false) << "Failed to write size.";
139 return NULL;
140 }
141 // Tags
142 for (it = message.tag_value_map.begin();
143 it != message.tag_value_map.end(); ++it) {
144 if (!writer.WriteUInt32(it->first)) {
145 DCHECK(false) << "Failed to write tag.";
146 return NULL;
147 }
148 }
149 // Lengths
150 for (it = message.tag_value_map.begin();
151 it != message.tag_value_map.end(); ++it) {
152 if (!writer.WriteUInt16(it->second.length())) {
153 DCHECK(false) << "Failed to write length.";
154 return NULL;
155 }
156 }
157 // Possible padding
158 if (message.tag_value_map.size() % 2 == 1) {
159 if (!writer.WriteUInt16(0xABAB)) {
160 DCHECK(false) << "Failed to write padding.";
161 return NULL;
162 }
163 }
164 // Values
165 for (it = message.tag_value_map.begin();
166 it != message.tag_value_map.end(); ++it) {
167 if (!writer.WriteBytes(it->second.data(), it->second.length())) {
168 DCHECK(false) << "Failed to write value.";
169 return NULL;
170 }
171 }
172 return new QuicData(writer.take(), len, true);
173}
174
175void CryptoFramer::Clear() {
176 tag_value_map_.clear();
177 tag_length_map_.clear();
178 tags_.clear();
179 error_ = QUIC_NO_ERROR;
180 state_ = STATE_READING_TAG;
181}
182
183} // namespace net