blob: d5b4635d1d46f3cd1b3a4963038df06108e8ed77 [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
53void CryptoHandshakeMessage::Clear() {
54 tag_ = 0;
55 tag_value_map_.clear();
56 minimum_size_ = 0;
57 serialized_.reset();
58}
59
60const QuicData& CryptoHandshakeMessage::GetSerialized() const {
wub07a2b072019-10-24 11:23:20 -070061 if (!serialized_) {
QUICHE team3fe6a8b2019-03-14 09:10:38 -070062 serialized_ = CryptoFramer::ConstructHandshakeMessage(*this);
QUICHE teama6ef0a62019-03-07 20:34:33 -050063 }
64 return *serialized_;
65}
66
67void CryptoHandshakeMessage::MarkDirty() {
68 serialized_.reset();
69}
70
71void CryptoHandshakeMessage::SetVersionVector(
72 QuicTag tag,
73 ParsedQuicVersionVector versions) {
74 QuicVersionLabelVector version_labels;
75 for (ParsedQuicVersion version : versions) {
76 version_labels.push_back(
QUICHE team173c48f2019-11-19 16:34:44 -080077 quiche::QuicheEndian::HostToNet32(CreateQuicVersionLabel(version)));
QUICHE teama6ef0a62019-03-07 20:34:33 -050078 }
79 SetVector(tag, version_labels);
80}
81
82void CryptoHandshakeMessage::SetVersion(QuicTag tag,
83 ParsedQuicVersion version) {
QUICHE team173c48f2019-11-19 16:34:44 -080084 SetValue(tag,
85 quiche::QuicheEndian::HostToNet32(CreateQuicVersionLabel(version)));
QUICHE teama6ef0a62019-03-07 20:34:33 -050086}
87
88void CryptoHandshakeMessage::SetStringPiece(QuicTag tag,
dmcardle904ef182019-12-13 08:34:33 -080089 quiche::QuicheStringPiece value) {
vasilvvc48c8712019-03-11 13:38:16 -070090 tag_value_map_[tag] = std::string(value);
QUICHE teama6ef0a62019-03-07 20:34:33 -050091}
92
93void CryptoHandshakeMessage::Erase(QuicTag tag) {
94 tag_value_map_.erase(tag);
95}
96
97QuicErrorCode CryptoHandshakeMessage::GetTaglist(
98 QuicTag tag,
99 QuicTagVector* out_tags) const {
100 auto it = tag_value_map_.find(tag);
101 QuicErrorCode ret = QUIC_NO_ERROR;
102
103 if (it == tag_value_map_.end()) {
104 ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
105 } else if (it->second.size() % sizeof(QuicTag) != 0) {
106 ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
107 }
108
109 if (ret != QUIC_NO_ERROR) {
110 out_tags->clear();
111 return ret;
112 }
113
114 size_t num_tags = it->second.size() / sizeof(QuicTag);
115 out_tags->resize(num_tags);
116 for (size_t i = 0; i < num_tags; ++i) {
117 QuicTag tag;
118 memcpy(&tag, it->second.data() + i * sizeof(tag), sizeof(tag));
119 (*out_tags)[i] = tag;
120 }
121 return ret;
122}
123
124QuicErrorCode CryptoHandshakeMessage::GetVersionLabelList(
125 QuicTag tag,
126 QuicVersionLabelVector* out) const {
127 QuicErrorCode error = GetTaglist(tag, out);
128 if (error != QUIC_NO_ERROR) {
129 return error;
130 }
131
132 for (size_t i = 0; i < out->size(); ++i) {
QUICHE team173c48f2019-11-19 16:34:44 -0800133 (*out)[i] = quiche::QuicheEndian::HostToNet32((*out)[i]);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500134 }
135
136 return QUIC_NO_ERROR;
137}
138
139QuicErrorCode CryptoHandshakeMessage::GetVersionLabel(
140 QuicTag tag,
141 QuicVersionLabel* out) const {
142 QuicErrorCode error = GetUint32(tag, out);
143 if (error != QUIC_NO_ERROR) {
144 return error;
145 }
146
QUICHE team173c48f2019-11-19 16:34:44 -0800147 *out = quiche::QuicheEndian::HostToNet32(*out);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500148 return QUIC_NO_ERROR;
149}
150
dmcardle904ef182019-12-13 08:34:33 -0800151bool CryptoHandshakeMessage::GetStringPiece(
152 QuicTag tag,
153 quiche::QuicheStringPiece* out) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500154 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
162bool CryptoHandshakeMessage::HasStringPiece(QuicTag tag) const {
163 return QuicContainsKey(tag_value_map_, tag);
164}
165
166QuicErrorCode CryptoHandshakeMessage::GetNthValue24(
167 QuicTag tag,
168 unsigned index,
dmcardle904ef182019-12-13 08:34:33 -0800169 quiche::QuicheStringPiece* out) const {
170 quiche::QuicheStringPiece value;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500171 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) {
dmcardle904ef182019-12-13 08:34:33 -0800195 *out = quiche::QuicheStringPiece(value.data(), size);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500196 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::GetUint128(QuicTag tag,
214 QuicUint128* out) const {
215 return GetPOD(tag, out, sizeof(QuicUint128));
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
238size_t CryptoHandshakeMessage::minimum_size() const {
239 return minimum_size_;
240}
241
vasilvvc48c8712019-03-11 13:38:16 -0700242std::string CryptoHandshakeMessage::DebugString() const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500243 return DebugStringInternal(0);
244}
245
246QuicErrorCode CryptoHandshakeMessage::GetPOD(QuicTag tag,
247 void* out,
248 size_t len) const {
249 auto it = tag_value_map_.find(tag);
250 QuicErrorCode ret = QUIC_NO_ERROR;
251
252 if (it == tag_value_map_.end()) {
253 ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
254 } else if (it->second.size() != len) {
255 ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
256 }
257
258 if (ret != QUIC_NO_ERROR) {
259 memset(out, 0, len);
260 return ret;
261 }
262
263 memcpy(out, it->second.data(), len);
264 return ret;
265}
266
vasilvvc48c8712019-03-11 13:38:16 -0700267std::string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const {
268 std::string ret =
269 std::string(2 * indent, ' ') + QuicTagToString(tag_) + "<\n";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500270 ++indent;
271 for (auto it = tag_value_map_.begin(); it != tag_value_map_.end(); ++it) {
vasilvvc48c8712019-03-11 13:38:16 -0700272 ret += std::string(2 * indent, ' ') + QuicTagToString(it->first) + ": ";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500273
274 bool done = false;
275 switch (it->first) {
276 case kICSL:
277 case kCFCW:
278 case kSFCW:
279 case kIRTT:
fkastenholzd3a1de92019-05-15 07:00:07 -0700280 case kMIUS:
281 case kMIBS:
QUICHE teama6ef0a62019-03-07 20:34:33 -0500282 case kSCLS:
283 case kTCID:
fkastenholz4c7303c2019-07-29 08:17:07 -0700284 case kMAD:
QUICHE teama6ef0a62019-03-07 20:34:33 -0500285 // uint32_t value
286 if (it->second.size() == 4) {
287 uint32_t value;
288 memcpy(&value, it->second.data(), sizeof(value));
dmcardle904ef182019-12-13 08:34:33 -0800289 ret += quiche::QuicheTextUtils::Uint64ToString(value);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500290 done = true;
291 }
292 break;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500293 case kKEXS:
294 case kAEAD:
295 case kCOPT:
296 case kPDMD:
297 case kVER:
298 // tag lists
299 if (it->second.size() % sizeof(QuicTag) == 0) {
300 for (size_t j = 0; j < it->second.size(); j += sizeof(QuicTag)) {
301 QuicTag tag;
302 memcpy(&tag, it->second.data() + j, sizeof(tag));
303 if (j > 0) {
304 ret += ",";
305 }
306 ret += "'" + QuicTagToString(tag) + "'";
307 }
308 done = true;
309 }
310 break;
311 case kRREJ:
312 // uint32_t lists
313 if (it->second.size() % sizeof(uint32_t) == 0) {
314 for (size_t j = 0; j < it->second.size(); j += sizeof(uint32_t)) {
315 uint32_t value;
316 memcpy(&value, it->second.data() + j, sizeof(value));
317 if (j > 0) {
318 ret += ",";
319 }
320 ret += CryptoUtils::HandshakeFailureReasonToString(
321 static_cast<HandshakeFailureReason>(value));
322 }
323 done = true;
324 }
325 break;
326 case kCADR:
327 // IP address and port
328 if (!it->second.empty()) {
329 QuicSocketAddressCoder decoder;
330 if (decoder.Decode(it->second.data(), it->second.size())) {
331 ret += QuicSocketAddress(decoder.ip(), decoder.port()).ToString();
332 done = true;
333 }
334 }
335 break;
336 case kSCFG:
337 // nested messages.
338 if (!it->second.empty()) {
339 std::unique_ptr<CryptoHandshakeMessage> msg(
340 CryptoFramer::ParseMessage(it->second));
341 if (msg) {
342 ret += "\n";
343 ret += msg->DebugStringInternal(indent + 1);
344
345 done = true;
346 }
347 }
348 break;
349 case kPAD:
dmcardle904ef182019-12-13 08:34:33 -0800350 ret += quiche::QuicheStringPrintf("(%d bytes of padding)",
351 static_cast<int>(it->second.size()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500352 done = true;
353 break;
354 case kSNI:
355 case kUAID:
356 ret += "\"" + it->second + "\"";
357 done = true;
358 break;
359 }
360
361 if (!done) {
362 // If there's no specific format for this tag, or the value is invalid,
363 // then just use hex.
dmcardle904ef182019-12-13 08:34:33 -0800364 ret += "0x" + quiche::QuicheTextUtils::HexEncode(it->second);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500365 }
366 ret += "\n";
367 }
368 --indent;
vasilvvc48c8712019-03-11 13:38:16 -0700369 ret += std::string(2 * indent, ' ') + ">";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500370 return ret;
371}
372
373} // namespace quic