xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/quic_connection_id.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // 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 "quiche/quic/core/quic_connection_id.h"
6 
7 #include <cstddef>
8 #include <cstdint>
9 #include <cstring>
10 #include <iomanip>
11 #include <string>
12 
13 #include "absl/strings/escaping.h"
14 #include "openssl/siphash.h"
15 #include "quiche/quic/core/crypto/quic_random.h"
16 #include "quiche/quic/core/quic_types.h"
17 #include "quiche/quic/platform/api/quic_bug_tracker.h"
18 #include "quiche/quic/platform/api/quic_flag_utils.h"
19 #include "quiche/quic/platform/api/quic_flags.h"
20 #include "quiche/quic/platform/api/quic_logging.h"
21 #include "quiche/common/quiche_endian.h"
22 
23 namespace quic {
24 
25 namespace {
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.
33 class QuicConnectionIdHasher {
34  public:
QuicConnectionIdHasher()35   inline QuicConnectionIdHasher()
36       : QuicConnectionIdHasher(QuicRandom::GetInstance()) {}
37 
QuicConnectionIdHasher(QuicRandom * random)38   explicit inline QuicConnectionIdHasher(QuicRandom* random) {
39     random->RandBytes(&sip_hash_key_, sizeof(sip_hash_key_));
40   }
41 
Hash(const char * input,size_t input_len) const42   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 
QuicConnectionId()53 QuicConnectionId::QuicConnectionId() : QuicConnectionId(nullptr, 0) {
54   static_assert(offsetof(QuicConnectionId, padding_) ==
55                     offsetof(QuicConnectionId, length_),
56                 "bad offset");
57   static_assert(sizeof(QuicConnectionId) <= 16, "bad size");
58 }
59 
QuicConnectionId(const char * data,uint8_t length)60 QuicConnectionId::QuicConnectionId(const char* data, uint8_t length) {
61   length_ = length;
62   if (length_ == 0) {
63     return;
64   }
65   if (length_ <= sizeof(data_short_)) {
66     memcpy(data_short_, data, length_);
67     return;
68   }
69   data_long_ = reinterpret_cast<char*>(malloc(length_));
70   QUICHE_CHECK_NE(nullptr, data_long_);
71   memcpy(data_long_, data, length_);
72 }
73 
QuicConnectionId(const absl::Span<const uint8_t> data)74 QuicConnectionId::QuicConnectionId(const absl::Span<const uint8_t> data)
75     : QuicConnectionId(reinterpret_cast<const char*>(data.data()),
76                        data.length()) {}
77 
~QuicConnectionId()78 QuicConnectionId::~QuicConnectionId() {
79   if (length_ > sizeof(data_short_)) {
80     free(data_long_);
81     data_long_ = nullptr;
82   }
83 }
84 
QuicConnectionId(const QuicConnectionId & other)85 QuicConnectionId::QuicConnectionId(const QuicConnectionId& other)
86     : QuicConnectionId(other.data(), other.length()) {}
87 
operator =(const QuicConnectionId & other)88 QuicConnectionId& QuicConnectionId::operator=(const QuicConnectionId& other) {
89   set_length(other.length());
90   memcpy(mutable_data(), other.data(), length_);
91   return *this;
92 }
93 
data() const94 const char* QuicConnectionId::data() const {
95   if (length_ <= sizeof(data_short_)) {
96     return data_short_;
97   }
98   return data_long_;
99 }
100 
mutable_data()101 char* QuicConnectionId::mutable_data() {
102   if (length_ <= sizeof(data_short_)) {
103     return data_short_;
104   }
105   return data_long_;
106 }
107 
length() const108 uint8_t QuicConnectionId::length() const { return length_; }
109 
set_length(uint8_t length)110 void QuicConnectionId::set_length(uint8_t length) {
111   char temporary_data[sizeof(data_short_)];
112   if (length > sizeof(data_short_)) {
113     if (length_ <= sizeof(data_short_)) {
114       // Copy data from data_short_ to data_long_.
115       memcpy(temporary_data, data_short_, length_);
116       data_long_ = reinterpret_cast<char*>(malloc(length));
117       QUICHE_CHECK_NE(nullptr, data_long_);
118       memcpy(data_long_, temporary_data, length_);
119     } else {
120       // Resize data_long_.
121       char* realloc_result =
122           reinterpret_cast<char*>(realloc(data_long_, length));
123       QUICHE_CHECK_NE(nullptr, realloc_result);
124       data_long_ = realloc_result;
125     }
126   } else if (length_ > sizeof(data_short_)) {
127     // Copy data from data_long_ to data_short_.
128     memcpy(temporary_data, data_long_, length);
129     free(data_long_);
130     data_long_ = nullptr;
131     memcpy(data_short_, temporary_data, length);
132   }
133   length_ = length;
134 }
135 
IsEmpty() const136 bool QuicConnectionId::IsEmpty() const { return length_ == 0; }
137 
Hash() const138 size_t QuicConnectionId::Hash() const {
139   static const QuicConnectionIdHasher hasher = QuicConnectionIdHasher();
140   return hasher.Hash(data(), length_);
141 }
142 
ToString() const143 std::string QuicConnectionId::ToString() const {
144   if (IsEmpty()) {
145     return std::string("0");
146   }
147   return absl::BytesToHexString(absl::string_view(data(), length_));
148 }
149 
operator <<(std::ostream & os,const QuicConnectionId & v)150 std::ostream& operator<<(std::ostream& os, const QuicConnectionId& v) {
151   os << v.ToString();
152   return os;
153 }
154 
operator ==(const QuicConnectionId & v) const155 bool QuicConnectionId::operator==(const QuicConnectionId& v) const {
156   return length_ == v.length_ && memcmp(data(), v.data(), length_) == 0;
157 }
158 
operator !=(const QuicConnectionId & v) const159 bool QuicConnectionId::operator!=(const QuicConnectionId& v) const {
160   return !(v == *this);
161 }
162 
operator <(const QuicConnectionId & v) const163 bool QuicConnectionId::operator<(const QuicConnectionId& v) const {
164   if (length_ < v.length_) {
165     return true;
166   }
167   if (length_ > v.length_) {
168     return false;
169   }
170   return memcmp(data(), v.data(), length_) < 0;
171 }
172 
EmptyQuicConnectionId()173 QuicConnectionId EmptyQuicConnectionId() { return QuicConnectionId(); }
174 
175 static_assert(kQuicDefaultConnectionIdLength == sizeof(uint64_t),
176               "kQuicDefaultConnectionIdLength changed");
177 static_assert(kQuicDefaultConnectionIdLength == 8,
178               "kQuicDefaultConnectionIdLength changed");
179 
180 }  // namespace quic
181