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