• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 25139258422

29 Apr 2026 08:02PM UTC coverage: 89.37% (-0.02%) from 89.385%
25139258422

push

github

web-flow
Merge pull request #5550 from randombit/jack/tls-misc

TLS conformance, hardening, and performance fixes

107055 of 119789 relevant lines covered (89.37%)

11415549.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.8
/src/lib/tls/msg_client_hello.cpp
1
/*
2
* TLS Client Hello Messages
3
* (C) 2004-2011,2015,2016 Jack Lloyd
4
*     2016 Matthias Gierlings
5
*     2017 Harry Reimann, Rohde & Schwarz Cybersecurity
6
*     2021 Elektrobit Automotive GmbH
7
*     2022 René Meusel, Hannes Rantzsch - neXenio GmbH
8
*     2026 René Meusel - Rohde & Schwarz Cybersecurity GmbH
9
*
10
* Botan is released under the Simplified BSD License (see license.txt)
11
*/
12

13
#include <botan/tls_messages.h>
14
#include <botan/internal/tls_messages_internal.h>
15

16
#include <botan/hash.h>
17
#include <botan/rng.h>
18
#include <botan/tls_callbacks.h>
19
#include <botan/tls_policy.h>
20
#include <botan/internal/tls_reader.h>
21
#include <algorithm>
22

