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); 23 24// OneShotVisitor is a framer visitor that records a single handshake message. 25class OneShotVisitor : public CryptoFramerVisitorInterface { 26 public: 27 explicit OneShotVisitor(CryptoHandshakeMessage* out) 28 : out_(out), 29 error_(false) { 30 } 31 32 virtual void OnError(CryptoFramer* framer) OVERRIDE { error_ = true; } 33 34 virtual void OnHandshakeMessage( 35 const CryptoHandshakeMessage& message) OVERRIDE { 36 *out_ = message; 37 } 38 39 bool error() const { return error_; } 40 41 private: 42 CryptoHandshakeMessage* const out_; 43 bool error_; 44}; 45 46} // namespace 47 48CryptoFramer::CryptoFramer() 49 : visitor_(NULL), 50 num_entries_(0), 51 values_len_(0) { 52 Clear(); 53} 54 55CryptoFramer::~CryptoFramer() {} 56 57// static 58CryptoHandshakeMessage* CryptoFramer::ParseMessage(StringPiece in) { 59 scoped_ptr<CryptoHandshakeMessage> msg(new CryptoHandshakeMessage); 60 OneShotVisitor visitor(msg.get()); 61 CryptoFramer framer; 62 63 framer.set_visitor(&visitor); 64 if (!framer.ProcessInput(in) || visitor.error() || 65 framer.InputBytesRemaining()) { 66 return NULL; 67 } 68 69 return msg.release(); 70} 71 72bool CryptoFramer::ProcessInput(StringPiece input) { 73 DCHECK_EQ(QUIC_NO_ERROR, error_); 74 if (error_ != QUIC_NO_ERROR) { 75 return false; 76 } 77 error_ = Process(input); 78 if (error_ != QUIC_NO_ERROR) { 79 visitor_->OnError(this); 80 return false; 81 } 82 83 return true; 84} 85 86// static 87QuicData* CryptoFramer::ConstructHandshakeMessage( 88 const CryptoHandshakeMessage& message) { 89 size_t num_entries = message.tag_value_map().size(); 90 size_t pad_length = 0; 91 bool need_pad_tag = false; 92 bool need_pad_value = false; 93 94 size_t len = message.size(); 95 if (len < message.minimum_size()) { 96 need_pad_tag = true; 97 need_pad_value = true; 98 num_entries++; 99 100 size_t delta = message.minimum_size() - len; 101 const size_t overhead = kQuicTagSize + kCryptoEndOffsetSize; 102 if (delta > overhead) { 103 pad_length = delta - overhead; 104 } 105 len += overhead + pad_length; 106 } 107 108 if (num_entries > kMaxEntries) { 109 return NULL; 110 } 111 112 113 QuicDataWriter writer(len); 114 if (!writer.WriteUInt32(message.tag())) { 115 DCHECK(false) << "Failed to write message tag."; 116 return NULL; 117 } 118 if (!writer.WriteUInt16(num_entries)) { 119 DCHECK(false) << "Failed to write size."; 120 return NULL; 121 } 122 if (!writer.WriteUInt16(0)) { 123 DCHECK(false) << "Failed to write padding."; 124 return NULL; 125 } 126 127 uint32 end_offset = 0; 128 // Tags and offsets 129 for (QuicTagValueMap::const_iterator it = message.tag_value_map().begin(); 130 it != message.tag_value_map().end(); ++it) { 131 if (it->first == kPAD && need_pad_tag) { 132 // Existing PAD tags are only checked when padding needs to be added 133 // because parts of the code may need to reserialize received messages 134 // and those messages may, legitimately include padding. 135 DCHECK(false) << "Message needed padding but already contained a PAD tag"; 136 return NULL; 137 } 138 139 if (it->first > kPAD && need_pad_tag) { 140 need_pad_tag = false; 141 if (!WritePadTag(&writer, pad_length, &end_offset)) { 142 return NULL; 143 } 144 } 145 146 if (!writer.WriteUInt32(it->first)) { 147 DCHECK(false) << "Failed to write tag."; 148 return NULL; 149 } 150 end_offset += it->second.length(); 151 if (!writer.WriteUInt32(end_offset)) { 152 DCHECK(false) << "Failed to write end offset."; 153 return NULL; 154 } 155 } 156 157 if (need_pad_tag) { 158 if (!WritePadTag(&writer, pad_length, &end_offset)) { 159 return NULL; 160 } 161 } 162 163 // Values 164 for (QuicTagValueMap::const_iterator it = message.tag_value_map().begin(); 165 it != message.tag_value_map().end(); ++it) { 166 if (it->first > kPAD && need_pad_value) { 167 need_pad_value = false; 168 if (!writer.WriteRepeatedByte('-', pad_length)) { 169 DCHECK(false) << "Failed to write padding."; 170 return NULL; 171 } 172 } 173 174 if (!writer.WriteBytes(it->second.data(), it->second.length())) { 175 DCHECK(false) << "Failed to write value."; 176 return NULL; 177 } 178 } 179 180 if (need_pad_value) { 181 if (!writer.WriteRepeatedByte('-', pad_length)) { 182 DCHECK(false) << "Failed to write padding."; 183 return NULL; 184 } 185 } 186 187 return new QuicData(writer.take(), len, true); 188} 189 190void CryptoFramer::Clear() { 191 message_.Clear(); 192 tags_and_lengths_.clear(); 193 error_ = QUIC_NO_ERROR; 194 state_ = STATE_READING_TAG; 195} 196 197QuicErrorCode CryptoFramer::Process(StringPiece input) { 198 // Add this data to the buffer. 199 buffer_.append(input.data(), input.length()); 200 QuicDataReader reader(buffer_.data(), buffer_.length()); 201 202 switch (state_) { 203 case STATE_READING_TAG: 204 if (reader.BytesRemaining() < kQuicTagSize) { 205 break; 206 } 207 QuicTag message_tag; 208 reader.ReadUInt32(&message_tag); 209 message_.set_tag(message_tag); 210 state_ = STATE_READING_NUM_ENTRIES; 211 case STATE_READING_NUM_ENTRIES: 212 if (reader.BytesRemaining() < kNumEntriesSize + sizeof(uint16)) { 213 break; 214 } 215 reader.ReadUInt16(&num_entries_); 216 if (num_entries_ > kMaxEntries) { 217 return QUIC_CRYPTO_TOO_MANY_ENTRIES; 218 } 219 uint16 padding; 220 reader.ReadUInt16(&padding); 221 222 tags_and_lengths_.reserve(num_entries_); 223 state_ = STATE_READING_TAGS_AND_LENGTHS; 224 values_len_ = 0; 225 case STATE_READING_TAGS_AND_LENGTHS: { 226 if (reader.BytesRemaining() < 227 num_entries_ * (kQuicTagSize + kCryptoEndOffsetSize)) { 228 break; 229 } 230 231 uint32 last_end_offset = 0; 232 for (unsigned i = 0; i < num_entries_; ++i) { 233 QuicTag tag; 234 reader.ReadUInt32(&tag); 235 if (i > 0 && tag <= tags_and_lengths_[i-1].first) { 236 if (tag == tags_and_lengths_[i-1].first) { 237 return QUIC_CRYPTO_DUPLICATE_TAG; 238 } 239 return QUIC_CRYPTO_TAGS_OUT_OF_ORDER; 240 } 241 242 uint32 end_offset; 243 reader.ReadUInt32(&end_offset); 244 245 if (end_offset < last_end_offset) { 246 return QUIC_CRYPTO_TAGS_OUT_OF_ORDER; 247 } 248 tags_and_lengths_.push_back( 249 make_pair(tag, static_cast<size_t>(end_offset - last_end_offset))); 250 last_end_offset = end_offset; 251 } 252 values_len_ = last_end_offset; 253 state_ = STATE_READING_VALUES; 254 } 255 case STATE_READING_VALUES: 256 if (reader.BytesRemaining() < values_len_) { 257 break; 258 } 259 for (vector<pair<QuicTag, size_t> >::const_iterator 260 it = tags_and_lengths_.begin(); it != tags_and_lengths_.end(); 261 it++) { 262 StringPiece value; 263 reader.ReadStringPiece(&value, it->second); 264 message_.SetStringPiece(it->first, value); 265 } 266 visitor_->OnHandshakeMessage(message_); 267 Clear(); 268 state_ = STATE_READING_TAG; 269 break; 270 } 271 // Save any remaining data. 272 buffer_ = reader.PeekRemainingPayload().as_string(); 273 return QUIC_NO_ERROR; 274} 275 276// static 277bool CryptoFramer::WritePadTag(QuicDataWriter* writer, 278 size_t pad_length, 279 uint32* end_offset) { 280 if (!writer->WriteUInt32(kPAD)) { 281 DCHECK(false) << "Failed to write tag."; 282 return false; 283 } 284 *end_offset += pad_length; 285 if (!writer->WriteUInt32(*end_offset)) { 286 DCHECK(false) << "Failed to write end offset."; 287 return false; 288 } 289 return true; 290} 291 292} // namespace net 293