From 528058b432304a863290dd606e42d258a8ea08f3 Mon Sep 17 00:00:00 2001 From: Rene Meusel Date: Mon, 16 Oct 2023 12:26:49 +0200 Subject: [PATCH 1/3] introduce TLS::Channel::is_handshake_complete() Co-Authored-By: Fabian Albert --- src/lib/tls/tls12/tls_channel_impl_12.cpp | 9 +++++---- src/lib/tls/tls12/tls_channel_impl_12.h | 5 +++++ src/lib/tls/tls13/tls_channel_impl_13.cpp | 4 ++-- src/lib/tls/tls13/tls_channel_impl_13.h | 1 - src/lib/tls/tls13/tls_client_impl_13.cpp | 8 ++++---- src/lib/tls/tls13/tls_client_impl_13.h | 6 +++++- src/lib/tls/tls13/tls_server_impl_13.cpp | 13 ++++++------- src/lib/tls/tls13/tls_server_impl_13.h | 4 ++-- src/lib/tls/tls_channel.h | 16 ++++++++++++++++ src/lib/tls/tls_channel_impl.h | 5 +++++ src/lib/tls/tls_client.cpp | 4 ++++ src/lib/tls/tls_client.h | 3 +++ src/lib/tls/tls_server.cpp | 4 ++++ src/lib/tls/tls_server.h | 2 ++ src/tests/unit_asio_stream.cpp | 2 ++ 15 files changed, 65 insertions(+), 21 deletions(-) diff --git a/src/lib/tls/tls12/tls_channel_impl_12.cpp b/src/lib/tls/tls12/tls_channel_impl_12.cpp index 93030abfe91..5adcc7de7dc 100644 --- a/src/lib/tls/tls12/tls_channel_impl_12.cpp +++ b/src/lib/tls/tls12/tls_channel_impl_12.cpp @@ -237,13 +237,14 @@ void Channel_Impl_12::change_cipher_spec_writer(Connection_Side side) { m_write_cipher_states[epoch] = write_state; } -bool Channel_Impl_12::is_active() const { - if(is_closed()) { - return false; - } +bool Channel_Impl_12::is_handshake_complete() const { return (active_state() != nullptr); } +bool Channel_Impl_12::is_active() const { + return !is_closed() && is_handshake_complete(); +} + bool Channel_Impl_12::is_closed() const { return m_has_been_closed; } diff --git a/src/lib/tls/tls12/tls_channel_impl_12.h b/src/lib/tls/tls12/tls_channel_impl_12.h index 5b9f9ee6e8e..ccfe0780ce7 100644 --- a/src/lib/tls/tls12/tls_channel_impl_12.h +++ b/src/lib/tls/tls12/tls_channel_impl_12.h @@ -83,6 +83,11 @@ class Channel_Impl_12 : public Channel_Impl { */ void send_alert(const Alert& alert) override; + /** + * @return true iff the TLS handshake completed successfully + */ + bool is_handshake_complete() const override; + /** * @return true iff the connection is active for sending application data */ diff --git a/src/lib/tls/tls13/tls_channel_impl_13.cpp b/src/lib/tls/tls13/tls_channel_impl_13.cpp index 6cb23437589..aa49fe81718 100644 --- a/src/lib/tls/tls13/tls_channel_impl_13.cpp +++ b/src/lib/tls/tls13/tls_channel_impl_13.cpp @@ -107,7 +107,7 @@ size_t Channel_Impl_13::from_peer(std::span data) { if(record.type == Record_Type::Handshake) { m_handshake_layer.copy_data(record.fragment); - if(!handshake_finished()) { + if(!is_handshake_complete()) { while(auto handshake_msg = m_handshake_layer.next_message(policy(), m_transcript_hash)) { // RFC 8446 5.1 // Handshake messages MUST NOT span key changes. Implementations @@ -316,7 +316,7 @@ SymmetricKey Channel_Impl_13::key_material_export(std::string_view label, void Channel_Impl_13::update_traffic_keys(bool request_peer_update) { BOTAN_STATE_CHECK(!is_downgrading()); - BOTAN_STATE_CHECK(handshake_finished()); + BOTAN_STATE_CHECK(is_handshake_complete()); BOTAN_ASSERT_NONNULL(m_cipher_state); send_post_handshake_message(Key_Update(request_peer_update)); m_cipher_state->update_write_keys(); diff --git a/src/lib/tls/tls13/tls_channel_impl_13.h b/src/lib/tls/tls13/tls_channel_impl_13.h index 660869ba3cb..b3f0e35c1ba 100644 --- a/src/lib/tls/tls13/tls_channel_impl_13.h +++ b/src/lib/tls/tls13/tls_channel_impl_13.h @@ -193,7 +193,6 @@ class Channel_Impl_13 : public Channel_Impl { virtual void process_handshake_msg(Handshake_Message_13 msg) = 0; virtual void process_post_handshake_msg(Post_Handshake_Message_13 msg) = 0; virtual void process_dummy_change_cipher_spec() = 0; - virtual bool handshake_finished() const = 0; /** * @return whether a change cipher spec record should be prepended _now_ diff --git a/src/lib/tls/tls13/tls_client_impl_13.cpp b/src/lib/tls/tls13/tls_client_impl_13.cpp index ce4c9a0b900..3d097fddb0b 100644 --- a/src/lib/tls/tls13/tls_client_impl_13.cpp +++ b/src/lib/tls/tls13/tls_client_impl_13.cpp @@ -91,7 +91,7 @@ void Client_Impl_13::process_handshake_msg(Handshake_Message_13 message) { } void Client_Impl_13::process_post_handshake_msg(Post_Handshake_Message_13 message) { - BOTAN_STATE_CHECK(handshake_finished()); + BOTAN_STATE_CHECK(is_handshake_complete()); std::visit([&](auto msg) { handle(msg); }, m_handshake_state.received(std::move(message))); } @@ -114,7 +114,7 @@ void Client_Impl_13::process_dummy_change_cipher_spec() { // ... no further processing. } -bool Client_Impl_13::handshake_finished() const { +bool Client_Impl_13::is_handshake_complete() const { return m_handshake_state.handshake_finished(); } @@ -418,7 +418,7 @@ void Client_Impl_13::handle(const Certificate_Request_13& certificate_request_ms // RFC 8446 4.3.2 // [The 'context' field] SHALL be zero length unless used for the // post-handshake authentication exchanges described in Section 4.6.2. - if(!m_handshake_state.handshake_finished() && !certificate_request_msg.context().empty()) { + if(!is_handshake_complete() && !certificate_request_msg.context().empty()) { throw TLS_Exception(Alert::DecodeError, "Certificate_Request context must be empty in the main handshake"); } @@ -595,7 +595,7 @@ bool Client_Impl_13::prepend_ccs() { } std::string Client_Impl_13::application_protocol() const { - if(m_handshake_state.handshake_finished()) { + if(is_handshake_complete()) { const auto& eee = m_handshake_state.encrypted_extensions().extensions(); if(eee.has()) { return eee.get()->single_protocol(); diff --git a/src/lib/tls/tls13/tls_client_impl_13.h b/src/lib/tls/tls13/tls_client_impl_13.h index 97aca116658..33c7a9037cc 100644 --- a/src/lib/tls/tls13/tls_client_impl_13.h +++ b/src/lib/tls/tls13/tls_client_impl_13.h @@ -68,12 +68,16 @@ class Client_Impl_13 : public Channel_Impl_13 { */ std::optional external_psk_identity() const override; + /** + * @return true if the TLS handshake finished successfully + */ + bool is_handshake_complete() const override; + private: void process_handshake_msg(Handshake_Message_13 msg) override; void process_post_handshake_msg(Post_Handshake_Message_13 msg) override; void process_dummy_change_cipher_spec() override; - bool handshake_finished() const override; bool prepend_ccs() override; using Channel_Impl_13::handle; diff --git a/src/lib/tls/tls13/tls_server_impl_13.cpp b/src/lib/tls/tls13/tls_server_impl_13.cpp index e2711876d18..f9d0c5ed146 100644 --- a/src/lib/tls/tls13/tls_server_impl_13.cpp +++ b/src/lib/tls/tls13/tls_server_impl_13.cpp @@ -32,7 +32,7 @@ Server_Impl_13::Server_Impl_13(const std::shared_ptr& callbacks, } std::string Server_Impl_13::application_protocol() const { - if(m_handshake_state.handshake_finished()) { + if(is_handshake_complete()) { const auto& eee = m_handshake_state.encrypted_extensions().extensions(); if(const auto alpn = eee.get()) { return alpn->single_protocol(); @@ -67,14 +67,13 @@ bool Server_Impl_13::new_session_ticket_supported() const { // regardless of this method indicating no support for tickets. // // TODO: Implement other PSK KE modes than PSK_DHE_KE - return m_handshake_state.handshake_finished() && - m_handshake_state.client_hello().extensions().has() && + return is_handshake_complete() && m_handshake_state.client_hello().extensions().has() && value_exists(m_handshake_state.client_hello().extensions().get()->modes(), PSK_Key_Exchange_Mode::PSK_DHE_KE); } size_t Server_Impl_13::send_new_session_tickets(const size_t tickets) { - BOTAN_STATE_CHECK(handshake_finished()); + BOTAN_STATE_CHECK(is_handshake_complete()); if(tickets == 0) { return 0; @@ -125,7 +124,7 @@ void Server_Impl_13::process_handshake_msg(Handshake_Message_13 message) { } void Server_Impl_13::process_post_handshake_msg(Post_Handshake_Message_13 message) { - BOTAN_STATE_CHECK(handshake_finished()); + BOTAN_STATE_CHECK(is_handshake_complete()); std::visit([&](auto msg) { handle(msg); }, m_handshake_state.received(std::move(message))); } @@ -148,7 +147,7 @@ void Server_Impl_13::process_dummy_change_cipher_spec() { // ... no further processing. } -bool Server_Impl_13::handshake_finished() const { +bool Server_Impl_13::is_handshake_complete() const { return m_handshake_state.handshake_finished(); } @@ -440,7 +439,7 @@ void Server_Impl_13::handle(const Certificate_13& certificate_msg) { // RFC 8446 4.3.2 // certificate_request_context: [...] This field SHALL be zero length // unless used for the post-handshake authentication exchanges [...]. - if(!handshake_finished() && !certificate_msg.request_context().empty()) { + if(!is_handshake_complete() && !certificate_msg.request_context().empty()) { throw TLS_Exception(Alert::DecodeError, "Received a client certificate message with non-empty request context"); } diff --git a/src/lib/tls/tls13/tls_server_impl_13.h b/src/lib/tls/tls13/tls_server_impl_13.h index d8b5f3cae15..dd848e3407c 100644 --- a/src/lib/tls/tls13/tls_server_impl_13.h +++ b/src/lib/tls/tls13/tls_server_impl_13.h @@ -33,6 +33,8 @@ class Server_Impl_13 : public Channel_Impl_13 { bool new_session_ticket_supported() const override; size_t send_new_session_tickets(size_t tickets) override; + bool is_handshake_complete() const override; + private: void process_handshake_msg(Handshake_Message_13 msg) override; void process_post_handshake_msg(Post_Handshake_Message_13 msg) override; @@ -50,8 +52,6 @@ class Server_Impl_13 : public Channel_Impl_13 { void maybe_handle_compatibility_mode(); - bool handshake_finished() const override; - void downgrade(); private: diff --git a/src/lib/tls/tls_channel.h b/src/lib/tls/tls_channel.h index 6819cfb9ced..dc74ba46851 100644 --- a/src/lib/tls/tls_channel.h +++ b/src/lib/tls/tls_channel.h @@ -89,6 +89,22 @@ class BOTAN_PUBLIC_API(2, 0) Channel { virtual void close() = 0; /** + * Becomes true as soon as the TLS handshake is fully complete and all + * security assurances TLS provides can be guaranteed. + * + * @returns true once the TLS handshake has finished successfully + */ + virtual bool is_handshake_complete() const = 0; + + /** + * Check whether the connection is ready to send application data. Note + * that a TLS 1.3 server MAY send data _before_ receiving the client's + * Finished message. Only _after_ receiving the client's Finished, can the + * server be sure about the client's liveness and (optional) identity. + * + * Consider using is_handshake_complete() if you need to wait until the + * handshake if fully complete. + * * @return true iff the connection is active for sending application data */ virtual bool is_active() const = 0; diff --git a/src/lib/tls/tls_channel_impl.h b/src/lib/tls/tls_channel_impl.h index b9bf8bc5078..e39b88c10e2 100644 --- a/src/lib/tls/tls_channel_impl.h +++ b/src/lib/tls/tls_channel_impl.h @@ -79,6 +79,11 @@ class Channel_Impl { */ void close() { send_warning_alert(Alert::CloseNotify); } + /** + * @return true iff the TLS handshake has finished successfully + */ + virtual bool is_handshake_complete() const = 0; + /** * @return true iff the connection is active for sending application data */ diff --git a/src/lib/tls/tls_client.cpp b/src/lib/tls/tls_client.cpp index 6fbb7504053..c28cc2a6579 100644 --- a/src/lib/tls/tls_client.cpp +++ b/src/lib/tls/tls_client.cpp @@ -97,6 +97,10 @@ size_t Client::from_peer(std::span data) { return read; } +bool Client::is_handshake_complete() const { + return m_impl->is_handshake_complete(); +} + bool Client::is_active() const { return m_impl->is_active(); } diff --git a/src/lib/tls/tls_client.h b/src/lib/tls/tls_client.h index 918e87eb881..fce64d16ed2 100644 --- a/src/lib/tls/tls_client.h +++ b/src/lib/tls/tls_client.h @@ -70,6 +70,9 @@ class BOTAN_PUBLIC_API(2, 0) Client final : public Channel { std::string application_protocol() const override; size_t from_peer(std::span data) override; + + bool is_handshake_complete() const override; + bool is_active() const override; bool is_closed() const override; diff --git a/src/lib/tls/tls_server.cpp b/src/lib/tls/tls_server.cpp index 1993e418fb5..428d0b55a37 100644 --- a/src/lib/tls/tls_server.cpp +++ b/src/lib/tls/tls_server.cpp @@ -65,6 +65,10 @@ size_t Server::from_peer(std::span data) { return read; } +bool Server::is_handshake_complete() const { + return m_impl->is_handshake_complete(); +} + bool Server::is_active() const { return m_impl->is_active(); } diff --git a/src/lib/tls/tls_server.h b/src/lib/tls/tls_server.h index 9e29bdfaad8..e7dbf35f59e 100644 --- a/src/lib/tls/tls_server.h +++ b/src/lib/tls/tls_server.h @@ -66,6 +66,8 @@ class BOTAN_PUBLIC_API(2, 0) Server final : public Channel { size_t from_peer(std::span data) override; + bool is_handshake_complete() const override; + bool is_active() const override; bool is_closed() const override; diff --git a/src/tests/unit_asio_stream.cpp b/src/tests/unit_asio_stream.cpp index 79a32f5746d..03f7f6e9017 100644 --- a/src/tests/unit_asio_stream.cpp +++ b/src/tests/unit_asio_stream.cpp @@ -64,6 +64,8 @@ class MockChannel { bool is_active() const { return m_active; } + bool is_handshake_complete() const { return m_active; } + private: std::shared_ptr m_callbacks; std::size_t m_bytes_till_complete_record; // number of bytes still to read before tls record is completed From 4edb845b5ae37d5eb970200254f3fa6d0e30af0e Mon Sep 17 00:00:00 2001 From: Rene Meusel Date: Mon, 16 Oct 2023 12:27:19 +0200 Subject: [PATCH 2/3] FIX: ASIO stream finishes handshake prematurely --- src/lib/tls/asio/asio_async_ops.h | 2 +- src/lib/tls/asio/asio_stream.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/tls/asio/asio_async_ops.h b/src/lib/tls/asio/asio_async_ops.h index 254a1a7f475..9911dbe1623 100644 --- a/src/lib/tls/asio/asio_async_ops.h +++ b/src/lib/tls/asio/asio_async_ops.h @@ -278,7 +278,7 @@ class AsyncHandshakeOperation : public AsyncBaseis_active() && !ec) { + if(!m_stream.native_handle()->is_handshake_complete() && !ec) { // Read more encrypted TLS data from the network m_stream.next_layer().async_read_some(m_stream.input_buffer(), std::move(*this)); return; diff --git a/src/lib/tls/asio/asio_stream.h b/src/lib/tls/asio/asio_stream.h index 9da6c1a23d7..cd6532ae67a 100644 --- a/src/lib/tls/asio/asio_stream.h +++ b/src/lib/tls/asio/asio_stream.h @@ -229,7 +229,7 @@ class Stream { send_pending_encrypted_data(ec); } - while(!native_handle()->is_active() && !ec) { + while(!native_handle()->is_handshake_complete() && !ec) { boost::asio::const_buffer read_buffer{input_buffer().data(), m_nextLayer.read_some(input_buffer(), ec)}; if(ec) { return; From a248ed1451eaaf61855de8420d130d7416f02e71 Mon Sep 17 00:00:00 2001 From: Rene Meusel Date: Mon, 16 Oct 2023 10:15:57 +0200 Subject: [PATCH 3/3] Test is_handshake_complete() in RFC 8448 tests Co-Authored-By: Fabian Albert --- src/tests/test_tls_rfc8448.cpp | 42 +++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/tests/test_tls_rfc8448.cpp b/src/tests/test_tls_rfc8448.cpp index 2f0acbcacb5..a3dff9f713f 100644 --- a/src/tests/test_tls_rfc8448.cpp +++ b/src/tests/test_tls_rfc8448.cpp @@ -977,6 +977,7 @@ class Test_TLS_RFC8448_Client : public Test_TLS_RFC8448 { "tls_ephemeral_key_agreement"}); result.confirm("client is not yet active", !ctx->client.is_active()); + result.confirm("handshake is not yet complete", !ctx->client.is_handshake_complete()); }), Botan_Tests::CHECK( @@ -1002,6 +1003,7 @@ class Test_TLS_RFC8448_Client : public Test_TLS_RFC8448 { result.require("certificate exists", !ctx->certs_verified().empty()); result.require("correct certificate", ctx->certs_verified().front() == server_certificate()); result.require("client is active", ctx->client.is_active()); + result.confirm("handshake is complete", ctx->client.is_handshake_complete()); result.test_eq( "correct handshake finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished")); @@ -1452,6 +1454,7 @@ class Test_TLS_RFC8448_Client : public Test_TLS_RFC8448 { result.confirm("client is ready to send application traffic", ctx->client.is_active()); + result.confirm("handshake is complete", ctx->client.is_handshake_complete()); }), Botan_Tests::CHECK( @@ -1465,6 +1468,7 @@ class Test_TLS_RFC8448_Client : public Test_TLS_RFC8448 { result.require("client cannot send application traffic anymore", !ctx->client.is_active()); result.require("client is not fully closed yet", !ctx->client.is_closed()); + result.confirm("handshake stays completed", ctx->client.is_handshake_complete()); ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify")); @@ -1541,6 +1545,7 @@ class Test_TLS_RFC8448_Client : public Test_TLS_RFC8448 { "tls_ephemeral_key_agreement"}); result.confirm("client is not yet active", !ctx->client.is_active()); + result.confirm("handshake is not yet complete", !ctx->client.is_handshake_complete()); }), Botan_Tests::CHECK( @@ -1560,6 +1565,7 @@ class Test_TLS_RFC8448_Client : public Test_TLS_RFC8448 { "tls_session_activated"}); result.require("PSK negotiated", ctx->psk_identity_negotiated() == vars.get_req_str("PskIdentity")); result.require("client is active", ctx->client.is_active()); + result.confirm("handshake is complete", ctx->client.is_handshake_complete()); result.test_eq( "correct handshake finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished")); @@ -1691,7 +1697,13 @@ class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 { concat(vars.get_req_bin("Record_ServerHello"), vars.get_req_bin("Record_ServerHandshakeMessages"))); + // Note: is_active() defines that we can send application data. + // RFC 8446 Section 4.4.4 explicitly allows that for servers + // that did not receive the client's Finished message, yet. + // However, before receiving and validating this message, + // the handshake is not yet finished. result.confirm("Server can now send application data", ctx->server.is_active()); + result.confirm("handshake is not yet complete", !ctx->server.is_handshake_complete()); }), Botan_Tests::CHECK("Send Client Finished", @@ -1765,6 +1777,7 @@ class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 { result.confirm("connection is not yet closed", !ctx->server.is_closed()); result.confirm("connection is still active", ctx->server.is_active()); + result.confirm("handshake is still finished", ctx->server.is_handshake_complete()); }), Botan_Tests::CHECK("Expect Server close_notify", @@ -1774,6 +1787,7 @@ class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 { result.confirm("connection is now inactive", !ctx->server.is_active()); result.confirm("connection is now closed", ctx->server.is_closed()); + result.confirm("handshake is still finished", ctx->server.is_handshake_complete()); result.test_eq("Server's close notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Server_CloseNotify")); @@ -1849,7 +1863,13 @@ class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 { concat(vars.get_req_bin("Record_ServerHello"), vars.get_req_bin("Record_ServerHandshakeMessages"))); + // Note: is_active() defines that we can send application data. + // RFC 8446 Section 4.4.4 explicitly allows that for servers + // that did not receive the client's Finished message, yet. + // However, before receiving and validating this message, + // the handshake is not yet finished. result.confirm("Server can now send application data", ctx->server.is_active()); + result.confirm("handshake is not yet complete", !ctx->server.is_handshake_complete()); }), // TODO: The rest of this test vector requires 0-RTT which is not @@ -1908,6 +1928,7 @@ class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 { ctx->pull_send_buffer(), vars.get_req_bin("Record_HelloRetryRequest")); result.confirm("TLS handshake not yet finished", !ctx->server.is_active()); + result.confirm("handshake is not yet complete", !ctx->server.is_handshake_complete()); }), Botan_Tests::CHECK("Receive updated Client Hello message", @@ -1960,6 +1981,8 @@ class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 { concat(vars.get_req_bin("Record_ServerHello"), vars.get_req_bin("Record_ServerHandshakeMessages"))); result.confirm("Server could now send application data", ctx->server.is_active()); + result.confirm("handshake is not yet complete", + !ctx->server.is_handshake_complete()); // See RFC 8446 4.4.4 }), Botan_Tests::CHECK("Receive Client Finished", @@ -1975,6 +1998,7 @@ class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 { "tls_session_activated"}); result.confirm("TLS handshake finished", ctx->server.is_active()); + result.confirm("handshake is complete", ctx->server.is_handshake_complete()); }), Botan_Tests::CHECK("Receive Client close_notify", @@ -1987,6 +2011,7 @@ class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 { result.confirm("connection is not yet closed", !ctx->server.is_closed()); result.confirm("connection is still active", ctx->server.is_active()); + result.confirm("handshake is still complete", ctx->server.is_handshake_complete()); }), Botan_Tests::CHECK("Expect Server close_notify", @@ -1996,6 +2021,7 @@ class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 { result.confirm("connection is now inactive", !ctx->server.is_active()); result.confirm("connection is now closed", ctx->server.is_closed()); + result.confirm("handshake is still complete", ctx->server.is_handshake_complete()); result.test_eq("Server's close notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Server_CloseNotify")); @@ -2078,6 +2104,8 @@ class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 { result.confirm("Not yet aware of client's cert chain", ctx->server.peer_cert_chain().empty()); result.confirm("Server could now send application data", ctx->server.is_active()); + result.confirm("handshake is not yet complete", + !ctx->server.is_handshake_complete()); // See RFC 8446 4.4.4 }), Botan_Tests::CHECK("Receive Client's second flight", @@ -2106,6 +2134,7 @@ class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 { !cert_chain.empty() && cert_chain.front() == client_certificate()); result.confirm("TLS handshake finished", ctx->server.is_active()); + result.confirm("handshake is complete", ctx->server.is_handshake_complete()); }), Botan_Tests::CHECK("Receive Client close_notify", @@ -2118,6 +2147,7 @@ class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 { result.confirm("connection is not yet closed", !ctx->server.is_closed()); result.confirm("connection is still active", ctx->server.is_active()); + result.confirm("handshake is still complete", ctx->server.is_handshake_complete()); }), Botan_Tests::CHECK("Expect Server close_notify", @@ -2127,6 +2157,7 @@ class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 { result.confirm("connection is now inactive", !ctx->server.is_active()); result.confirm("connection is now closed", ctx->server.is_closed()); + result.confirm("handshake is still complete", ctx->server.is_handshake_complete()); result.test_eq("Server's close notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Server_CloseNotify")); @@ -2204,6 +2235,8 @@ class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 { vars.get_req_bin("Record_ServerHandshakeMessages"))); result.confirm("Server could now send application data", ctx->server.is_active()); + result.confirm("handshake is not yet complete", + !ctx->server.is_handshake_complete()); // See RFC 8446 4.4.4 }), Botan_Tests::CHECK("Receive Client Finished", @@ -2218,7 +2251,8 @@ class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 { "tls_session_established", "tls_session_activated"}); - result.confirm("TLS handshake finished", ctx->server.is_active()); + result.confirm("TLS handshake fully finished", ctx->server.is_active()); + result.confirm("handshake is complete", ctx->server.is_handshake_complete()); }), Botan_Tests::CHECK("Receive Client close_notify", @@ -2231,6 +2265,7 @@ class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 { result.confirm("connection is not yet closed", !ctx->server.is_closed()); result.confirm("connection is still active", ctx->server.is_active()); + result.confirm("handshake is still complete", ctx->server.is_handshake_complete()); }), Botan_Tests::CHECK("Expect Server close_notify", @@ -2240,6 +2275,7 @@ class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 { result.confirm("connection is now inactive", !ctx->server.is_active()); result.confirm("connection is now closed", ctx->server.is_closed()); + result.confirm("handshake is still complete", ctx->server.is_handshake_complete()); result.test_eq("Server's close notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Server_CloseNotify")); @@ -2333,6 +2369,8 @@ class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 { vars.get_req_bin("Record_ServerHandshakeMessages"))); result.confirm("Server can now send application data", ctx->server.is_active()); + result.confirm("handshake is not yet complete", + !ctx->server.is_handshake_complete()); // See RFC 8446 4.4.4 }), Botan_Tests::CHECK("Send Client Finished", @@ -2378,11 +2416,13 @@ class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 { result.confirm("connection is not yet closed", !ctx->server.is_closed()); result.confirm("connection is still active", ctx->server.is_active()); + result.confirm("handshake is still complete", ctx->server.is_handshake_complete()); ctx->server.close(); result.confirm("connection is now inactive", !ctx->server.is_active()); result.confirm("connection is now closed", ctx->server.is_closed()); + result.confirm("handshake is still complete", ctx->server.is_handshake_complete()); result.test_eq("Server's close notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Server_CloseNotify"));