blob: 9fa4dfa5319c0681c6e4b411262021c1022b4094 [file] [log] [blame]
Bence Békybac04052022-04-07 15:44:29 -04001// 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
21namespace quic {
22
23CryptoHandshakeMessage::CryptoHandshakeMessage() : tag_(0), minimum_size_(0) {}
24
25CryptoHandshakeMessage::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
34CryptoHandshakeMessage::CryptoHandshakeMessage(CryptoHandshakeMessage&& other) =
35 default;
36
37CryptoHandshakeMessage::~CryptoHandshakeMessage() {}
38
39CryptoHandshakeMessage& 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
50CryptoHandshakeMessage& CryptoHandshakeMessage::operator=(
51 CryptoHandshakeMessage&& other) = default;
52
53bool 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
59bool CryptoHandshakeMessage::operator!=(
60 const CryptoHandshakeMessage& rhs) const {
61 return !(*this == rhs);
62}
63
64void CryptoHandshakeMessage::Clear() {
65 tag_ = 0;
66 tag_value_map_.clear();
67 minimum_size_ = 0;
68 serialized_.reset();
69}
70
71const QuicData& CryptoHandshakeMessage::GetSerialized() const {
72 if (!serialized_) {
73 serialized_ = CryptoFramer::ConstructHandshakeMessage(*this);
74 }
75 return *serialized_;
76}
77
bncb91850e2022-04-13 08:34:05 -070078void CryptoHandshakeMessage::MarkDirty() { serialized_.reset(); }
Bence Békybac04052022-04-07 15:44:29 -040079
80void CryptoHandshakeMessage::SetVersionVector(
bncb91850e2022-04-13 08:34:05 -070081 QuicTag tag, ParsedQuicVersionVector versions) {
Bence Békybac04052022-04-07 15:44:29 -040082 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
90void CryptoHandshakeMessage::SetVersion(QuicTag tag,
91 ParsedQuicVersion version) {
92 SetValue(tag,
93 quiche::QuicheEndian::HostToNet32(CreateQuicVersionLabel(version)));
94}
95
96void CryptoHandshakeMessage::SetStringPiece(QuicTag tag,
97 absl::string_view value) {
98 tag_value_map_[tag] = std::string(value);
99}
100
bncb91850e2022-04-13 08:34:05 -0700101void CryptoHandshakeMessage::Erase(QuicTag tag) { tag_value_map_.erase(tag); }
Bence Békybac04052022-04-07 15:44:29 -0400102
103QuicErrorCode CryptoHandshakeMessage::GetTaglist(
bncb91850e2022-04-13 08:34:05 -0700104 QuicTag tag, QuicTagVector* out_tags) const {
Bence Békybac04052022-04-07 15:44:29 -0400105 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
129QuicErrorCode CryptoHandshakeMessage::GetVersionLabelList(
bncb91850e2022-04-13 08:34:05 -0700130 QuicTag tag, QuicVersionLabelVector* out) const {
Bence Békybac04052022-04-07 15:44:29 -0400131 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
143QuicErrorCode CryptoHandshakeMessage::GetVersionLabel(
bncb91850e2022-04-13 08:34:05 -0700144 QuicTag tag, QuicVersionLabel* out) const {
Bence Békybac04052022-04-07 15:44:29 -0400145 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
154bool 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
164bool CryptoHandshakeMessage::HasStringPiece(QuicTag tag) const {
165 return tag_value_map_.find(tag) != tag_value_map_.end();
166}
167
168QuicErrorCode CryptoHandshakeMessage::GetNthValue24(
bncb91850e2022-04-13 08:34:05 -0700169 QuicTag tag, unsigned index, absl::string_view* out) const {
Bence Békybac04052022-04-07 15:44:29 -0400170 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
203QuicErrorCode CryptoHandshakeMessage::GetUint32(QuicTag tag,
204 uint32_t* out) const {
205 return GetPOD(tag, out, sizeof(uint32_t));
206}
207
208QuicErrorCode CryptoHandshakeMessage::GetUint64(QuicTag tag,
209 uint64_t* out) const {
210 return GetPOD(tag, out, sizeof(uint64_t));
211}
212
213QuicErrorCode CryptoHandshakeMessage::GetStatelessResetToken(
bncb91850e2022-04-13 08:34:05 -0700214 QuicTag tag, StatelessResetToken* out) const {
Bence Békybac04052022-04-07 15:44:29 -0400215 return GetPOD(tag, out, kStatelessResetTokenLength);
216}
217
218size_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
230void 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
bncb91850e2022-04-13 08:34:05 -0700238size_t CryptoHandshakeMessage::minimum_size() const { return minimum_size_; }
Bence Békybac04052022-04-07 15:44:29 -0400239
240std::string CryptoHandshakeMessage::DebugString() const {
241 return DebugStringInternal(0);
242}
243
bncb91850e2022-04-13 08:34:05 -0700244QuicErrorCode CryptoHandshakeMessage::GetPOD(QuicTag tag, void* out,
Bence Békybac04052022-04-07 15:44:29 -0400245 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
264std::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