Commit 34bca2e3 authored by Himanshu Jaju's avatar Himanshu Jaju Committed by Commit Bot

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: default avatarAlex Chau <alexchau@chromium.org>
Cr-Commit-Position: refs/heads/master@{#797868}
parent cf3f515a
......@@ -3393,6 +3393,8 @@ 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,9 +5,11 @@
#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"
......@@ -53,6 +55,13 @@ 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,6 +44,9 @@ 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,7 +20,6 @@
#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"
......@@ -37,13 +36,6 @@ 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(..).
void ReadFrame(
virtual 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(..).
void ReadFrame(
virtual 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,6 +3725,7 @@ 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