23
namespace Botan::TLS {
24

25
std::vector<uint8_t> make_hello_random(RandomNumberGenerator& rng, Callbacks& cb, const Policy& policy) {
7,312✔
26
   auto buf = rng.random_vec<std::vector<uint8_t>>(32);
7,312✔
27

28
   if(policy.hash_hello_random()) {
7,312✔
29
      auto sha256 = HashFunction::create_or_throw("SHA-256");
7,297✔
30
      sha256->update(buf);
7,297✔
31
      sha256->final(buf);
7,297✔
32
   }
7,297✔
33

34
   // TLS 1.3 does not require the insertion of a timestamp in the client hello
35
   // random. When offering both TLS 1.2 and 1.3 we nevertheless comply with the
36
   // legacy specification.
37
   if(policy.include_time_in_hello_random() && (policy.allow_tls12() || policy.allow_dtls12())) {
7,312✔
38
      const uint32_t time32 = static_cast<uint32_t>(std::chrono::system_clock::to_time_t(cb.tls_current_timestamp()));
7,283✔
39

40
      store_be(time32, buf.data());
7,283✔
41
   }
42

43
   return buf;
7,312✔
44
}
×
45

46
Client_Hello_Internal::Client_Hello_Internal(const std::vector<uint8_t>& buf) {
4,096✔
47
   /*
48
   Minimum possible client hello
49

50
   version: 2 bytes
51
   random: 32 bytes
52
   session_id len: 1 byte
53
   ciphersuite_len: 2
54
   ciphersuite (single): 2
55
   compression_len: 1
56
   compression (single): 1
57
   */
58

59
   constexpr size_t MinimumClientHelloBytes = 2 + 32 + 1 + 2 + 2 + 1 + 1;
4,096✔
60
   if(buf.size() < MinimumClientHelloBytes) {
4,096✔
61
      throw Decoding_Error("Client_Hello: Packet corrupted");
45✔
62
   }
63

64
   TLS_Data_Reader reader("ClientHello", buf);
4,051✔
65

66
   const uint8_t major_version = reader.get_byte();
4,051✔
67
   const uint8_t minor_version = reader.get_byte();
4,051✔
68

69
   m_legacy_version = Protocol_Version(major_version, minor_version);
4,051✔
70

71
   // DTLS has an additional 1 byte cookie length field
72
   if(m_legacy_version.is_datagram_protocol() && buf.size() < MinimumClientHelloBytes + 1) {
4,051✔
73
      throw Decoding_Error("Client_Hello: DTLS packet corrupted");
×
74
   }
75

76
   m_random = reader.get_fixed<uint8_t>(32);
4,051✔
77
   m_session_id = Session_ID(reader.get_range<uint8_t>(1, 0, 32));
4,051✔
78

79
   if(m_legacy_version.is_datagram_protocol()) {
3,200✔
80
      auto sha256 = HashFunction::create_or_throw("SHA-256");
956✔
81
      sha256->update(reader.get_data_read_so_far());
956✔
82

83
      m_hello_cookie = reader.get_range<uint8_t>(1, 0, 255);
956✔
84

85
      sha256->update(reader.get_remaining());
956✔
86
      m_cookie_input_bits = sha256->final_stdvec();
956✔
87
   }
956✔
88

89
   m_suites = reader.get_range_vector<uint16_t>(2, 1, 32767);
3,200✔
90
   m_comp_methods = reader.get_range_vector<uint8_t>(1, 1, 255);
3,087✔
91

92
   m_extensions.deserialize(reader, Connection_Side::Client, Handshake_Type::ClientHello);
3,086✔
93
}
6,224✔
94

95
Protocol_Version Client_Hello_Internal::version() const {
1,017✔
96
   // RFC 8446 4.2.1
97
   //    If [the "supported_versions"] extension is not present, servers
98
   //    which are compliant with this specification and which also support
99
   //    TLS 1.2 MUST negotiate TLS 1.2 or prior as specified in [RFC5246],
100
   //    even if ClientHello.legacy_version is 0x0304 or later.
101
   //
102
   // RFC 8446 4.2.1
103
   //    Servers MUST be prepared to receive ClientHellos that include
104
   //    [the supported_versions] extension but do not include 0x0304 in
105
   //    the list of versions.
106
   //
107
   // RFC 8446 4.1.2
108
   //    TLS 1.3 ClientHellos are identified as having a legacy_version of
109
   //    0x0303 and a supported_versions extension present with 0x0304 as
110
   //    the highest version indicated therein.
111
   if(!extensions().has<Supported_Versions>() ||
1,548✔
112
      !extensions().get<Supported_Versions>()->supports(Protocol_Version::TLS_V13)) {
531✔
113
      // The exact legacy_version is ignored we just inspect it to
114
      // distinguish TLS and DTLS.
115
      return (m_legacy_version.is_datagram_protocol()) ? Protocol_Version::DTLS_V12 : Protocol_Version::TLS_V12;
1,008✔
116
   }
117

118
   // Note: The Client_Hello_13 class will make sure that legacy_version
119
   //       is exactly 0x0303 (aka ossified TLS 1.2)
120
   return Protocol_Version::TLS_V13;
513✔
121
}
122

123
Client_Hello::Client_Hello(Client_Hello&&) noexcept = default;
10,936✔
124
Client_Hello& Client_Hello::operator=(Client_Hello&&) noexcept = default;
47✔
125

126
Client_Hello::~Client_Hello() = default;
17,771✔
127

128
Client_Hello::Client_Hello() : m_data(std::make_unique<Client_Hello_Internal>()) {}
3,802✔
129

130
/*
131
* Read a counterparty client hello
132
*/
133
Client_Hello::Client_Hello(std::unique_ptr<Client_Hello_Internal> data) : m_data(std::move(data)) {
3,050✔
134
   BOTAN_ASSERT_NONNULL(m_data);
3,050✔
135
}
3,050✔
136

137
Handshake_Type Client_Hello::type() const {
17,066✔
138
   return Handshake_Type::ClientHello;
17,066✔
139
}
140

141
Protocol_Version Client_Hello::legacy_version() const {
9,869✔
142
   return m_data->legacy_version();
9,869✔
143
}
144

145
const std::vector<uint8_t>& Client_Hello::random() const {
4,041✔
146
   return m_data->random();
4,041✔
147
}
148

149
const Session_ID& Client_Hello::session_id() const {
3,506✔
150
   return m_data->session_id();
3,506✔
151
}
152

153
const std::vector<uint8_t>& Client_Hello::compression_methods() const {
1,532✔
154
   return m_data->comp_methods();
1,532✔
155
}
156

157
const std::vector<uint16_t>& Client_Hello::ciphersuites() const {
1,543✔
158
   return m_data->ciphersuites();
1,543✔
159
}
160

161
std::set<Extension_Code> Client_Hello::extension_types() const {
3,918✔
162
   return m_data->extensions().extension_types();
3,918✔
163
}
164

165
const Extensions& Client_Hello::extensions() const {
11,660✔
166
   return m_data->extensions();
11,660✔
167
}
168

169
/*
170
* Serialize a Client Hello message
171
*/
172
std::vector<uint8_t> Client_Hello::serialize() const {
4,556✔
173
   std::vector<uint8_t> buf;
4,556✔
174
   buf.reserve(1024);  // working around GCC warning
4,556✔
175

176
   buf.push_back(m_data->legacy_version().major_version());
4,556✔
177
   buf.push_back(m_data->legacy_version().minor_version());
4,556✔
178
   buf += m_data->random();
4,556✔
179

180
   append_tls_length_value(buf, m_data->session_id().get(), 1);
4,556✔
181

182
   if(m_data->legacy_version().is_datagram_protocol()) {
4,556✔
183
      append_tls_length_value(buf, m_data->hello_cookie(), 1);
1,063✔
184
   }
185

186
   append_tls_length_value(buf, m_data->ciphersuites(), 2);
4,556✔
187
   append_tls_length_value(buf, m_data->comp_methods(), 1);
4,556✔
188

189
   /*
190
   * May not want to send extensions at all in some cases. If so,
191
   * should include SCSV value (if reneg info is empty, if not we are
192
   * renegotiating with a modern server)
193
   */
194

195
   buf += m_data->extensions().serialize(Connection_Side::Client);
4,556✔
196

197
   return buf;
4,556✔
198
}
×
199

200
std::vector<uint8_t> Client_Hello::cookie_input_data() const {
948✔
201
   BOTAN_STATE_CHECK(!m_data->hello_cookie_input_bits().empty());
948✔
202

203
   return m_data->hello_cookie_input_bits();
948✔
204
}
205

206
/*
207
* Check if we offered this ciphersuite
208
*/
209
bool Client_Hello::offered_suite(uint16_t ciphersuite) const {
5,554✔
210
   return std::find(m_data->ciphersuites().cbegin(), m_data->ciphersuites().cend(), ciphersuite) !=
5,554✔
211
          m_data->ciphersuites().cend();
5,554✔
212
}
213

214
std::vector<Signature_Scheme> Client_Hello::signature_schemes() const {
4,332✔
215
   if(const Signature_Algorithms* sigs = m_data->extensions().get<Signature_Algorithms>()) {
4,332✔
216
      return sigs->supported_schemes();
4,330✔
217
   }
218
   return {};
2✔
219
}
220

221
std::vector<Signature_Scheme> Client_Hello::certificate_signature_schemes() const {
1,066✔
222
   // RFC 8446 4.2.3
223
   //   If no "signature_algorithms_cert" extension is present, then the
224
   //   "signature_algorithms" extension also applies to signatures appearing
225
   //   in certificates.
226
   if(const Signature_Algorithms_Cert* sigs = m_data->extensions().get<Signature_Algorithms_Cert>()) {
1,066✔
227
      return sigs->supported_schemes();
×
228
   } else {
229
      return signature_schemes();
1,066✔
230
   }
231
}
232

233
std::vector<Group_Params> Client_Hello::supported_ecc_curves() const {
2,162✔
234
   if(const Supported_Groups* groups = m_data->extensions().get<Supported_Groups>()) {
2,162✔
235
      return groups->ec_groups();
2,159✔
236
   }
237
   return {};
3✔
238
}
239

240
std::vector<Group_Params> Client_Hello::supported_dh_groups() const {
1,583✔
241
   if(const Supported_Groups* groups = m_data->extensions().get<Supported_Groups>()) {
1,583✔
242
      return groups->dh_groups();
1,577✔
243
   }
244
   return std::vector<Group_Params>();
6✔
245
}
246

247
std::string Client_Hello::sni_hostname() const {
4,509✔
248
   if(const Server_Name_Indicator* sni = m_data->extensions().get<Server_Name_Indicator>()) {
4,509✔
249
      return sni->host_name();
4,379✔
250
   }
251
   return "";
130✔
252
}
253

254
std::vector<Protocol_Version> Client_Hello::supported_versions() const {
1,534✔
255
   if(const Supported_Versions* versions = m_data->extensions().get<Supported_Versions>()) {
1,534✔
256
      return versions->versions();
456✔
257
   }
258
   return {};
1,078✔
259
}
260

261
bool Client_Hello::supports_alpn() const {
1,198✔
262
   return m_data->extensions().has<Application_Layer_Protocol_Notification>();
1,198✔
263
}
264

265
bool Client_Hello::sent_signature_algorithms() const {
×
266
   return m_data->extensions().has<Signature_Algorithms>();
×
267
}
268

269
std::vector<std::string> Client_Hello::next_protocols() const {
146✔
270
   if(auto* alpn = m_data->extensions().get<Application_Layer_Protocol_Notification>()) {
146✔
271
      return alpn->protocols();
146✔
272
   }
273
   return {};
×
274
}
275

276
std::vector<uint16_t> Client_Hello::srtp_profiles() const {
334✔
277
   if(const SRTP_Protection_Profiles* srtp = m_data->extensions().get<SRTP_Protection_Profiles>()) {
334✔
278
      return srtp->profiles();
4✔
279
   }
280
   return {};
330✔
281
}
282

283
const std::vector<uint8_t>& Client_Hello::cookie() const {
948✔
284
   return m_data->hello_cookie();
948✔
285
}
286

287
Client_Hello_12_Shim::Client_Hello_12_Shim(std::unique_ptr<Client_Hello_Internal> data) :
2,537✔
288
      Client_Hello(std::move(data)) {}
2,537✔
289

290
Client_Hello_12_Shim::Client_Hello_12_Shim(const std::vector<uint8_t>& buf) :
×
291
      Client_Hello_12_Shim(std::make_unique<Client_Hello_Internal>(buf)) {}
×
292

293
}  // namespace Botan::TLS
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc