blob: 3df9f12a033fabd92d4b11237e62634e67565dc8 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
6
7#include <memory>
vasilvv872e7a32019-03-12 16:42:44 -07008#include <string>
QUICHE teama6ef0a62019-03-07 20:34:33 -05009
10#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h"
11#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
12#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h"
13#include "net/third_party/quiche/src/quic/core/quic_socket_address_coder.h"
14#include "net/third_party/quiche/src/quic/core/quic_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050015#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
QUICHE team173c48f2019-11-19 16:34:44 -080016#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h"
dmcardle904ef182019-12-13 08:34:33 -080017#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
18#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
19#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050020
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
renjietangdef6e342020-04-09 11:30:00 -070053bool 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
dschinazid5361d82020-04-09 12:11:44 -070059bool CryptoHandshakeMessage::operator!=(
60 const CryptoHandshakeMessage& rhs) const {
61 return !(*this == rhs);
62}
63
QUICHE teama6ef0a62019-03-07 20:34:33 -050064void CryptoHandshakeMessage::Clear() {
65 tag_ = 0;
66 tag_value_map_.clear();
67 minimum_size_ = 0;
68 serialized_.reset();
69}
70
71const QuicData& CryptoHandshakeMessage::GetSerialized() const {
wub07a2b072019-10-24 11:23:20 -070072 if (!serialized_) {
QUICHE team3fe6a8b2019-03-14 09:10:38 -070073 serialized_ = CryptoFramer::ConstructHandshakeMessage(*this);
QUICHE teama6ef0a62019-03-07 20:34:33 -050074 }
75 return *serialized_;
76}
77
78void CryptoHandshakeMessage::MarkDirty() {
79 serialized_.reset();
80}
81
82void CryptoHandshakeMessage::SetVersionVector(
83 QuicTag tag,
84 ParsedQuicVersionVector versions) {
85 QuicVersionLabelVector version_labels;
QUICHE team6a5a8aa2020-08-19 14:57:24 -070086 for (const ParsedQuicVersion& version : versions) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050087 version_labels.push_back(
QUICHE team173c48f2019-11-19 16:34:44 -080088 quiche::QuicheEndian::HostToNet32(CreateQuicVersionLabel(version)));
QUICHE teama6ef0a62019-03-07 20:34:33 -050089 }
90 SetVector(tag, version_labels);
91}
92
93void CryptoHandshakeMessage::SetVersion(QuicTag tag,
94 ParsedQuicVersion version) {
QUICHE team173c48f2019-11-19 16:34:44 -080095 SetValue(tag,
96 quiche::QuicheEndian::HostToNet32(CreateQuicVersionLabel(version)));
QUICHE teama6ef0a62019-03-07 20:34:33 -050097}
98
99void CryptoHandshakeMessage::SetStringPiece(QuicTag tag,
dmcardle904ef182019-12-13 08:34:33 -0800100 quiche::QuicheStringPiece value) {
vasilvvc48c8712019-03-11 13:38:16 -0700101 tag_value_map_[tag] = std::string(value);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500102}
103
104void CryptoHandshakeMessage::Erase(QuicTag tag) {
105 tag_value_map_.erase(tag);
106}
107
108QuicErrorCode CryptoHandshakeMessage::GetTaglist(
109 QuicTag tag,
110 QuicTagVector* out_tags) const {
111 auto it = tag_value_map_.find(tag);
112 QuicErrorCode ret = QUIC_NO_ERROR;
113
114 if (it == tag_value_map_.end()) {
115 ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
116 } else if (it->second.size() % sizeof(QuicTag) != 0) {
117 ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
118 }
119
120 if (ret != QUIC_NO_ERROR) {
121 out_tags->clear();
122 return ret;
123 }
124
125 size_t num_tags = it->second.size() / sizeof(QuicTag);
126 out_tags->resize(num_tags);
127 for (size_t i = 0; i < num_tags; ++i) {
128 QuicTag tag;
129 memcpy(&tag, it->second.data() + i * sizeof(tag), sizeof(tag));
130 (*out_tags)[i] = tag;
131 }
132 return ret;
133}
134
135QuicErrorCode CryptoHandshakeMessage::GetVersionLabelList(
136 QuicTag tag,
137 QuicVersionLabelVector* out) const {
138 QuicErrorCode error = GetTaglist(tag, out);
139 if (error != QUIC_NO_ERROR) {
140 return error;
141 }
142
143 for (size_t i = 0; i < out->size(); ++i) {
QUICHE team173c48f2019-11-19 16:34:44 -0800144 (*out)[i] = quiche::QuicheEndian::HostToNet32((*out)[i]);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500145 }
146
147 return QUIC_NO_ERROR;
148}
149
150QuicErrorCode CryptoHandshakeMessage::GetVersionLabel(
151 QuicTag tag,
152 QuicVersionLabel* out) const {
153 QuicErrorCode error = GetUint32(tag, out);
154 if (error != QUIC_NO_ERROR) {
155 return error;
156 }
157
QUICHE team173c48f2019-11-19 16:34:44 -0800158 *out = quiche::QuicheEndian::HostToNet32(*out);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500159 return QUIC_NO_ERROR;
160}
161
dmcardle904ef182019-12-13 08:34:33 -0800162bool CryptoHandshakeMessage::GetStringPiece(
163 QuicTag tag,
164 quiche::QuicheStringPiece* out) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500165 auto it = tag_value_map_.find(tag);
166 if (it == tag_value_map_.end()) {
167 return false;
168 }
169 *out = it->second;
170 return true;
171}
172
173bool CryptoHandshakeMessage::HasStringPiece(QuicTag tag) const {
174 return QuicContainsKey(tag_value_map_, tag);
175}
176
177QuicErrorCode CryptoHandshakeMessage::GetNthValue24(
178 QuicTag tag,
179 unsigned index,
dmcardle904ef182019-12-13 08:34:33 -0800180 quiche::QuicheStringPiece* out) const {
181 quiche::QuicheStringPiece value;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500182 if (!GetStringPiece(tag, &value)) {
183 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
184 }
185
186 for (unsigned i = 0;; i++) {
187 if (value.empty()) {
188 return QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND;
189 }
190 if (value.size() < 3) {
191 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
192 }
193
194 const unsigned char* data =
195 reinterpret_cast<const unsigned char*>(value.data());
196 size_t size = static_cast<size_t>(data[0]) |
197 (static_cast<size_t>(data[1]) << 8) |
198 (static_cast<size_t>(data[2]) << 16);
199 value.remove_prefix(3);
200
201 if (value.size() < size) {
202 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
203 }
204
205 if (i == index) {
dmcardle904ef182019-12-13 08:34:33 -0800206 *out = quiche::QuicheStringPiece(value.data(), size);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500207 return QUIC_NO_ERROR;
208 }
209
210 value.remove_prefix(size);
211 }
212}
213
214QuicErrorCode CryptoHandshakeMessage::GetUint32(QuicTag tag,
215 uint32_t* out) const {
216 return GetPOD(tag, out, sizeof(uint32_t));
217}
218
219QuicErrorCode CryptoHandshakeMessage::GetUint64(QuicTag tag,
220 uint64_t* out) const {
221 return GetPOD(tag, out, sizeof(uint64_t));
222}
223
224QuicErrorCode CryptoHandshakeMessage::GetUint128(QuicTag tag,
225 QuicUint128* out) const {
226 return GetPOD(tag, out, sizeof(QuicUint128));
227}
228
229size_t CryptoHandshakeMessage::size() const {
230 size_t ret = sizeof(QuicTag) + sizeof(uint16_t) /* number of entries */ +
231 sizeof(uint16_t) /* padding */;
232 ret += (sizeof(QuicTag) + sizeof(uint32_t) /* end offset */) *
233 tag_value_map_.size();
234 for (auto i = tag_value_map_.begin(); i != tag_value_map_.end(); ++i) {
235 ret += i->second.size();
236 }
237
238 return ret;
239}
240
241void CryptoHandshakeMessage::set_minimum_size(size_t min_bytes) {
242 if (min_bytes == minimum_size_) {
243 return;
244 }
245 serialized_.reset();
246 minimum_size_ = min_bytes;
247}
248
249size_t CryptoHandshakeMessage::minimum_size() const {
250 return minimum_size_;
251}
252
vasilvvc48c8712019-03-11 13:38:16 -0700253std::string CryptoHandshakeMessage::DebugString() const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500254 return DebugStringInternal(0);
255}
256
257QuicErrorCode CryptoHandshakeMessage::GetPOD(QuicTag tag,
258 void* out,
259 size_t len) const {
260 auto it = tag_value_map_.find(tag);
261 QuicErrorCode ret = QUIC_NO_ERROR;
262
263 if (it == tag_value_map_.end()) {
264 ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
265 } else if (it->second.size() != len) {
266 ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
267 }
268
269 if (ret != QUIC_NO_ERROR) {
270 memset(out, 0, len);
271 return ret;
272 }
273
274 memcpy(out, it->second.data(), len);
275 return ret;
276}
277
vasilvvc48c8712019-03-11 13:38:16 -0700278std::string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const {
279 std::string ret =
280 std::string(2 * indent, ' ') + QuicTagToString(tag_) + "<\n";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500281 ++indent;
282 for (auto it = tag_value_map_.begin(); it != tag_value_map_.end(); ++it) {
vasilvvc48c8712019-03-11 13:38:16 -0700283 ret += std::string(2 * indent, ' ') + QuicTagToString(it->first) + ": ";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500284
285 bool done = false;
286 switch (it->first) {
287 case kICSL:
288 case kCFCW:
289 case kSFCW:
290 case kIRTT:
fkastenholzd3a1de92019-05-15 07:00:07 -0700291 case kMIUS:
292 case kMIBS:
QUICHE teama6ef0a62019-03-07 20:34:33 -0500293 case kTCID:
fkastenholz4c7303c2019-07-29 08:17:07 -0700294 case kMAD:
QUICHE teama6ef0a62019-03-07 20:34:33 -0500295 // uint32_t value
296 if (it->second.size() == 4) {
297 uint32_t value;
298 memcpy(&value, it->second.data(), sizeof(value));
dmcardle904ef182019-12-13 08:34:33 -0800299 ret += quiche::QuicheTextUtils::Uint64ToString(value);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500300 done = true;
301 }
302 break;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500303 case kKEXS:
304 case kAEAD:
305 case kCOPT:
306 case kPDMD:
307 case kVER:
308 // tag lists
309 if (it->second.size() % sizeof(QuicTag) == 0) {
310 for (size_t j = 0; j < it->second.size(); j += sizeof(QuicTag)) {
311 QuicTag tag;
312 memcpy(&tag, it->second.data() + j, sizeof(tag));
313 if (j > 0) {
314 ret += ",";
315 }
316 ret += "'" + QuicTagToString(tag) + "'";
317 }
318 done = true;
319 }
320 break;
321 case kRREJ:
322 // uint32_t lists
323 if (it->second.size() % sizeof(uint32_t) == 0) {
324 for (size_t j = 0; j < it->second.size(); j += sizeof(uint32_t)) {
325 uint32_t value;
326 memcpy(&value, it->second.data() + j, sizeof(value));
327 if (j > 0) {
328 ret += ",";
329 }
330 ret += CryptoUtils::HandshakeFailureReasonToString(
331 static_cast<HandshakeFailureReason>(value));
332 }
333 done = true;
334 }
335 break;
336 case kCADR:
337 // IP address and port
338 if (!it->second.empty()) {
339 QuicSocketAddressCoder decoder;
340 if (decoder.Decode(it->second.data(), it->second.size())) {
341 ret += QuicSocketAddress(decoder.ip(), decoder.port()).ToString();
342 done = true;
343 }
344 }
345 break;
346 case kSCFG:
347 // nested messages.
348 if (!it->second.empty()) {
349 std::unique_ptr<CryptoHandshakeMessage> msg(
350 CryptoFramer::ParseMessage(it->second));
351 if (msg) {
352 ret += "\n";
353 ret += msg->DebugStringInternal(indent + 1);
354
355 done = true;
356 }
357 }
358 break;
359 case kPAD:
dmcardle904ef182019-12-13 08:34:33 -0800360 ret += quiche::QuicheStringPrintf("(%d bytes of padding)",
361 static_cast<int>(it->second.size()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500362 done = true;
363 break;
364 case kSNI:
365 case kUAID:
366 ret += "\"" + it->second + "\"";
367 done = true;
368 break;
369 }
370
371 if (!done) {
372 // If there's no specific format for this tag, or the value is invalid,
373 // then just use hex.
dmcardle904ef182019-12-13 08:34:33 -0800374 ret += "0x" + quiche::QuicheTextUtils::HexEncode(it->second);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500375 }
376 ret += "\n";
377 }
378 --indent;
vasilvvc48c8712019-03-11 13:38:16 -0700379 ret += std::string(2 * indent, ' ') + ">";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500380 return ret;
381}
382
383} // namespace quic