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

randombit / botan / 21943010187

12 Feb 2026 10:33AM UTC coverage: 90.061% (-0.006%) from 90.067%
21943010187

Pull #5318

github

web-flow
Merge 005a803db into f97d7db3f
Pull Request #5318: Allow disabling TLS 1.2 at Build Time

102245 of 113528 relevant lines covered (90.06%)

11733046.67 hits per line

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

91.11
/src/lib/tls/tls13/msg_server_hello_13.cpp
1
/*
2
* TLS Server Hello and Server Hello Done
3
* (C) 2004-2011,2015,2016,2019 Jack Lloyd
4
*     2021 Elektrobit Automotive GmbH
5
*     2022 René Meusel, Hannes Rantzsch - neXenio GmbH
6
*     2026 René Meusel - Rohde & Schwarz Cybersecurity GmbH
7
*
8
* Botan is released under the Simplified BSD License (see license.txt)
9
*/
10

11
#include <botan/tls_messages_13.h>
12

13
#include <botan/tls_alert.h>
14
#include <botan/tls_callbacks.h>
15
#include <botan/tls_exceptn.h>
16
#include <botan/tls_extensions_13.h>
17
#include <botan/tls_policy.h>
18
#include <botan/internal/loadstor.h>
19
#include <botan/internal/stl_util.h>
20
#include <botan/internal/tls_messages_internal.h>
21

