Home | History | Annotate | Download | only in crypto
      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 
     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   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 
     48 CryptoFramer::CryptoFramer()
     49     : visitor_(NULL),
     50       num_entries_(0),
     51       values_len_(0) {
     52   Clear();
     53 }
     54 
     55 CryptoFramer::~CryptoFramer() {}
     56 
     57 // static
     58 CryptoHandshakeMessage* 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 
     72 bool 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
     87 QuicData* 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 
    190 void CryptoFramer::Clear() {
    191   message_.Clear();
    192   tags_and_lengths_.clear();
    193   error_ = QUIC_NO_ERROR;
    194   state_ = STATE_READING_TAG;
    195 }
    196 
    197 QuicErrorCode 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
    277 bool 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