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