blob: c514450348ebf6c92c1d3b2952df50c5138c1165 [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"
QUICHE teama6ef0a62019-03-07 20:34:33 -050017#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
18#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
19#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
QUICHE team173c48f2019-11-19 16:34:44 -080020#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h"
dmcardlecf0bfcf2019-12-13 08:08:21 -080021#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050022
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:
dschinazi2d014822019-07-18 15:28:13 -070035 inline QuicConnectionIdHasher()
dschinazi0fdff8e2019-07-18 09:07:39 -070036 : 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) {
dschinaziffa83552019-12-17 11:00:23 -080056 if (!GetQuicRestartFlag(quic_allow_very_long_connection_ids)) {
57 // TODO(dschinazi) remove kQuicMaxConnectionIdAllVersionsLength entirely
58 // when we deprecate quic_allow_very_long_connection_ids.
59 static_assert(kQuicMaxConnectionIdAllVersionsLength <=
60 std::numeric_limits<uint8_t>::max(),
61 "kQuicMaxConnectionIdAllVersionsLength too high");
62 if (length > kQuicMaxConnectionIdAllVersionsLength) {
63 QUIC_BUG << "Attempted to create connection ID of length "
64 << static_cast<int>(length);
65 length = kQuicMaxConnectionIdAllVersionsLength;
66 }
67 } else {
68 QUIC_RESTART_FLAG_COUNT_N(quic_allow_very_long_connection_ids, 3, 5);
QUICHE teama6ef0a62019-03-07 20:34:33 -050069 }
70 length_ = length;
dschinazib3241162019-06-10 17:59:37 -070071 if (length_ == 0) {
72 return;
73 }
dschinazib3241162019-06-10 17:59:37 -070074 if (length_ <= sizeof(data_short_)) {
75 memcpy(data_short_, data, length_);
76 return;
77 }
78 data_long_ = reinterpret_cast<char*>(malloc(length_));
79 CHECK_NE(nullptr, data_long_);
80 memcpy(data_long_, data, length_);
81}
82
83QuicConnectionId::~QuicConnectionId() {
dschinazib3241162019-06-10 17:59:37 -070084 if (length_ > sizeof(data_short_)) {
85 free(data_long_);
86 data_long_ = nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -050087 }
88}
89
dschinazib3241162019-06-10 17:59:37 -070090QuicConnectionId::QuicConnectionId(const QuicConnectionId& other)
91 : QuicConnectionId(other.data(), other.length()) {}
92
93QuicConnectionId& QuicConnectionId::operator=(const QuicConnectionId& other) {
94 set_length(other.length());
95 memcpy(mutable_data(), other.data(), length_);
96 return *this;
97}
QUICHE teama6ef0a62019-03-07 20:34:33 -050098
99const char* QuicConnectionId::data() const {
dschinazib3241162019-06-10 17:59:37 -0700100 if (length_ <= sizeof(data_short_)) {
101 return data_short_;
102 }
103 return data_long_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500104}
105
106char* QuicConnectionId::mutable_data() {
dschinazib3241162019-06-10 17:59:37 -0700107 if (length_ <= sizeof(data_short_)) {
108 return data_short_;
109 }
110 return data_long_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500111}
112
113uint8_t QuicConnectionId::length() const {
114 return length_;
115}
116
117void QuicConnectionId::set_length(uint8_t length) {
dschinaziffa83552019-12-17 11:00:23 -0800118 if (!GetQuicRestartFlag(quic_allow_very_long_connection_ids)) {
119 if (length > kQuicMaxConnectionIdAllVersionsLength) {
120 QUIC_BUG << "Attempted to set connection ID length to "
121 << static_cast<int>(length);
122 length = kQuicMaxConnectionIdAllVersionsLength;
123 }
124 } else {
125 QUIC_RESTART_FLAG_COUNT_N(quic_allow_very_long_connection_ids, 4, 5);
dschinazi6c84c142019-07-31 09:11:49 -0700126 }
dschinazi0d06d7b2019-08-19 14:33:07 -0700127 char temporary_data[sizeof(data_short_)];
128 if (length > sizeof(data_short_)) {
129 if (length_ <= sizeof(data_short_)) {
130 // Copy data from data_short_ to data_long_.
131 memcpy(temporary_data, data_short_, length_);
132 data_long_ = reinterpret_cast<char*>(malloc(length));
133 CHECK_NE(nullptr, data_long_);
134 memcpy(data_long_, temporary_data, length_);
135 } else {
136 // Resize data_long_.
137 char* realloc_result =
138 reinterpret_cast<char*>(realloc(data_long_, length));
139 CHECK_NE(nullptr, realloc_result);
140 data_long_ = realloc_result;
dschinazib3241162019-06-10 17:59:37 -0700141 }
dschinazi0d06d7b2019-08-19 14:33:07 -0700142 } else if (length_ > sizeof(data_short_)) {
143 // Copy data from data_long_ to data_short_.
144 memcpy(temporary_data, data_long_, length);
145 free(data_long_);
146 data_long_ = nullptr;
147 memcpy(data_short_, temporary_data, length);
dschinazib3241162019-06-10 17:59:37 -0700148 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500149 length_ = length;
150}
151
152bool QuicConnectionId::IsEmpty() const {
153 return length_ == 0;
154}
155
156size_t QuicConnectionId::Hash() const {
dschinazi0fdff8e2019-07-18 09:07:39 -0700157 static const QuicConnectionIdHasher hasher = QuicConnectionIdHasher();
158 return hasher.Hash(data(), length_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500159}
160
vasilvvc48c8712019-03-11 13:38:16 -0700161std::string QuicConnectionId::ToString() const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500162 if (IsEmpty()) {
vasilvvc48c8712019-03-11 13:38:16 -0700163 return std::string("0");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500164 }
dmcardlecf0bfcf2019-12-13 08:08:21 -0800165 return quiche::QuicheTextUtils::HexEncode(data(), length_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500166}
167
168std::ostream& operator<<(std::ostream& os, const QuicConnectionId& v) {
169 os << v.ToString();
170 return os;
171}
172
173bool QuicConnectionId::operator==(const QuicConnectionId& v) const {
dschinazib3241162019-06-10 17:59:37 -0700174 return length_ == v.length_ && memcmp(data(), v.data(), length_) == 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500175}
176
177bool QuicConnectionId::operator!=(const QuicConnectionId& v) const {
178 return !(v == *this);
179}
180
181bool QuicConnectionId::operator<(const QuicConnectionId& v) const {
182 if (length_ < v.length_) {
183 return true;
184 }
185 if (length_ > v.length_) {
186 return false;
187 }
dschinazib3241162019-06-10 17:59:37 -0700188 return memcmp(data(), v.data(), length_) < 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500189}
190
191QuicConnectionId EmptyQuicConnectionId() {
192 return QuicConnectionId();
193}
194
195static_assert(kQuicDefaultConnectionIdLength == sizeof(uint64_t),
196 "kQuicDefaultConnectionIdLength changed");
197static_assert(kQuicDefaultConnectionIdLength == PACKET_8BYTE_CONNECTION_ID,
198 "kQuicDefaultConnectionIdLength changed");
199
200} // namespace quic