crypto_framer.cc revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
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); 23const size_t kValueLenSize = sizeof(uint16); 24 25// OneShotVisitor is a framer visitor that records a single handshake message. 26class OneShotVisitor : public CryptoFramerVisitorInterface { 27 public: 28 explicit OneShotVisitor(CryptoHandshakeMessage* out) 29 : out_(out), 30 error_(false) { 31 } 32 33 virtual void OnError(CryptoFramer* framer) OVERRIDE { error_ = true; } 34 35 virtual void OnHandshakeMessage( 36 const CryptoHandshakeMessage& message) OVERRIDE { 37 *out_ = message; 38 } 39 40 bool error() const { return error_; } 41 42 private: 43 CryptoHandshakeMessage* const out_; 44 bool error_; 45}; 46 47} // namespace 48 49CryptoFramer::CryptoFramer() 50 : visitor_(NULL), 51 num_entries_(0), 52 values_len_(0) { 53 Clear(); 54} 55 56CryptoFramer::~CryptoFramer() {} 57 58// static 59CryptoHandshakeMessage* CryptoFramer::ParseMessage(StringPiece in) { 60 scoped_ptr<CryptoHandshakeMessage> msg(new CryptoHandshakeMessage); 61 OneShotVisitor visitor(msg.get()); 62 CryptoFramer framer; 63 64 framer.set_visitor(&visitor); 65 if (!framer.ProcessInput(in) || visitor.error() || 66 framer.InputBytesRemaining()) { 67 return NULL; 68 } 69 70 return msg.release(); 71} 72 73bool CryptoFramer::ProcessInput(StringPiece input) { 74 DCHECK_EQ(QUIC_NO_ERROR, error_); 75 if (error_ != QUIC_NO_ERROR) { 76 return false; 77 } 78 // Add this data to the buffer. 79 buffer_.append(input.data(), input.length()); 80 QuicDataReader reader(buffer_.data(), buffer_.length()); 81 82 switch (state_) { 83 case STATE_READING_TAG: 84 if (reader.BytesRemaining() < kQuicTagSize) { 85 break; 86 } 87 QuicTag message_tag; 88 reader.ReadUInt32(&message_tag); 89 message_.set_tag(message_tag); 90 state_ = STATE_READING_NUM_ENTRIES; 91 case STATE_READING_NUM_ENTRIES: 92 if (reader.BytesRemaining() < kNumEntriesSize + sizeof(uint16)) { 93 break; 94 } 95 reader.ReadUInt16(&num_entries_); 96 if (num_entries_ > kMaxEntries) { 97 error_ = QUIC_CRYPTO_TOO_MANY_ENTRIES; 98 return false; 99 } 100 uint16 padding; 101 reader.ReadUInt16(&padding); 102 103 tags_and_lengths_.reserve(num_entries_); 104 state_ = STATE_READING_TAGS_AND_LENGTHS; 105 values_len_ = 0; 106 case STATE_READING_TAGS_AND_LENGTHS: { 107 if (reader.BytesRemaining() < 108 num_entries_ * (kQuicTagSize + kCryptoEndOffsetSize)) { 109 break; 110 } 111 112 uint32 last_end_offset = 0; 113 for (unsigned i = 0; i < num_entries_; ++i) { 114 QuicTag tag; 115 reader.ReadUInt32(&tag); 116 if (i > 0 && tag <= tags_and_lengths_[i-1].first) { 117 if (tag == tags_and_lengths_[i-1].first) { 118 error_ = QUIC_CRYPTO_DUPLICATE_TAG; 119 } else { 120 error_ = QUIC_CRYPTO_TAGS_OUT_OF_ORDER; 121 } 122 return false; 123 } 124 125 uint32 end_offset; 126 reader.ReadUInt32(&end_offset); 127 128 if (end_offset < last_end_offset) { 129 error_ = QUIC_CRYPTO_TAGS_OUT_OF_ORDER; 130 return false; 131 } 132 tags_and_lengths_.push_back( 133 make_pair(tag, static_cast<size_t>(end_offset - last_end_offset))); 134 last_end_offset = end_offset; 135 } 136 values_len_ = last_end_offset; 137 state_ = STATE_READING_VALUES; 138 } 139 case STATE_READING_VALUES: 140 if (reader.BytesRemaining() < values_len_) { 141 break; 142 } 143 for (vector<pair<QuicTag, size_t> >::const_iterator 144 it = tags_and_lengths_.begin(); it != tags_and_lengths_.end(); 145 it++) { 146 StringPiece value; 147 reader.ReadStringPiece(&value, it->second); 148 message_.SetStringPiece(it->first, value); 149 } 150 visitor_->OnHandshakeMessage(message_); 151 Clear(); 152 state_ = STATE_READING_TAG; 153 break; 154 } 155 // Save any remaining data. 156 buffer_ = reader.PeekRemainingPayload().as_string(); 157 return true; 158} 159 160// static 161QuicData* CryptoFramer::ConstructHandshakeMessage( 162 const CryptoHandshakeMessage& message) { 163 if (message.tag_value_map().size() > kMaxEntries) { 164 return NULL; 165 } 166 size_t len = kQuicTagSize; // message tag 167 len += sizeof(uint16); // number of map entries 168 len += sizeof(uint16); // padding. 169 QuicTagValueMap::const_iterator it = message.tag_value_map().begin(); 170 while (it != message.tag_value_map().end()) { 171 len += kQuicTagSize; // tag 172 len += kCryptoEndOffsetSize; // end offset 173 len += it->second.length(); // value 174 ++it; 175 } 176 177 QuicDataWriter writer(len); 178 if (!writer.WriteUInt32(message.tag())) { 179 DCHECK(false) << "Failed to write message tag."; 180 return NULL; 181 } 182 if (!writer.WriteUInt16(message.tag_value_map().size())) { 183 DCHECK(false) << "Failed to write size."; 184 return NULL; 185 } 186 if (!writer.WriteUInt16(0)) { 187 DCHECK(false) << "Failed to write padding."; 188 return NULL; 189 } 190 191 uint32 end_offset = 0; 192 // Tags and offsets 193 for (it = message.tag_value_map().begin(); 194 it != message.tag_value_map().end(); ++it) { 195 if (!writer.WriteUInt32(it->first)) { 196 DCHECK(false) << "Failed to write tag."; 197 return NULL; 198 } 199 end_offset += it->second.length(); 200 if (!writer.WriteUInt32(end_offset)) { 201 DCHECK(false) << "Failed to write end offset."; 202 return NULL; 203 } 204 } 205 206 // Values 207 for (it = message.tag_value_map().begin(); 208 it != message.tag_value_map().end(); ++it) { 209 if (!writer.WriteBytes(it->second.data(), it->second.length())) { 210 DCHECK(false) << "Failed to write value."; 211 return NULL; 212 } 213 } 214 return new QuicData(writer.take(), len, true); 215} 216 217void CryptoFramer::Clear() { 218 message_.Clear(); 219 tags_and_lengths_.clear(); 220 error_ = QUIC_NO_ERROR; 221 state_ = STATE_READING_TAG; 222} 223 224} // namespace net 225