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.
5 #include "net/quic/crypto/crypto_handshake_message.h"
7 #include "base/strings/stringprintf.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "net/quic/crypto/crypto_framer.h"
10 #include "net/quic/crypto/crypto_protocol.h"
11 #include "net/quic/quic_socket_address_coder.h"
12 #include "net/quic/quic_utils.h"
14 using base::StringPiece
;
15 using base::StringPrintf
;
21 CryptoHandshakeMessage::CryptoHandshakeMessage()
25 CryptoHandshakeMessage::CryptoHandshakeMessage(
26 const CryptoHandshakeMessage
& other
)
28 tag_value_map_(other
.tag_value_map_
),
29 minimum_size_(other
.minimum_size_
) {
30 // Don't copy serialized_. scoped_ptr doesn't have a copy constructor.
31 // The new object can lazily reconstruct serialized_.
34 CryptoHandshakeMessage::~CryptoHandshakeMessage() {}
36 CryptoHandshakeMessage
& CryptoHandshakeMessage::operator=(
37 const CryptoHandshakeMessage
& other
) {
39 tag_value_map_
= other
.tag_value_map_
;
40 // Don't copy serialized_. scoped_ptr doesn't have an assignment operator.
41 // However, invalidate serialized_.
43 minimum_size_
= other
.minimum_size_
;
47 void CryptoHandshakeMessage::Clear() {
49 tag_value_map_
.clear();
54 const QuicData
& CryptoHandshakeMessage::GetSerialized() const {
55 if (!serialized_
.get()) {
56 serialized_
.reset(CryptoFramer::ConstructHandshakeMessage(*this));
61 void CryptoHandshakeMessage::MarkDirty() {
65 void CryptoHandshakeMessage::SetTaglist(QuicTag tag
, ...) {
66 // Warning, if sizeof(QuicTag) > sizeof(int) then this function will break
67 // because the terminating 0 will only be promoted to int.
68 static_assert(sizeof(QuicTag
) <= sizeof(int),
69 "crypto tag may not be larger than int or varargs will break");
76 QuicTag list_item
= va_arg(ap
, QuicTag
);
80 tags
.push_back(list_item
);
83 // Because of the way that we keep tags in memory, we can copy the contents
84 // of the vector and get the correct bytes in wire format. See
85 // crypto_protocol.h. This assumes that the system is little-endian.
91 void CryptoHandshakeMessage::SetStringPiece(QuicTag tag
, StringPiece value
) {
92 tag_value_map_
[tag
] = value
.as_string();
95 void CryptoHandshakeMessage::Erase(QuicTag tag
) {
96 tag_value_map_
.erase(tag
);
99 QuicErrorCode
CryptoHandshakeMessage::GetTaglist(QuicTag tag
,
100 const QuicTag
** out_tags
,
101 size_t* out_len
) const {
102 QuicTagValueMap::const_iterator it
= tag_value_map_
.find(tag
);
103 QuicErrorCode ret
= QUIC_NO_ERROR
;
105 if (it
== tag_value_map_
.end()) {
106 ret
= QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
;
107 } else if (it
->second
.size() % sizeof(QuicTag
) != 0) {
108 ret
= QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
111 if (ret
!= QUIC_NO_ERROR
) {
117 *out_tags
= reinterpret_cast<const QuicTag
*>(it
->second
.data());
118 *out_len
= it
->second
.size() / sizeof(QuicTag
);
122 bool CryptoHandshakeMessage::GetStringPiece(QuicTag tag
,
123 StringPiece
* out
) const {
124 QuicTagValueMap::const_iterator it
= tag_value_map_
.find(tag
);
125 if (it
== tag_value_map_
.end()) {
132 QuicErrorCode
CryptoHandshakeMessage::GetNthValue24(QuicTag tag
,
134 StringPiece
* out
) const {
136 if (!GetStringPiece(tag
, &value
)) {
137 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
;
140 for (unsigned i
= 0;; i
++) {
142 return QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND
;
144 if (value
.size() < 3) {
145 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
148 const unsigned char* data
=
149 reinterpret_cast<const unsigned char*>(value
.data());
150 size_t size
= static_cast<size_t>(data
[0]) |
151 (static_cast<size_t>(data
[1]) << 8) |
152 (static_cast<size_t>(data
[2]) << 16);
153 value
.remove_prefix(3);
155 if (value
.size() < size
) {
156 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
160 *out
= StringPiece(value
.data(), size
);
161 return QUIC_NO_ERROR
;
164 value
.remove_prefix(size
);
168 QuicErrorCode
CryptoHandshakeMessage::GetUint32(QuicTag tag
,
170 return GetPOD(tag
, out
, sizeof(uint32
));
173 QuicErrorCode
CryptoHandshakeMessage::GetUint64(QuicTag tag
,
175 return GetPOD(tag
, out
, sizeof(uint64
));
178 size_t CryptoHandshakeMessage::size() const {
179 size_t ret
= sizeof(QuicTag
) +
180 sizeof(uint16
) /* number of entries */ +
181 sizeof(uint16
) /* padding */;
182 ret
+= (sizeof(QuicTag
) + sizeof(uint32
) /* end offset */) *
183 tag_value_map_
.size();
184 for (QuicTagValueMap::const_iterator i
= tag_value_map_
.begin();
185 i
!= tag_value_map_
.end(); ++i
) {
186 ret
+= i
->second
.size();
192 void CryptoHandshakeMessage::set_minimum_size(size_t min_bytes
) {
193 if (min_bytes
== minimum_size_
) {
197 minimum_size_
= min_bytes
;
200 size_t CryptoHandshakeMessage::minimum_size() const {
201 return minimum_size_
;
204 string
CryptoHandshakeMessage::DebugString() const {
205 return DebugStringInternal(0);
208 QuicErrorCode
CryptoHandshakeMessage::GetPOD(
209 QuicTag tag
, void* out
, size_t len
) const {
210 QuicTagValueMap::const_iterator it
= tag_value_map_
.find(tag
);
211 QuicErrorCode ret
= QUIC_NO_ERROR
;
213 if (it
== tag_value_map_
.end()) {
214 ret
= QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
;
215 } else if (it
->second
.size() != len
) {
216 ret
= QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
219 if (ret
!= QUIC_NO_ERROR
) {
224 memcpy(out
, it
->second
.data(), len
);
228 string
CryptoHandshakeMessage::DebugStringInternal(size_t indent
) const {
229 string ret
= string(2 * indent
, ' ') + QuicUtils::TagToString(tag_
) + "<\n";
231 for (QuicTagValueMap::const_iterator it
= tag_value_map_
.begin();
232 it
!= tag_value_map_
.end(); ++it
) {
233 ret
+= string(2 * indent
, ' ') + QuicUtils::TagToString(it
->first
) + ": ";
245 if (it
->second
.size() == 4) {
247 memcpy(&value
, it
->second
.data(), sizeof(value
));
248 ret
+= base::UintToString(value
);
258 if (it
->second
.size() % sizeof(QuicTag
) == 0) {
259 for (size_t j
= 0; j
< it
->second
.size(); j
+= sizeof(QuicTag
)) {
261 memcpy(&tag
, it
->second
.data() + j
, sizeof(tag
));
265 ret
+= "'" + QuicUtils::TagToString(tag
) + "'";
271 // IP address and port
272 if (!it
->second
.empty()) {
273 QuicSocketAddressCoder decoder
;
274 if (decoder
.Decode(it
->second
.data(), it
->second
.size())) {
275 ret
+= IPAddressToStringWithPort(decoder
.ip(), decoder
.port());
282 if (!it
->second
.empty()) {
283 scoped_ptr
<CryptoHandshakeMessage
> msg(
284 CryptoFramer::ParseMessage(it
->second
));
287 ret
+= msg
->DebugStringInternal(indent
+ 1);
294 ret
+= StringPrintf("(%d bytes of padding)",
295 static_cast<int>(it
->second
.size()));
300 ret
+= "\"" + it
->second
+ "\"";
306 // If there's no specific format for this tag, or the value is invalid,
307 // then just use hex.
308 ret
+= "0x" + base::HexEncode(it
->second
.data(), it
->second
.size());
313 ret
+= string(2 * indent
, ' ') + ">";