xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/crypto/crypto_handshake_message.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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