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

randombit / botan / 21863608093

10 Feb 2026 11:46AM UTC coverage: 90.064% (-0.004%) from 90.068%
21863608093

Pull #5303

github

web-flow
Merge aea1c629d into 1d119e57a
Pull Request #5303: Refactor: Organize TLS Extensions into TLS 1.2 and 1.3 Modules

102231 of 113509 relevant lines covered (90.06%)

11483899.99 hits per line

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

93.44
/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

22
namespace Botan::TLS {
23

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

27
   if(policy.hash_hello_random()) {
6,962✔
28
      auto sha256 = HashFunction::create_or_throw("SHA-256");
6,947✔
29
      sha256->update(buf);
6,947✔
30
      sha256->final(buf);
6,947✔
31
   }
6,947✔
32

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

39
      store_be(time32, buf.data());
6,939✔
40
   }
41

42
   return buf;
6,962✔
43
}
×
44

45
Client_Hello_Internal::Client_Hello_Internal(const std::vector<uint8_t>& buf) {
3,901✔
46
   if(buf.size() < 41) {
3,901✔
47
      throw Decoding_Error("Client_Hello: Packet corrupted");
45✔
48
   }
49

50
   TLS_Data_Reader reader("ClientHello", buf);
3,856✔
51

52
   const uint8_t major_version = reader.get_byte();
3,856✔
53
   const uint8_t minor_version = reader.get_byte();
3,856✔
54

55
   m_legacy_version = Protocol_Version(major_version, minor_version);
3,856✔
56
   m_random = reader.get_fixed<uint8_t>(32);
3,856✔
57
   m_session_id = Session_ID(reader.get_range<uint8_t>(1, 0, 32));
3,856✔
58

59
   if(m_legacy_version.is_datagram_protocol()) {
3,009✔
60
      auto sha256 = HashFunction::create_or_throw("SHA-256");
796✔
61
      sha256->update(reader.get_data_read_so_far());
796✔
62

63
      m_hello_cookie = reader.get_range<uint8_t>(1, 0, 255);
796✔
64

65
      sha256->update(reader.get_remaining());
796✔
66
      m_cookie_input_bits = sha256->final_stdvec();
796✔
67
   }
796✔
68

69
   m_suites = reader.get_range_vector<uint16_t>(2, 1, 32767);
3,009✔
70
   m_comp_methods = reader.get_range_vector<uint8_t>(1, 1, 255);
2,891✔
71

72
   m_extensions.deserialize(reader, Connection_Side::Client, Handshake_Type::ClientHello);
2,891✔
73
}
5,997✔
74

75
Protocol_Version Client_Hello_Internal::version() const {
978✔
76
   // RFC 8446 4.2.1
77
   //    If [the "supported_versions"] extension is not present, servers
78
   //    which are compliant with this specification and which also support
79
   //    TLS 1.2 MUST negotiate TLS 1.2 or prior as specified in [RFC5246],
80
   //    even if ClientHello.legacy_version is 0x0304 or later.
81
   //
82
   // RFC 8446 4.2.1
83
   //    Servers MUST be prepared to receive ClientHellos that include
84
   //    [the supported_versions] extension but do not include 0x0304 in
85
   //    the list of versions.
86
   //
87
   // RFC 8446 4.1.2
88
   //    TLS 1.3 ClientHellos are identified as having a legacy_version of
89
   //    0x0303 and a supported_versions extension present with 0x0304 as
90
   //    the highest version indicated therein.
91
   if(!extensions().has<Supported_Versions>() ||
1,461✔
92
      !extensions().get<Supported_Versions>()->supports(Protocol_Version::TLS_V13)) {
483✔
93
      // The exact legacy_version is ignored we just inspect it to
94
      // distinguish TLS and DTLS.
95
      return (m_legacy_version.is_datagram_protocol()) ? Protocol_Version::DTLS_V12 : Protocol_Version::TLS_V12;
1,026✔
96
   }
97

98
   // Note: The Client_Hello_13 class will make sure that legacy_version
99
   //       is exactly 0x0303 (aka ossified TLS 1.2)
100
   return Protocol_Version::TLS_V13;
465✔
101
}
102

