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 "quiche/quic/core/crypto/crypto_handshake_message.h"
6
7 #include <memory>
8 #include <string>
9
10 #include "absl/strings/escaping.h"
11 #include "absl/strings/str_cat.h"
12 #include "absl/strings/str_format.h"
13 #include "absl/strings/string_view.h"
14 #include "quiche/quic/core/crypto/crypto_framer.h"
15 #include "quiche/quic/core/crypto/crypto_protocol.h"
16 #include "quiche/quic/core/crypto/crypto_utils.h"
17 #include "quiche/quic/core/quic_socket_address_coder.h"
18 #include "quiche/quic/core/quic_utils.h"
19 #include "quiche/common/quiche_endian.h"
20
21 namespace quic {
22
CryptoHandshakeMessage()23 CryptoHandshakeMessage::CryptoHandshakeMessage() : tag_(0), 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_. unique_ptr doesn't have a copy constructor.
31 // The new object can lazily reconstruct serialized_.
32 }
33
34 CryptoHandshakeMessage::CryptoHandshakeMessage(CryptoHandshakeMessage&& other) =
35 default;
36
~CryptoHandshakeMessage()37 CryptoHandshakeMessage::~CryptoHandshakeMessage() {}
38
operator =(const CryptoHandshakeMessage & other)39 CryptoHandshakeMessage& CryptoHandshakeMessage::operator=(
40 const CryptoHandshakeMessage& other) {
41 tag_ = other.tag_;
42 tag_value_map_ = other.tag_value_map_;
43 // Don't copy serialized_. unique_ptr doesn't have an assignment operator.
44 // However, invalidate serialized_.
45 serialized_.reset();
46 minimum_size_ = other.minimum_size_;
47 return *this;
48 }
49
50 CryptoHandshakeMessage& CryptoHandshakeMessage::operator=(
51 CryptoHandshakeMessage&& other) = default;
52
operator ==(const CryptoHandshakeMessage & rhs) const53 bool CryptoHandshakeMessage::operator==(
54 const CryptoHandshakeMessage& rhs) const {
55 return tag_ == rhs.tag_ && tag_value_map_ == rhs.tag_value_map_ &&
56 minimum_size_ == rhs.minimum_size_;
57 }
58
operator !=(const CryptoHandshakeMessage & rhs) const59 bool CryptoHandshakeMessage::operator!=(
60 const CryptoHandshakeMessage& rhs) const {
61 return !(*this == rhs);
62 }
63
Clear()64 void CryptoHandshakeMessage::Clear() {
65 tag_ = 0;
66 tag_value_map_.clear();
67 minimum_size_ = 0;
68 serialized_.reset();
69 }
70
GetSerialized() const71 const QuicData& CryptoHandshakeMessage::GetSerialized() const {
72 if (!serialized_) {
73 serialized_ = CryptoFramer::ConstructHandshakeMessage(*this);
74 }
75 return *serialized_;
76 }
77
MarkDirty()78 void CryptoHandshakeMessage::MarkDirty() { serialized_.reset(); }
79
SetVersionVector(QuicTag tag,ParsedQuicVersionVector versions)80 void CryptoHandshakeMessage::SetVersionVector(
81 QuicTag tag, ParsedQuicVersionVector versions) {
82 QuicVersionLabelVector version_labels;
83 for (const ParsedQuicVersion& version : versions) {
84 version_labels.push_back(
85 quiche::QuicheEndian::HostToNet32(CreateQuicVersionLabel(version)));
86 }
87 SetVector(tag, version_labels);
88 }
89
SetVersion(QuicTag tag,ParsedQuicVersion version)90 void CryptoHandshakeMessage::SetVersion(QuicTag tag,
91 ParsedQuicVersion version) {
92 SetValue(tag,
93 quiche::QuicheEndian::HostToNet32(CreateQuicVersionLabel(version)));
94 }
95
SetStringPiece(QuicTag tag,absl::string_view value)96 void CryptoHandshakeMessage::SetStringPiece(QuicTag tag,
97 absl::string_view value) {
98 tag_value_map_[tag] = std::string(value);
99 }
100
Erase(QuicTag tag)101 void CryptoHandshakeMessage::Erase(QuicTag tag) { tag_value_map_.erase(tag); }
102
GetTaglist(QuicTag tag,QuicTagVector * out_tags) const103 QuicErrorCode CryptoHandshakeMessage::GetTaglist(
104 QuicTag tag, QuicTagVector* out_tags) const {
105 auto it = tag_value_map_.find(tag);
106 QuicErrorCode ret = QUIC_NO_ERROR;
107
108 if (it == tag_value_map_.end()) {
109 ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
110 } else if (it->second.size() % sizeof(QuicTag) != 0) {
111 ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
112 }
113
114 if (ret != QUIC_NO_ERROR) {
115 out_tags->clear();
116 return ret;
117 }
118
119 size_t num_tags = it->second.size() / sizeof(QuicTag);
120 out_tags->resize(num_tags);
121 for (size_t i = 0; i < num_tags; ++i) {
122 memcpy(&(*out_tags)[i], it->second.data() + i * sizeof(tag), sizeof(tag));
123 }
124 return ret;
125 }
126
GetVersionLabelList(QuicTag tag,QuicVersionLabelVector * out) const127 QuicErrorCode CryptoHandshakeMessage::GetVersionLabelList(
128 QuicTag tag, QuicVersionLabelVector* out) const {
129 QuicErrorCode error = GetTaglist(tag, out);
130 if (error != QUIC_NO_ERROR) {
131 return error;
132 }
133
134 for (size_t i = 0; i < out->size(); ++i) {
135 (*out)[i] = quiche::QuicheEndian::HostToNet32((*out)[i]);
136 }
137
138 return QUIC_NO_ERROR;
139 }
140
GetVersionLabel(QuicTag tag,QuicVersionLabel * out) const141 QuicErrorCode CryptoHandshakeMessage::GetVersionLabel(
142 QuicTag tag, QuicVersionLabel* out) const {
143 QuicErrorCode error = GetUint32(tag, out);
144 if (error != QUIC_NO_ERROR) {
145 return error;
146 }
147
148 *out = quiche::QuicheEndian::HostToNet32(*out);
149 return QUIC_NO_ERROR;
150 }
151
GetStringPiece(QuicTag tag,absl::string_view * out) const152 bool CryptoHandshakeMessage::GetStringPiece(QuicTag tag,
153 absl::string_view* out) const {
154 auto it = tag_value_map_.find(tag);
155 if (it == tag_value_map_.end()) {
156 return false;
157 }
158 *out = it->second;
159 return true;
160 }
161
HasStringPiece(QuicTag tag) const162 bool CryptoHandshakeMessage::HasStringPiece(QuicTag tag) const {
163 return tag_value_map_.find(tag) != tag_value_map_.end();
164 }
165
GetNthValue24(QuicTag tag,unsigned index,absl::string_view * out) const166 QuicErrorCode CryptoHandshakeMessage::GetNthValue24(
167 QuicTag tag, unsigned index, absl::string_view* out) const {
168 absl::string_view value;
169 if (!GetStringPiece(tag, &value)) {
170 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
171 }
172
173 for (unsigned i = 0;; i++) {
174 if (value.empty()) {
175 return QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND;
176 }
177 if (value.size() < 3) {
178 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
179 }
180
181 const unsigned char* data =
182 reinterpret_cast<const unsigned char*>(value.data());
183 size_t size = static_cast<size_t>(data[0]) |
184 (static_cast<size_t>(data[1]) << 8) |
185 (static_cast<size_t>(data[2]) << 16);
186 value.remove_prefix(3);
187
188 if (value.size() < size) {
189 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
190 }
191
192 if (i == index) {
193 *out = absl::string_view(value.data(), size);
194 return QUIC_NO_ERROR;
195 }
196
197 value.remove_prefix(size);
198 }
199 }
200
GetUint32(QuicTag tag,uint32_t * out) const201 QuicErrorCode CryptoHandshakeMessage::GetUint32(QuicTag tag,
202 uint32_t* out) const {
203 return GetPOD(tag, out, sizeof(uint32_t));
204 }
205
GetUint64(QuicTag tag,uint64_t * out) const206 QuicErrorCode CryptoHandshakeMessage::GetUint64(QuicTag tag,
207 uint64_t* out) const {
208 return GetPOD(tag, out, sizeof(uint64_t));
209 }
210
GetStatelessResetToken(QuicTag tag,StatelessResetToken * out) const211 QuicErrorCode CryptoHandshakeMessage::GetStatelessResetToken(
212 QuicTag tag, StatelessResetToken* out) const {
213 return GetPOD(tag, out, kStatelessResetTokenLength);
214 }
215
size() const216 size_t CryptoHandshakeMessage::size() const {
217 size_t ret = sizeof(QuicTag) + sizeof(uint16_t) /* number of entries */ +
218 sizeof(uint16_t) /* padding */;
219 ret += (sizeof(QuicTag) + sizeof(uint32_t) /* end offset */) *
220 tag_value_map_.size();
221 for (auto i = tag_value_map_.begin(); i != tag_value_map_.end(); ++i) {
222 ret += i->second.size();
223 }
224
225 return ret;
226 }
227
set_minimum_size(size_t min_bytes)228 void CryptoHandshakeMessage::set_minimum_size(size_t min_bytes) {
229 if (min_bytes == minimum_size_) {
230 return;
231 }
232 serialized_.reset();
233 minimum_size_ = min_bytes;
234 }
235
minimum_size() const236 size_t CryptoHandshakeMessage::minimum_size() const { return minimum_size_; }
237
DebugString() const238 std::string CryptoHandshakeMessage::DebugString() const {
239 return DebugStringInternal(0);
240 }
241
GetPOD(QuicTag tag,void * out,size_t len) const242 QuicErrorCode CryptoHandshakeMessage::GetPOD(QuicTag tag, void* out,
243 size_t len) const {
244 auto it = tag_value_map_.find(tag);
245 QuicErrorCode ret = QUIC_NO_ERROR;
246
247 if (it == tag_value_map_.end()) {
248 ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
249 } else if (it->second.size() != len) {
250 ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
251 }
252
253 if (ret != QUIC_NO_ERROR) {
254 memset(out, 0, len);
255 return ret;
256 }
257
258 memcpy(out, it->second.data(), len);
259 return ret;
260 }
261
DebugStringInternal(size_t indent) const262 std::string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const {
263 std::string ret =
264 std::string(2 * indent, ' ') + QuicTagToString(tag_) + "<\n";
265 ++indent;
266 for (auto it = tag_value_map_.begin(); it != tag_value_map_.end(); ++it) {
267 ret += std::string(2 * indent, ' ') + QuicTagToString(it->first) + ": ";
268
269 bool done = false;
270 switch (it->first) {
271 case kICSL:
272 case kCFCW:
273 case kSFCW:
274 case kIRTT:
275 case kMIUS:
276 case kMIBS:
277 case kTCID:
278 case kMAD:
279 // uint32_t value
280 if (it->second.size() == 4) {
281 uint32_t value;
282 memcpy(&value, it->second.data(), sizeof(value));
283 absl::StrAppend(&ret, value);
284 done = true;
285 }
286 break;
287 case kKEXS:
288 case kAEAD:
289 case kCOPT:
290 case kPDMD:
291 case kVER:
292 // tag lists
293 if (it->second.size() % sizeof(QuicTag) == 0) {
294 for (size_t j = 0; j < it->second.size(); j += sizeof(QuicTag)) {
295 QuicTag tag;
296 memcpy(&tag, it->second.data() + j, sizeof(tag));
297 if (j > 0) {
298 ret += ",";
299 }
300 ret += "'" + QuicTagToString(tag) + "'";
301 }
302 done = true;
303 }
304 break;
305 case kRREJ:
306 // uint32_t lists
307 if (it->second.size() % sizeof(uint32_t) == 0) {
308 for (size_t j = 0; j < it->second.size(); j += sizeof(uint32_t)) {
309 uint32_t value;
310 memcpy(&value, it->second.data() + j, sizeof(value));
311 if (j > 0) {
312 ret += ",";
313 }
314 ret += CryptoUtils::HandshakeFailureReasonToString(
315 static_cast<HandshakeFailureReason>(value));
316 }
317 done = true;
318 }
319 break;
320 case kCADR:
321 // IP address and port
322 if (!it->second.empty()) {
323 QuicSocketAddressCoder decoder;
324 if (decoder.Decode(it->second.data(), it->second.size())) {
325 ret += QuicSocketAddress(decoder.ip(), decoder.port()).ToString();
326 done = true;
327 }
328 }
329 break;
330 case kSCFG:
331 // nested messages.
332 if (!it->second.empty()) {
333 std::unique_ptr<CryptoHandshakeMessage> msg(
334 CryptoFramer::ParseMessage(it->second));
335 if (msg) {
336 ret += "\n";
337 ret += msg->DebugStringInternal(indent + 1);
338
339 done = true;
340 }
341 }
342 break;
343 case kPAD:
344 ret += absl::StrFormat("(%d bytes of padding)", it->second.size());
345 done = true;
346 break;
347 case kSNI:
348 case kUAID:
349 ret += "\"" + it->second + "\"";
350 done = true;
351 break;
352 }
353
354 if (!done) {
355 // If there's no specific format for this tag, or the value is invalid,
356 // then just use hex.
357 ret += "0x" + absl::BytesToHexString(it->second);
358 }
359 ret += "\n";
360 }
361 --indent;
362 ret += std::string(2 * indent, ' ') + ">";
363 return ret;
364 }
365
366 } // namespace quic
367