Commit 2a2103bf authored by Himanshu Jaju's avatar Himanshu Jaju Committed by Commit Bot

Integrate PairedKeyVerificationRunner in NearbyService.

Integrates PairedKeyVerificationRunner in NearbyServiceImpl to verify
remote device before receiving introduction and starting the transfer
flow.

Bug: 1085068
Change-Id: I73d42d9f85f3254007cdf3fdf46c6f5e05a48630
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2352799Reviewed-by: default avatarAlex Chau <alexchau@chromium.org>
Commit-Queue: Himanshu Jaju <himanshujaju@chromium.org>
Cr-Commit-Position: refs/heads/master@{#798649}
parent d008c023
......@@ -52,6 +52,10 @@ std::vector<uint8_t> FakeNearbyConnection::GetWrittenData() {
return bytes;
}
bool FakeNearbyConnection::IsClosed() {
return closed_;
}
void FakeNearbyConnection::MaybeRunCallback() {
DCHECK(!closed_);
if (!callback_ || read_data_.empty())
......
......@@ -24,6 +24,8 @@ class FakeNearbyConnection : public NearbyConnection {
void AppendReadableData(std::vector<uint8_t> bytes);
std::vector<uint8_t> GetWrittenData();
bool IsClosed();
private:
void MaybeRunCallback();
......
......@@ -99,10 +99,20 @@ base::Optional<std::vector<uint8_t>>
FakeNearbyConnectionsManager::GetRawAuthenticationToken(
const std::string& endpoint_id) {
DCHECK(!IsShutdown());
// TODO(alexchau): Implement.
auto iter = endpoint_auth_tokens_.find(endpoint_id);
if (iter != endpoint_auth_tokens_.end())
return iter->second;
return base::nullopt;
}
void FakeNearbyConnectionsManager::SetRawAuthenticationToken(
const std::string& endpoint_id,
std::vector<uint8_t> token) {
endpoint_auth_tokens_[endpoint_id] = std::move(token);
}
void FakeNearbyConnectionsManager::UpgradeBandwidth(
const std::string& endpoint_id) {
upgrade_bandwidth_endpoint_ids_.insert(endpoint_id);
......
......@@ -51,6 +51,9 @@ class FakeNearbyConnectionsManager
const std::string& endpoint_id) override;
void UpgradeBandwidth(const std::string& endpoint_id) override;
void SetRawAuthenticationToken(const std::string& endpoint_id,
std::vector<uint8_t> token);
// mojom::EndpointDiscoveryListener:
void OnEndpointFound(
const std::string& endpoint_id,
......@@ -73,6 +76,7 @@ class FakeNearbyConnectionsManager
DataUsage advertising_data_usage_ = DataUsage::kUnknown;
PowerLevel advertising_power_level_ = PowerLevel::kUnknown;
std::set<std::string> upgrade_bandwidth_endpoint_ids_;
std::map<std::string, std::vector<uint8_t>> endpoint_auth_tokens_;
};
#endif // CHROME_BROWSER_NEARBY_SHARING_FAKE_NEARBY_CONNECTIONS_MANAGER_H_
......@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
#include "base/task_runner_util.h"
#include "base/threading/sequenced_task_runner_handle.h"
......@@ -20,6 +21,7 @@
#include "chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl.h"
#include "chrome/browser/nearby_sharing/logging/logging.h"
#include "chrome/browser/nearby_sharing/nearby_connections_manager.h"
#include "chrome/browser/nearby_sharing/paired_key_verification_runner.h"
#include "chrome/browser/nearby_sharing/transfer_metadata_builder.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/identity_manager_factory.h"
......@@ -42,6 +44,10 @@ constexpr base::TimeDelta kIncomingRejectionDelay =
constexpr base::TimeDelta kInvalidateDelay =
base::TimeDelta::FromMilliseconds(500);
// Used to hash a token into a 4 digit string.
constexpr int kHashModulo = 9973;
constexpr int kHashBaseMultiplier = 31;
std::string ReceiveSurfaceStateToString(
NearbySharingService::ReceiveSurfaceState state) {
switch (state) {
......@@ -93,6 +99,17 @@ std::string GetDeviceId(
return std::string(certificate->id().begin(), certificate->id().end());
}
std::string ToFourDigitString(const std::vector<uint8_t>& bytes) {
int hash = 0;
int multiplier = 1;
for (auto byte : bytes) {
hash = (hash + byte * multiplier) % kHashModulo;
multiplier = (multiplier * kHashBaseMultiplier) % kHashModulo;
}
return base::StringPrintf("%04d", std::abs(hash));
}
} // namespace
NearbySharingServiceImpl::NearbySharingServiceImpl(
......@@ -456,12 +473,23 @@ void NearbySharingServiceImpl::OnIncomingConnection(
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(connection);
ShareTarget placeholder_share_target;
auto& share_target_info =
GetIncomingShareTargetInfo(placeholder_share_target);
share_target_info.set_connection(connection);
share_target_info.set_endpoint_id(endpoint_id);
connection->SetDisconnectionListener(
base::BindOnce(&NearbySharingServiceImpl::RefreshUIOnDisconnection,
weak_ptr_factory_.GetWeakPtr(), placeholder_share_target));
process_manager_->GetOrStartNearbySharingDecoder(profile_)
->DecodeAdvertisement(
endpoint_info,
base::BindOnce(
&NearbySharingServiceImpl::OnIncomingAdvertisementDecoded,
weak_ptr_factory_.GetWeakPtr(), endpoint_id, connection));
weak_ptr_factory_.GetWeakPtr(), endpoint_id,
std::move(placeholder_share_target)));
}
void NearbySharingServiceImpl::OnEndpointDiscovered(
......@@ -1259,8 +1287,16 @@ void NearbySharingServiceImpl::CloseConnection(
void NearbySharingServiceImpl::OnIncomingAdvertisementDecoded(
const std::string& endpoint_id,
NearbyConnection* connection,
ShareTarget placeholder_share_target,
sharing::mojom::AdvertisementPtr advertisement) {
NearbyConnection* connection =
GetIncomingConnection(placeholder_share_target);
if (!connection) {
NS_LOG(VERBOSE) << __func__ << ": Invalid connection for endoint id - "
<< endpoint_id;
return;
}
if (!advertisement) {
NS_LOG(VERBOSE) << __func__
<< "Failed to parse incoming connection from endpoint - "
......@@ -1274,15 +1310,28 @@ void NearbySharingServiceImpl::OnIncomingAdvertisementDecoded(
GetCertificateManager()->GetDecryptedPublicCertificate(
std::move(encrypted_metadata_key),
base::BindOnce(&NearbySharingServiceImpl::OnIncomingDecryptedCertificate,
weak_ptr_factory_.GetWeakPtr(), endpoint_id, connection,
std::move(advertisement)));
weak_ptr_factory_.GetWeakPtr(), endpoint_id,
std::move(advertisement),
std::move(placeholder_share_target)));
}
void NearbySharingServiceImpl::OnIncomingDecryptedCertificate(
const std::string& endpoint_id,
NearbyConnection* connection,
sharing::mojom::AdvertisementPtr advertisement,
ShareTarget placeholder_share_target,
base::Optional<NearbyShareDecryptedPublicCertificate> certificate) {
NearbyConnection* connection =
GetIncomingConnection(placeholder_share_target);
if (!connection) {
NS_LOG(VERBOSE) << __func__ << ": Invalid connection for endpoint id - "
<< endpoint_id;
return;
}
// Remove placeholder share target since we are creating the actual share
// target below.
incoming_share_target_info_map_.erase(placeholder_share_target.id);
base::Optional<ShareTarget> share_target = CreateShareTarget(
endpoint_id, advertisement, std::move(certificate), /*is_incoming=*/true);
......@@ -1305,10 +1354,98 @@ void NearbySharingServiceImpl::OnIncomingDecryptedCertificate(
connection->SetDisconnectionListener(
base::BindOnce(&NearbySharingServiceImpl::UnregisterShareTarget,
weak_ptr_factory_.GetWeakPtr(), *share_target));
base::Optional<std::vector<uint8_t>> token =
nearby_connections_manager_->GetRawAuthenticationToken(endpoint_id);
if (!token) {
NS_LOG(VERBOSE) << __func__
<< ": Failed to read authentication token from endpoint - "
<< endpoint_id;
OnIncomingConnectionKeyVerificationDone(
std::move(*share_target), std::move(token),
PairedKeyVerificationRunner::PairedKeyVerificationResult::kFail);
return;
}
share_target_info.set_frames_reader(std::make_unique<IncomingFramesReader>(
process_manager_, profile_, connection));
bool restrict_to_contacts =
advertising_power_level_ != PowerLevel::kHighPower;
share_target_info.set_key_verification_runner(
std::make_unique<PairedKeyVerificationRunner>(
*share_target, endpoint_id, *token, connection,
share_target_info.certificate(), GetCertificateManager(),
settings_.GetVisibility(), restrict_to_contacts,
share_target_info.frames_reader(), kReadFramesTimeout));
share_target_info.key_verification_runner()->Run(base::BindOnce(
&NearbySharingServiceImpl::OnIncomingConnectionKeyVerificationDone,
weak_ptr_factory_.GetWeakPtr(), std::move(*share_target),
std::move(token)));
}
void NearbySharingServiceImpl::OnIncomingConnectionKeyVerificationDone(
ShareTarget share_target,
base::Optional<std::vector<uint8_t>> token,
PairedKeyVerificationRunner::PairedKeyVerificationResult result) {
NearbyConnection* connection = GetIncomingConnection(share_target);
const base::Optional<std::string>& endpoint_id =
GetIncomingShareTargetInfo(share_target).endpoint_id();
if (!connection || !endpoint_id) {
NS_LOG(VERBOSE) << __func__ << ": Invalid connection or endpoint id";
return;
}
// TODO(himanshujaju) - Implement RunPairedKeyVerification.
base::Optional<std::string> token_string;
if (token)
token_string = ToFourDigitString(*token);
ReceiveIntroduction(std::move(*share_target), /*token=*/base::nullopt);
switch (result) {
case PairedKeyVerificationRunner::PairedKeyVerificationResult::kFail:
NS_LOG(VERBOSE) << __func__
<< ": Paired key handshake failed, disconnecting.";
connection->Close();
return;
case PairedKeyVerificationRunner::PairedKeyVerificationResult::kSuccess:
NS_LOG(VERBOSE) << __func__
<< ": Paired key handshake succeeded for target - "
<< share_target.device_name;
nearby_connections_manager_->UpgradeBandwidth(*endpoint_id);
ReceiveIntroduction(share_target, /*token=*/base::nullopt);
break;
case PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnable:
NS_LOG(VERBOSE) << __func__
<< ": Unable to verify paired key encryption when "
"receiving connection from target - "
<< share_target.device_name;
if (advertising_power_level_ == PowerLevel::kHighPower)
nearby_connections_manager_->UpgradeBandwidth(*endpoint_id);
if (token_string)
GetIncomingShareTargetInfo(share_target).set_token(*token_string);
ReceiveIntroduction(share_target, std::move(token_string));
break;
case PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnknown:
NS_LOG(VERBOSE)
<< __func__
<< ": Unknown PairedKeyVerificationResult, disconnecting.";
connection->Close();
break;
}
}
void NearbySharingServiceImpl::RefreshUIOnDisconnection(
ShareTarget share_target) {
OnIncomingTransferUpdate(
share_target,
TransferMetadataBuilder()
.set_status(TransferMetadata::Status::kAwaitingRemoteAcceptanceFailed)
.build());
UnregisterShareTarget(share_target);
}
void NearbySharingServiceImpl::ReceiveIntroduction(
......@@ -1326,8 +1463,6 @@ void NearbySharingServiceImpl::ReceiveIntroduction(
}
auto& share_target_info = GetIncomingShareTargetInfo(share_target);
share_target_info.set_frames_reader(std::make_unique<IncomingFramesReader>(
process_manager_, profile_, connection));
share_target_info.frames_reader()->ReadFrame(
sharing::mojom::V1Frame::Tag::INTRODUCTION,
base::BindOnce(&NearbySharingServiceImpl::OnReceivedIntroduction,
......@@ -1426,6 +1561,7 @@ void NearbySharingServiceImpl::OnReceivedIntroduction(
share_target,
TransferMetadataBuilder()
.set_status(TransferMetadata::Status::kAwaitingLocalConfirmation)
.set_token(std::move(token))
.build());
if (!incoming_share_target_info_map_.count(share_target.id)) {
......@@ -1606,6 +1742,9 @@ void NearbySharingServiceImpl::ClearOutgoingShareTargetInfoMap() {
void NearbySharingServiceImpl::UnregisterShareTarget(
const ShareTarget& share_target) {
NS_LOG(VERBOSE) << __func__ << ": Unregistering share target - "
<< share_target.device_name;
if (share_target.is_incoming) {
incoming_share_target_info_map_.erase(share_target.id);
// Clear legacy incoming payloads to release resource
......
......@@ -174,16 +174,21 @@ class NearbySharingServiceImpl
StatusCodes StopScanning();
void OnIncomingAdvertisementDecoded(
const std::string& endpoint_id,
NearbyConnection* connection,
ShareTarget placeholder_share_target,
sharing::mojom::AdvertisementPtr advertisement);
void OnIncomingTransferUpdate(const ShareTarget& share_target,
TransferMetadata metadata);
void CloseConnection(const ShareTarget& share_target);
void OnIncomingDecryptedCertificate(
const std::string& endpoint_id,
NearbyConnection* connection,
sharing::mojom::AdvertisementPtr advertisement,
ShareTarget placeholder_share_target,
base::Optional<NearbyShareDecryptedPublicCertificate> certificate);
void OnIncomingConnectionKeyVerificationDone(
ShareTarget share_target,
base::Optional<std::vector<uint8_t>> token,
PairedKeyVerificationRunner::PairedKeyVerificationResult result);
void RefreshUIOnDisconnection(ShareTarget share_target);
void ReceiveIntroduction(ShareTarget share_target,
base::Optional<std::string> token);
void OnReceivedIntroduction(ShareTarget share_target,
......
......@@ -176,6 +176,19 @@ const std::vector<uint8_t> kValidV1EndpointInfo = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 10, 100, 101, 118, 105, 99, 101, 78, 97, 109, 101};
const std::vector<uint8_t> kToken = {0, 1, 2};
const char kFourDigitToken[] = "1953";
const std::vector<uint8_t> kPrivateCertificateHashAuthToken = {
0x8b, 0xcb, 0xa2, 0xf8, 0xe4, 0x06};
const std::vector<uint8_t> kIncomingConnectionSignedData = {
0x30, 0x45, 0x02, 0x20, 0x4f, 0x83, 0x72, 0xbd, 0x02, 0x70, 0xd9, 0xda,
0x62, 0x83, 0x5d, 0xb2, 0xdc, 0x6e, 0x3f, 0xa6, 0xa8, 0xa1, 0x4f, 0x5f,
0xd3, 0xe3, 0xd9, 0x1a, 0x5d, 0x2d, 0x61, 0xd2, 0x6c, 0xdd, 0x8d, 0xa5,
0x02, 0x21, 0x00, 0xd4, 0xe1, 0x1d, 0x14, 0xcb, 0x58, 0xf7, 0x02, 0xd5,
0xab, 0x48, 0xe2, 0x2f, 0xcb, 0xc0, 0x53, 0x41, 0x06, 0x50, 0x65, 0x95,
0x19, 0xa9, 0x22, 0x92, 0x00, 0x42, 0x01, 0x26, 0x25, 0xcb, 0x8c};
sharing::mojom::FramePtr GetValidIntroductionFrame() {
std::vector<sharing::mojom::TextMetadataPtr> mojo_text_metadatas;
// TODO(himanshujaju) - Parameterise number of text and file metadatas.
......@@ -207,7 +220,8 @@ sharing::mojom::FramePtr GetEmptyIntroductionFrame() {
class NearbySharingServiceImplTest : public testing::Test {
public:
NearbySharingServiceImplTest() {
NearbySharingServiceImplTest()
: task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
scoped_feature_list_.InitAndEnableFeature(features::kNearbySharing);
RegisterNearbySharingPrefs(prefs_.registry());
}
......@@ -269,6 +283,11 @@ class NearbySharingServiceImplTest : public testing::Test {
return service;
}
void SetVisibility(nearby_share::mojom::Visibility visibility) {
NearbyShareSettings settings(&prefs_);
settings.SetVisibility(visibility);
}
void SetFakeFastInitiationManagerFactory(bool should_succeed_on_start) {
fast_initiation_manager_factory_ =
std::make_unique<FakeFastInitiationManagerFactory>(
......@@ -295,7 +314,8 @@ class NearbySharingServiceImplTest : public testing::Test {
return mock_nearby_process_manager_;
}
void SetUpReceiveSurface(NiceMock<MockTransferUpdateCallback>& callback) {
void SetUpForegroundReceiveSurface(
NiceMock<MockTransferUpdateCallback>& callback) {
NearbySharingService::StatusCodes result = service_->RegisterReceiveSurface(
&callback, NearbySharingService::ReceiveSurfaceState::kForeground);
EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
......@@ -326,6 +346,52 @@ class NearbySharingServiceImplTest : public testing::Test {
}
}
void SetUpKeyVerification(
sharing::mojom::PairedKeyResultFrame::Status status) {
SetVisibility(nearby_share::mojom::Visibility::kAllContacts);
std::string encryption_frame = "test_encryption_frame";
std::vector<uint8_t> encryption_bytes(encryption_frame.begin(),
encryption_frame.end());
EXPECT_CALL(mock_decoder_,
DecodeFrame(testing::Eq(encryption_bytes), testing::_))
.WillOnce(testing::Invoke(
[](const std::vector<uint8_t>& data,
MockNearbySharingDecoder::DecodeFrameCallback callback) {
sharing::mojom::V1FramePtr mojo_v1frame =
sharing::mojom::V1Frame::New();
mojo_v1frame->set_paired_key_encryption(
sharing::mojom::PairedKeyEncryptionFrame::New(
kIncomingConnectionSignedData,
kPrivateCertificateHashAuthToken));
sharing::mojom::FramePtr mojo_frame =
sharing::mojom::Frame::New();
mojo_frame->set_v1(std::move(mojo_v1frame));
std::move(callback).Run(std::move(mojo_frame));
}));
connection_.AppendReadableData(encryption_bytes);
std::string encryption_result = "test_encryption_result";
std::vector<uint8_t> result_bytes(encryption_result.begin(),
encryption_result.end());
EXPECT_CALL(mock_decoder_,
DecodeFrame(testing::Eq(result_bytes), testing::_))
.WillOnce(testing::Invoke(
[=](const std::vector<uint8_t>& data,
MockNearbySharingDecoder::DecodeFrameCallback callback) {
sharing::mojom::V1FramePtr mojo_v1frame =
sharing::mojom::V1Frame::New();
mojo_v1frame->set_paired_key_result(
sharing::mojom::PairedKeyResultFrame::New(status));
sharing::mojom::FramePtr mojo_frame =
sharing::mojom::Frame::New();
mojo_frame->set_v1(std::move(mojo_v1frame));
std::move(callback).Run(std::move(mojo_frame));
}));
connection_.AppendReadableData(result_bytes);
}
void SetUpAdvertisementDecoder(const std::vector<uint8_t>& endpoint_info,
bool return_empty_advertisement) {
EXPECT_CALL(mock_decoder_,
......@@ -364,6 +430,8 @@ class NearbySharingServiceImplTest : public testing::Test {
ShareTarget SetUpIncomingConnection(
NiceMock<MockTransferUpdateCallback>& callback) {
fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
kToken);
SetUpAdvertisementDecoder(kValidV1EndpointInfo,
/*return_empty_advertisement=*/false);
SetUpIntroductionFrameDecoder(/*return_empty_introduction_frame=*/false);
......@@ -381,16 +449,48 @@ class NearbySharingServiceImplTest : public testing::Test {
share_target = incoming_share_target;
run_loop.Quit();
}));
SetUpReceiveSurface(callback);
SetUpKeyVerification(sharing::mojom::PairedKeyResultFrame_Status::kSuccess);
SetUpForegroundReceiveSurface(callback);
service_->OnIncomingConnection(kEndpointId, kValidV1EndpointInfo,
&connection_);
ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
/*success=*/true);
run_loop.Run();
EXPECT_TRUE(
fake_nearby_connections_manager_->DidUpgradeBandwidth(kEndpointId));
return share_target;
}
sharing::nearby::Frame GetWrittenFrame() {
std::vector<uint8_t> data = connection_.GetWrittenData();
sharing::nearby::Frame frame;
frame.ParseFromArray(data.data(), data.size());
return frame;
}
void ExpectPairedKeyEncryptionFrame() {
sharing::nearby::Frame frame = GetWrittenFrame();
ASSERT_TRUE(frame.has_v1());
ASSERT_TRUE(frame.v1().has_paired_key_encryption());
}
void ExpectPairedKeyResultFrame() {
sharing::nearby::Frame frame = GetWrittenFrame();
ASSERT_TRUE(frame.has_v1());
ASSERT_TRUE(frame.v1().has_paired_key_result());
}
void ExpectConnectionResponseFrame(
sharing::nearby::ConnectionResponseFrame::Status status) {
sharing::nearby::Frame frame = GetWrittenFrame();
ASSERT_TRUE(frame.has_v1());
ASSERT_TRUE(frame.v1().has_connection_response());
EXPECT_EQ(status, frame.v1().connection_response().status());
}
protected:
FakeNearbyShareLocalDeviceDataManager* local_device_data_manager() {
EXPECT_EQ(1u, local_device_data_manager_factory_.instances().size());
......@@ -1328,6 +1428,8 @@ TEST_F(NearbySharingServiceImplTest, UnregisterReceiveSurfaceNeverRegistered) {
TEST_F(NearbySharingServiceImplTest,
IncomingConnection_ClosedReadingIntroduction) {
fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
kToken);
SetUpAdvertisementDecoder(kValidV1EndpointInfo,
/*return_empty_advertisement=*/false);
......@@ -1335,7 +1437,9 @@ TEST_F(NearbySharingServiceImplTest,
SetConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI);
NiceMock<MockTransferUpdateCallback> callback;
EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_)).Times(0);
SetUpReceiveSurface(callback);
SetUpKeyVerification(sharing::mojom::PairedKeyResultFrame_Status::kSuccess);
SetUpForegroundReceiveSurface(callback);
service_->OnIncomingConnection(kEndpointId, kValidV1EndpointInfo,
&connection_);
ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
......@@ -1350,6 +1454,8 @@ TEST_F(NearbySharingServiceImplTest,
TEST_F(NearbySharingServiceImplTest,
IncomingConnection_EmptyIntroductionFrame) {
fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
kToken);
SetUpAdvertisementDecoder(kValidV1EndpointInfo,
/*return_empty_advertisement=*/false);
SetUpIntroductionFrameDecoder(/*return_empty_introduction_frame=*/true);
......@@ -1377,7 +1483,9 @@ TEST_F(NearbySharingServiceImplTest,
EXPECT_TRUE(metadata.is_final_status());
run_loop.Quit();
}));
SetUpReceiveSurface(callback);
SetUpKeyVerification(sharing::mojom::PairedKeyResultFrame_Status::kSuccess);
SetUpForegroundReceiveSurface(callback);
service_->OnIncomingConnection(kEndpointId, kValidV1EndpointInfo,
&connection_);
ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
......@@ -1385,15 +1493,10 @@ TEST_F(NearbySharingServiceImplTest,
run_loop.Run();
// Check data written to connection_.
std::vector<uint8_t> data = connection_.GetWrittenData();
sharing::nearby::Frame frame;
frame.ParseFromArray(data.data(), data.size());
EXPECT_TRUE(frame.has_v1());
EXPECT_TRUE(frame.v1().has_connection_response());
EXPECT_EQ(
sharing::nearby::ConnectionResponseFrame::UNSUPPORTED_ATTACHMENT_TYPE,
frame.v1().connection_response().status());
ExpectPairedKeyEncryptionFrame();
ExpectPairedKeyResultFrame();
ExpectConnectionResponseFrame(
sharing::nearby::ConnectionResponseFrame::UNSUPPORTED_ATTACHMENT_TYPE);
// To avoid UAF in OnIncomingTransferUpdate().
service_->UnregisterReceiveSurface(&callback);
......@@ -1401,6 +1504,8 @@ TEST_F(NearbySharingServiceImplTest,
TEST_F(NearbySharingServiceImplTest,
IncomingConnection_ValidIntroductionFrame_InvalidCertificate) {
fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
kToken);
SetUpAdvertisementDecoder(kValidV1EndpointInfo,
/*return_empty_advertisement=*/false);
SetUpIntroductionFrameDecoder(/*return_empty_introduction_frame=*/false);
......@@ -1429,13 +1534,17 @@ TEST_F(NearbySharingServiceImplTest,
EXPECT_FALSE(metadata.is_final_status());
run_loop.Quit();
}));
SetUpReceiveSurface(callback);
SetUpKeyVerification(sharing::mojom::PairedKeyResultFrame_Status::kSuccess);
SetUpForegroundReceiveSurface(callback);
service_->OnIncomingConnection(kEndpointId, kValidV1EndpointInfo,
&connection_);
ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
/*success=*/false);
run_loop.Run();
EXPECT_FALSE(connection_.IsClosed());
// To avoid UAF in OnIncomingTransferUpdate().
service_->UnregisterReceiveSurface(&callback);
}
......@@ -1463,6 +1572,8 @@ TEST_F(NearbySharingServiceImplTest,
TEST_F(NearbySharingServiceImplTest,
IncomingConnection_ValidIntroductionFrame_ValidCertificate) {
fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
kToken);
SetUpAdvertisementDecoder(kValidV1EndpointInfo,
/*return_empty_advertisement=*/false);
SetUpIntroductionFrameDecoder(/*return_empty_introduction_frame=*/false);
......@@ -1487,18 +1598,24 @@ TEST_F(NearbySharingServiceImplTest,
EXPECT_NE(kEndpointId, share_target.device_id);
EXPECT_EQ(kTestMetadataFullName, share_target.full_name);
EXPECT_FALSE(metadata.token().has_value());
EXPECT_EQ(TransferMetadata::Status::kAwaitingLocalConfirmation,
metadata.status());
EXPECT_FALSE(metadata.is_final_status());
run_loop.Quit();
}));
SetUpReceiveSurface(callback);
SetUpKeyVerification(sharing::mojom::PairedKeyResultFrame_Status::kSuccess);
SetUpForegroundReceiveSurface(callback);
service_->OnIncomingConnection(kEndpointId, kValidV1EndpointInfo,
&connection_);
ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
/*success=*/true);
run_loop.Run();
EXPECT_FALSE(connection_.IsClosed());
// To avoid UAF in OnIncomingTransferUpdate().
service_->UnregisterReceiveSurface(&callback);
}
......@@ -1543,15 +1660,14 @@ TEST_F(NearbySharingServiceImplTest, AcceptValidShareTarget) {
EXPECT_TRUE(
fake_nearby_connections_manager_->DidUpgradeBandwidth(kEndpointId));
// Check data written to connection_.
std::vector<uint8_t> data = connection_.GetWrittenData();
sharing::nearby::Frame frame;
frame.ParseFromArray(data.data(), data.size());
ExpectPairedKeyEncryptionFrame();
ExpectPairedKeyResultFrame();
ExpectConnectionResponseFrame(
sharing::nearby::ConnectionResponseFrame::ACCEPT);
EXPECT_TRUE(frame.has_v1());
EXPECT_TRUE(frame.v1().has_connection_response());
EXPECT_EQ(sharing::nearby::ConnectionResponseFrame::ACCEPT,
frame.v1().connection_response().status());
EXPECT_FALSE(connection_.IsClosed());
// To avoid UAF in OnIncomingTransferUpdate().
service_->UnregisterReceiveSurface(&callback);
......@@ -1595,14 +1711,185 @@ TEST_F(NearbySharingServiceImplTest, RejectValidShareTarget) {
run_loop_reject.Run();
// Check data written to connection_.
std::vector<uint8_t> data = connection_.GetWrittenData();
sharing::nearby::Frame frame;
frame.ParseFromArray(data.data(), data.size());
ExpectPairedKeyEncryptionFrame();
ExpectPairedKeyResultFrame();
ExpectConnectionResponseFrame(
sharing::nearby::ConnectionResponseFrame::REJECT);
// TODO(himanshujaju) - Extract out to a common constant b/w impl and test.
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(2));
EXPECT_TRUE(connection_.IsClosed());
// To avoid UAF in OnIncomingTransferUpdate().
service_->UnregisterReceiveSurface(&callback);
}
TEST_F(NearbySharingServiceImplTest,
IncomingConnection_KeyVerificationRunnerStatusUnable) {
fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
kToken);
SetUpAdvertisementDecoder(kValidV1EndpointInfo,
/*return_empty_advertisement=*/false);
SetUpIntroductionFrameDecoder(/*return_empty_introduction_frame=*/false);
ui::ScopedSetIdleState unlocked(ui::IDLE_STATE_IDLE);
SetConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI);
NiceMock<MockTransferUpdateCallback> callback;
base::RunLoop run_loop;
EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_))
.WillOnce(testing::Invoke([&run_loop](const ShareTarget& share_target,
TransferMetadata metadata) {
EXPECT_TRUE(share_target.is_incoming);
EXPECT_TRUE(share_target.is_known);
EXPECT_TRUE(share_target.has_attachments());
EXPECT_EQ(3u, share_target.text_attachments.size());
EXPECT_EQ(0u, share_target.file_attachments.size());
EXPECT_EQ(kDeviceName, share_target.device_name);
EXPECT_EQ(GURL(kTestMetadataIconUrl), share_target.image_url);
EXPECT_EQ(nearby_share::mojom::ShareTargetType::kUnknown,
share_target.type);
EXPECT_TRUE(share_target.device_id);
EXPECT_NE(kEndpointId, share_target.device_id);
EXPECT_EQ(kTestMetadataFullName, share_target.full_name);
EXPECT_EQ(kFourDigitToken, metadata.token());
EXPECT_EQ(TransferMetadata::Status::kAwaitingLocalConfirmation,
metadata.status());
EXPECT_FALSE(metadata.is_final_status());
run_loop.Quit();
}));
SetUpKeyVerification(sharing::mojom::PairedKeyResultFrame_Status::kUnable);
SetUpForegroundReceiveSurface(callback);
service_->OnIncomingConnection(kEndpointId, kValidV1EndpointInfo,
&connection_);
ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
/*success=*/true);
run_loop.Run();
EXPECT_TRUE(
fake_nearby_connections_manager_->DidUpgradeBandwidth(kEndpointId));
EXPECT_FALSE(connection_.IsClosed());
// To avoid UAF in OnIncomingTransferUpdate().
service_->UnregisterReceiveSurface(&callback);
}
TEST_F(NearbySharingServiceImplTest,
IncomingConnection_KeyVerificationRunnerStatusUnable_LowPower) {
fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
kToken);
SetUpAdvertisementDecoder(kValidV1EndpointInfo,
/*return_empty_advertisement=*/false);
SetUpIntroductionFrameDecoder(/*return_empty_introduction_frame=*/false);
ui::ScopedSetIdleState unlocked(ui::IDLE_STATE_IDLE);
SetConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI);
NiceMock<MockTransferUpdateCallback> callback;
base::RunLoop run_loop;
EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_))
.WillOnce(testing::Invoke([&run_loop](const ShareTarget& share_target,
TransferMetadata metadata) {
EXPECT_TRUE(share_target.is_incoming);
EXPECT_TRUE(share_target.is_known);
EXPECT_TRUE(share_target.has_attachments());
EXPECT_EQ(3u, share_target.text_attachments.size());
EXPECT_EQ(0u, share_target.file_attachments.size());
EXPECT_EQ(kDeviceName, share_target.device_name);
EXPECT_EQ(GURL(kTestMetadataIconUrl), share_target.image_url);
EXPECT_EQ(nearby_share::mojom::ShareTargetType::kUnknown,
share_target.type);
EXPECT_TRUE(share_target.device_id);
EXPECT_NE(kEndpointId, share_target.device_id);
EXPECT_EQ(kTestMetadataFullName, share_target.full_name);
EXPECT_EQ(kFourDigitToken, metadata.token());
EXPECT_EQ(TransferMetadata::Status::kAwaitingLocalConfirmation,
metadata.status());
EXPECT_FALSE(metadata.is_final_status());
run_loop.Quit();
}));
SetUpKeyVerification(sharing::mojom::PairedKeyResultFrame_Status::kUnable);
NearbySharingService::StatusCodes result = service_->RegisterReceiveSurface(
&callback, NearbySharingService::ReceiveSurfaceState::kBackground);
EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
service_->OnIncomingConnection(kEndpointId, kValidV1EndpointInfo,
&connection_);
ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
/*success=*/true);
run_loop.Run();
EXPECT_FALSE(
fake_nearby_connections_manager_->DidUpgradeBandwidth(kEndpointId));
EXPECT_FALSE(connection_.IsClosed());
// To avoid UAF in OnIncomingTransferUpdate().
service_->UnregisterReceiveSurface(&callback);
}
TEST_F(NearbySharingServiceImplTest,
IncomingConnection_KeyVerificationRunnerStatusFail) {
fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
kToken);
SetUpAdvertisementDecoder(kValidV1EndpointInfo,
/*return_empty_advertisement=*/false);
ui::ScopedSetIdleState unlocked(ui::IDLE_STATE_IDLE);
SetConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI);
NiceMock<MockTransferUpdateCallback> callback;
SetUpKeyVerification(sharing::mojom::PairedKeyResultFrame_Status::kFail);
SetUpForegroundReceiveSurface(callback);
// Ensures that introduction is never received for failed key verification.
std::string intro = "introduction_frame";
std::vector<uint8_t> bytes(intro.begin(), intro.end());
EXPECT_CALL(mock_decoder_, DecodeFrame(testing::Eq(bytes), testing::_))
.Times(0);
connection_.AppendReadableData(bytes);
service_->OnIncomingConnection(kEndpointId, kValidV1EndpointInfo,
&connection_);
ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
/*success=*/true);
EXPECT_TRUE(connection_.IsClosed());
// To avoid UAF in OnIncomingTransferUpdate().
service_->UnregisterReceiveSurface(&callback);
}
TEST_F(NearbySharingServiceImplTest,
IncomingConnection_EmptyAuthToken_KeyVerificationRunnerStatusFail) {
SetUpAdvertisementDecoder(kValidV1EndpointInfo,
/*return_empty_advertisement=*/false);
ui::ScopedSetIdleState unlocked(ui::IDLE_STATE_IDLE);
SetConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI);
NiceMock<MockTransferUpdateCallback> callback;
SetUpForegroundReceiveSurface(callback);
// Ensures that introduction is never received for empty auth token.
std::string intro = "introduction_frame";
std::vector<uint8_t> bytes(intro.begin(), intro.end());
EXPECT_CALL(mock_decoder_, DecodeFrame(testing::Eq(bytes), testing::_))
.Times(0);
connection_.AppendReadableData(bytes);
service_->OnIncomingConnection(kEndpointId, kValidV1EndpointInfo,
&connection_);
ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
/*success=*/true);
EXPECT_TRUE(frame.has_v1());
EXPECT_TRUE(frame.v1().has_connection_response());
EXPECT_EQ(sharing::nearby::ConnectionResponseFrame::REJECT,
frame.v1().connection_response().status());
EXPECT_TRUE(connection_.IsClosed());
// To avoid UAF in OnIncomingTransferUpdate().
service_->UnregisterReceiveSurface(&callback);
......
......@@ -11,6 +11,7 @@
#include "base/optional.h"
#include "chrome/browser/nearby_sharing/certificates/nearby_share_decrypted_public_certificate.h"
#include "chrome/browser/nearby_sharing/incoming_frames_reader.h"
#include "chrome/browser/nearby_sharing/paired_key_verification_runner.h"
class NearbyConnection;
......@@ -55,12 +56,22 @@ class ShareTargetInfo {
frames_reader_ = std::move(frames_reader);
}
PairedKeyVerificationRunner* key_verification_runner() {
return key_verification_runner_.get();
}
void set_key_verification_runner(
std::unique_ptr<PairedKeyVerificationRunner> key_verification_runner) {
key_verification_runner_ = std::move(key_verification_runner);
}
private:
base::Optional<std::string> endpoint_id_;
base::Optional<NearbyShareDecryptedPublicCertificate> certificate_;
NearbyConnection* connection_ = nullptr;
base::Optional<std::string> token_;
std::unique_ptr<IncomingFramesReader> frames_reader_;
std::unique_ptr<PairedKeyVerificationRunner> key_verification_runner_;
};
#endif // CHROME_BROWSER_NEARBY_SHARING_SHARE_TARGET_INFO_H_
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