Home | History | Annotate | Download | only in crypto
      1 // Copyright (c) 2013 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_handshake_message.h"
      6 
      7 #include "base/strings/stringprintf.h"
      8 #include "base/strings/string_number_conversions.h"
      9 #include "net/quic/crypto/crypto_framer.h"
     10 #include "net/quic/crypto/crypto_protocol.h"
     11 #include "net/quic/quic_socket_address_coder.h"
     12 #include "net/quic/quic_utils.h"
     13 
     14 using base::StringPiece;
     15 using base::StringPrintf;
     16 using std::string;
     17 using std::vector;
     18 
     19 namespace net {
     20 
     21 CryptoHandshakeMessage::CryptoHandshakeMessage()
     22     : tag_(0),
     23       minimum_size_(0) {}
     24 
     25 CryptoHandshakeMessage::CryptoHandshakeMessage(
     26     const CryptoHandshakeMessage& other)
     27     : tag_(other.tag_),
     28       tag_value_map_(other.tag_value_map_),
     29       minimum_size_(other.minimum_size_) {
     30   // Don't copy serialized_. scoped_ptr doesn't have a copy constructor.
     31   // The new object can lazily reconstruct serialized_.
     32 }
     33 
     34 CryptoHandshakeMessage::~CryptoHandshakeMessage() {}
     35 
     36 CryptoHandshakeMessage& CryptoHandshakeMessage::operator=(
     37     const CryptoHandshakeMessage& other) {
     38   tag_ = other.tag_;
     39   tag_value_map_ = other.tag_value_map_;
     40   // Don't copy serialized_. scoped_ptr doesn't have an assignment operator.
     41   // However, invalidate serialized_.
     42   serialized_.reset();
     43   minimum_size_ = other.minimum_size_;
     44   return *this;
     45 }
     46 
     47 void CryptoHandshakeMessage::Clear() {
     48   tag_ = 0;
     49   tag_value_map_.clear();
     50   minimum_size_ = 0;
     51   serialized_.reset();
     52 }
     53 
     54 const QuicData& CryptoHandshakeMessage::GetSerialized() const {
     55   if (!serialized_.get()) {
     56     serialized_.reset(CryptoFramer::ConstructHandshakeMessage(*this));
     57   }
     58   return *serialized_.get();
     59 }
     60 
     61 void CryptoHandshakeMessage::MarkDirty() {
     62   serialized_.reset();
     63 }
     64 
     65 void CryptoHandshakeMessage::SetTaglist(QuicTag tag, ...) {
     66   // Warning, if sizeof(QuicTag) > sizeof(int) then this function will break
     67   // because the terminating 0 will only be promoted to int.
     68   COMPILE_ASSERT(sizeof(QuicTag) <= sizeof(int),
     69                  crypto_tag_may_not_be_larger_than_int_or_varargs_will_break);
     70 
     71   vector<QuicTag> tags;
     72   va_list ap;
     73 
     74   va_start(ap, tag);
     75   for (;;) {
     76     QuicTag list_item = va_arg(ap, QuicTag);
     77     if (list_item == 0) {
     78       break;
     79     }
     80     tags.push_back(list_item);
     81   }
     82 
     83   // Because of the way that we keep tags in memory, we can copy the contents
     84   // of the vector and get the correct bytes in wire format. See
     85   // crypto_protocol.h. This assumes that the system is little-endian.
     86   SetVector(tag, tags);
     87 
     88   va_end(ap);
     89 }
     90 
     91 void CryptoHandshakeMessage::SetStringPiece(QuicTag tag, StringPiece value) {
     92   tag_value_map_[tag] = value.as_string();
     93 }
     94 
     95 void CryptoHandshakeMessage::Erase(QuicTag tag) {
     96   tag_value_map_.erase(tag);
     97 }
     98 
     99 QuicErrorCode CryptoHandshakeMessage::GetTaglist(QuicTag tag,
    100                                                  const QuicTag** out_tags,
    101                                                  size_t* out_len) const {
    102   QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
    103   QuicErrorCode ret = QUIC_NO_ERROR;
    104 
    105   if (it == tag_value_map_.end()) {
    106     ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
    107   } else if (it->second.size() % sizeof(QuicTag) != 0) {
    108     ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
    109   }
    110 
    111   if (ret != QUIC_NO_ERROR) {
    112     *out_tags = NULL;
    113     *out_len = 0;
    114     return ret;
    115   }
    116 
    117   *out_tags = reinterpret_cast<const QuicTag*>(it->second.data());
    118   *out_len = it->second.size() / sizeof(QuicTag);
    119   return ret;
    120 }
    121 
    122 bool CryptoHandshakeMessage::GetStringPiece(QuicTag tag,
    123                                             StringPiece* out) const {
    124   QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
    125   if (it == tag_value_map_.end()) {
    126     return false;
    127   }
    128   *out = it->second;
    129   return true;
    130 }
    131 
    132 QuicErrorCode CryptoHandshakeMessage::GetNthValue24(QuicTag tag,
    133                                                     unsigned index,
    134                                                     StringPiece* out) const {
    135   StringPiece value;
    136   if (!GetStringPiece(tag, &value)) {
    137     return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
    138   }
    139 
    140   for (unsigned i = 0;; i++) {
    141     if (value.empty()) {
    142       return QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND;
    143     }
    144     if (value.size() < 3) {
    145       return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
    146     }
    147 
    148     const unsigned char* data =
    149         reinterpret_cast<const unsigned char*>(value.data());
    150     size_t size = static_cast<size_t>(data[0]) |
    151                   (static_cast<size_t>(data[1]) << 8) |
    152                   (static_cast<size_t>(data[2]) << 16);
    153     value.remove_prefix(3);
    154 
    155     if (value.size() < size) {
    156       return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
    157     }
    158 
    159     if (i == index) {
    160       *out = StringPiece(value.data(), size);
    161       return QUIC_NO_ERROR;
    162     }
    163 
    164     value.remove_prefix(size);
    165   }
    166 }
    167 
    168 QuicErrorCode CryptoHandshakeMessage::GetUint16(QuicTag tag,
    169                                                 uint16* out) const {
    170   return GetPOD(tag, out, sizeof(uint16));
    171 }
    172 
    173 QuicErrorCode CryptoHandshakeMessage::GetUint32(QuicTag tag,
    174                                                 uint32* out) const {
    175   return GetPOD(tag, out, sizeof(uint32));
    176 }
    177 
    178 QuicErrorCode CryptoHandshakeMessage::GetUint64(QuicTag tag,
    179                                                 uint64* out) const {
    180   return GetPOD(tag, out, sizeof(uint64));
    181 }
    182 
    183 size_t CryptoHandshakeMessage::size() const {
    184   size_t ret = sizeof(QuicTag) +
    185                sizeof(uint16) /* number of entries */ +
    186                sizeof(uint16) /* padding */;
    187   ret += (sizeof(QuicTag) + sizeof(uint32) /* end offset */) *
    188          tag_value_map_.size();
    189   for (QuicTagValueMap::const_iterator i = tag_value_map_.begin();
    190        i != tag_value_map_.end(); ++i) {
    191     ret += i->second.size();
    192   }
    193 
    194   return ret;
    195 }
    196 
    197 void CryptoHandshakeMessage::set_minimum_size(size_t min_bytes) {
    198   if (min_bytes == minimum_size_) {
    199     return;
    200   }
    201   serialized_.reset();
    202   minimum_size_ = min_bytes;
    203 }
    204 
    205 size_t CryptoHandshakeMessage::minimum_size() const {
    206   return minimum_size_;
    207 }
    208 
    209 string CryptoHandshakeMessage::DebugString() const {
    210   return DebugStringInternal(0);
    211 }
    212 
    213 QuicErrorCode CryptoHandshakeMessage::GetPOD(
    214     QuicTag tag, void* out, size_t len) const {
    215   QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
    216   QuicErrorCode ret = QUIC_NO_ERROR;
    217 
    218   if (it == tag_value_map_.end()) {
    219     ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
    220   } else if (it->second.size() != len) {
    221     ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
    222   }
    223 
    224   if (ret != QUIC_NO_ERROR) {
    225     memset(out, 0, len);
    226     return ret;
    227   }
    228 
    229   memcpy(out, it->second.data(), len);
    230   return ret;
    231 }
    232 
    233 string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const {
    234   string ret = string(2 * indent, ' ') + QuicUtils::TagToString(tag_) + "<\n";
    235   ++indent;
    236   for (QuicTagValueMap::const_iterator it = tag_value_map_.begin();
    237        it != tag_value_map_.end(); ++it) {
    238     ret += string(2 * indent, ' ') + QuicUtils::TagToString(it->first) + ": ";
    239 
    240     bool done = false;
    241     switch (it->first) {
    242       case kICSL:
    243       case kIFCW:
    244       case kCFCW:
    245       case kSFCW:
    246       case kIRTT:
    247       case kKATO:
    248       case kMSPC:
    249       case kSWND:
    250         // uint32 value
    251         if (it->second.size() == 4) {
    252           uint32 value;
    253           memcpy(&value, it->second.data(), sizeof(value));
    254           ret += base::UintToString(value);
    255           done = true;
    256         }
    257         break;
    258       case kKEXS:
    259       case kAEAD:
    260       case kCGST:
    261       case kCOPT:
    262       case kLOSS:
    263       case kPDMD:
    264       case kVER:
    265         // tag lists
    266         if (it->second.size() % sizeof(QuicTag) == 0) {
    267           for (size_t j = 0; j < it->second.size(); j += sizeof(QuicTag)) {
    268             QuicTag tag;
    269             memcpy(&tag, it->second.data() + j, sizeof(tag));
    270             if (j > 0) {
    271               ret += ",";
    272             }
    273             ret += "'" + QuicUtils::TagToString(tag) + "'";
    274           }
    275           done = true;
    276         }
    277         break;
    278       case kCADR:
    279         // IP address and port
    280         if (!it->second.empty()) {
    281           QuicSocketAddressCoder decoder;
    282           if (decoder.Decode(it->second.data(), it->second.size())) {
    283             ret += IPAddressToStringWithPort(decoder.ip(), decoder.port());
    284             done = true;
    285           }
    286         }
    287         break;
    288       case kSCFG:
    289         // nested messages.
    290         if (!it->second.empty()) {
    291           scoped_ptr<CryptoHandshakeMessage> msg(
    292               CryptoFramer::ParseMessage(it->second));
    293           if (msg.get()) {
    294             ret += "\n";
    295             ret += msg->DebugStringInternal(indent + 1);
    296 
    297             done = true;
    298           }
    299         }
    300         break;
    301       case kPAD:
    302         ret += StringPrintf("(%d bytes of padding)",
    303                             static_cast<int>(it->second.size()));
    304         done = true;
    305         break;
    306       case kUAID:
    307         ret += it->second;
    308         done = true;
    309         break;
    310     }
    311 
    312     if (!done) {
    313       // If there's no specific format for this tag, or the value is invalid,
    314       // then just use hex.
    315       ret += "0x" + base::HexEncode(it->second.data(), it->second.size());
    316     }
    317     ret += "\n";
    318   }
    319   --indent;
    320   ret += string(2 * indent, ' ') + ">";
    321   return ret;
    322 }
    323 
    324 }  // namespace net
    325