103
Client_Hello::Client_Hello(Client_Hello&&) noexcept = default;
10,494✔
104
Client_Hello& Client_Hello::operator=(Client_Hello&&) noexcept = default;
43✔
105

106
Client_Hello::~Client_Hello() = default;
17,023✔
107

108
Client_Hello::Client_Hello() : m_data(std::make_unique<Client_Hello_Internal>()) {}
3,684✔
109

110
/*
111
* Read a counterparty client hello
112
*/
113
Client_Hello::Client_Hello(std::unique_ptr<Client_Hello_Internal> data) : m_data(std::move(data)) {
2,862✔
114
   BOTAN_ASSERT_NONNULL(m_data);
2,862✔
115
}
2,862✔
116

117
Handshake_Type Client_Hello::type() const {
16,308✔
118
   return Handshake_Type::ClientHello;
16,308✔
119
}
120

121
Protocol_Version Client_Hello::legacy_version() const {
8,243✔
122
   return m_data->legacy_version();
8,243✔
123
}
124

125
const std::vector<uint8_t>& Client_Hello::random() const {
3,842✔
126
   return m_data->random();
3,842✔
127
}
128

129
const Session_ID& Client_Hello::session_id() const {
3,322✔
130
   return m_data->session_id();
3,322✔
131
}
132

133
const std::vector<uint8_t>& Client_Hello::compression_methods() const {
1,383✔
134
   return m_data->comp_methods();
1,383✔
135
}
136

137
const std::vector<uint16_t>& Client_Hello::ciphersuites() const {
1,430✔
138
   return m_data->ciphersuites();
1,430✔
139
}
140

141
std::set<Extension_Code> Client_Hello::extension_types() const {
3,256✔
142
   return m_data->extensions().extension_types();
3,256✔
143
}
144

145
const Extensions& Client_Hello::extensions() const {
9,821✔
146
   return m_data->extensions();
9,821✔
147
}
148

149
/*
150
* Serialize a Client Hello message
151
*/
152
std::vector<uint8_t> Client_Hello::serialize() const {
4,347✔
153
   std::vector<uint8_t> buf;
4,347✔
154
   buf.reserve(1024);  // working around GCC warning
4,347✔
155

156
   buf.push_back(m_data->legacy_version().major_version());
4,347✔
157
   buf.push_back(m_data->legacy_version().minor_version());
4,347✔
158
   buf += m_data->random();
4,347✔
159

160
   append_tls_length_value(buf, m_data->session_id().get(), 1);
4,347✔
161

162
   if(m_data->legacy_version().is_datagram_protocol()) {
4,347✔
163
      append_tls_length_value(buf, m_data->hello_cookie(), 1);
951✔
164
   }
165

166
   append_tls_length_value(buf, m_data->ciphersuites(), 2);
4,347✔
167
   append_tls_length_value(buf, m_data->comp_methods(), 1);
4,347✔
168

169
   /*
170
   * May not want to send extensions at all in some cases. If so,
171
   * should include SCSV value (if reneg info is empty, if not we are
172
   * renegotiating with a modern server)
173
   */
174

175
   buf += m_data->extensions().serialize(Connection_Side::Client);
4,347✔
176

177
   return buf;
4,347✔
178
}
×
179

180
std::vector<uint8_t> Client_Hello::cookie_input_data() const {
790✔
181
   BOTAN_STATE_CHECK(!m_data->hello_cookie_input_bits().empty());
790✔
182

183
   return m_data->hello_cookie_input_bits();
790✔
184
}
185

186
/*
187
* Check if we offered this ciphersuite
188
*/
189
bool Client_Hello::offered_suite(uint16_t ciphersuite) const {
4,771✔
190
   return std::find(m_data->ciphersuites().cbegin(), m_data->ciphersuites().cend(), ciphersuite) !=
4,771✔
191
          m_data->ciphersuites().cend();
4,771✔
192
}
193

