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_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