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 QuicTag tag;
123 memcpy(&tag, it->second.data() + i * sizeof(tag), sizeof(tag));
124 (*out_tags)[i] = tag;
125 }
126 return ret;
127 }
128
GetVersionLabelList(QuicTag tag,QuicVersionLabelVector * out) const129 QuicErrorCode CryptoHandshakeMessage::GetVersionLabelList(
130 QuicTag tag, QuicVersionLabelVector* out) const {
131 QuicErrorCode error = GetTaglist(tag, out);
132 if (error != QUIC_NO_ERROR) {
133 return error;
134 }
135
136 for (size_t i = 0; i < out->size(); ++i) {
137 (*out)[i] = quiche::QuicheEndian::HostToNet32((*out)[i]);
138 }
139
140 return QUIC_NO_ERROR;
141 }
142
GetVersionLabel(QuicTag tag,QuicVersionLabel * out) const143 QuicErrorCode CryptoHandshakeMessage::GetVersionLabel(
144 QuicTag tag, QuicVersionLabel* out) const {
145 QuicErrorCode error = GetUint32(tag, out);
146 if (error != QUIC_NO_ERROR) {
147 return error;
148 }
149
150 *out = quiche::QuicheEndian::HostToNet32(*out);
151 return QUIC_NO_ERROR;
152 }
153
GetStringPiece(QuicTag tag,absl::string_view * out) const154 bool CryptoHandshakeMessage::GetStringPiece(QuicTag tag,
155 absl::string_view* out) const {
156 auto it = tag_value_map_.find(tag);
157 if (it == tag_value_map_.end()) {
158 return false;
159 }
160 *out = it->second;
161 return true;
162 }
163
HasStringPiece(QuicTag tag) const164 bool CryptoHandshakeMessage::HasStringPiece(QuicTag tag) const {
165 return tag_value_map_.find(tag) != tag_value_map_.end();
166 }
167
GetNthValue24(QuicTag tag,unsigned index,absl::string_view * out) const168 QuicErrorCode CryptoHandshakeMessage::GetNthValue24(
169 QuicTag tag, unsigned index, absl::string_view* out) const {
170 absl::string_view value;
171 if (!GetStringPiece(tag, &value)) {
172 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
173 }
174
175 for (unsigned i = 0;; i++) {
176 if (value.empty()) {
177 return QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND;
178 }
179 if (value.size() < 3) {
180 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
181 }
182
183 const unsigned char* data =
184 reinterpret_cast<const unsigned char*>(value.data());
185 size_t size = static_cast<size_t>(data[0]) |
186 (static_cast<size_t>(data[1]) << 8) |
187 (static_cast<size_t>(data[2]) << 16);
188 value.remove_prefix(3);
189
190 if (value.size() < size) {
191 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
192 }
193
194 if (i == index) {
195 *out = absl::string_view(value.data(), size);
196 return QUIC_NO_ERROR;
197 }
198
199 value.remove_prefix(size);
200 }
201 }
202
GetUint32(QuicTag tag,uint32_t * out) const203 QuicErrorCode CryptoHandshakeMessage::GetUint32(QuicTag tag,
204 uint32_t* out) const {
205 return GetPOD(tag, out, sizeof(uint32_t));
206 }
207
GetUint64(QuicTag tag,uint64_t * out) const208 QuicErrorCode CryptoHandshakeMessage::GetUint64(QuicTag tag,
209 uint64_t* out) const {
210 return GetPOD(tag, out, sizeof(uint64_t));
211 }
212
GetStatelessResetToken(QuicTag tag,StatelessResetToken * out) const213 QuicErrorCode CryptoHandshakeMessage::GetStatelessResetToken(
214 QuicTag tag, StatelessResetToken* out) const {
215 return GetPOD(tag, out, kStatelessResetTokenLength);
216 }
217
size() const218 size_t CryptoHandshakeMessage::size() const {
219 size_t ret = sizeof(QuicTag) + sizeof(uint16_t) /* number of entries */ +
220 sizeof(uint16_t) /* padding */;
221 ret += (sizeof(QuicTag) + sizeof(uint32_t) /* end offset */) *
222 tag_value_map_.size();
223 for (auto i = tag_value_map_.begin(); i != tag_value_map_.end(); ++i) {
224 ret += i->second.size();
225 }
226
227 return ret;
228 }
229
set_minimum_size(size_t min_bytes)230 void CryptoHandshakeMessage::set_minimum_size(size_t min_bytes) {
231 if (min_bytes == minimum_size_) {
232 return;
233 }
234 serialized_.reset();
235 minimum_size_ = min_bytes;
236 }
237
minimum_size() const238 size_t CryptoHandshakeMessage::minimum_size() const { return minimum_size_; }
239
DebugString() const240 std::string CryptoHandshakeMessage::DebugString() const {
241 return DebugStringInternal(0);
242 }
243
GetPOD(QuicTag tag,void * out,size_t len) const244 QuicErrorCode CryptoHandshakeMessage::GetPOD(QuicTag tag, void* out,
245 size_t len) const {
246 auto it = tag_value_map_.find(tag);
247 QuicErrorCode ret = QUIC_NO_ERROR;
248
249 if (it == tag_value_map_.end()) {
250 ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
251 } else if (it->second.size() != len) {
252 ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
253 }
254
255 if (ret != QUIC_NO_ERROR) {
256 memset(out, 0, len);
257 return ret;
258 }
259
260 memcpy(out, it->second.data(), len);
261 return ret;
262 }
263
DebugStringInternal(size_t indent) const264 std::string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const {
265 std::string ret =
266 std::string(2 * indent, ' ') + QuicTagToString(tag_) + "<\n";
267 ++indent;
268 for (auto it = tag_value_map_.begin(); it != tag_value_map_.end(); ++it) {
269 ret += std::string(2 * indent, ' ') + QuicTagToString(it->first) + ": ";
270
271 bool done = false;
272 switch (it->first) {
273 case kICSL:
274 case kCFCW:
275 case kSFCW:
276 case kIRTT:
277 case kMIUS:
278 case kMIBS:
279 case kTCID:
280 case kMAD:
281 // uint32_t value
282 if (it->second.size() == 4) {
283 uint32_t value;
284 memcpy(&value, it->second.data(), sizeof(value));
285 absl::StrAppend(&ret, value);
286 done = true;
287 }
288 break;
289 case kKEXS:
290 case kAEAD:
291 case kCOPT:
292 case kPDMD:
293 case kVER:
294 // tag lists
295 if (it->second.size() % sizeof(QuicTag) == 0) {
296 for (size_t j = 0; j < it->second.size(); j += sizeof(QuicTag)) {
297 QuicTag tag;
298 memcpy(&tag, it->second.data() + j, sizeof(tag));
299 if (j > 0) {
300 ret += ",";
301 }
302 ret += "'" + QuicTagToString(tag) + "'";
303 }
304 done = true;
305 }
306 break;
307 case kRREJ:
308 // uint32_t lists
309 if (it->second.size() % sizeof(uint32_t) == 0) {
310 for (size_t j = 0; j < it->second.size(); j += sizeof(uint32_t)) {
311 uint32_t value;
312 memcpy(&value, it->second.data() + j, sizeof(value));
313 if (j > 0) {
314 ret += ",";
315 }
316 ret += CryptoUtils::HandshakeFailureReasonToString(
317 static_cast<HandshakeFailureReason>(value));
318 }
319 done = true;
320 }
321 break;
322 case kCADR:
323 // IP address and port
324 if (!it->second.empty()) {
325 QuicSocketAddressCoder decoder;
326 if (decoder.Decode(it->second.data(), it->second.size())) {
327 ret += QuicSocketAddress(decoder.ip(), decoder.port()).ToString();
328 done = true;
329 }
330 }
331 break;
332 case kSCFG:
333 // nested messages.
334 if (!it->second.empty()) {
335 std::unique_ptr<CryptoHandshakeMessage> msg(
336 CryptoFramer::ParseMessage(it->second));
337 if (msg) {
338 ret += "\n";
339 ret += msg->DebugStringInternal(indent + 1);
340
341 done = true;
342 }
343 }
344 break;
345 case kPAD:
346 ret += absl::StrFormat("(%d bytes of padding)", it->second.size());
347 done = true;
348 break;
349 case kSNI:
350 case kUAID:
351 ret += "\"" + it->second + "\"";
352 done = true;
353 break;
354 }
355
356 if (!done) {
357 // If there's no specific format for this tag, or the value is invalid,
358 // then just use hex.
359 ret += "0x" + absl::BytesToHexString(it->second);
360 }
361 ret += "\n";
362 }
363 --indent;
364 ret += std::string(2 * indent, ' ') + ">";
365 return ret;
366 }
367
368 } // namespace quic
369