194
std::vector<Signature_Scheme> Client_Hello::signature_schemes() const {
4,118✔
195
   if(const Signature_Algorithms* sigs = m_data->extensions().get<Signature_Algorithms>()) {
4,118✔
196
      return sigs->supported_schemes();
4,116✔
197
   }
198
   return {};
2✔
199
}
200

201
std::vector<Signature_Scheme> Client_Hello::certificate_signature_schemes() const {
1,021✔
202
   // RFC 8446 4.2.3
203
   //   If no "signature_algorithms_cert" extension is present, then the
204
   //   "signature_algorithms" extension also applies to signatures appearing
205
   //   in certificates.
206
   if(const Signature_Algorithms_Cert* sigs = m_data->extensions().get<Signature_Algorithms_Cert>()) {
1,021✔
207
      return sigs->supported_schemes();
×
208
   } else {
209
      return signature_schemes();
1,021✔
210
   }
211
}
212

213
std::vector<Group_Params> Client_Hello::supported_ecc_curves() const {
1,370✔
214
   if(const Supported_Groups* groups = m_data->extensions().get<Supported_Groups>()) {
1,370✔
215
      return groups->ec_groups();
1,367✔
216
   }
217
   return {};
3✔
218
}
219

220
std::vector<Group_Params> Client_Hello::supported_dh_groups() const {
1,515✔
221
   if(const Supported_Groups* groups = m_data->extensions().get<Supported_Groups>()) {
1,515✔
222
      return groups->dh_groups();
1,509✔
223
   }
224
   return std::vector<Group_Params>();
6✔
225
}
226

227
std::string Client_Hello::sni_hostname() const {
4,227✔
228
   if(const Server_Name_Indicator* sni = m_data->extensions().get<Server_Name_Indicator>()) {
4,227✔
229
      return sni->host_name();
4,097✔
230
   }
231
   return "";
130✔
232
}
233

234
std::vector<Protocol_Version> Client_Hello::supported_versions() const {
1,385✔
235
   if(const Supported_Versions* versions = m_data->extensions().get<Supported_Versions>()) {
1,385✔
236
      return versions->versions();
301✔
237
   }
238
   return {};
1,084✔
239
}
240

241
bool Client_Hello::supports_alpn() const {
1,127✔
242
   return m_data->extensions().has<Application_Layer_Protocol_Notification>();
1,127✔
243
}
244

245
bool Client_Hello::sent_signature_algorithms() const {
×
246
   return m_data->extensions().has<Signature_Algorithms>();
×
247
}
248

249
std::vector<std::string> Client_Hello::next_protocols() const {
149✔
250
   if(auto* alpn = m_data->extensions().get<Application_Layer_Protocol_Notification>()) {
149✔
251
      return alpn->protocols();
149✔
252
   }
253
   return {};
×
254
}
255

256
std::vector<uint16_t> Client_Hello::srtp_profiles() const {
294✔
257
   if(const SRTP_Protection_Profiles* srtp = m_data->extensions().get<SRTP_Protection_Profiles>()) {
294✔
258
      return srtp->profiles();
4✔
259
   }
260
   return {};
290✔
261
}
262

263
const std::vector<uint8_t>& Client_Hello::cookie() const {
790✔
264
   return m_data->hello_cookie();
790✔
265
}
266

267
Client_Hello_12_Shim::Client_Hello_12_Shim(std::unique_ptr<Client_Hello_Internal> data) :
2,397✔
268
      Client_Hello(std::move(data)) {}
2,397✔
269

270
Client_Hello_12_Shim::Client_Hello_12_Shim(const std::vector<uint8_t>& buf) :
×
271
      Client_Hello_12_Shim(std::make_unique<Client_Hello_Internal>(buf)) {}
×
272

273
}  // 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