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 virtual void OnError(CryptoFramer
* framer
) OVERRIDE
{ error_
= true; }
31 virtual void OnHandshakeMessage(
32 const CryptoHandshakeMessage
& message
) OVERRIDE
{
33 out_
.reset(new CryptoHandshakeMessage(message
));
36 bool error() const { return error_
; }
38 CryptoHandshakeMessage
* release() { return out_
.release(); }
41 scoped_ptr
<CryptoHandshakeMessage
> out_
;
47 CryptoFramer::CryptoFramer()
54 CryptoFramer::~CryptoFramer() {}
57 CryptoHandshakeMessage
* CryptoFramer::ParseMessage(StringPiece in
) {
58 OneShotVisitor visitor
;
61 framer
.set_visitor(&visitor
);
62 if (!framer
.ProcessInput(in
) || visitor
.error() ||
63 framer
.InputBytesRemaining()) {
67 return visitor
.release();
70 bool CryptoFramer::ProcessInput(StringPiece input
) {
71 DCHECK_EQ(QUIC_NO_ERROR
, error_
);
72 if (error_
!= QUIC_NO_ERROR
) {
75 error_
= Process(input
);
76 if (error_
!= QUIC_NO_ERROR
) {
77 visitor_
->OnError(this);
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;
92 size_t len
= message
.size();
93 if (len
< message
.minimum_size()) {
95 need_pad_value
= true;
98 size_t delta
= message
.minimum_size() - len
;
99 const size_t overhead
= kQuicTagSize
+ kCryptoEndOffsetSize
;
100 if (delta
> overhead
) {
101 pad_length
= delta
- overhead
;
103 len
+= overhead
+ pad_length
;
106 if (num_entries
> kMaxEntries
) {
111 QuicDataWriter
writer(len
);
112 if (!writer
.WriteUInt32(message
.tag())) {
113 DCHECK(false) << "Failed to write message tag.";
116 if (!writer
.WriteUInt16(num_entries
)) {
117 DCHECK(false) << "Failed to write size.";
120 if (!writer
.WriteUInt16(0)) {
121 DCHECK(false) << "Failed to write padding.";
125 uint32 end_offset
= 0;
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";
137 if (it
->first
> kPAD
&& need_pad_tag
) {
138 need_pad_tag
= false;
139 if (!WritePadTag(&writer
, pad_length
, &end_offset
)) {
144 if (!writer
.WriteUInt32(it
->first
)) {
145 DCHECK(false) << "Failed to write tag.";
148 end_offset
+= it
->second
.length();
149 if (!writer
.WriteUInt32(end_offset
)) {
150 DCHECK(false) << "Failed to write end offset.";
156 if (!WritePadTag(&writer
, pad_length
, &end_offset
)) {
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.";
172 if (!writer
.WriteBytes(it
->second
.data(), it
->second
.length())) {
173 DCHECK(false) << "Failed to write value.";
178 if (need_pad_value
) {
179 if (!writer
.WriteRepeatedByte('-', pad_length
)) {
180 DCHECK(false) << "Failed to write padding.";
185 return new QuicData(writer
.take(), len
, true);
188 void CryptoFramer::Clear() {
190 tags_and_lengths_
.clear();
191 error_
= QUIC_NO_ERROR
;
192 state_
= STATE_READING_TAG
;
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());
201 case STATE_READING_TAG
:
202 if (reader
.BytesRemaining() < kQuicTagSize
) {
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
)) {
213 reader
.ReadUInt16(&num_entries_
);
214 if (num_entries_
> kMaxEntries
) {
215 return QUIC_CRYPTO_TOO_MANY_ENTRIES
;
218 reader
.ReadUInt16(&padding
);
220 tags_and_lengths_
.reserve(num_entries_
);
221 state_
= STATE_READING_TAGS_AND_LENGTHS
;
223 case STATE_READING_TAGS_AND_LENGTHS
: {
224 if (reader
.BytesRemaining() <
225 num_entries_
* (kQuicTagSize
+ kCryptoEndOffsetSize
)) {
229 uint32 last_end_offset
= 0;
230 for (unsigned i
= 0; i
< num_entries_
; ++i
) {
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
;
237 return QUIC_CRYPTO_TAGS_OUT_OF_ORDER
;
241 reader
.ReadUInt32(&end_offset
);
243 if (end_offset
< last_end_offset
) {
244 return QUIC_CRYPTO_TAGS_OUT_OF_ORDER
;
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
;
250 values_len_
= last_end_offset
;
251 state_
= STATE_READING_VALUES
;
253 case STATE_READING_VALUES
:
254 if (reader
.BytesRemaining() < values_len_
) {
257 for (vector
<pair
<QuicTag
, size_t> >::const_iterator
258 it
= tags_and_lengths_
.begin(); it
!= tags_and_lengths_
.end();
261 reader
.ReadStringPiece(&value
, it
->second
);
262 message_
.SetStringPiece(it
->first
, value
);
264 visitor_
->OnHandshakeMessage(message_
);
266 state_
= STATE_READING_TAG
;
269 // Save any remaining data.
270 buffer_
= reader
.PeekRemainingPayload().as_string();
271 return QUIC_NO_ERROR
;
275 bool CryptoFramer::WritePadTag(QuicDataWriter
* writer
,
277 uint32
* end_offset
) {
278 if (!writer
->WriteUInt32(kPAD
)) {
279 DCHECK(false) << "Failed to write tag.";
282 *end_offset
+= pad_length
;
283 if (!writer
->WriteUInt32(*end_offset
)) {
284 DCHECK(false) << "Failed to write end offset.";