Botan 3.13.0
Crypto and TLS for C&
tls_client_impl_13.cpp
Go to the documentation of this file.
1/*
2* TLS Client - implementation for TLS 1.3
3* (C) 2022 Jack Lloyd
4* 2021 Elektrobit Automotive GmbH
5* 2022 Hannes Rantzsch, René Meusel - neXenio GmbH
6*
7* Botan is released under the Simplified BSD License (see license.txt)
8*/
9
10#include <botan/internal/tls_client_impl_13.h>
11
12#include <botan/credentials_manager.h>
13#include <botan/tls_callbacks.h>
14#include <botan/tls_extensions_13.h>
15#include <botan/tls_messages_13.h>
16#include <botan/tls_policy.h>
17#include <botan/x509cert.h>
18#include <botan/internal/stl_util.h>
19#include <botan/internal/tls_channel_impl_13.h>
20#include <botan/internal/tls_cipher_state.h>
21
22#include <utility>
23
24namespace Botan::TLS {
25
26Client_Impl_13::Client_Impl_13(const std::shared_ptr<Callbacks>& callbacks,
27 const std::shared_ptr<Session_Manager>& session_manager,
28 const std::shared_ptr<Credentials_Manager>& creds,
29 const std::shared_ptr<const Policy>& policy,
30 const std::shared_ptr<RandomNumberGenerator>& rng,
32 const std::vector<std::string>& next_protocols) :
33 Channel_Impl_13(callbacks, session_manager, creds, rng, policy, false /* is_server */),
34 m_info(std::move(info)),
35 m_handshake(std::make_unique<Pending_Handshake>()) {
36#if defined(BOTAN_HAS_TLS_DOWNGRADE_SUPPORT)
37 if(policy->allow_tls12()) {
38 expect_downgrade(m_info, next_protocols);
39 }
40#endif
41
42 if(auto session = find_session_for_resumption()) {
43 if(session->session.version().is_tls_13_or_later()) {
44 m_handshake->resumed_session = std::move(session);
45 }
46#if defined(BOTAN_HAS_TLS_DOWNGRADE_SUPPORT)
47 else if(expects_downgrade()) {
48 // If we found a session that was created with TLS 1.2, we downgrade
49 // the implementation right away, before even issuing a Client Hello.
50 request_downgrade_for_resumption(std::move(session.value()));
51 return;
52 }
53#endif
54 }
55
56 send_handshake_message(m_handshake->state.sending(
58 *callbacks,
59 *rng,
60 m_info.hostname(),
61 next_protocols,
62 m_handshake->resumed_session,
63 creds->find_preshared_keys(m_info.hostname(), Connection_Side::Client))));
64
65 maybe_handle_compatibility_mode(Compat_Mode_Situation::AfterSendingFirstClientHello);
66
67 m_handshake->transitions.set_expected_next({Handshake_Type::ServerHello, Handshake_Type::HelloRetryRequest});
68}
69
70void Client_Impl_13::process_handshake_msg(Handshake_Message_13 message) {
71 BOTAN_STATE_CHECK(m_handshake != nullptr);
72
73 // first verify that the message was expected by the state machine
74 // (and only then store it in the handshake state)
75 m_handshake->transitions.confirm_transition_to(std::visit([](const auto& msg) { return msg.type(); }, message));
76
77 std::visit(
78 [&](auto msg) {
79 // ... then allow the library user to abort on their discretion
81
82 // ... finally handle the message
83 handle(msg.get());
84 },
85 m_handshake->state.received(std::move(message)));
86}
87
88void Client_Impl_13::process_post_handshake_msg(Post_Handshake_Message_13 message) {
90
91 const auto msg = specialize_to<Server_Post_Handshake_13_Message>(std::move(message));
92 if(!msg) {
93 throw TLS_Exception(Alert::UnexpectedMessage, "received an unexpected post-handshake message");
94 }
95
96 std::visit([&](auto&& m) { handle(m); }, *msg);
97}
98
100 // RFC 8446 5.
101 // If an implementation detects a change_cipher_spec record received before
102 // the first ClientHello message or after the peer's Finished message, it MUST be
103 // treated as an unexpected record type [("unexpected_message" alert)].
104 if(!m_handshake || !m_handshake->state.has_client_hello() || m_handshake->state.has_server_finished()) {
105 throw TLS_Exception(Alert::UnexpectedMessage, "Received an unexpected dummy Change Cipher Spec");
106 }
107
108 // RFC 8446 5.
109 // An implementation may receive an unencrypted record of type change_cipher_spec [...]
110 // at any time after the first ClientHello message has been sent or received
111 // and before the peer's Finished message has been received [...]
112 // and MUST simply drop it without further processing.
113 //
114 // ... no further processing.
115}
116
118 return m_active_state.has_value();
119}
120
121std::optional<Session_with_Handle> Client_Impl_13::find_session_for_resumption() {
122 // RFC 8446 4.6.1
123 // Clients MUST only resume if the new SNI value is valid for the
124 // server certificate presented in the original session and SHOULD only
125 // resume if the SNI value matches the one used in the original session.
126 //
127 // Below we search sessions based on their SNI value. Assuming that a
128 // 3rd party session manager does not lie to the implementation, we don't
129 // explicitly re-check that the SNI values match.
130 //
131 // Also, the default implementation did verify that very same SNI information
132 // against the server's certificate (via Callbacks::tls_verify_cert_chain())
133 // before storing it in the session.
134 //
135 // We therefore assume that the session returned by the `Session_Manager` is
136 // suitable for resumption in this context.
137 auto sessions = session_manager().find(m_info, callbacks(), policy());
138 if(sessions.empty()) {
139 return std::nullopt;
140 }
141
142 // TODO: TLS 1.3 allows sending more than one ticket (for resumption) in a
143 // Client Hello. Currently, we do not support that. The Session_Manager
144 // does imply otherwise with its API, though.
145 auto& session_to_resume = sessions.front();
146
147 return std::move(session_to_resume);
148}
149
150void Client_Impl_13::handle(const Server_Hello_12_Shim& server_hello_msg) {
151 BOTAN_ASSERT_NONNULL(m_handshake);
152
153 if(m_handshake->state.has_hello_retry_request()) {
154 throw TLS_Exception(Alert::UnexpectedMessage, "Version downgrade received after Hello Retry");
155 }
156
157#if !defined(BOTAN_HAS_TLS_DOWNGRADE_SUPPORT)
158 BOTAN_UNUSED(server_hello_msg);
159 throw TLS_Exception(Alert::ProtocolVersion, "Received an unsupported Server Hello");
160#else
161
162 // RFC 8446 Appendix D.1
163 // If the version chosen by the server is not supported by the client
164 // (or is not acceptable), the client MUST abort the handshake with a
165 // "protocol_version" alert.
166 if(!expects_downgrade()) {
167 throw TLS_Exception(Alert::ProtocolVersion, "Received an unexpected legacy Server Hello");
168 }
169
170 // RFC 8446 4.1.3
171 // TLS 1.3 has a downgrade protection mechanism embedded in the server's
172 // random value. TLS 1.3 servers which negotiate TLS 1.2 or below in
173 // response to a ClientHello MUST set the last 8 bytes of their Random
174 // value specially in their ServerHello.
175 //
176 // TLS 1.3 clients receiving a ServerHello indicating TLS 1.2 or below
177 // MUST check that the [downgrade indication is not set]. [...] If a match
178 // is found, the client MUST abort the handshake with an
179 // "illegal_parameter" alert.
180 if(server_hello_msg.random_signals_downgrade().has_value()) {
181 throw TLS_Exception(Alert::IllegalParameter, "Downgrade attack detected");
182 }
183
184 // RFC 8446 4.2.1
185 // A server which negotiates a version of TLS prior to TLS 1.3 [...]
186 // MUST NOT send the "supported_versions" extension.
187 //
188 // Note that this condition should never happen, as the Server_Hello parsing
189 // code decides to create a Server_Hello_12 based on the absence of this extension.
190 if(server_hello_msg.extensions().has<Supported_Versions>()) {
191 throw TLS_Exception(Alert::IllegalParameter, "Unexpected extension received");
192 }
193
194 // RFC 8446 Appendix D.1
195 // If the version chosen by the server is not supported by the client
196 // (or is not acceptable), the client MUST abort the handshake with a
197 // "protocol_version" alert.
198 const auto& client_hello_exts = m_handshake->state.client_hello().extensions();
199 BOTAN_ASSERT_NOMSG(client_hello_exts.has<Supported_Versions>());
200 if(!client_hello_exts.get<Supported_Versions>()->supports(server_hello_msg.selected_version())) {
201 throw TLS_Exception(Alert::ProtocolVersion, "Protocol version was not offered");
202 }
203
204 if(policy().tls_13_middlebox_compatibility_mode() &&
205 m_handshake->state.client_hello().session_id() == server_hello_msg.session_id()) {
206 // In compatibility mode, the server will reflect the session ID we sent in the client hello.
207 // However, a TLS 1.2 server that wants to downgrade cannot have found the random session ID
208 // we sent. Therefore, we have to consider this as an attack.
209 // (Thanks BoGo test EchoTLS13CompatibilitySessionID!)
210 throw TLS_Exception(Alert::IllegalParameter, "Unexpected session ID during downgrade");
211 }
212
213 preserve_client_hello(m_handshake->state.take_client_hello());
214 request_downgrade();
215
216 // After this, no further messages are expected here because this instance will be replaced
217 // by a Client_Impl_12.
218 m_handshake->transitions.set_expected_next({});
219#endif
220}
221
222namespace {
223// validate Server_Hello_13 and Hello_Retry_Request
224void validate_server_hello_ish(const Client_Hello_13& ch, const Server_Hello_13& sh) {
225 // RFC 8446 4.1.3
226 // A client which receives a legacy_session_id_echo field that does not match what
227 // it sent in the ClientHello MUST abort the handshake with an "illegal_parameter" alert.
228 if(ch.session_id() != sh.session_id()) {
229 throw TLS_Exception(Alert::IllegalParameter, "echoed session id did not match");
230 }
231
232 // RFC 8446 4.1.3
233 // A client which receives a cipher suite that was not offered MUST abort the handshake
234 // with an "illegal_parameter" alert.
235 if(!ch.offered_suite(sh.ciphersuite())) {
236 throw TLS_Exception(Alert::IllegalParameter, "Server replied with ciphersuite we didn't send");
237 }
238
239 // RFC 8446 4.2.1
240 // If the "supported_versions" extension in the ServerHello contains a
241 // version not offered by the client or contains a version prior to
242 // TLS 1.3, the client MUST abort the handshake with an "illegal_parameter" alert.
243 //
244 // Note: Server_Hello_13 parsing checks that its selected version is TLS 1.3
245 BOTAN_ASSERT_NOMSG(ch.extensions().has<Supported_Versions>());
246 if(!ch.extensions().get<Supported_Versions>()->supports(sh.selected_version())) {
247 throw TLS_Exception(Alert::IllegalParameter, "Protocol version was not offered");
248 }
249}
250} // namespace
251
252void Client_Impl_13::handle(const Server_Hello_13& sh) {
253 // Note: Basic checks (that do not require contextual information) were already
254 // performed during the construction of the Server_Hello_13 object.
255 BOTAN_ASSERT_NONNULL(m_handshake);
256
257 const auto& ch = m_handshake->state.client_hello();
258
259 validate_server_hello_ish(ch, sh);
260
261 // RFC 8446 4.1.3: TLS 1.3 servers downgrading to TLS 1.2 or below set
262 // the last 8 bytes of ServerHello.random to a magic value so the client
263 // can detect a stripped-supported_versions downgrade attack. The Shim
264 // path (Server_Hello_12_Shim) already enforces this; catch it here too
265 // as defense in depth in case a misbehaving server writes the sentinel
266 // into an actual TLS 1.3 ServerHello.
267 if(sh.random_signals_downgrade().has_value()) {
268 throw TLS_Exception(Alert::IllegalParameter, "Downgrade attack detected");
269 }
270
271 // RFC 8446 4.2
272 // Implementations MUST NOT send extension responses if the remote
273 // endpoint did not send the corresponding extension requests, [...]. Upon
274 // receiving such an extension, an endpoint MUST abort the handshake
275 // with an "unsupported_extension" alert.
276 if(sh.extensions().contains_other_than(ch.extensions().extension_types())) {
277 throw TLS_Exception(Alert::UnsupportedExtension, "Unsupported extension found in Server Hello");
278 }
279
280 if(m_handshake->state.has_hello_retry_request()) {
281 const auto& hrr = m_handshake->state.hello_retry_request();
282
283 // RFC 8446 4.1.4
284 // Upon receiving the ServerHello, clients MUST check that the cipher suite
285 // supplied in the ServerHello is the same as that in the HelloRetryRequest
286 // and otherwise abort the handshake with an "illegal_parameter" alert.
287 if(hrr.ciphersuite() != sh.ciphersuite()) {
288 throw TLS_Exception(Alert::IllegalParameter, "server changed its chosen ciphersuite");
289 }
290
291 // RFC 8446 4.1.4
292 // The value of selected_version in the HelloRetryRequest "supported_versions"
293 // extension MUST be retained in the ServerHello, and a client MUST abort the
294 // handshake with an "illegal_parameter" alert if the value changes.
295 if(hrr.selected_version() != sh.selected_version()) {
296 throw TLS_Exception(Alert::IllegalParameter, "server changed its chosen protocol version");
297 }
298 }
299
300 auto cipher = Ciphersuite::by_id(sh.ciphersuite());
301 BOTAN_ASSERT_NOMSG(cipher.has_value()); // should work, since we offered this suite
302
303 // RFC 8446 Appendix B.4
304 // Although TLS 1.3 uses the same cipher suite space as previous versions
305 // of TLS [...] cipher suites for TLS 1.2 and lower cannot be used with
306 // TLS 1.3.
307 if(!cipher->usable_in_version(Protocol_Version::TLS_V13)) {
308 throw TLS_Exception(Alert::IllegalParameter,
309 "Server replied using a ciphersuite not allowed in version it offered");
310 }
311
312 // RFC 8446 4.2.11
313 // Clients MUST verify that [...] a server "key_share" extension is present
314 // if required by the ClientHello "psk_key_exchange_modes" extension. If
315 // these values are not consistent, the client MUST abort the handshake
316 // with an "illegal_parameter" alert.
317 //
318 // Currently, we don't support PSK-only mode, hence a key share extension is
319 // considered mandatory.
320 //
321 // TODO: Implement PSK-only mode.
322 if(!sh.extensions().has<Key_Share>()) {
323 throw TLS_Exception(Alert::IllegalParameter, "Server Hello did not contain a key share extension");
324 }
325
326 auto* my_keyshare = ch.extensions().get<Key_Share>();
327 auto shared_secret = my_keyshare->decapsulate(*sh.extensions().get<Key_Share>(), policy(), callbacks(), rng());
328
329 m_transcript_hash.set_algorithm(cipher.value().prf_algo());
330
331 if(sh.extensions().has<PSK>()) {
332 std::tie(m_handshake->psk_identity, m_cipher_state) =
333 ch.extensions().get<PSK>()->take_selected_psk_info(*sh.extensions().get<PSK>(), cipher.value());
334
335 // If we offered a session for resumption *and* an externally provided PSK
336 // and the latter was chosen by the server over the offered resumption, we
337 // want to invalidate the now-outdated session in m_handshake->resumed_session.
338 if(m_handshake->psk_identity.has_value() && m_handshake->resumed_session.has_value()) {
339 m_handshake->resumed_session.reset();
340 }
341
342 // TODO: When implementing early data, `advance_with_client_hello` must
343 // happen _before_ encrypting any early application data.
344 // Same when we want to support early key export.
345 m_cipher_state->advance_with_client_hello(m_transcript_hash.previous(), *this);
346 m_cipher_state->advance_with_server_hello(
347 cipher.value(), std::move(shared_secret), m_transcript_hash.current(), *this);
348 } else {
349 m_handshake->resumed_session.reset(); // might have been set if we attempted a resumption
351 m_side, std::move(shared_secret), cipher.value(), m_transcript_hash.current(), *this);
352 }
353
355
356 m_handshake->transitions.set_expected_next(Handshake_Type::EncryptedExtensions);
357}
358
359void Client_Impl_13::handle(const Hello_Retry_Request& hrr) {
360 // Note: Basic checks (that do not require contextual information) were already
361 // performed during the construction of the Hello_Retry_Request object as
362 // a subclass of Server_Hello_13.
363 BOTAN_ASSERT_NONNULL(m_handshake);
364
365 auto& ch = m_handshake->state.client_hello();
366
367 validate_server_hello_ish(ch, hrr);
368
369 // RFC 8446 4.1.4.
370 // A HelloRetryRequest MUST NOT contain any
371 // extensions that were not first offered by the client in its
372 // ClientHello, with the exception of optionally the "cookie".
373 auto allowed_exts = ch.extensions().extension_types();
374 allowed_exts.insert(Extension_Code::Cookie);
375 if(hrr.extensions().contains_other_than(allowed_exts)) {
376 throw TLS_Exception(Alert::UnsupportedExtension, "Unsupported extension found in Hello Retry Request");
377 }
378
379 auto cipher = Ciphersuite::by_id(hrr.ciphersuite());
380 BOTAN_ASSERT_NOMSG(cipher.has_value()); // should work, since we offered this suite
381
382 // RFC 8446 4.1.4 / Appendix B.4
383 // Similarly, cipher suites for TLS 1.2 and lower cannot be used with
384 // TLS 1.3.
385 if(!cipher->usable_in_version(Protocol_Version::TLS_V13)) {
386 throw TLS_Exception(Alert::IllegalParameter, "HelloRetryRequest selected a cipher suite not usable in TLS 1.3");
387 }
388
391
392 ch.retry(hrr, m_transcript_hash, callbacks(), rng());
393
395
396 maybe_handle_compatibility_mode(Compat_Mode_Situation::BeforeSendingSecondClientHello);
397 send_handshake_message(std::reference_wrapper(ch));
398
399 // RFC 8446 4.1.4
400 // If a client receives a second HelloRetryRequest in the same connection [...],
401 // it MUST abort the handshake with an "unexpected_message" alert.
402 m_handshake->transitions.set_expected_next(Handshake_Type::ServerHello);
403}
404
405void Client_Impl_13::handle(const Encrypted_Extensions& encrypted_extensions_msg) {
406 BOTAN_ASSERT_NONNULL(m_handshake);
407
408 const auto& exts = encrypted_extensions_msg.extensions();
409
410 // RFC 8446 4.2
411 // Implementations MUST NOT send extension responses if the remote
412 // endpoint did not send the corresponding extension requests, [...]. Upon
413 // receiving such an extension, an endpoint MUST abort the handshake
414 // with an "unsupported_extension" alert.
415 const auto& requested_exts = m_handshake->state.client_hello().extensions().extension_types();
416 if(exts.contains_other_than(requested_exts)) {
417 throw TLS_Exception(Alert::UnsupportedExtension,
418 "Encrypted Extensions contained an extension that was not offered");
419 }
420
421 // Note: As per RFC 6066 3. we can check for an empty SNI extensions to
422 // determine if the server used the SNI we sent here.
423
424 if(exts.has<Application_Layer_Protocol_Notification>()) {
425 // RFC 7301 3.2
426 // The "extension_data" field of the [...] "application_layer_protocol_negotiation"
427 // extension [...] SHALL include the server's selection of a protocol from among
428 // the list that was advertised by the client.
429 const auto* server_alpn = exts.get<Application_Layer_Protocol_Notification>();
430 const auto selected = server_alpn->single_protocol();
431 const auto* client_alpn =
432 m_handshake->state.client_hello().extensions().get<Application_Layer_Protocol_Notification>();
433 BOTAN_ASSERT_NONNULL(client_alpn); // unrequested extension check above ensures this
434 const auto& offered = client_alpn->protocols();
435 if(!value_exists(offered, selected)) {
436 throw TLS_Exception(Alert::IllegalParameter, "Server selected an ALPN protocol not offered by the client");
437 }
438 }
439
440 if(exts.has<Record_Size_Limit>() && m_handshake->state.client_hello().extensions().has<Record_Size_Limit>()) {
441 // RFC 8449 4.
442 // The record size limit only applies to records sent toward the
443 // endpoint that advertises the limit. An endpoint can send records
444 // that are larger than the limit it advertises as its own limit.
445 //
446 // Hence, the "outgoing" limit is what the server requested and the
447 // "incoming" limit is what we requested in the Client Hello.
448 auto* const outgoing_limit = exts.get<Record_Size_Limit>();
449 auto* const incoming_limit = m_handshake->state.client_hello().extensions().get<Record_Size_Limit>();
450 set_record_size_limits(outgoing_limit->limit(), incoming_limit->limit());
451 }
452
453 if(exts.has<Server_Certificate_Type>()) {
454 // The unrequested-extension check above ensures the client offered this.
455 BOTAN_ASSERT_NOMSG(m_handshake->state.client_hello().extensions().has<Server_Certificate_Type>());
456 const auto* server_cert_type = exts.get<Server_Certificate_Type>();
457 const auto* our_server_cert_types = m_handshake->state.client_hello().extensions().get<Server_Certificate_Type>();
458 our_server_cert_types->validate_selection(*server_cert_type);
459
460 // RFC 7250 4.2
461 // With the server_certificate_type extension in the server hello, the
462 // TLS server indicates the certificate type carried in the Certificate
463 // payload.
464 //
465 // Note: TLS 1.3 carries this extension in the Encrypted Extensions
466 // message instead of the Server Hello.
467 set_selected_certificate_type(server_cert_type->selected_certificate_type());
468 }
469
471
472 if(m_handshake->state.server_hello().extensions().has<PSK>()) {
473 // RFC 8446 2.2
474 // As the server is authenticating via a PSK, it does not send a
475 // Certificate or a CertificateVerify message.
476 m_handshake->transitions.set_expected_next(Handshake_Type::Finished);
477 } else {
478 m_handshake->transitions.set_expected_next({Handshake_Type::Certificate, Handshake_Type::CertificateRequest});
479 }
480}
481
482void Client_Impl_13::handle(const Certificate_Request_13& certificate_request_msg) {
483 BOTAN_ASSERT_NONNULL(m_handshake);
484
485 // RFC 8446 4.3.2
486 // [The 'context' field] SHALL be zero length unless used for the
487 // post-handshake authentication exchanges described in Section 4.6.2.
488 if(!is_handshake_complete() && !certificate_request_msg.context().empty()) {
489 throw TLS_Exception(Alert::DecodeError, "Certificate_Request context must be empty in the main handshake");
490 }
491
493 certificate_request_msg.extensions(), Connection_Side::Server, Handshake_Type::CertificateRequest);
494 m_handshake->transitions.set_expected_next(Handshake_Type::Certificate);
495}
496
497void Client_Impl_13::handle(const Certificate_13& certificate_msg) {
498 BOTAN_ASSERT_NONNULL(m_handshake);
499
500 // RFC 8446 4.4.2
501 // certificate_request_context: [...] In the case of server authentication,
502 // this field SHALL be zero length.
503 if(!certificate_msg.request_context().empty()) {
504 throw TLS_Exception(Alert::DecodeError, "Received a server certificate message with non-empty request context");
505 }
506
507 // RFC 8446 4.4.2
508 // Extensions in the Certificate message from the server MUST correspond
509 // to ones from the ClientHello message.
510 certificate_msg.validate_extensions(m_handshake->state.client_hello().extensions().extension_types(), callbacks());
511 certificate_msg.verify(callbacks(),
512 policy(),
514 m_info.hostname(),
515 m_handshake->state.client_hello().extensions().has<Certificate_Status_Request>());
516
517 m_handshake->transitions.set_expected_next(Handshake_Type::CertificateVerify);
518}
519
520void Client_Impl_13::handle(const Certificate_Verify_13& certificate_verify_msg) {
521 BOTAN_ASSERT_NONNULL(m_handshake);
522
523 // RFC 8446 4.4.3
524 // If the CertificateVerify message is sent by a server, the signature
525 // algorithm MUST be one offered in the client's "signature_algorithms"
526 // extension unless no valid certificate chain can be produced without
527 // unsupported algorithms.
528 //
529 // Note: if the server failed to produce a certificate chain without using
530 // an unsupported signature scheme, we opt to abort the handshake.
531 const auto offered = m_handshake->state.client_hello().signature_schemes();
532 if(!value_exists(offered, certificate_verify_msg.signature_scheme())) {
533 throw TLS_Exception(Alert::IllegalParameter,
534 "We did not offer the usage of " + certificate_verify_msg.signature_scheme().to_string() +
535 " as a signature scheme");
536 }
537
538 const bool sig_valid = certificate_verify_msg.verify(
539 *m_handshake->state.server_certificate().public_key(), callbacks(), m_transcript_hash.previous());
540
541 if(!sig_valid) {
542 throw TLS_Exception(Alert::DecryptError, "Server certificate verification failed");
543 }
544
545 m_handshake->transitions.set_expected_next(Handshake_Type::Finished);
546}
547
548void Client_Impl_13::send_client_authentication(Channel_Impl_13::AggregatedHandshakeMessages& flight) {
549 BOTAN_ASSERT_NOMSG(m_handshake->state.has_certificate_request());
550 const auto& cert_request = m_handshake->state.certificate_request();
551
552 const auto cert_type = [&] {
553 const auto& exts = m_handshake->state.encrypted_extensions().extensions();
554 const auto& chexts = m_handshake->state.client_hello().extensions();
555 if(exts.has<Client_Certificate_Type>()) {
556 // The unrequested-extension check in handle(Encrypted_Extensions) ensures the client offered this.
557 BOTAN_ASSERT_NOMSG(chexts.has<Client_Certificate_Type>());
558 const auto* client_cert_type = exts.get<Client_Certificate_Type>();
559 chexts.get<Client_Certificate_Type>()->validate_selection(*client_cert_type);
560
561 // RFC 7250 4.2
562 // This client_certificate_type extension in the server hello then
563 // indicates the type of certificates the client is requested to
564 // provide in a subsequent certificate payload.
565 //
566 // Note: TLS 1.3 carries this extension in the Encrypted Extensions
567 // message instead of the Server Hello.
568 return client_cert_type->selected_certificate_type();
569 } else {
570 // RFC 8446 4.4.2
571 // If the corresponding certificate type extension [...] was not
572 // negotiated in EncryptedExtensions, [...] then each
573 // CertificateEntry contains a DER-encoded X.509 certificate.
575 }
576 }();
577
578 // RFC 8446 4.4.2
579 // certificate_request_context: If this message is in response to a
580 // CertificateRequest, the value of certificate_request_context in
581 // that message.
582 flight.add(m_handshake->state.sending(
583 Certificate_13(cert_request, m_info.hostname(), credentials_manager(), callbacks(), cert_type)));
584
585 // RFC 8446 4.4.2
586 // If the server requests client authentication but no suitable certificate
587 // is available, the client MUST send a Certificate message containing no
588 // certificates.
589 //
590 // In that case, no Certificate Verify message will be sent.
591 if(!m_handshake->state.client_certificate().empty()) {
592 flight.add(m_handshake->state.sending(Certificate_Verify_13(m_handshake->state.client_certificate(),
593 cert_request.signature_schemes(),
594 m_info.hostname(),
595 m_transcript_hash.current(),
598 policy(),
599 callbacks(),
600 rng())));
601 }
602}
603
604void Client_Impl_13::handle(const Finished_13& finished_msg) {
605 BOTAN_ASSERT_NONNULL(m_handshake);
606
607 // RFC 8446 4.4.4
608 // Recipients of Finished messages MUST verify that the contents are
609 // correct and if incorrect MUST terminate the connection with a
610 // "decrypt_error" alert.
611 if(!finished_msg.verify(m_cipher_state.get(), m_transcript_hash.previous())) {
612 throw TLS_Exception(Alert::DecryptError, "Finished message didn't verify");
613 }
614
615 m_handshake->state.confirm_peer_finished_verified();
616
617 // Give the application a chance for a final veto before fully
618 // establishing the connection.
619 callbacks().tls_session_established(Session_Summary(m_handshake->state.server_hello(),
624 m_handshake->resumed_session.has_value(),
625 m_info,
626 callbacks().tls_current_timestamp()));
627
628 // Derives the secrets for receiving application data but defers
629 // the derivation of sending application data.
630 m_cipher_state->advance_with_server_finished(m_transcript_hash.current(), *this);
631
632 auto flight = aggregate_handshake_messages();
633
634 // RFC 8446 4.4.2
635 // The client MUST send a Certificate message if and only if the server
636 // has requested client authentication via a CertificateRequest message.
637 if(m_handshake->state.has_certificate_request()) {
638 send_client_authentication(flight);
639 }
640
641 // send client finished handshake message (still using handshake traffic secrets)
642 flight.add(m_handshake->state.sending(Finished_13(m_cipher_state.get(), m_transcript_hash.current())));
643
644 maybe_handle_compatibility_mode(Compat_Mode_Situation::BeforeSendingEncryptedClientFlight);
645 flight.send();
646
647 // derives the sending application traffic secrets
648 m_cipher_state->advance_with_client_finished(m_transcript_hash.current());
649
650 // TODO: Create a dummy session object and invoke tls_session_established.
651 // Alternatively, consider changing the expectations described in the
652 // callback's doc string.
653
654 // no more handshake messages expected
655 m_handshake->transitions.set_expected_next({});
656
657 // Extract post-handshake state before signaling activation.
658 // After this point, only m_active_state should be consulted
659 // for connection properties.
660 {
661 auto extract_certs = [&]() -> std::vector<X509_Certificate> {
662 if(m_handshake->state.has_server_certificate_msg() &&
663 m_handshake->state.server_certificate().has_certificate_chain()) {
664 return m_handshake->state.server_certificate().cert_chain();
665 }
666 if(m_handshake->resumed_session.has_value()) {
667 return m_handshake->resumed_session->session.peer_certs();
668 }
669 return {};
670 };
671
672 auto extract_raw_pk = [&]() -> std::shared_ptr<const Public_Key> {
673 if(m_handshake->state.has_server_certificate_msg() &&
674 m_handshake->state.server_certificate().is_raw_public_key()) {
675 return m_handshake->state.server_certificate().public_key();
676 }
677 if(m_handshake->resumed_session.has_value()) {
678 return m_handshake->resumed_session->session.peer_raw_public_key();
679 }
680 return nullptr;
681 };
682
683 m_active_state = Active_Connection_State_13(m_handshake->state,
684 extract_certs(),
685 extract_raw_pk(),
686 m_handshake->psk_identity,
687 m_info.hostname(),
688 false /* peer_supports_psk_dhe_ke - client doesn't need this */);
689 }
690
691 m_handshake.reset();
692 m_transcript_hash = Transcript_Hash_State();
694}
695
696void TLS::Client_Impl_13::handle(const New_Session_Ticket_13& new_session_ticket) {
697 BOTAN_STATE_CHECK(m_active_state.has_value());
698
699 if(const size_t max_tickets = policy().maximum_session_tickets_per_connection();
700 max_tickets > 0 && m_session_tickets_received >= max_tickets) {
701 // Silently ignore excess tickets rather than terminating the connection,
702 // since the server may have legitimate reasons to send many tickets.
703 return;
704 }
705 ++m_session_tickets_received;
706
707 callbacks().tls_examine_extensions(
708 new_session_ticket.extensions(), Connection_Side::Server, Handshake_Type::NewSessionTicket);
709
710 const Session session(m_cipher_state->psk(new_session_ticket.nonce()),
711 new_session_ticket.early_data_byte_limit(),
712 new_session_ticket.ticket_age_add(),
713 new_session_ticket.lifetime_hint(),
714 m_active_state->version(),
715 m_active_state->ciphersuite_code(),
717 peer_cert_chain(),
718 peer_raw_public_key(),
719 m_info,
720 callbacks().tls_current_timestamp());
721
722 if(callbacks().tls_should_persist_resumption_information(session)) {
723 session_manager().store(session, Session_Handle(new_session_ticket.handle()));
724 }
725}
726
727std::vector<X509_Certificate> Client_Impl_13::peer_cert_chain() const {
728 if(m_active_state.has_value()) {
729 return m_active_state->peer_certs();
730 }
731
732 // During handshake, before m_active_state is populated
733 if(m_handshake) {
734 if(m_handshake->state.has_server_certificate_msg() &&
735 m_handshake->state.server_certificate().has_certificate_chain()) {
736 return m_handshake->state.server_certificate().cert_chain();
737 }
738
739 if(m_handshake->resumed_session.has_value()) {
740 return m_handshake->resumed_session->session.peer_certs();
741 }
742 }
743
744 return {};
745}
746
747std::shared_ptr<const Public_Key> Client_Impl_13::peer_raw_public_key() const {
748 if(m_active_state.has_value()) {
749 return m_active_state->peer_raw_public_key();
750 }
751
752 // During handshake, before m_active_state is populated
753 if(m_handshake) {
754 if(m_handshake->state.has_server_certificate_msg() &&
755 m_handshake->state.server_certificate().is_raw_public_key()) {
756 return m_handshake->state.server_certificate().public_key();
757 }
758
759 if(m_handshake->resumed_session.has_value()) {
760 return m_handshake->resumed_session->session.peer_raw_public_key();
761 }
762 }
763
764 return nullptr;
765}
766
767std::optional<std::string> Client_Impl_13::external_psk_identity() const {
768 if(m_active_state.has_value()) {
769 return m_active_state->psk_identity();
770 }
771 if(m_handshake) {
772 return m_handshake->psk_identity;
773 }
774 return std::nullopt;
775}
776
777void Client_Impl_13::maybe_handle_compatibility_mode(Compat_Mode_Situation situation) {
778 // RFC 9846 E.4
779 // This "compatibility mode" is partially negotiated: the client can opt
780 // [in] or not [...].
781 if(!policy().tls_13_middlebox_compatibility_mode()) {
782 return;
783 }
784
785 // RFC 9846 5.
786 // An implementation [...] which receives a protected change_cipher_spec
787 // record MUST abort the handshake with an "unexpected_message" alert.
788 if(m_handshake == nullptr) {
789 return;
790 }
791
792 switch(situation) {
794 // RFC 9846 E.4
795 // If offering early data, the record is placed immediately after
796 // the first ClientHello.
797 //
798 // TODO: Implement early data support
799 break;
800
802 // RFC 9846 E.4
803 // [...] the client sends a dummy change_cipher_spec record [...]
804 // immediately before its second flight. This may either be before
805 // its second ClientHello [...].
806 BOTAN_ASSERT_NOMSG(m_handshake->state.has_hello_retry_request());
808 break;
809
811 // RFC 9846 E.4
812 // [...] or before its encrypted handshake flight.
813 BOTAN_ASSERT_NOMSG(m_handshake->state.has_server_finished());
814 if(!m_handshake->state.has_hello_retry_request()) {
816 }
817 break;
818
820 // RFC 9846 E.4
821 // [...] or before its encrypted handshake flight.
822 //
823 // Note that an encrypted alert message also counts as an encrypted
824 // handshake flight, so we also send a dummy CCS in that case. Except
825 // if we did receive a HelloRetryRequest, in which case we already sent
826 // a dummy CCS before the second ClientHello.
827 if(m_cipher_state != nullptr && !m_handshake->state.has_hello_retry_request()) {
829 }
830 break;
831
834 BOTAN_ASSERT_UNREACHABLE(); // These situations occur on the server side.
835 }
836}
837
838void Client_Impl_13::maybe_log_secret(std::string_view label, std::span<const uint8_t> secret) const {
839 if(policy().allow_ssl_key_log_file()) {
840 if(m_active_state.has_value()) {
841 callbacks().tls_ssl_key_log_data(label, m_active_state->client_random(), secret);
842 } else {
843 callbacks().tls_ssl_key_log_data(label, m_handshake->state.client_hello().random(), secret);
844 }
845 }
846}
847
849 if(m_active_state.has_value()) {
850 return m_active_state->application_protocol();
851 }
852
853 return "";
854}
855
856} // namespace Botan::TLS
#define BOTAN_UNUSED
Definition assert.h:144
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:49
#define BOTAN_ASSERT_NONNULL(ptr)
Definition assert.h:114
#define BOTAN_ASSERT_UNREACHABLE()
Definition assert.h:166
virtual void tls_session_activated()
virtual void tls_examine_extensions(const Extensions &extn, Connection_Side which_side, Handshake_Type which_message)
virtual void tls_session_established(const Session_Summary &session)
virtual void tls_ssl_key_log_data(std::string_view label, std::span< const uint8_t > client_random, std::span< const uint8_t > secret) const
virtual void tls_inspect_handshake_msg(const Handshake_Message &message)
const Policy & policy() const
void send_handshake_message(const std::variant< MsgTs... > &message)
AggregatedHandshakeMessages aggregate_handshake_messages()
Credentials_Manager & credentials_manager()
RandomNumberGenerator & rng()
Transcript_Hash_State m_transcript_hash
std::optional< Active_Connection_State_13 > m_active_state
Channel_Impl_13(const std::shared_ptr< Callbacks > &callbacks, const std::shared_ptr< Session_Manager > &session_manager, const std::shared_ptr< Credentials_Manager > &credentials_manager, const std::shared_ptr< RandomNumberGenerator > &rng, const std::shared_ptr< const Policy > &policy, bool is_server)
virtual void process_dummy_change_cipher_spec()=0
Session_Manager & session_manager()
std::unique_ptr< Cipher_State > m_cipher_state
void set_selected_certificate_type(Certificate_Type cert_type)
void set_record_size_limits(uint16_t outgoing_limit, uint16_t incoming_limit)
static std::unique_ptr< Cipher_State > init_with_server_hello(Connection_Side side, secure_vector< uint8_t > &&shared_secret, const Ciphersuite &cipher, const Transcript_Hash &transcript_hash, const Secret_Logger &channel)
static std::optional< Ciphersuite > by_id(uint16_t suite)
Client_Impl_13(const std::shared_ptr< Callbacks > &callbacks, const std::shared_ptr< Session_Manager > &session_manager, const std::shared_ptr< Credentials_Manager > &creds, const std::shared_ptr< const Policy > &policy, const std::shared_ptr< RandomNumberGenerator > &rng, Server_Information server_info=Server_Information(), const std::vector< std::string > &next_protocols={})
std::optional< std::string > external_psk_identity() const override
std::string application_protocol() const override
std::shared_ptr< const Public_Key > peer_raw_public_key() const override
bool is_handshake_complete() const override
std::vector< X509_Certificate > peer_cert_chain() const override
Helper class to embody a session handle in all protocol versions.
virtual std::vector< Session_with_Handle > find(const Server_Information &info, Callbacks &callbacks, const Policy &policy)
Find all sessions that match a given server info.
bool supports(Protocol_Version version) const
static Transcript_Hash_State recreate_after_hello_retry_request(std::string_view algo_spec, const Transcript_Hash_State &prev_transcript_hash_state)
std::variant< Client_Hello_13, Client_Hello_12_Shim, Server_Hello_13, Server_Hello_12_Shim, Hello_Retry_Request, Encrypted_Extensions, Certificate_13, Certificate_Request_13, Certificate_Verify_13, Finished_13 > Handshake_Message_13
std::variant< New_Session_Ticket_13, Key_Update > Post_Handshake_Message_13
constexpr std::optional< SpecificVariantT > specialize_to(GeneralVariantT &&v)
Converts a given variant into another variant whose type states are a subset of the given variant.
Definition stl_util.h:117
bool value_exists(const std::vector< T > &vec, const V &val)
Definition stl_util.h:44