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
;
19 const size_t kQuicTagSize
= sizeof(uint32
);
20 const size_t kCryptoEndOffsetSize
= sizeof(uint32
);
21 const size_t kNumEntriesSize
= sizeof(uint16
);
23 // OneShotVisitor is a framer visitor that records a single handshake message.
24 class OneShotVisitor
: public CryptoFramerVisitorInterface
{
26 OneShotVisitor() : error_(false) {}
28 void OnError(CryptoFramer
* framer
) override
{ error_
= true; }
30 void OnHandshakeMessage(const CryptoHandshakeMessage
& message
) override
{
31 out_
.reset(new CryptoHandshakeMessage(message
));
34 bool error() const { return error_
; }
36 CryptoHandshakeMessage
* release() { return out_
.release(); }
39 scoped_ptr
<CryptoHandshakeMessage
> out_
;
45 CryptoFramer::CryptoFramer()
52 CryptoFramer::~CryptoFramer() {}
55 CryptoHandshakeMessage
* CryptoFramer::ParseMessage(StringPiece in
) {
56 OneShotVisitor visitor
;
59 framer
.set_visitor(&visitor
);
60 if (!framer
.ProcessInput(in
) || visitor
.error() ||
61 framer
.InputBytesRemaining()) {
65 return visitor
.release();
68 bool CryptoFramer::ProcessInput(StringPiece input
) {
69 DCHECK_EQ(QUIC_NO_ERROR
, error_
);
70 if (error_
!= QUIC_NO_ERROR
) {
73 error_
= Process(input
);
74 if (error_
!= QUIC_NO_ERROR
) {
75 visitor_
->OnError(this);
83 QuicData
* CryptoFramer::ConstructHandshakeMessage(
84 const CryptoHandshakeMessage
& message
) {
85 size_t num_entries
= message
.tag_value_map().size();
86 size_t pad_length
= 0;
87 bool need_pad_tag
= false;
88 bool need_pad_value
= false;
90 size_t len
= message
.size();
91 if (len
< message
.minimum_size()) {
93 need_pad_value
= true;
96 size_t delta
= message
.minimum_size() - len
;
97 const size_t overhead
= kQuicTagSize
+ kCryptoEndOffsetSize
;
98 if (delta
> overhead
) {
99 pad_length
= delta
- overhead
;
101 len
+= overhead
+ pad_length
;
104 if (num_entries
> kMaxEntries
) {
108 scoped_ptr
<char[]> buffer(new char[len
]);
109 QuicDataWriter
writer(len
, buffer
.get());
110 if (!writer
.WriteUInt32(message
.tag())) {
111 DCHECK(false) << "Failed to write message tag.";
114 if (!writer
.WriteUInt16(static_cast<uint16
>(num_entries
))) {
115 DCHECK(false) << "Failed to write size.";
118 if (!writer
.WriteUInt16(0)) {
119 DCHECK(false) << "Failed to write padding.";
123 uint32 end_offset
= 0;
125 for (QuicTagValueMap::const_iterator it
= message
.tag_value_map().begin();
126 it
!= message
.tag_value_map().end(); ++it
) {
127 if (it
->first
== kPAD
&& need_pad_tag
) {
128 // Existing PAD tags are only checked when padding needs to be added
129 // because parts of the code may need to reserialize received messages
130 // and those messages may, legitimately include padding.
131 DCHECK(false) << "Message needed padding but already contained a PAD tag";
135 if (it
->first
> kPAD
&& need_pad_tag
) {
136 need_pad_tag
= false;
137 if (!WritePadTag(&writer
, pad_length
, &end_offset
)) {
142 if (!writer
.WriteUInt32(it
->first
)) {
143 DCHECK(false) << "Failed to write tag.";
146 end_offset
+= it
->second
.length();
147 if (!writer
.WriteUInt32(end_offset
)) {
148 DCHECK(false) << "Failed to write end offset.";
154 if (!WritePadTag(&writer
, pad_length
, &end_offset
)) {
160 for (QuicTagValueMap::const_iterator it
= message
.tag_value_map().begin();
161 it
!= message
.tag_value_map().end(); ++it
) {
162 if (it
->first
> kPAD
&& need_pad_value
) {
163 need_pad_value
= false;
164 if (!writer
.WriteRepeatedByte('-', pad_length
)) {
165 DCHECK(false) << "Failed to write padding.";
170 if (!writer
.WriteBytes(it
->second
.data(), it
->second
.length())) {
171 DCHECK(false) << "Failed to write value.";
176 if (need_pad_value
) {
177 if (!writer
.WriteRepeatedByte('-', pad_length
)) {
178 DCHECK(false) << "Failed to write padding.";
183 return new QuicData(buffer
.release(), len
, true);
186 void CryptoFramer::Clear() {
188 tags_and_lengths_
.clear();
189 error_
= QUIC_NO_ERROR
;
190 state_
= STATE_READING_TAG
;
193 QuicErrorCode
CryptoFramer::Process(StringPiece input
) {
194 // Add this data to the buffer.
195 buffer_
.append(input
.data(), input
.length());
196 QuicDataReader
reader(buffer_
.data(), buffer_
.length());
199 case STATE_READING_TAG
:
200 if (reader
.BytesRemaining() < kQuicTagSize
) {
204 reader
.ReadUInt32(&message_tag
);
205 message_
.set_tag(message_tag
);
206 state_
= STATE_READING_NUM_ENTRIES
;
207 case STATE_READING_NUM_ENTRIES
:
208 if (reader
.BytesRemaining() < kNumEntriesSize
+ sizeof(uint16
)) {
211 reader
.ReadUInt16(&num_entries_
);
212 if (num_entries_
> kMaxEntries
) {
213 return QUIC_CRYPTO_TOO_MANY_ENTRIES
;
216 reader
.ReadUInt16(&padding
);
218 tags_and_lengths_
.reserve(num_entries_
);
219 state_
= STATE_READING_TAGS_AND_LENGTHS
;
221 case STATE_READING_TAGS_AND_LENGTHS
: {
222 if (reader
.BytesRemaining() <
223 num_entries_
* (kQuicTagSize
+ kCryptoEndOffsetSize
)) {
227 uint32 last_end_offset
= 0;
228 for (unsigned i
= 0; i
< num_entries_
; ++i
) {
230 reader
.ReadUInt32(&tag
);
231 if (i
> 0 && tag
<= tags_and_lengths_
[i
-1].first
) {
232 if (tag
== tags_and_lengths_
[i
-1].first
) {
233 return QUIC_CRYPTO_DUPLICATE_TAG
;
235 return QUIC_CRYPTO_TAGS_OUT_OF_ORDER
;
239 reader
.ReadUInt32(&end_offset
);
241 if (end_offset
< last_end_offset
) {
242 return QUIC_CRYPTO_TAGS_OUT_OF_ORDER
;
244 tags_and_lengths_
.push_back(std::make_pair(
245 tag
, static_cast<size_t>(end_offset
- last_end_offset
)));
246 last_end_offset
= end_offset
;
248 values_len_
= last_end_offset
;
249 state_
= STATE_READING_VALUES
;
251 case STATE_READING_VALUES
:
252 if (reader
.BytesRemaining() < values_len_
) {
255 for (const pair
<QuicTag
, size_t>& item
: tags_and_lengths_
) {
257 reader
.ReadStringPiece(&value
, item
.second
);
258 message_
.SetStringPiece(item
.first
, value
);
260 visitor_
->OnHandshakeMessage(message_
);
262 state_
= STATE_READING_TAG
;
265 // Save any remaining data.
266 buffer_
= reader
.PeekRemainingPayload().as_string();
267 return QUIC_NO_ERROR
;
271 bool CryptoFramer::WritePadTag(QuicDataWriter
* writer
,
273 uint32
* end_offset
) {
274 if (!writer
->WriteUInt32(kPAD
)) {
275 DCHECK(false) << "Failed to write tag.";
278 *end_offset
+= pad_length
;
279 if (!writer
->WriteUInt32(*end_offset
)) {
280 DCHECK(false) << "Failed to write end offset.";