diff --git a/cpp/core/internal/base_endpoint_channel.cc b/cpp/core/internal/base_endpoint_channel.cc index 6914e806..bc490833 100644 --- a/cpp/core/internal/base_endpoint_channel.cc +++ b/cpp/core/internal/base_endpoint_channel.cc @@ -259,6 +259,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 c23c6888..d72309d4 100644 --- a/cpp/core/internal/base_endpoint_channel.h +++ b/cpp/core/internal/base_endpoint_channel.h @@ -67,6 +67,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 09cb529c..f7b38fea 100644 --- a/cpp/core/internal/bwu_manager.cc +++ b/cpp/core/internal/bwu_manager.cc @@ -562,8 +562,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 f2ed6b55..de0d97b1 100644 --- a/cpp/core/internal/encryption_runner_test.cc +++ b/cpp/core/internal/encryption_runner_test.cc @@ -55,6 +55,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 057a1102..39cf7309 100644 --- a/cpp/core/internal/endpoint_channel.h +++ b/cpp/core/internal/endpoint_channel.h @@ -59,6 +59,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 b21bd3f2..5a3ca675 100644 --- a/cpp/core/internal/endpoint_manager_test.cc +++ b/cpp/core/internal/endpoint_manager_test.cc @@ -56,6 +56,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));