blob: f446ac837c6be28aeabe3490c04d99fa87f23bd9 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright 2018 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/quic_connection_id.h"
6
dschinazi0fdff8e2019-07-18 09:07:39 -07007#include <cstddef>
QUICHE teama6ef0a62019-03-07 20:34:33 -05008#include <cstdint>
9#include <cstring>
10#include <iomanip>
vasilvv872e7a32019-03-12 16:42:44 -070011#include <string>
QUICHE teama6ef0a62019-03-07 20:34:33 -050012
dschinazi0fdff8e2019-07-18 09:07:39 -070013#include "third_party/boringssl/src/include/openssl/siphash.h"
14#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050015#include "net/third_party/quiche/src/quic/core/quic_types.h"
16#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
17#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
18#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
19#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
20#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050021#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
22
23namespace quic {
24
dschinazi0fdff8e2019-07-18 09:07:39 -070025namespace {
26
27// QuicConnectionIdHasher can be used to generate a stable connection ID hash
28// function that will return the same value for two equal connection IDs for
29// the duration of process lifetime. It is meant to be used as input to data
30// structures that do not outlast process lifetime. A new key is generated once
31// per process to prevent attackers from crafting connection IDs in such a way
32// that they always land in the same hash bucket.
33class QuicConnectionIdHasher {
34 public:
35 explicit inline QuicConnectionIdHasher()
36 : QuicConnectionIdHasher(QuicRandom::GetInstance()) {}
37
38 explicit inline QuicConnectionIdHasher(QuicRandom* random) {
39 random->RandBytes(&sip_hash_key_, sizeof(sip_hash_key_));
40 }
41
42 inline size_t Hash(const char* input, size_t input_len) const {
43 return static_cast<size_t>(SIPHASH_24(
44 sip_hash_key_, reinterpret_cast<const uint8_t*>(input), input_len));
45 }
46
47 private:
48 uint64_t sip_hash_key_[2];
49};
50
51} // namespace
52
dschinazib3241162019-06-10 17:59:37 -070053QuicConnectionId::QuicConnectionId() : QuicConnectionId(nullptr, 0) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -050054
55QuicConnectionId::QuicConnectionId(const char* data, uint8_t length) {
dschinazib3241162019-06-10 17:59:37 -070056 static_assert(
57 kQuicMaxConnectionIdLength <= std::numeric_limits<uint8_t>::max(),
58 "kQuicMaxConnectionIdLength too high");
QUICHE teama6ef0a62019-03-07 20:34:33 -050059 if (length > kQuicMaxConnectionIdLength) {
60 QUIC_BUG << "Attempted to create connection ID of length " << length;
61 length = kQuicMaxConnectionIdLength;
62 }
63 length_ = length;
dschinazib3241162019-06-10 17:59:37 -070064 if (length_ == 0) {
65 return;
66 }
67 if (!GetQuicRestartFlag(quic_use_allocated_connection_ids)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050068 memcpy(data_, data, length_);
dschinazib3241162019-06-10 17:59:37 -070069 return;
70 }
dschinazi6abd56b2019-06-18 18:04:30 -070071 QUIC_RESTART_FLAG_COUNT_N(quic_use_allocated_connection_ids, 1, 6);
dschinazib3241162019-06-10 17:59:37 -070072 if (length_ <= sizeof(data_short_)) {
73 memcpy(data_short_, data, length_);
74 return;
75 }
76 data_long_ = reinterpret_cast<char*>(malloc(length_));
77 CHECK_NE(nullptr, data_long_);
78 memcpy(data_long_, data, length_);
79}
80
81QuicConnectionId::~QuicConnectionId() {
82 if (!GetQuicRestartFlag(quic_use_allocated_connection_ids)) {
83 return;
84 }
dschinazi6abd56b2019-06-18 18:04:30 -070085 QUIC_RESTART_FLAG_COUNT_N(quic_use_allocated_connection_ids, 2, 6);
dschinazib3241162019-06-10 17:59:37 -070086 if (length_ > sizeof(data_short_)) {
87 free(data_long_);
88 data_long_ = nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -050089 }
90}
91
dschinazib3241162019-06-10 17:59:37 -070092QuicConnectionId::QuicConnectionId(const QuicConnectionId& other)
93 : QuicConnectionId(other.data(), other.length()) {}
94
95QuicConnectionId& QuicConnectionId::operator=(const QuicConnectionId& other) {
96 set_length(other.length());
97 memcpy(mutable_data(), other.data(), length_);
98 return *this;
99}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500100
101const char* QuicConnectionId::data() const {
dschinazib3241162019-06-10 17:59:37 -0700102 if (!GetQuicRestartFlag(quic_use_allocated_connection_ids)) {
103 return data_;
104 }
dschinazi6abd56b2019-06-18 18:04:30 -0700105 QUIC_RESTART_FLAG_COUNT_N(quic_use_allocated_connection_ids, 3, 6);
dschinazib3241162019-06-10 17:59:37 -0700106 if (length_ <= sizeof(data_short_)) {
107 return data_short_;
108 }
109 return data_long_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500110}
111
112char* QuicConnectionId::mutable_data() {
dschinazib3241162019-06-10 17:59:37 -0700113 if (!GetQuicRestartFlag(quic_use_allocated_connection_ids)) {
114 return data_;
115 }
dschinazi6abd56b2019-06-18 18:04:30 -0700116 QUIC_RESTART_FLAG_COUNT_N(quic_use_allocated_connection_ids, 4, 6);
dschinazib3241162019-06-10 17:59:37 -0700117 if (length_ <= sizeof(data_short_)) {
118 return data_short_;
119 }
120 return data_long_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500121}
122
123uint8_t QuicConnectionId::length() const {
124 return length_;
125}
126
127void QuicConnectionId::set_length(uint8_t length) {
dschinazib3241162019-06-10 17:59:37 -0700128 if (GetQuicRestartFlag(quic_use_allocated_connection_ids)) {
dschinazi6abd56b2019-06-18 18:04:30 -0700129 QUIC_RESTART_FLAG_COUNT_N(quic_use_allocated_connection_ids, 5, 6);
dschinazib3241162019-06-10 17:59:37 -0700130 char temporary_data[sizeof(data_short_)];
131 if (length > sizeof(data_short_)) {
132 if (length_ <= sizeof(data_short_)) {
133 // Copy data from data_short_ to data_long_.
134 memcpy(temporary_data, data_short_, length_);
135 data_long_ = reinterpret_cast<char*>(malloc(length));
136 CHECK_NE(nullptr, data_long_);
137 memcpy(data_long_, temporary_data, length_);
138 } else {
139 // Resize data_long_.
140 char* realloc_result =
141 reinterpret_cast<char*>(realloc(data_long_, length));
142 CHECK_NE(nullptr, realloc_result);
143 data_long_ = realloc_result;
144 }
145 } else if (length_ > sizeof(data_short_)) {
146 // Copy data from data_long_ to data_short_.
147 memcpy(temporary_data, data_long_, length);
148 free(data_long_);
149 data_long_ = nullptr;
150 memcpy(data_short_, temporary_data, length);
151 }
152 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500153 length_ = length;
154}
155
156bool QuicConnectionId::IsEmpty() const {
157 return length_ == 0;
158}
159
160size_t QuicConnectionId::Hash() const {
dschinazi0fdff8e2019-07-18 09:07:39 -0700161 if (!GetQuicRestartFlag(quic_connection_id_use_siphash)) {
162 uint64_t data_bytes[3] = {0, 0, 0};
163 static_assert(sizeof(data_bytes) >= kQuicMaxConnectionIdLength,
164 "kQuicMaxConnectionIdLength changed");
165 memcpy(data_bytes, data(), length_);
166 // This Hash function is designed to return the same value as the host byte
167 // order representation when the connection ID length is 64 bits.
168 return QuicEndian::NetToHost64(kQuicDefaultConnectionIdLength ^ length_ ^
169 data_bytes[0] ^ data_bytes[1] ^
170 data_bytes[2]);
171 }
172 QUIC_RESTART_FLAG_COUNT(quic_connection_id_use_siphash);
173 static const QuicConnectionIdHasher hasher = QuicConnectionIdHasher();
174 return hasher.Hash(data(), length_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500175}
176
vasilvvc48c8712019-03-11 13:38:16 -0700177std::string QuicConnectionId::ToString() const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500178 if (IsEmpty()) {
vasilvvc48c8712019-03-11 13:38:16 -0700179 return std::string("0");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500180 }
dschinazib3241162019-06-10 17:59:37 -0700181 return QuicTextUtils::HexEncode(data(), length_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500182}
183
184std::ostream& operator<<(std::ostream& os, const QuicConnectionId& v) {
185 os << v.ToString();
186 return os;
187}
188
189bool QuicConnectionId::operator==(const QuicConnectionId& v) const {
dschinazib3241162019-06-10 17:59:37 -0700190 return length_ == v.length_ && memcmp(data(), v.data(), length_) == 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500191}
192
193bool QuicConnectionId::operator!=(const QuicConnectionId& v) const {
194 return !(v == *this);
195}
196
197bool QuicConnectionId::operator<(const QuicConnectionId& v) const {
198 if (length_ < v.length_) {
199 return true;
200 }
201 if (length_ > v.length_) {
202 return false;
203 }
dschinazib3241162019-06-10 17:59:37 -0700204 return memcmp(data(), v.data(), length_) < 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500205}
206
207QuicConnectionId EmptyQuicConnectionId() {
208 return QuicConnectionId();
209}
210
211static_assert(kQuicDefaultConnectionIdLength == sizeof(uint64_t),
212 "kQuicDefaultConnectionIdLength changed");
213static_assert(kQuicDefaultConnectionIdLength == PACKET_8BYTE_CONNECTION_ID,
214 "kQuicDefaultConnectionIdLength changed");
215
216} // namespace quic