Commit d460dcfe authored by Kunihiko Sakamoto's avatar Kunihiko Sakamoto Committed by Commit Bot

Revert "Implement key verification for incoming connection."

This reverts commit 34bca2e3.

Reason for revert: Suspected for TSan error (data race) in
BluetoothSocketTest.TestOutputStream and BluetoothSocketTest.TestInputStream.

https://ci.chromium.org/p/chromium/builders/ci/Linux%20TSan%20Tests/57982


Original change's description:
> Implement key verification for incoming connection.
> 
> Implements the key verification module that to verify remote device
> before requesting introduction and beginning the transfer flow.
> 
> Bug: 1085068
> Change-Id: I4bb75dce474042ef43ca86199db3456d63406874
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2346325
> Commit-Queue: Himanshu Jaju <himanshujaju@chromium.org>
> Reviewed-by: Alex Chau <alexchau@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#797868}

TBR=alexchau@chromium.org,nohle@chromium.org,himanshujaju@chromium.org

Change-Id: I04ef174610f0e3751299ea7aeccdd16c4bf8683f
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 1085068
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2352300Reviewed-by: default avatarKunihiko Sakamoto <ksakamoto@chromium.org>
Commit-Queue: Kunihiko Sakamoto <ksakamoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#797963}
parent 1e06ab1a
......@@ -3393,8 +3393,6 @@ static_library("browser") {
"nearby_sharing/nearby_sharing_service_impl.h",
"nearby_sharing/outgoing_share_target_info.cc",
"nearby_sharing/outgoing_share_target_info.h",
"nearby_sharing/paired_key_verification_runner.cc",
"nearby_sharing/paired_key_verification_runner.h",
"nearby_sharing/share_target.cc",
"nearby_sharing/share_target.h",
"nearby_sharing/share_target_discovered_callback.h",
......
......@@ -5,11 +5,9 @@
#include "chrome/browser/nearby_sharing/certificates/common.h"
#include "base/logging.h"
#include "base/rand_util.h"
#include "chrome/browser/nearby_sharing/certificates/constants.h"
#include "crypto/encryptor.h"
#include "crypto/hkdf.h"
#include "crypto/random.h"
#include "crypto/sha2.h"
#include "crypto/symmetric_key.h"
......@@ -55,13 +53,6 @@ std::vector<uint8_t> ComputeAuthenticationTokenHash(
kNearbyShareNumBytesAuthenticationTokenHash);
}
std::vector<uint8_t> GenerateRandomBytes(size_t num_bytes) {
std::vector<uint8_t> bytes(num_bytes);
crypto::RandBytes(bytes);
return bytes;
}
std::unique_ptr<crypto::Encryptor> CreateNearbyShareCtrEncryptor(
const crypto::SymmetricKey* secret_key,
base::span<const uint8_t> salt) {
......
......@@ -44,9 +44,6 @@ std::vector<uint8_t> ComputeAuthenticationTokenHash(
std::vector<uint8_t> DeriveNearbyShareKey(base::span<const uint8_t> key,
size_t new_num_bytes);
// Generates a random byte array with size |num_bytes|.
std::vector<uint8_t> GenerateRandomBytes(size_t num_bytes);
// Creates a CTR encryptor used for metadata key encryption/decryption.
std::unique_ptr<crypto::Encryptor> CreateNearbyShareCtrEncryptor(
const crypto::SymmetricKey* secret_key,
......
......@@ -20,6 +20,7 @@
#include "crypto/ec_signature_creator.h"
#include "crypto/encryptor.h"
#include "crypto/hmac.h"
#include "crypto/random.h"
#include "crypto/sha2.h"
#include "crypto/symmetric_key.h"
......@@ -36,6 +37,13 @@ const char kId[] = "id";
const char kUnencryptedMetadata[] = "unencrypted_metadata";
const char kConsumedSalts[] = "consumed_salts";
std::vector<uint8_t> GenerateRandomBytes(size_t num_bytes) {
std::vector<uint8_t> bytes(num_bytes);
crypto::RandBytes(bytes);
return bytes;
}
// Generates a random validity bound offset in the interval
// [0, kNearbyShareMaxPrivateCertificateValidityBoundOffset).
base::TimeDelta GenerateRandomOffset() {
......
......@@ -34,7 +34,7 @@ class IncomingFramesReader : public NearbyProcessManager::Observer {
//
// Note: Callers are expected wait for |callback| to be run before scheduling
// subsequent calls to ReadFrame(..).
virtual void ReadFrame(
void ReadFrame(
base::OnceCallback<void(base::Optional<sharing::mojom::V1FramePtr>)>
callback);
......@@ -44,7 +44,7 @@ class IncomingFramesReader : public NearbyProcessManager::Observer {
//
// Note: Callers are expected wait for |callback| to be run before scheduling
// subsequent calls to ReadFrame(..).
virtual void ReadFrame(
void ReadFrame(
sharing::mojom::V1Frame::Tag frame_type,
base::OnceCallback<void(base::Optional<sharing::mojom::V1FramePtr>)>
callback,
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/nearby_sharing/paired_key_verification_runner.h"
#include <iomanip>
#include <iostream>
#include "base/bind.h"
#include "chrome/browser/nearby_sharing/certificates/common.h"
#include "chrome/browser/nearby_sharing/certificates/constants.h"
#include "chrome/browser/nearby_sharing/certificates/nearby_share_visibility.h"
#include "chrome/browser/nearby_sharing/logging/logging.h"
#include "chrome/browser/nearby_sharing/proto/rpc_resources.pb.h"
#include "chrome/services/sharing/public/proto/wire_format.pb.h"
namespace {
std::ostream& operator<<(
std::ostream& out,
const PairedKeyVerificationRunner::PairedKeyVerificationResult& obj) {
out << static_cast<std::underlying_type<
PairedKeyVerificationRunner::PairedKeyVerificationResult>::type>(obj);
return out;
}
PairedKeyVerificationRunner::PairedKeyVerificationResult Convert(
sharing::mojom::PairedKeyResultFrame::Status status) {
switch (status) {
case sharing::mojom::PairedKeyResultFrame_Status::kUnknown:
return PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnknown;
case sharing::mojom::PairedKeyResultFrame_Status::kSuccess:
return PairedKeyVerificationRunner::PairedKeyVerificationResult::kSuccess;
case sharing::mojom::PairedKeyResultFrame_Status::kFail:
return PairedKeyVerificationRunner::PairedKeyVerificationResult::kFail;
case sharing::mojom::PairedKeyResultFrame_Status::kUnable:
return PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnable;
}
}
NearbyShareVisibility Convert(nearby_share::mojom::Visibility visibility) {
switch (visibility) {
case nearby_share::mojom::Visibility::kAllContacts:
return NearbyShareVisibility::kAllContacts;
case nearby_share::mojom::Visibility::kSelectedContacts:
return NearbyShareVisibility::kSelectedContacts;
case nearby_share::mojom::Visibility::kNoOne:
return NearbyShareVisibility::kNoOne;
case nearby_share::mojom::Visibility::kUnknown:
return NearbyShareVisibility::kNoOne;
}
}
std::vector<uint8_t> PadPrefix(char prefix, std::vector<uint8_t> bytes) {
bytes.insert(bytes.begin(), prefix);
return bytes;
}
} // namespace
PairedKeyVerificationRunner::PairedKeyVerificationRunner(
const ShareTarget& share_target,
const std::string& endpoint_id,
const std::vector<uint8_t>& token,
NearbyConnection* connection,
const base::Optional<NearbyShareDecryptedPublicCertificate>& certificate,
NearbyShareCertificateManager* certificate_manager,
nearby_share::mojom::Visibility visibility,
bool restrict_to_contacts,
IncomingFramesReader* frames_reader,
base::TimeDelta read_frame_timeout)
: share_target_(share_target),
endpoint_id_(endpoint_id),
raw_token_(token),
connection_(connection),
certificate_(certificate),
certificate_manager_(certificate_manager),
visibility_(visibility),
restrict_to_contacts_(restrict_to_contacts),
frames_reader_(frames_reader),
read_frame_timeout_(read_frame_timeout) {
DCHECK(connection);
DCHECK(certificate_manager);
DCHECK(frames_reader);
if (share_target.is_incoming) {
local_prefix_ = kNearbyShareReceiverVerificationPrefix;
remote_prefix_ = kNearbyShareSenderVerificationPrefix;
} else {
remote_prefix_ = kNearbyShareReceiverVerificationPrefix;
local_prefix_ = kNearbyShareSenderVerificationPrefix;
}
}
PairedKeyVerificationRunner::~PairedKeyVerificationRunner() = default;
void PairedKeyVerificationRunner::Run(
base::OnceCallback<void(PairedKeyVerificationResult)> callback) {
DCHECK(!callback_);
callback_ = std::move(callback);
SendPairedKeyEncryptionFrame();
frames_reader_->ReadFrame(
sharing::mojom::V1Frame::Tag::PAIRED_KEY_ENCRYPTION,
base::BindOnce(
&PairedKeyVerificationRunner::OnReadPairedKeyEncryptionFrame,
weak_ptr_factory_.GetWeakPtr()),
read_frame_timeout_);
}
void PairedKeyVerificationRunner::OnReadPairedKeyEncryptionFrame(
base::Optional<sharing::mojom::V1FramePtr> frame) {
if (!frame) {
NS_LOG(WARNING) << __func__
<< ": Failed to read remote paired key encrpytion";
std::move(callback_).Run(PairedKeyVerificationResult::kFail);
return;
}
std::vector<PairedKeyVerificationResult> verification_results;
PairedKeyVerificationResult remote_public_certificate_result =
VerifyRemotePublicCertificate(*frame);
verification_results.push_back(remote_public_certificate_result);
NS_LOG(VERBOSE) << __func__
<< ": Remote public certificate verification result "
<< remote_public_certificate_result;
if (remote_public_certificate_result ==
PairedKeyVerificationResult::kSuccess) {
SendCertificateInfo();
} else if (restrict_to_contacts_) {
NS_LOG(VERBOSE) << __func__
<< ": we are only allowing connections with contacts. "
"Rejecting connection from unknown ShareTarget - "
<< share_target_.device_name;
std::move(callback_).Run(PairedKeyVerificationResult::kFail);
return;
}
PairedKeyVerificationResult local_result =
VerifyPairedKeyEncryptionFrame(*frame);
verification_results.push_back(local_result);
NS_LOG(VERBOSE) << __func__ << ": Paired key encryption verification result "
<< local_result;
SendPairedKeyResultFrame(local_result);
frames_reader_->ReadFrame(
sharing::mojom::V1Frame::Tag::PAIRED_KEY_RESULT,
base::BindOnce(&PairedKeyVerificationRunner::OnReadPairedKeyResultFrame,
weak_ptr_factory_.GetWeakPtr(),
std::move(verification_results)),
read_frame_timeout_);
}
void PairedKeyVerificationRunner::OnReadPairedKeyResultFrame(
std::vector<PairedKeyVerificationResult> verification_results,
base::Optional<sharing::mojom::V1FramePtr> frame) {
if (!frame) {
NS_LOG(WARNING) << __func__ << ": Failed to read remote paired key result";
std::move(callback_).Run(PairedKeyVerificationResult::kFail);
return;
}
PairedKeyVerificationResult key_result =
Convert(frame.value()->get_paired_key_result()->status);
verification_results.push_back(key_result);
NS_LOG(VERBOSE) << __func__ << ": Paired key result frame result "
<< key_result;
PairedKeyVerificationResult combined_result =
MergeResults(verification_results);
NS_LOG(VERBOSE) << __func__ << ": Combined verification result "
<< combined_result;
std::move(callback_).Run(combined_result);
}
void PairedKeyVerificationRunner::SendPairedKeyResultFrame(
PairedKeyVerificationResult result) {
sharing::nearby::Frame frame;
sharing::nearby::V1Frame* v1_frame = frame.mutable_v1();
sharing::nearby::PairedKeyResultFrame* result_frame =
v1_frame->mutable_paired_key_result();
switch (result) {
case PairedKeyVerificationResult::kUnable:
result_frame->set_status(sharing::nearby::PairedKeyResultFrame::UNABLE);
break;
case PairedKeyVerificationResult::kSuccess:
result_frame->set_status(sharing::nearby::PairedKeyResultFrame::SUCCESS);
break;
case PairedKeyVerificationResult::kFail:
result_frame->set_status(sharing::nearby::PairedKeyResultFrame::FAIL);
break;
case PairedKeyVerificationResult::kUnknown:
result_frame->set_status(sharing::nearby::PairedKeyResultFrame::UNKNOWN);
break;
}
std::vector<uint8_t> data(frame.ByteSize());
frame.SerializeToArray(data.data(), frame.ByteSize());
connection_->Write(std::move(data));
}
void PairedKeyVerificationRunner::SendCertificateInfo() {
// TODO(https://crbug.com/1114765): Update once the bug is resolved.
std::vector<nearbyshare::proto::PublicCertificate> certificates;
if (certificates.empty())
return;
sharing::nearby::Frame frame;
sharing::nearby::V1Frame* v1_frame = frame.mutable_v1();
sharing::nearby::CertificateInfoFrame* cert_frame =
v1_frame->mutable_certificate_info();
for (const auto& certificate : certificates) {
sharing::nearby::PublicCertificate* cert =
cert_frame->add_public_certificate();
cert->set_secret_id(certificate.secret_id());
cert->set_authenticity_key(certificate.secret_key());
cert->set_public_key(certificate.public_key());
cert->set_start_time(certificate.start_time().seconds() * 1000);
cert->set_end_time(certificate.end_time().seconds() * 1000);
cert->set_encrypted_metadata_bytes(certificate.encrypted_metadata_bytes());
cert->set_metadata_encryption_key_tag(
certificate.metadata_encryption_key_tag());
}
std::vector<uint8_t> data(frame.ByteSize());
frame.SerializeToArray(data.data(), frame.ByteSize());
connection_->Write(std::move(data));
}
void PairedKeyVerificationRunner::SendPairedKeyEncryptionFrame() {
NearbySharePrivateCertificate private_certificate =
certificate_manager_->GetValidPrivateCertificate(Convert(visibility_));
sharing::nearby::Frame frame;
sharing::nearby::PairedKeyEncryptionFrame* encryption_frame =
frame.mutable_v1()->mutable_paired_key_encryption();
base::Optional<std::vector<uint8_t>> signature =
private_certificate.Sign(PadPrefix(local_prefix_, raw_token_));
if (signature) {
std::vector<uint8_t> certificate_id_hash;
if (certificate_)
certificate_id_hash = certificate_->HashAuthenticationToken(raw_token_);
if (certificate_id_hash.empty()) {
certificate_id_hash =
GenerateRandomBytes(kNearbyShareNumBytesAuthenticationTokenHash);
}
encryption_frame->set_signed_data(signature->data(), signature->size());
encryption_frame->set_secret_id_hash(certificate_id_hash.data(),
certificate_id_hash.size());
}
std::vector<uint8_t> data(frame.ByteSize());
frame.SerializeToArray(data.data(), frame.ByteSize());
connection_->Write(std::move(data));
}
PairedKeyVerificationRunner::PairedKeyVerificationResult
PairedKeyVerificationRunner::VerifyRemotePublicCertificate(
const sharing::mojom::V1FramePtr& frame) {
NearbySharePrivateCertificate private_certificate =
certificate_manager_->GetValidPrivateCertificate(Convert(visibility_));
if (private_certificate.HashAuthenticationToken(raw_token_) ==
frame->get_paired_key_encryption()->secret_id_hash) {
NS_LOG(VERBOSE) << __func__
<< ": Successfully verified remote public certificate.";
return PairedKeyVerificationResult::kSuccess;
}
NS_LOG(VERBOSE) << __func__
<< ": Unable to verify remote public certificate.";
return PairedKeyVerificationResult::kUnable;
}
PairedKeyVerificationRunner::PairedKeyVerificationResult
PairedKeyVerificationRunner::VerifyPairedKeyEncryptionFrame(
const sharing::mojom::V1FramePtr& frame) {
if (!certificate_) {
NS_LOG(VERBOSE) << __func__
<< ": Unable to verify remote paired key encryption frame. "
"Certificate not found.";
return PairedKeyVerificationResult::kUnable;
}
if (!certificate_->VerifySignature(
PadPrefix(remote_prefix_, raw_token_),
frame->get_paired_key_encryption()->signed_data)) {
return PairedKeyVerificationResult::kFail;
}
if (!share_target_.is_known) {
NS_LOG(VERBOSE) << __func__
<< ": Unable to verify remote paired key encryption frame. "
"Remote side is not a known share target.";
return PairedKeyVerificationResult::kUnable;
}
NS_LOG(VERBOSE)
<< __func__
<< ": Successfully verified remote paired key encryption frame.";
return PairedKeyVerificationResult::kSuccess;
}
PairedKeyVerificationRunner::PairedKeyVerificationResult
PairedKeyVerificationRunner::MergeResults(
const std::vector<PairedKeyVerificationResult>& results) {
bool all_success = true;
for (const auto& result : results) {
if (result == PairedKeyVerificationResult::kFail)
return result;
if (result != PairedKeyVerificationResult::kSuccess)
all_success = false;
}
return all_success ? PairedKeyVerificationResult::kSuccess
: PairedKeyVerificationResult::kUnable;
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_NEARBY_SHARING_PAIRED_KEY_VERIFICATION_RUNNER_H_
#define CHROME_BROWSER_NEARBY_SHARING_PAIRED_KEY_VERIFICATION_RUNNER_H_
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/time/time.h"
#include "chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager.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/nearby_connection.h"
#include "chrome/browser/nearby_sharing/share_target.h"
#include "chrome/browser/ui/webui/nearby_share/public/mojom/nearby_share_settings.mojom.h"
#include "chrome/services/sharing/public/mojom/nearby_decoder_types.mojom.h"
class PairedKeyVerificationRunner {
public:
enum class PairedKeyVerificationResult {
// Default value for verification result.
kUnknown,
// Succeeded with verification.
kSuccess,
// Failed to verify.
kFail,
// Unable to verify. Occurs when missing proper certificates.
kUnable,
};
PairedKeyVerificationRunner(
const ShareTarget& share_target,
const std::string& endpoint_id,
const std::vector<uint8_t>& token,
NearbyConnection* connection,
const base::Optional<NearbyShareDecryptedPublicCertificate>& certificate,
NearbyShareCertificateManager* certificate_manager,
nearby_share::mojom::Visibility visibility,
bool restrict_to_contacts,
IncomingFramesReader* frames_reader,
base::TimeDelta read_frame_timeout);
~PairedKeyVerificationRunner();
void Run(base::OnceCallback<void(PairedKeyVerificationResult)> callback);
private:
void SendPairedKeyEncryptionFrame();
void OnReadPairedKeyEncryptionFrame(
base::Optional<sharing::mojom::V1FramePtr> frame);
void OnReadPairedKeyResultFrame(
std::vector<PairedKeyVerificationResult> verification_results,
base::Optional<sharing::mojom::V1FramePtr> frame);
void SendPairedKeyResultFrame(PairedKeyVerificationResult result);
PairedKeyVerificationResult VerifyRemotePublicCertificate(
const sharing::mojom::V1FramePtr& frame);
PairedKeyVerificationResult VerifyPairedKeyEncryptionFrame(
const sharing::mojom::V1FramePtr& frame);
PairedKeyVerificationResult MergeResults(
const std::vector<PairedKeyVerificationResult>& results);
void SendCertificateInfo();
ShareTarget share_target_;
std::string endpoint_id_;
std::vector<uint8_t> raw_token_;
NearbyConnection* connection_;
base::Optional<NearbyShareDecryptedPublicCertificate> certificate_;
NearbyShareCertificateManager* certificate_manager_;
nearby_share::mojom::Visibility visibility_;
bool restrict_to_contacts_;
IncomingFramesReader* frames_reader_;
const base::TimeDelta read_frame_timeout_;
base::OnceCallback<void(PairedKeyVerificationResult)> callback_;
char local_prefix_;
char remote_prefix_;
base::WeakPtrFactory<PairedKeyVerificationRunner> weak_ptr_factory_{this};
};
#endif // CHROME_BROWSER_NEARBY_SHARING_PAIRED_KEY_VERIFICATION_RUNNER_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/nearby_sharing/paired_key_verification_runner.h"
#include <stdint.h>
#include <vector>
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/optional.h"
#include "base/run_loop.h"
#include "base/test/bind_test_util.h"
#include "base/time/time.h"
#include "chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager.h"
#include "chrome/browser/nearby_sharing/certificates/nearby_share_decrypted_public_certificate.h"
#include "chrome/browser/nearby_sharing/certificates/test_util.h"
#include "chrome/browser/nearby_sharing/fake_nearby_connection.h"
#include "chrome/browser/nearby_sharing/incoming_frames_reader.h"
#include "chrome/browser/nearby_sharing/mock_nearby_process_manager.h"
#include "chrome/browser/nearby_sharing/share_target.h"
#include "chrome/services/sharing/public/proto/wire_format.pb.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
const char kEndpointId[] = "test_endpoint_id";
const std::vector<uint8_t> kAuthToken = {0, 1, 2};
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};
const base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(1);
class MockIncomingFramesReader : public IncomingFramesReader {
public:
MockIncomingFramesReader(NearbyProcessManager* process_manager,
Profile* profile,
NearbyConnection* connection)
: IncomingFramesReader(process_manager, profile, connection) {}
MOCK_METHOD(void,
ReadFrame,
(base::OnceCallback<
void(base::Optional<sharing::mojom::V1FramePtr>)> callback),
(override));
MOCK_METHOD(
void,
ReadFrame,
(sharing::mojom::V1Frame::Tag frame_type,
base::OnceCallback<void(base::Optional<sharing::mojom::V1FramePtr>)>
callback,
base::TimeDelta timeout),
(override));
};
class MockNearbyShareCertificateManager : public NearbyShareCertificateManager {
public:
MOCK_METHOD(NearbySharePrivateCertificate,
GetValidPrivateCertificate,
(NearbyShareVisibility visibility),
(override));
MOCK_METHOD(void,
GetDecryptedPublicCertificate,
(base::span<const uint8_t> encrypted_metadata_key,
base::span<const uint8_t> salt,
CertDecryptedCallback callback),
(override));
MOCK_METHOD(void, DownloadPublicCertificates, (), (override));
protected:
MOCK_METHOD(void, OnStart, (), (override));
MOCK_METHOD(void, OnStop, (), (override));
};
PairedKeyVerificationRunner::PairedKeyVerificationResult Merge(
PairedKeyVerificationRunner::PairedKeyVerificationResult local_result,
sharing::mojom::PairedKeyResultFrame::Status remote_result) {
if (remote_result == sharing::mojom::PairedKeyResultFrame_Status::kFail ||
local_result ==
PairedKeyVerificationRunner::PairedKeyVerificationResult::kFail) {
return PairedKeyVerificationRunner::PairedKeyVerificationResult::kFail;
}
if (remote_result == sharing::mojom::PairedKeyResultFrame_Status::kSuccess &&
local_result ==
PairedKeyVerificationRunner::PairedKeyVerificationResult::kSuccess) {
return PairedKeyVerificationRunner::PairedKeyVerificationResult::kSuccess;
}
return PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnable;
}
} // namespace
class PairedKeyVerificationRunnerTest : public testing::Test {
public:
enum class ReturnFrameType {
// Return base::nullopt for the frame.
kNull,
// Return an empty frame.
kEmpty,
// Return a valid frame.
kValid,
};
PairedKeyVerificationRunnerTest()
: frames_reader_(&mock_nearby_process_manager_, &profile_, &connection_) {
}
void SetUp() override {
share_target.is_incoming = true;
EXPECT_CALL(certificate_manager_, GetValidPrivateCertificate(testing::_))
.WillRepeatedly(testing::Return(GetNearbyShareTestPrivateCertificate(
NearbyShareVisibility::kAllContacts)));
}
void SetUpPairedKeyEncryptionFrame(ReturnFrameType frame_type) {
EXPECT_CALL(
frames_reader_,
ReadFrame(
testing::Eq(sharing::mojom::V1Frame::Tag::PAIRED_KEY_ENCRYPTION),
testing::_, testing::Eq(kTimeout)))
.WillOnce(testing::WithArg<1>(testing::Invoke(
[frame_type](
base::OnceCallback<void(
base::Optional<sharing::mojom::V1FramePtr>)> callback) {
if (frame_type == ReturnFrameType::kNull) {
std::move(callback).Run(base::nullopt);
return;
}
sharing::mojom::V1FramePtr mojo_v1frame =
sharing::mojom::V1Frame::New();
if (frame_type == ReturnFrameType::kValid) {
mojo_v1frame->set_paired_key_encryption(
sharing::mojom::PairedKeyEncryptionFrame::New(
kIncomingConnectionSignedData,
kPrivateCertificateHashAuthToken));
} else {
mojo_v1frame->set_paired_key_encryption(
sharing::mojom::PairedKeyEncryptionFrame::New());
}
std::move(callback).Run(std::move(mojo_v1frame));
})));
}
void SetUpPairedKeyResultFrame(
ReturnFrameType frame_type,
sharing::mojom::PairedKeyResultFrame::Status status =
sharing::mojom::PairedKeyResultFrame_Status::kUnknown) {
EXPECT_CALL(
frames_reader_,
ReadFrame(testing::Eq(sharing::mojom::V1Frame::Tag::PAIRED_KEY_RESULT),
testing::_, testing::Eq(kTimeout)))
.WillOnce(testing::WithArg<1>(testing::Invoke(
[=](base::OnceCallback<void(
base::Optional<sharing::mojom::V1FramePtr>)> callback) {
if (frame_type == ReturnFrameType::kNull) {
std::move(callback).Run(base::nullopt);
return;
}
sharing::mojom::V1FramePtr mojo_v1frame =
sharing::mojom::V1Frame::New();
mojo_v1frame->set_paired_key_result(
sharing::mojom::PairedKeyResultFrame::New(status));
std::move(callback).Run(std::move(mojo_v1frame));
})));
}
sharing::nearby::Frame GetWrittenFrame() {
std::vector<uint8_t> data = connection_.GetWrittenData();
sharing::nearby::Frame frame;
frame.ParseFromArray(data.data(), data.size());
return frame;
}
void ExpectPairedKeyEncryptionFrameSent() {
sharing::nearby::Frame frame = GetWrittenFrame();
ASSERT_TRUE(frame.has_v1());
ASSERT_TRUE(frame.v1().has_paired_key_encryption());
}
void ExpectCertificateInfoSent() {
// TODO - Uncomment when crbug.com/1114765 is resolved.
// sharing::nearby::Frame frame = GetWrittenFrame();
// ASSERT_TRUE(frame.has_v1());
// ASSERT_TRUE(frame.v1().has_certificate_info());
}
void ExpectPairedKeyResultFrameSent(
sharing::nearby::PairedKeyResultFrame::Status status) {
sharing::nearby::Frame frame = GetWrittenFrame();
ASSERT_TRUE(frame.has_v1());
ASSERT_TRUE(frame.v1().has_paired_key_result());
EXPECT_EQ(status, frame.v1().paired_key_result().status());
}
protected:
content::BrowserTaskEnvironment task_environment_;
testing::NiceMock<MockNearbyProcessManager> mock_nearby_process_manager_;
TestingProfile profile_;
FakeNearbyConnection connection_;
testing::NiceMock<MockNearbyShareCertificateManager> certificate_manager_;
testing::NiceMock<MockIncomingFramesReader> frames_reader_;
ShareTarget share_target;
};
TEST_F(PairedKeyVerificationRunnerTest,
NullCertificate_InvalidPairedKeyEncryptionFrame_RestrictToContacts) {
PairedKeyVerificationRunner runner(
share_target, kEndpointId, kAuthToken, &connection_,
/*certificate=*/base::nullopt, &certificate_manager_,
nearby_share::mojom::Visibility::kAllContacts,
/*restrict_to_contacts=*/true, &frames_reader_, kTimeout);
// Empty key encryption frame fails the certificate verification.
SetUpPairedKeyEncryptionFrame(ReturnFrameType::kEmpty);
base::RunLoop run_loop;
runner.Run(base::BindLambdaForTesting(
[&](PairedKeyVerificationRunner::PairedKeyVerificationResult result) {
EXPECT_EQ(
PairedKeyVerificationRunner::PairedKeyVerificationResult::kFail,
result);
run_loop.Quit();
}));
run_loop.Run();
ExpectPairedKeyEncryptionFrameSent();
}
TEST_F(PairedKeyVerificationRunnerTest,
ValidPairedKeyEncryptionFrame_ResultFrameTimedOut) {
PairedKeyVerificationRunner runner(
share_target, kEndpointId, kAuthToken, &connection_,
NearbyShareDecryptedPublicCertificate::DecryptPublicCertificate(
GetNearbyShareTestPublicCertificate(),
GetNearbyShareTestEncryptedMetadataKey()),
&certificate_manager_, nearby_share::mojom::Visibility::kAllContacts,
/*restrict_to_contacts=*/false, &frames_reader_, kTimeout);
SetUpPairedKeyEncryptionFrame(ReturnFrameType::kValid);
// Null result frame fails the certificate verification process.
SetUpPairedKeyResultFrame(ReturnFrameType::kNull);
base::RunLoop run_loop;
runner.Run(base::BindLambdaForTesting(
[&](PairedKeyVerificationRunner::PairedKeyVerificationResult result) {
EXPECT_EQ(
PairedKeyVerificationRunner::PairedKeyVerificationResult::kFail,
result);
run_loop.Quit();
}));
run_loop.Run();
ExpectPairedKeyEncryptionFrameSent();
ExpectPairedKeyResultFrameSent(sharing::nearby::PairedKeyResultFrame::UNABLE);
}
struct TestParameters {
bool is_target_known;
bool is_valid_certificate;
PairedKeyVerificationRunnerTest::ReturnFrameType encryption_frame_type;
PairedKeyVerificationRunner::PairedKeyVerificationResult result;
} kParameters[] = {
{true, true, PairedKeyVerificationRunnerTest::ReturnFrameType::kValid,
PairedKeyVerificationRunner::PairedKeyVerificationResult::kSuccess},
{true, true, PairedKeyVerificationRunnerTest::ReturnFrameType::kEmpty,
PairedKeyVerificationRunner::PairedKeyVerificationResult::kFail},
{true, false, PairedKeyVerificationRunnerTest::ReturnFrameType::kValid,
PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnable},
{true, false, PairedKeyVerificationRunnerTest::ReturnFrameType::kEmpty,
PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnable},
{false, true, PairedKeyVerificationRunnerTest::ReturnFrameType::kValid,
PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnable},
};
using KeyVerificationTestParam =
std::tuple<TestParameters, sharing::mojom::PairedKeyResultFrame_Status>;
class ParameterisedPairedKeyVerificationRunnerTest
: public PairedKeyVerificationRunnerTest,
public testing::WithParamInterface<KeyVerificationTestParam> {};
TEST_P(ParameterisedPairedKeyVerificationRunnerTest,
ValidEncryptionFrame_ValidResultFrame) {
const TestParameters& params = std::get<0>(GetParam());
sharing::mojom::PairedKeyResultFrame::Status status = std::get<1>(GetParam());
PairedKeyVerificationRunner::PairedKeyVerificationResult expected_result =
Merge(params.result, status);
share_target.is_known = params.is_target_known;
base::Optional<NearbyShareDecryptedPublicCertificate> certificate;
if (params.is_valid_certificate) {
certificate =
NearbyShareDecryptedPublicCertificate::DecryptPublicCertificate(
GetNearbyShareTestPublicCertificate(),
GetNearbyShareTestEncryptedMetadataKey());
}
PairedKeyVerificationRunner runner(
share_target, kEndpointId, kAuthToken, &connection_,
std::move(certificate), &certificate_manager_,
nearby_share::mojom::Visibility::kAllContacts,
/*restricted_to_contacts=*/false, &frames_reader_, kTimeout);
SetUpPairedKeyEncryptionFrame(params.encryption_frame_type);
SetUpPairedKeyResultFrame(
PairedKeyVerificationRunnerTest::ReturnFrameType::kValid, status);
base::RunLoop run_loop;
runner.Run(base::BindLambdaForTesting(
[&](PairedKeyVerificationRunner::PairedKeyVerificationResult result) {
EXPECT_EQ(expected_result, result);
run_loop.Quit();
}));
run_loop.Run();
ExpectPairedKeyEncryptionFrameSent();
if (params.encryption_frame_type ==
PairedKeyVerificationRunnerTest::ReturnFrameType::kValid)
ExpectCertificateInfoSent();
// Check for result frame sent.
if (!params.is_valid_certificate) {
ExpectPairedKeyResultFrameSent(
sharing::nearby::PairedKeyResultFrame::UNABLE);
return;
}
if (params.encryption_frame_type ==
PairedKeyVerificationRunnerTest::ReturnFrameType::kEmpty) {
ExpectPairedKeyResultFrameSent(sharing::nearby::PairedKeyResultFrame::FAIL);
return;
}
if (params.is_target_known) {
ExpectPairedKeyResultFrameSent(
sharing::nearby::PairedKeyResultFrame::SUCCESS);
} else {
ExpectPairedKeyResultFrameSent(
sharing::nearby::PairedKeyResultFrame::UNABLE);
}
}
INSTANTIATE_TEST_SUITE_P(
/*no prefix*/,
ParameterisedPairedKeyVerificationRunnerTest,
testing::Combine(
testing::ValuesIn(kParameters),
testing::Values(sharing::mojom::PairedKeyResultFrame_Status::kUnknown,
sharing::mojom::PairedKeyResultFrame_Status::kSuccess,
sharing::mojom::PairedKeyResultFrame_Status::kFail,
sharing::mojom::PairedKeyResultFrame_Status::kUnable)));
......@@ -3725,7 +3725,6 @@ test("unit_tests") {
"../browser/nearby_sharing/nearby_process_manager_unittest.cc",
"../browser/nearby_sharing/nearby_share_settings_unittest.cc",
"../browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc",
"../browser/nearby_sharing/paired_key_verification_runner_unittest.cc",
"../browser/nearby_sharing/webrtc_signaling_messenger_unittest.cc",
"../browser/password_manager/generated_password_leak_detection_pref_unittest.cc",
"../browser/performance_manager/test_support/page_discarding_utils.cc",
......
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