Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / net / quic / crypto / crypto_handshake_message.cc
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 kIRTT:
244       case kKATO:
245       case kMSPC:
246       case kSWND:
247         // uint32 value
248         if (it->second.size() == 4) {
249           uint32 value;
250           memcpy(&value, it->second.data(), sizeof(value));
251           ret += base::UintToString(value);
252           done = true;
253         }
254         break;
255       case kVERS:
256         // uint16 value
257         if (it->second.size() == 2) {
258           uint16 value;
259           memcpy(&value, it->second.data(), sizeof(value));
260           ret += base::UintToString(value);
261           done = true;
262         }
263         break;
264       case kKEXS:
265       case kAEAD:
266       case kCGST:
267       case kPDMD:
268       case kVER:
269         // tag lists
270         if (it->second.size() % sizeof(QuicTag) == 0) {
271           for (size_t j = 0; j < it->second.size(); j += sizeof(QuicTag)) {
272             QuicTag tag;
273             memcpy(&tag, it->second.data() + j, sizeof(tag));
274             if (j > 0) {
275               ret += ",";
276             }
277             ret += "'" + QuicUtils::TagToString(tag) + "'";
278           }
279           done = true;
280         }
281         break;
282       case kCADR:
283         // IP address and port
284         if (!it->second.empty()) {
285           QuicSocketAddressCoder decoder;
286           if (decoder.Decode(it->second.data(), it->second.size())) {
287             ret += IPAddressToStringWithPort(decoder.ip(), decoder.port());
288             done = true;
289           }
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 }  // namespace net