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