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_protocol.h" 8 #include "net/quic/quic_data_reader.h" 9 #include "net/quic/quic_data_writer.h" 10 11 using base::StringPiece; 12 using std::make_pair; 13 using std::pair; 14 using std::vector; 15 16 namespace net { 17 18 namespace { 19 20 const size_t kQuicTagSize = sizeof(uint32); 21 const size_t kCryptoEndOffsetSize = sizeof(uint32); 22 const size_t kNumEntriesSize = sizeof(uint16); 23 24 // OneShotVisitor is a framer visitor that records a single handshake message. 25 class OneShotVisitor : public CryptoFramerVisitorInterface { 26 public: 27 OneShotVisitor() : error_(false) {} 28 29 virtual void OnError(CryptoFramer* framer) OVERRIDE { error_ = true; } 30 31 virtual void OnHandshakeMessage( 32 const CryptoHandshakeMessage& message) OVERRIDE { 33 out_.reset(new CryptoHandshakeMessage(message)); 34 } 35 36 bool error() const { return error_; } 37 38 CryptoHandshakeMessage* release() { return out_.release(); } 39 40 private: 41 scoped_ptr<CryptoHandshakeMessage> out_; 42 bool error_; 43 }; 44 45 } // namespace 46 47 CryptoFramer::CryptoFramer() 48 : visitor_(NULL), 49 num_entries_(0), 50 values_len_(0) { 51 Clear(); 52 } 53 54 CryptoFramer::~CryptoFramer() {} 55 56 // static 57 CryptoHandshakeMessage* CryptoFramer::ParseMessage(StringPiece in) { 58 OneShotVisitor visitor; 59 CryptoFramer framer; 60 61 framer.set_visitor(&visitor); 62 if (!framer.ProcessInput(in) || visitor.error() || 63 framer.InputBytesRemaining()) { 64 return NULL; 65 } 66 67 return visitor.release(); 68 } 69 70 bool CryptoFramer::ProcessInput(StringPiece input) { 71 DCHECK_EQ(QUIC_NO_ERROR, error_); 72 if (error_ != QUIC_NO_ERROR) { 73 return false; 74 } 75 error_ = Process(input); 76 if (error_ != QUIC_NO_ERROR) { 77 visitor_->OnError(this); 78 return false; 79 } 80 81 return true; 82 } 83 84 // static 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; 91 92 size_t len = message.size(); 93 if (len < message.minimum_size()) { 94 need_pad_tag = true; 95 need_pad_value = true; 96 num_entries++; 97 98 size_t delta = message.minimum_size() - len; 99 const size_t overhead = kQuicTagSize + kCryptoEndOffsetSize; 100 if (delta > overhead) { 101 pad_length = delta - overhead; 102 } 103 len += overhead + pad_length; 104 } 105 106 if (num_entries > kMaxEntries) { 107 return NULL; 108 } 109 110 111 QuicDataWriter writer(len); 112 if (!writer.WriteUInt32(message.tag())) { 113 DCHECK(false) << "Failed to write message tag."; 114 return NULL; 115 } 116 if (!writer.WriteUInt16(num_entries)) { 117 DCHECK(false) << "Failed to write size."; 118 return NULL; 119 } 120 if (!writer.WriteUInt16(0)) { 121 DCHECK(false) << "Failed to write padding."; 122 return NULL; 123 } 124 125 uint32 end_offset = 0; 126 // Tags and offsets 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"; 134 return NULL; 135 } 136 137 if (it->first > kPAD && need_pad_tag) { 138 need_pad_tag = false; 139 if (!WritePadTag(&writer, pad_length, &end_offset)) { 140 return NULL; 141 } 142 } 143 144 if (!writer.WriteUInt32(it->first)) { 145 DCHECK(false) << "Failed to write tag."; 146 return NULL; 147 } 148 end_offset += it->second.length(); 149 if (!writer.WriteUInt32(end_offset)) { 150 DCHECK(false) << "Failed to write end offset."; 151 return NULL; 152 } 153 } 154 155 if (need_pad_tag) { 156 if (!WritePadTag(&writer, pad_length, &end_offset)) { 157 return NULL; 158 } 159 } 160 161 // Values 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."; 168 return NULL; 169 } 170 } 171 172 if (!writer.WriteBytes(it->second.data(), it->second.length())) { 173 DCHECK(false) << "Failed to write value."; 174 return NULL; 175 } 176 } 177 178 if (need_pad_value) { 179 if (!writer.WriteRepeatedByte('-', pad_length)) { 180 DCHECK(false) << "Failed to write padding."; 181 return NULL; 182 } 183 } 184 185 return new QuicData(writer.take(), len, true); 186 } 187 188 void CryptoFramer::Clear() { 189 message_.Clear(); 190 tags_and_lengths_.clear(); 191 error_ = QUIC_NO_ERROR; 192 state_ = STATE_READING_TAG; 193 } 194 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()); 199 200 switch (state_) { 201 case STATE_READING_TAG: 202 if (reader.BytesRemaining() < kQuicTagSize) { 203 break; 204 } 205 QuicTag message_tag; 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)) { 211 break; 212 } 213 reader.ReadUInt16(&num_entries_); 214 if (num_entries_ > kMaxEntries) { 215 return QUIC_CRYPTO_TOO_MANY_ENTRIES; 216 } 217 uint16 padding; 218 reader.ReadUInt16(&padding); 219 220 tags_and_lengths_.reserve(num_entries_); 221 state_ = STATE_READING_TAGS_AND_LENGTHS; 222 values_len_ = 0; 223 case STATE_READING_TAGS_AND_LENGTHS: { 224 if (reader.BytesRemaining() < 225 num_entries_ * (kQuicTagSize + kCryptoEndOffsetSize)) { 226 break; 227 } 228 229 uint32 last_end_offset = 0; 230 for (unsigned i = 0; i < num_entries_; ++i) { 231 QuicTag tag; 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; 236 } 237 return QUIC_CRYPTO_TAGS_OUT_OF_ORDER; 238 } 239 240 uint32 end_offset; 241 reader.ReadUInt32(&end_offset); 242 243 if (end_offset < last_end_offset) { 244 return QUIC_CRYPTO_TAGS_OUT_OF_ORDER; 245 } 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; 249 } 250 values_len_ = last_end_offset; 251 state_ = STATE_READING_VALUES; 252 } 253 case STATE_READING_VALUES: 254 if (reader.BytesRemaining() < values_len_) { 255 break; 256 } 257 for (vector<pair<QuicTag, size_t> >::const_iterator 258 it = tags_and_lengths_.begin(); it != tags_and_lengths_.end(); 259 it++) { 260 StringPiece value; 261 reader.ReadStringPiece(&value, it->second); 262 message_.SetStringPiece(it->first, value); 263 } 264 visitor_->OnHandshakeMessage(message_); 265 Clear(); 266 state_ = STATE_READING_TAG; 267 break; 268 } 269 // Save any remaining data. 270 buffer_ = reader.PeekRemainingPayload().as_string(); 271 return QUIC_NO_ERROR; 272 } 273 274 // static 275 bool CryptoFramer::WritePadTag(QuicDataWriter* writer, 276 size_t pad_length, 277 uint32* end_offset) { 278 if (!writer->WriteUInt32(kPAD)) { 279 DCHECK(false) << "Failed to write tag."; 280 return false; 281 } 282 *end_offset += pad_length; 283 if (!writer->WriteUInt32(*end_offset)) { 284 DCHECK(false) << "Failed to write end offset."; 285 return false; 286 } 287 return true; 288 } 289 290 } // namespace net 291