Commit 59a50b0d authored by Michael Hansen's avatar Michael Hansen Committed by Commit Bot

[Nearby] Periodically rotate Nearby Connections advertisement.

This adds a mechanism to rotate the Nearby Connections advertisement
and Bluetooth MAC address every [12, 15) minutes. This is to protect
user privacy by preventing tracking using this data.

Spec: go/nearby-chrome-bt

Bug: b:154846485
Change-Id: I841aa103fb374a4812ab928bc862af026835a03c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2419692
Commit-Queue: Michael Hansen <hansenmichael@google.com>
Reviewed-by: default avatarRyan Hansberry <hansberry@chromium.org>
Cr-Commit-Position: refs/heads/master@{#809928}
parent 4ecf0779
...@@ -44,8 +44,8 @@ FakeNearbyShareCertificateManager::GetDecryptedPublicCertificateCall::operator=( ...@@ -44,8 +44,8 @@ FakeNearbyShareCertificateManager::GetDecryptedPublicCertificateCall::operator=(
FakeNearbyShareCertificateManager::GetDecryptedPublicCertificateCall:: FakeNearbyShareCertificateManager::GetDecryptedPublicCertificateCall::
~GetDecryptedPublicCertificateCall() = default; ~GetDecryptedPublicCertificateCall() = default;
FakeNearbyShareCertificateManager::FakeNearbyShareCertificateManager() = FakeNearbyShareCertificateManager::FakeNearbyShareCertificateManager()
default; : next_salt_(GetNearbyShareTestSalt()) {}
FakeNearbyShareCertificateManager::~FakeNearbyShareCertificateManager() = FakeNearbyShareCertificateManager::~FakeNearbyShareCertificateManager() =
default; default;
...@@ -75,7 +75,10 @@ void FakeNearbyShareCertificateManager::OnStop() {} ...@@ -75,7 +75,10 @@ void FakeNearbyShareCertificateManager::OnStop() {}
base::Optional<NearbySharePrivateCertificate> base::Optional<NearbySharePrivateCertificate>
FakeNearbyShareCertificateManager::GetValidPrivateCertificate( FakeNearbyShareCertificateManager::GetValidPrivateCertificate(
nearby_share::mojom::Visibility visibility) const { nearby_share::mojom::Visibility visibility) const {
return GetNearbyShareTestPrivateCertificate(visibility); auto cert = GetNearbyShareTestPrivateCertificate(visibility);
cert.next_salts_for_testing() = base::queue<std::vector<uint8_t>>();
cert.next_salts_for_testing().push(next_salt_);
return cert;
} }
void FakeNearbyShareCertificateManager::UpdatePrivateCertificateInStorage( void FakeNearbyShareCertificateManager::UpdatePrivateCertificateInStorage(
......
...@@ -84,6 +84,8 @@ class FakeNearbyShareCertificateManager : public NearbyShareCertificateManager { ...@@ -84,6 +84,8 @@ class FakeNearbyShareCertificateManager : public NearbyShareCertificateManager {
using NearbyShareCertificateManager::NotifyPrivateCertificatesChanged; using NearbyShareCertificateManager::NotifyPrivateCertificatesChanged;
using NearbyShareCertificateManager::NotifyPublicCertificatesDownloaded; using NearbyShareCertificateManager::NotifyPublicCertificatesDownloaded;
void set_next_salt(const std::vector<uint8_t>& salt) { next_salt_ = salt; }
size_t num_get_private_certificates_as_public_certificates_calls() { size_t num_get_private_certificates_as_public_certificates_calls() {
return num_get_private_certificates_as_public_certificates_calls_; return num_get_private_certificates_as_public_certificates_calls_;
} }
...@@ -110,6 +112,7 @@ class FakeNearbyShareCertificateManager : public NearbyShareCertificateManager { ...@@ -110,6 +112,7 @@ class FakeNearbyShareCertificateManager : public NearbyShareCertificateManager {
size_t num_download_public_certificates_calls_ = 0; size_t num_download_public_certificates_calls_ = 0;
std::vector<GetDecryptedPublicCertificateCall> std::vector<GetDecryptedPublicCertificateCall>
get_decrypted_public_certificate_calls_; get_decrypted_public_certificate_calls_;
std::vector<uint8_t> next_salt_;
}; };
#endif // CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_FAKE_NEARBY_SHARE_CERTIFICATE_MANAGER_H_ #endif // CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_FAKE_NEARBY_SHARE_CERTIFICATE_MANAGER_H_
...@@ -24,7 +24,7 @@ void FakeNearbyConnectionsManager::StartAdvertising( ...@@ -24,7 +24,7 @@ void FakeNearbyConnectionsManager::StartAdvertising(
advertising_listener_ = listener; advertising_listener_ = listener;
advertising_data_usage_ = data_usage; advertising_data_usage_ = data_usage;
advertising_power_level_ = power_level; advertising_power_level_ = power_level;
adverting_endpoint_info_ = std::move(endpoint_info); advertising_endpoint_info_ = std::move(endpoint_info);
std::move(callback).Run( std::move(callback).Run(
NearbyConnectionsManager::ConnectionsStatus::kSuccess); NearbyConnectionsManager::ConnectionsStatus::kSuccess);
} }
...@@ -35,7 +35,7 @@ void FakeNearbyConnectionsManager::StopAdvertising() { ...@@ -35,7 +35,7 @@ void FakeNearbyConnectionsManager::StopAdvertising() {
advertising_listener_ = nullptr; advertising_listener_ = nullptr;
advertising_data_usage_ = DataUsage::kUnknown; advertising_data_usage_ = DataUsage::kUnknown;
advertising_power_level_ = PowerLevel::kUnknown; advertising_power_level_ = PowerLevel::kUnknown;
adverting_endpoint_info_.reset(); advertising_endpoint_info_.reset();
} }
void FakeNearbyConnectionsManager::StartDiscovery( void FakeNearbyConnectionsManager::StartDiscovery(
......
...@@ -91,8 +91,8 @@ class FakeNearbyConnectionsManager ...@@ -91,8 +91,8 @@ class FakeNearbyConnectionsManager
callback) { callback) {
send_payload_callback_ = std::move(callback); send_payload_callback_ = std::move(callback);
} }
const base::Optional<std::vector<uint8_t>>& adverting_endpoint_info() { const base::Optional<std::vector<uint8_t>>& advertising_endpoint_info() {
return adverting_endpoint_info_; return advertising_endpoint_info_;
} }
base::Optional<std::vector<uint8_t>> connection_endpoint_info( base::Optional<std::vector<uint8_t>> connection_endpoint_info(
...@@ -118,7 +118,7 @@ class FakeNearbyConnectionsManager ...@@ -118,7 +118,7 @@ class FakeNearbyConnectionsManager
DataUsage connected_data_usage_ = DataUsage::kUnknown; DataUsage connected_data_usage_ = DataUsage::kUnknown;
base::RepeatingCallback<void(PayloadPtr, PayloadStatusListener*)> base::RepeatingCallback<void(PayloadPtr, PayloadStatusListener*)>
send_payload_callback_; send_payload_callback_;
base::Optional<std::vector<uint8_t>> adverting_endpoint_info_; base::Optional<std::vector<uint8_t>> advertising_endpoint_info_;
std::set<std::string> disconnected_endpoints_; std::set<std::string> disconnected_endpoints_;
// Maps endpoint_id to endpoint_info. // Maps endpoint_id to endpoint_info.
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/files/file.h" #include "base/files/file.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/numerics/checked_math.h" #include "base/numerics/checked_math.h"
#include "base/rand_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/system/sys_info.h" #include "base/system/sys_info.h"
#include "base/task/post_task.h" #include "base/task/post_task.h"
...@@ -48,6 +49,11 @@ ...@@ -48,6 +49,11 @@
namespace { namespace {
constexpr base::TimeDelta kBackgroundAdvertisementRotationDelayMin =
base::TimeDelta::FromMinutes(12);
constexpr base::TimeDelta kBackgroundAdvertisementRotationDelayMax =
base::TimeDelta::FromMinutes(15);
// Used to hash a token into a 4 digit string. // Used to hash a token into a 4 digit string.
constexpr int kHashModulo = 9973; constexpr int kHashModulo = 9973;
constexpr int kHashBaseMultiplier = 31; constexpr int kHashBaseMultiplier = 31;
...@@ -1438,7 +1444,8 @@ void NearbySharingServiceImpl::InvalidateAdvertisingState() { ...@@ -1438,7 +1444,8 @@ void NearbySharingServiceImpl::InvalidateAdvertisingState() {
<< " visibility: " << settings_.GetVisibility() << " visibility: " << settings_.GetVisibility()
<< " data usage: " << data_usage << " device name: " << " data usage: " << data_usage << " device name: "
<< device_name.value_or("** no device name **"); << device_name.value_or("** no device name **");
return;
ScheduleRotateBackgroundAdvertisementTimer();
} }
void NearbySharingServiceImpl::StopAdvertising() { void NearbySharingServiceImpl::StopAdvertising() {
...@@ -1511,6 +1518,32 @@ NearbySharingService::StatusCodes NearbySharingServiceImpl::StopScanning() { ...@@ -1511,6 +1518,32 @@ NearbySharingService::StatusCodes NearbySharingServiceImpl::StopScanning() {
return StatusCodes::kOk; return StatusCodes::kOk;
} }
void NearbySharingServiceImpl::ScheduleRotateBackgroundAdvertisementTimer() {
uint64_t delayRangeMilliseconds = base::checked_cast<uint64_t>(
kBackgroundAdvertisementRotationDelayMax.InMilliseconds() -
kBackgroundAdvertisementRotationDelayMin.InMilliseconds());
uint64_t delayMilliseconds =
base::RandGenerator(delayRangeMilliseconds) +
base::checked_cast<uint64_t>(
kBackgroundAdvertisementRotationDelayMin.InMilliseconds());
rotate_background_advertisement_timer_.Start(
FROM_HERE,
base::TimeDelta::FromMilliseconds(
base::checked_cast<uint64_t>(delayMilliseconds)),
base::BindOnce(
&NearbySharingServiceImpl::OnRotateBackgroundAdvertisementTimerFired,
weak_ptr_factory_.GetWeakPtr()));
}
void NearbySharingServiceImpl::OnRotateBackgroundAdvertisementTimerFired() {
if (foreground_receive_callbacks_.might_have_observers()) {
ScheduleRotateBackgroundAdvertisementTimer();
} else {
StopAdvertising();
InvalidateSurfaceState();
}
}
void NearbySharingServiceImpl::OnTransferComplete() { void NearbySharingServiceImpl::OnTransferComplete() {
is_receiving_files_ = false; is_receiving_files_ = false;
is_transferring_ = false; is_transferring_ = false;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "base/scoped_observer.h" #include "base/scoped_observer.h"
#include "base/sequence_checker.h" #include "base/sequence_checker.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/unguessable_token.h" #include "base/unguessable_token.h"
#include "chrome/browser/nearby_sharing/attachment.h" #include "chrome/browser/nearby_sharing/attachment.h"
#include "chrome/browser/nearby_sharing/attachment_info.h" #include "chrome/browser/nearby_sharing/attachment_info.h"
...@@ -181,6 +182,8 @@ class NearbySharingServiceImpl ...@@ -181,6 +182,8 @@ class NearbySharingServiceImpl
void StopAdvertising(); void StopAdvertising();
void StartScanning(); void StartScanning();
StatusCodes StopScanning(); StatusCodes StopScanning();
void ScheduleRotateBackgroundAdvertisementTimer();
void OnRotateBackgroundAdvertisementTimerFired();
void OnTransferComplete(); void OnTransferComplete();
void OnTransferStarted(bool is_incoming); void OnTransferStarted(bool is_incoming);
...@@ -328,6 +331,7 @@ class NearbySharingServiceImpl ...@@ -328,6 +331,7 @@ class NearbySharingServiceImpl
NearbyShareSettings settings_; NearbyShareSettings settings_;
NearbyFileHandler file_handler_; NearbyFileHandler file_handler_;
bool is_screen_locked_ = false; bool is_screen_locked_ = false;
base::OneShotTimer rotate_background_advertisement_timer_;
// A list of service observers. // A list of service observers.
base::ObserverList<NearbySharingService::Observer> observers_; base::ObserverList<NearbySharingService::Observer> observers_;
......
...@@ -817,6 +817,16 @@ class NearbySharingServiceImplTest : public testing::Test { ...@@ -817,6 +817,16 @@ class NearbySharingServiceImplTest : public testing::Test {
success_run_loop.Run(); success_run_loop.Run();
} }
std::unique_ptr<sharing::Advertisement> GetCurrentAdvertisement() {
auto endpoint_info =
fake_nearby_connections_manager_->advertising_endpoint_info();
if (!endpoint_info)
return nullptr;
return sharing::AdvertisementDecoder::FromEndpointInfo(base::make_span(
*fake_nearby_connections_manager_->advertising_endpoint_info()));
}
protected: protected:
FakeNearbyShareLocalDeviceDataManager* local_device_data_manager() { FakeNearbyShareLocalDeviceDataManager* local_device_data_manager() {
EXPECT_EQ(1u, local_device_data_manager_factory_.instances().size()); EXPECT_EQ(1u, local_device_data_manager_factory_.instances().size());
...@@ -1493,10 +1503,8 @@ TEST_F(NearbySharingServiceImplTest, ...@@ -1493,10 +1503,8 @@ TEST_F(NearbySharingServiceImplTest,
EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising()); EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
EXPECT_EQ(PowerLevel::kHighPower, EXPECT_EQ(PowerLevel::kHighPower,
fake_nearby_connections_manager_->advertising_power_level()); fake_nearby_connections_manager_->advertising_power_level());
ASSERT_TRUE(fake_nearby_connections_manager_->adverting_endpoint_info()); ASSERT_TRUE(fake_nearby_connections_manager_->advertising_endpoint_info());
auto advertisement = auto advertisement = GetCurrentAdvertisement();
sharing::AdvertisementDecoder::FromEndpointInfo(base::make_span(
*fake_nearby_connections_manager_->adverting_endpoint_info()));
ASSERT_TRUE(advertisement); ASSERT_TRUE(advertisement);
EXPECT_EQ(kDeviceName, advertisement->device_name()); EXPECT_EQ(kDeviceName, advertisement->device_name());
EXPECT_EQ(nearby_share::mojom::ShareTargetType::kLaptop, EXPECT_EQ(nearby_share::mojom::ShareTargetType::kLaptop,
...@@ -1519,10 +1527,8 @@ TEST_F(NearbySharingServiceImplTest, ...@@ -1519,10 +1527,8 @@ TEST_F(NearbySharingServiceImplTest,
EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising()); EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
EXPECT_EQ(PowerLevel::kHighPower, EXPECT_EQ(PowerLevel::kHighPower,
fake_nearby_connections_manager_->advertising_power_level()); fake_nearby_connections_manager_->advertising_power_level());
ASSERT_TRUE(fake_nearby_connections_manager_->adverting_endpoint_info()); ASSERT_TRUE(fake_nearby_connections_manager_->advertising_endpoint_info());
auto advertisement = auto advertisement = GetCurrentAdvertisement();
sharing::AdvertisementDecoder::FromEndpointInfo(base::make_span(
*fake_nearby_connections_manager_->adverting_endpoint_info()));
ASSERT_TRUE(advertisement); ASSERT_TRUE(advertisement);
EXPECT_EQ(kDeviceName, advertisement->device_name()); EXPECT_EQ(kDeviceName, advertisement->device_name());
EXPECT_EQ(nearby_share::mojom::ShareTargetType::kLaptop, EXPECT_EQ(nearby_share::mojom::ShareTargetType::kLaptop,
...@@ -1548,10 +1554,8 @@ TEST_F(NearbySharingServiceImplTest, ...@@ -1548,10 +1554,8 @@ TEST_F(NearbySharingServiceImplTest,
EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising()); EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
EXPECT_EQ(PowerLevel::kLowPower, EXPECT_EQ(PowerLevel::kLowPower,
fake_nearby_connections_manager_->advertising_power_level()); fake_nearby_connections_manager_->advertising_power_level());
ASSERT_TRUE(fake_nearby_connections_manager_->adverting_endpoint_info()); ASSERT_TRUE(fake_nearby_connections_manager_->advertising_endpoint_info());
auto advertisement = auto advertisement = GetCurrentAdvertisement();
sharing::AdvertisementDecoder::FromEndpointInfo(base::make_span(
*fake_nearby_connections_manager_->adverting_endpoint_info()));
ASSERT_TRUE(advertisement); ASSERT_TRUE(advertisement);
EXPECT_FALSE(advertisement->device_name()); EXPECT_FALSE(advertisement->device_name());
EXPECT_EQ(nearby_share::mojom::ShareTargetType::kLaptop, EXPECT_EQ(nearby_share::mojom::ShareTargetType::kLaptop,
...@@ -3498,3 +3502,23 @@ TEST_F(NearbySharingServiceImplTest, ShutdownCallsObservers) { ...@@ -3498,3 +3502,23 @@ TEST_F(NearbySharingServiceImplTest, ShutdownCallsObservers) {
// Prevent a double shutdown. // Prevent a double shutdown.
service_.reset(); service_.reset();
} }
TEST_F(NearbySharingServiceImplTest,
PeriodicallyRotateBackgroundAdvertisement) {
certificate_manager()->set_next_salt({0x00, 0x01});
SetVisibility(nearby_share::mojom::Visibility::kAllContacts);
NiceMock<MockTransferUpdateCallback> callback;
NearbySharingService::StatusCodes result = service_->RegisterReceiveSurface(
&callback, NearbySharingService::ReceiveSurfaceState::kBackground);
EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
auto endpoint_info_initial =
fake_nearby_connections_manager_->advertising_endpoint_info();
certificate_manager()->set_next_salt({0x00, 0x02});
task_environment_.FastForwardBy(base::TimeDelta::FromMinutes(15));
EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
auto endpoint_info_rotated =
fake_nearby_connections_manager_->advertising_endpoint_info();
EXPECT_NE(endpoint_info_initial, endpoint_info_rotated);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment