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