22
namespace Botan::TLS {
23

24
const Server_Hello_13::Server_Hello_Tag Server_Hello_13::as_server_hello;
25
const Server_Hello_13::Hello_Retry_Request_Tag Server_Hello_13::as_hello_retry_request;
26
const Server_Hello_13::Hello_Retry_Request_Creation_Tag Server_Hello_13::as_new_hello_retry_request;
27

28
std::variant<Hello_Retry_Request, Server_Hello_13> Server_Hello_13::create(const Client_Hello_13& ch,
432✔
29
                                                                           bool hello_retry_request_allowed,
30
                                                                           Session_Manager& session_mgr,
31
                                                                           Credentials_Manager& credentials_mgr,
32
                                                                           RandomNumberGenerator& rng,
33
                                                                           const Policy& policy,
34
                                                                           Callbacks& cb) {
35
   const auto& exts = ch.extensions();
432✔
36

37
   // RFC 8446 4.2.9
38
   //    [With PSK with (EC)DHE key establishment], the client and server MUST
39
   //    supply "key_share" values [...].
40
   //
41
   // Note: We currently do not support PSK without (EC)DHE, hence, we can
42
   //       assume that those extensions are available.
43
   BOTAN_ASSERT_NOMSG(exts.has<Supported_Groups>() && exts.has<Key_Share>());
864✔
44
   const auto& supported_by_client = exts.get<Supported_Groups>()->groups();
432✔
45
   const auto& offered_by_client = exts.get<Key_Share>()->offered_groups();
432✔
46
   const auto selected_group = policy.choose_key_exchange_group(supported_by_client, offered_by_client);
432✔
47

48
   // RFC 8446 4.1.1
49
   //    If there is no overlap between the received "supported_groups" and the
50
   //    groups supported by the server, then the server MUST abort the
51
   //    handshake with a "handshake_failure" or an "insufficient_security" alert.
52
   if(selected_group == Named_Group::NONE) {
432✔
53
      throw TLS_Exception(Alert::HandshakeFailure, "Client did not offer any acceptable group");
×
54
   }
55

56
   // RFC 8446 4.2.8:
57
   //    Servers MUST NOT send a KeyShareEntry for any group not indicated in the
58
   //    client's "supported_groups" extension [...]
59
   if(!value_exists(supported_by_client, selected_group)) {
864✔
60
      throw TLS_Exception(Alert::InternalError, "Application selected a group that is not supported by the client");
×
61
   }
62

63
   // RFC 8446 4.1.4
64
   //    The server will send this message in response to a ClientHello
65
   //    message if it is able to find an acceptable set of parameters but the
66
   //    ClientHello does not contain sufficient information to proceed with
67
   //    the handshake.
68
   //
69
   // In this case, the Client Hello did not contain a key share offer for
70
   // the group selected by the application.
71
   if(!value_exists(offered_by_client, selected_group)) {
864✔
72
      // RFC 8446 4.1.4
73
      //    If a client receives a second HelloRetryRequest in the same
74
      //    connection (i.e., where the ClientHello was itself in response to a
75
      //    HelloRetryRequest), it MUST abort the handshake with an
76
      //    "unexpected_message" alert.
77
      BOTAN_STATE_CHECK(hello_retry_request_allowed);
49✔
78
      return Hello_Retry_Request(ch, selected_group, policy, cb);
98✔
79
   } else {
80
      return Server_Hello_13(ch, selected_group, session_mgr, credentials_mgr, rng, cb, policy);
750✔
81
   }
82
}
416✔
83

84
std::variant<Hello_Retry_Request, Server_Hello_13, Server_Hello_12_Shim> Server_Hello_13::parse(
1,047✔
85
   const std::vector<uint8_t>& buf) {
86
   auto data = std::make_unique<Server_Hello_Internal>(buf);
1,047✔
87
   const auto version = data->version();
1,035✔
88

89
   // server hello that appears to be pre-TLS 1.3, takes precedence over...
90
   if(version.is_pre_tls_13()) {
1,035✔
91
      return Server_Hello_12_Shim(std::move(data));
994✔
92
   }
93

94
   // ... the TLS 1.3 "special case" aka. Hello_Retry_Request
95
   if(version == Protocol_Version::TLS_V13) {
538✔
96
      if(data->is_hello_retry_request()) {
538✔
97
         return Hello_Retry_Request(std::move(data));
135✔
98
      }
99

100
      return Server_Hello_13(std::move(data));
930✔
101
   }
102

103
   throw TLS_Exception(Alert::ProtocolVersion, "unexpected server hello version: " + version.to_string());
×
104
}
1,035✔
105

106
/**
107
 * Validation that applies to both Server Hello and Hello Retry Request
108
 */
109
void Server_Hello_13::basic_validation() const {
538✔
110
   BOTAN_ASSERT_NOMSG(m_data->version() == Protocol_Version::TLS_V13);
538✔
111

112
   // Note: checks that cannot be performed without contextual information
113
   //       are done in the specific TLS client implementation.
114
   // Note: The Supported_Version extension makes sure internally that
115
   //       exactly one entry is provided.
116

117
   // Note: Hello Retry Request basic validation is equivalent with the
118
   //       basic validations required for Server Hello
119
   //
120
   // RFC 8446 4.1.4
121
   //    Upon receipt of a HelloRetryRequest, the client MUST check the
122
   //    legacy_version, [...], and legacy_compression_method as specified in
123
   //    Section 4.1.3 and then process the extensions, starting with determining
124
   //    the version using "supported_versions".
125

126
   // RFC 8446 4.1.3
127
   //    In TLS 1.3, [...] the legacy_version field MUST be set to 0x0303
128
   if(legacy_version() != Protocol_Version::TLS_V12) {
538✔
129
      throw TLS_Exception(Alert::ProtocolVersion,
2✔
130
                          "legacy_version '" + legacy_version().to_string() + "' is not allowed");
6✔
131
   }
132

133
   // RFC 8446 4.1.3
134
   //    legacy_compression_method:  A single byte which MUST have the value 0.
135
   if(compression_method() != 0x00) {
536✔
136
      throw TLS_Exception(Alert::DecodeError, "compression is not supported in TLS 1.3");
2✔
137
   }
138

139
   // RFC 8446 4.1.3
140
   //    All TLS 1.3 ServerHello messages MUST contain the "supported_versions" extension.
141
   if(!extensions().has<Supported_Versions>()) {
534✔
142
      throw TLS_Exception(Alert::MissingExtension, "server hello did not contain 'supported version' extension");
×
143
   }
144

145
   // RFC 8446 4.2.1
146
   //    A server which negotiates TLS 1.3 MUST respond by sending
147
   //    a "supported_versions" extension containing the selected version
148
   //    value (0x0304).
149
   if(selected_version() != Protocol_Version::TLS_V13) {
534✔
150
      throw TLS_Exception(Alert::IllegalParameter, "TLS 1.3 Server Hello selected a different version");
1✔
151
   }
152
}
533✔
153

154
Server_Hello_13::Server_Hello_13(std::unique_ptr<Server_Hello_Internal> data,
469✔
155
                                 Server_Hello_13::Server_Hello_Tag /*tag*/) :
469✔
156
      Server_Hello(std::move(data)) {
469✔
157
   BOTAN_ASSERT_NOMSG(!m_data->is_hello_retry_request());
469✔
158
   basic_validation();
469✔
159

160
   const auto& exts = extensions();
465✔
161

162
   // RFC 8446 4.1.3
163
   //    The ServerHello MUST only include extensions which are required to
164
   //    establish the cryptographic context and negotiate the protocol version.
165
   //    [...]
166
   //    Other extensions (see Section 4.2) are sent separately in the
167
   //    EncryptedExtensions message.
168
   //
169
   // Note that further validation dependent on the client hello is done in the
170
   // TLS client implementation.
171
   const std::set<Extension_Code> allowed = {
465✔
172
      Extension_Code::KeyShare,
173
      Extension_Code::SupportedVersions,
174
      Extension_Code::PresharedKey,
175
   };
465✔
176

177
   // As the ServerHello shall only contain essential extensions, we don't give
178
   // any slack for extensions not implemented by Botan here.
179
   if(exts.contains_other_than(allowed)) {
465✔
180
      throw TLS_Exception(Alert::UnsupportedExtension, "Server Hello contained an extension that is not allowed");
2✔
181
   }
182

183
   // RFC 8446 4.1.3
184
   //    Current ServerHello messages additionally contain
185
   //    either the "pre_shared_key" extension or the "key_share"
186
   //    extension, or both [...].
187
   if(!exts.has<Key_Share>() && !exts.has<PSK_Key_Exchange_Modes>()) {
465✔
188
      throw TLS_Exception(Alert::MissingExtension, "server hello must contain key exchange information");
2✔
189
   }
190
}
469✔
191

192
Server_Hello_13::Server_Hello_13(std::unique_ptr<Server_Hello_Internal> data,
69✔
193
                                 Server_Hello_13::Hello_Retry_Request_Tag /*tag*/) :
69✔
194
      Server_Hello(std::move(data)) {
69✔
195
   BOTAN_ASSERT_NOMSG(m_data->is_hello_retry_request());
69✔
196
   basic_validation();
69✔
197

198
   const auto& exts = extensions();
68✔
199

200
   // RFC 8446 4.1.4
201
   //     The HelloRetryRequest extensions defined in this specification are:
202
   //     -  supported_versions (see Section 4.2.1)
203
   //     -  cookie (see Section 4.2.2)
204
   //     -  key_share (see Section 4.2.8)
205
   const std::set<Extension_Code> allowed = {
68✔
206
      Extension_Code::Cookie,
207
      Extension_Code::SupportedVersions,
208
      Extension_Code::KeyShare,
209
   };
68✔
210

211
   // As the Hello Retry Request shall only contain essential extensions, we
212
   // don't give any slack for extensions not implemented by Botan here.
213
   if(exts.contains_other_than(allowed)) {
68✔
214
      throw TLS_Exception(Alert::UnsupportedExtension,
1✔
215
                          "Hello Retry Request contained an extension that is not allowed");
1✔
216
   }
217

218
   // RFC 8446 4.1.4
219
   //    Clients MUST abort the handshake with an "illegal_parameter" alert if
220
   //    the HelloRetryRequest would not result in any change in the ClientHello.
221
   if(!exts.has<Key_Share>() && !exts.has<Cookie>()) {
69✔
222
      throw TLS_Exception(Alert::IllegalParameter, "Hello Retry Request does not request any changes to Client Hello");
1✔
223
   }
224
}
69✔
225

226
Server_Hello_13::Server_Hello_13(std::unique_ptr<Server_Hello_Internal> data,
49✔
227
                                 Hello_Retry_Request_Creation_Tag /*tag*/) :
49✔
228
      Server_Hello(std::move(data)) {}
49✔
229

230
namespace {
231

232
uint16_t choose_ciphersuite(const Client_Hello_13& ch, const Policy& policy) {
432✔
233
   auto pref_list = ch.ciphersuites();
432✔
234
   // TODO: DTLS might need to make this version dynamic
235
   auto other_list = policy.ciphersuite_list(Protocol_Version::TLS_V13);
432✔
236

237
   if(policy.server_uses_own_ciphersuite_preferences()) {
432✔
238
      std::swap(pref_list, other_list);
432✔
239
   }
240

241
   for(auto suite_id : pref_list) {
1,263✔
242
      // TODO: take potentially available PSKs into account to select a
243
      //       compatible ciphersuite.
244
      //
245
      // Assuming the client sent one or more PSKs, we would first need to find
246
      // the hash functions they are associated to. For session tickets, that
247
      // would mean decrypting the ticket and comparing the cipher suite used in
248
      // those tickets. For (currently not yet supported) pre-assigned PSKs, the
249
      // hash function needs to be specified along with them.
250
      //
251
      // Then we could refine the ciphersuite selection using the required hash
252
      // function for the PSK(s) we are wishing to use down the road.
253
      //
254
      // For now, we just negotiate the cipher suite blindly and hope for the
255
      // best. As long as PSKs are used for session resumption only, this has a
256
      // high chance of success. Previous handshakes with this client have very
257
      // likely selected the same ciphersuite anyway.
258
      //
259
      // See also RFC 8446 4.2.11
260
      //    When session resumption is the primary use case of PSKs, the most
261
      //    straightforward way to implement the PSK/cipher suite matching
262
      //    requirements is to negotiate the cipher suite first [...].
263
      if(value_exists(other_list, suite_id)) {
2,526✔
264
         return suite_id;
432✔
265
      }
266
   }
267

268
   // RFC 8446 4.1.1
269
   //     If the server is unable to negotiate a supported set of parameters
270
   //     [...], it MUST abort the handshake with either a "handshake_failure"
271
   //     or "insufficient_security" fatal alert [...].
272
   throw TLS_Exception(Alert::HandshakeFailure, "Can't agree on a ciphersuite with client");
×
273
}
864✔
274
}  // namespace
275

276
Server_Hello_13::Server_Hello_13(const Client_Hello_13& ch,
383✔
277
                                 std::optional<Named_Group> key_exchange_group,
278
                                 Session_Manager& session_mgr,
279
                                 Credentials_Manager& credentials_mgr,
280
                                 RandomNumberGenerator& rng,
281
                                 Callbacks& cb,
282
                                 const Policy& policy) :
383✔
283
      Server_Hello(std::make_unique<Server_Hello_Internal>(
766✔
284
         Protocol_Version::TLS_V12,
285
         ch.session_id(),
383✔
286
         make_server_hello_random(rng, Protocol_Version::TLS_V13, cb, policy),
383✔
287
         choose_ciphersuite(ch, policy),
383✔
288
         uint8_t(0) /* compression method */
766✔
289
         )) {
766✔
290
   // RFC 8446 4.2.1
291
   //    A server which negotiates TLS 1.3 MUST respond by sending a
292
   //    "supported_versions" extension containing the selected version
293
   //    value (0x0304). It MUST set the ServerHello.legacy_version field to
294
   //     0x0303 (TLS 1.2).
295
   //
296
   // Note that the legacy version (TLS 1.2) is set in this constructor's
297
   // initializer list, accordingly.
298
   m_data->extensions().add(new Supported_Versions(Protocol_Version::TLS_V13));  // NOLINT(*-owning-memory)
383✔
299

300
   if(key_exchange_group.has_value()) {
383✔
301
      BOTAN_ASSERT_NOMSG(ch.extensions().has<Key_Share>());
383✔
302
      m_data->extensions().add(Key_Share::create_as_encapsulation(
1,133✔
303
         key_exchange_group.value(), *ch.extensions().get<Key_Share>(), policy, cb, rng));
383✔
304
   }
305

306
   const auto& ch_exts = ch.extensions();
367✔
307

308
   if(ch_exts.has<PSK>()) {
367✔
309
      const auto cs = Ciphersuite::by_id(m_data->ciphersuite());
97✔
310
      BOTAN_ASSERT_NOMSG(cs);
97✔
311

312
      // RFC 8446 4.2.9
313
      //    A client MUST provide a "psk_key_exchange_modes" extension if it
314
      //    offers a "pre_shared_key" extension.
315
      //
316
      // Note: Client_Hello_13 constructor already performed a graceful check.
317
      auto* const psk_modes = ch_exts.get<PSK_Key_Exchange_Modes>();
97✔
318
      BOTAN_ASSERT_NONNULL(psk_modes);
97✔
319

320
      // TODO: also support PSK_Key_Exchange_Mode::PSK_KE
321
      //       (PSK-based handshake without an additional ephemeral key exchange)
322
      if(value_exists(psk_modes->modes(), PSK_Key_Exchange_Mode::PSK_DHE_KE)) {
194✔
323
         if(auto server_psk = ch_exts.get<PSK>()->select_offered_psk(
96✔
324
               ch.sni_hostname(), cs.value(), session_mgr, credentials_mgr, cb, policy)) {
192✔
325
            // RFC 8446 4.2.11
326
            //    In order to accept PSK key establishment, the server sends a
327
            //    "pre_shared_key" extension indicating the selected identity.
328
            m_data->extensions().add(std::move(server_psk));
188✔
329
         }
96✔
330
      }
331
   }
332

333
   cb.tls_modify_extensions(m_data->extensions(), Connection_Side::Server, type());
367✔
334
}
383✔
335

336
std::optional<Protocol_Version> Server_Hello_13::random_signals_downgrade() const {
×
337
   const uint64_t last8 = load_be<uint64_t>(m_data->random().data(), 3);
×
338
   if(last8 == DOWNGRADE_TLS11) {
×
339
      return Protocol_Version::TLS_V11;
×
340
   }
341
   if(last8 == DOWNGRADE_TLS12) {
×
342
      return Protocol_Version::TLS_V12;
×
343
   }
344

345
   return std::nullopt;
×
346
}
347

348
Protocol_Version Server_Hello_13::selected_version() const {
2,604✔
349
   auto* const versions_ext = m_data->extensions().get<Supported_Versions>();
2,604✔
350
   BOTAN_ASSERT_NOMSG(versions_ext);
2,604✔
351
   const auto& versions = versions_ext->versions();
2,604✔
352
   BOTAN_ASSERT_NOMSG(versions.size() == 1);
2,604✔
353
   return versions.front();
2,604✔
354
}
355

356
Hello_Retry_Request::Hello_Retry_Request(std::unique_ptr<Server_Hello_Internal> data) :
69✔
357
      Server_Hello_13(std::move(data), Server_Hello_13::as_hello_retry_request) {}
69✔
358

359
Hello_Retry_Request::Hello_Retry_Request(const Client_Hello_13& ch,
49✔
360
                                         Named_Group selected_group,
361
                                         const Policy& policy,
362
                                         Callbacks& cb) :
49✔
363
      Server_Hello_13(std::make_unique<Server_Hello_Internal>(
98✔
364
                         Protocol_Version::TLS_V12 /* legacy_version */,
365
                         ch.session_id(),
49✔
366
                         std::vector<uint8_t>(HELLO_RETRY_REQUEST_MARKER.begin(), HELLO_RETRY_REQUEST_MARKER.end()),
49✔
367
                         choose_ciphersuite(ch, policy),
49✔
368
                         uint8_t(0) /* compression method */,
98✔
369
                         true /* is Hello Retry Request */
98✔
370
                         ),
371
                      as_new_hello_retry_request) {
98✔
372
   // RFC 8446 4.1.4
373
   //     As with the ServerHello, a HelloRetryRequest MUST NOT contain any
374
   //     extensions that were not first offered by the client in its
375
   //     ClientHello, with the exception of optionally the "cookie" [...]
376
   //     extension.
377
   BOTAN_STATE_CHECK(ch.extensions().has<Supported_Groups>());
49✔
378
   BOTAN_STATE_CHECK(ch.extensions().has<Key_Share>());
49✔
379

380
   BOTAN_STATE_CHECK(!value_exists(ch.extensions().get<Key_Share>()->offered_groups(), selected_group));
114✔
381

382
   // RFC 8446 4.1.4
383
   //    The server's extensions MUST contain "supported_versions".
384
   //
385
   // RFC 8446 4.2.1
386
   //    A server which negotiates TLS 1.3 MUST respond by sending a
387
   //    "supported_versions" extension containing the selected version
388
   //    value (0x0304). It MUST set the ServerHello.legacy_version field to
389
   //    0x0303 (TLS 1.2).
390
   //
391
   // Note that the legacy version (TLS 1.2) is set in this constructor's
392
   // initializer list, accordingly.
393
   // NOLINTBEGIN(*-owning-memory)
394
   m_data->extensions().add(new Supported_Versions(Protocol_Version::TLS_V13));
49✔
395

396
   m_data->extensions().add(new Key_Share(selected_group));
49✔
397
   // NOLINTEND(*-owning-memory)
398

399
   cb.tls_modify_extensions(m_data->extensions(), Connection_Side::Server, type());
49✔
400
}
49✔
401

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