• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CryptoHandshakeMessage()21 CryptoHandshakeMessage::CryptoHandshakeMessage()
22     : tag_(0),
23       minimum_size_(0) {}
24 
CryptoHandshakeMessage(const CryptoHandshakeMessage & other)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 
~CryptoHandshakeMessage()34 CryptoHandshakeMessage::~CryptoHandshakeMessage() {}
35 
operator =(const CryptoHandshakeMessage & other)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 
Clear()47 void CryptoHandshakeMessage::Clear() {
48   tag_ = 0;
49   tag_value_map_.clear();
50   minimum_size_ = 0;
51   serialized_.reset();
52 }
53 
GetSerialized() const54 const QuicData& CryptoHandshakeMessage::GetSerialized() const {
55   if (!serialized_.get()) {
56     serialized_.reset(CryptoFramer::ConstructHandshakeMessage(*this));
57   }
58   return *serialized_.get();
59 }
60 
MarkDirty()61 void CryptoHandshakeMessage::MarkDirty() {
62   serialized_.reset();
63 }
64 
SetTaglist(QuicTag tag,...)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 
SetStringPiece(QuicTag tag,StringPiece value)91 void CryptoHandshakeMessage::SetStringPiece(QuicTag tag, StringPiece value) {
92   tag_value_map_[tag] = value.as_string();
93 }
94 
Erase(QuicTag tag)95 void CryptoHandshakeMessage::Erase(QuicTag tag) {
96   tag_value_map_.erase(tag);
97 }
98 
GetTaglist(QuicTag tag,const QuicTag ** out_tags,size_t * out_len) const99 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 
GetStringPiece(QuicTag tag,StringPiece * out) const122 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 
GetNthValue24(QuicTag tag,unsigned index,StringPiece * out) const132 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 
GetUint16(QuicTag tag,uint16 * out) const168 QuicErrorCode CryptoHandshakeMessage::GetUint16(QuicTag tag,
169                                                 uint16* out) const {
170   return GetPOD(tag, out, sizeof(uint16));
171 }
172 
GetUint32(QuicTag tag,uint32 * out) const173 QuicErrorCode CryptoHandshakeMessage::GetUint32(QuicTag tag,
174                                                 uint32* out) const {
175   return GetPOD(tag, out, sizeof(uint32));
176 }
177 
GetUint64(QuicTag tag,uint64 * out) const178 QuicErrorCode CryptoHandshakeMessage::GetUint64(QuicTag tag,
179                                                 uint64* out) const {
180   return GetPOD(tag, out, sizeof(uint64));
181 }
182 
size() const183 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 
set_minimum_size(size_t min_bytes)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 
minimum_size() const205 size_t CryptoHandshakeMessage::minimum_size() const {
206   return minimum_size_;
207 }
208 
DebugString() const209 string CryptoHandshakeMessage::DebugString() const {
210   return DebugStringInternal(0);
211 }
212 
GetPOD(QuicTag tag,void * out,size_t len) const213 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 
DebugStringInternal(size_t indent) const233 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