diff --git a/cpp/core/internal/base_endpoint_channel.cc b/cpp/core/internal/base_endpoint_channel.cc index beffa04a..735cf6e2 100644 --- a/cpp/core/internal/base_endpoint_channel.cc +++ b/cpp/core/internal/base_endpoint_channel.cc @@ -245,6 +245,11 @@ void BaseEndpointChannel::EnableEncryption( crypto_context_ = context; } +void BaseEndpointChannel::DisableEncryption() { + MutexLock crypto_lock(&crypto_mutex_); + crypto_context_.reset(); +} + bool BaseEndpointChannel::IsPaused() const { MutexLock lock(&is_paused_mutex_); return is_paused_; diff --git a/cpp/core/internal/base_endpoint_channel.h b/cpp/core/internal/base_endpoint_channel.h index 10285aa1..b55cccdf 100644 --- a/cpp/core/internal/base_endpoint_channel.h +++ b/cpp/core/internal/base_endpoint_channel.h @@ -53,6 +53,9 @@ class BaseEndpointChannel : public EndpointChannel { // before entering data phase, where Payloads may be exchanged. void EnableEncryption(std::shared_ptr context) override; + // Disables encryption on the EndpointChannel. + void DisableEncryption() override; + // True if the EndpointChannel is currently pausing all writes. bool IsPaused() const ABSL_LOCKS_EXCLUDED(is_paused_mutex_) override; diff --git a/cpp/core/internal/bwu_manager.cc b/cpp/core/internal/bwu_manager.cc index be7e625d..1d021924 100644 --- a/cpp/core/internal/bwu_manager.cc +++ b/cpp/core/internal/bwu_manager.cc @@ -548,8 +548,15 @@ void BwuManager::ProcessSafeToClosePriorChannelEvent( "trying to upgrade endpoint %s.", endpoint_id.c_str()); + // Each encrypted message includes the key to decrypt the next message. The + // disconnect message is optional and may not be received under normal + // circumstances so it is necessary to send it unencrypted. This way the + // serial crypto context does not increment here. + previous_endpoint_channel->DisableEncryption(); previous_endpoint_channel->Write(parser::ForDisconnection()); + // TODO(b/172380349): Match the Java implementation with no sleep call + // Wait for in-flight messages to reach their peers. SystemClock::Sleep(absl::Seconds(1)); previous_endpoint_channel->Close(DisconnectionReason::UPGRADED); diff --git a/cpp/core/internal/encryption_runner_test.cc b/cpp/core/internal/encryption_runner_test.cc index 32c921a0..e1d5c634 100644 --- a/cpp/core/internal/encryption_runner_test.cc +++ b/cpp/core/internal/encryption_runner_test.cc @@ -41,6 +41,7 @@ class FakeEndpointChannel : public EndpointChannel { std::string GetName() const override { return "fake-channel"; } Medium GetMedium() const override { return Medium::BLE; } void EnableEncryption(std::shared_ptr context) override {} + void DisableEncryption() override {} bool IsPaused() const override { return false; } void Pause() override {} void Resume() override {} diff --git a/cpp/core/internal/endpoint_channel.h b/cpp/core/internal/endpoint_channel.h index 3d3e3c65..830e678e 100644 --- a/cpp/core/internal/endpoint_channel.h +++ b/cpp/core/internal/endpoint_channel.h @@ -45,6 +45,9 @@ class EndpointChannel { // Enables encryption on the EndpointChannel. virtual void EnableEncryption(std::shared_ptr context) = 0; + // Disables encryption on the EndpointChannel. + virtual void DisableEncryption() = 0; + // True if the EndpointChannel is currently pausing all writes. virtual bool IsPaused() const = 0; diff --git a/cpp/core/internal/endpoint_manager_test.cc b/cpp/core/internal/endpoint_manager_test.cc index deac4931..13c9002d 100644 --- a/cpp/core/internal/endpoint_manager_test.cc +++ b/cpp/core/internal/endpoint_manager_test.cc @@ -42,6 +42,7 @@ class MockEndpointChannel : public EndpointChannel { MOCK_METHOD(Medium, GetMedium, (), (const override)); MOCK_METHOD(void, EnableEncryption, (std::shared_ptr context), (override)); + MOCK_METHOD(void, DisableEncryption, (), (override)); MOCK_METHOD(bool, IsPaused, (), (const override)); MOCK_METHOD(void, Pause, (), (override)); MOCK_METHOD(void, Resume, (), (override));