Commit 77353e9c authored by Josh Nohle's avatar Josh Nohle Committed by Commit Bot

[Nearby] Create, refresh, and upload local device certificates

Ensure that the local device has 3 valid private certificates for each
visibility mode. Perform this check when the expiration scheduler
informs the certificate manager that a private certificate has expired.
When private certificates change, notify observers and upload the local
device certificates (converted to public certificates) to the Nearby
Share server.

Bug: b/166112705
Change-Id: I367ed1df0ca3b4c5eb044795539f05ba24b5311f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2377506
Commit-Queue: Josh Nohle <nohle@chromium.org>
Reviewed-by: default avatarJames Vecore <vecore@google.com>
Cr-Commit-Position: refs/heads/master@{#802487}
parent f03bec0c
...@@ -37,6 +37,7 @@ source_set("certificates") { ...@@ -37,6 +37,7 @@ source_set("certificates") {
"//components/leveldb_proto", "//components/leveldb_proto",
"//components/prefs", "//components/prefs",
"//crypto", "//crypto",
"//device/bluetooth",
] ]
} }
...@@ -59,6 +60,7 @@ source_set("test_support") { ...@@ -59,6 +60,7 @@ source_set("test_support") {
"//components/leveldb_proto", "//components/leveldb_proto",
"//components/prefs", "//components/prefs",
"//crypto", "//crypto",
"//device/bluetooth/public/cpp",
] ]
} }
...@@ -87,6 +89,8 @@ source_set("unit_tests") { ...@@ -87,6 +89,8 @@ source_set("unit_tests") {
"//components/leveldb_proto:test_support", "//components/leveldb_proto:test_support",
"//components/prefs:test_support", "//components/prefs:test_support",
"//crypto", "//crypto",
"//device/bluetooth",
"//device/bluetooth:mocks",
"//testing/gtest", "//testing/gtest",
] ]
} }
...@@ -99,7 +99,7 @@ FakeNearbyShareCertificateStorage::NextPublicCertificateExpirationTime() const { ...@@ -99,7 +99,7 @@ FakeNearbyShareCertificateStorage::NextPublicCertificateExpirationTime() const {
void FakeNearbyShareCertificateStorage::ReplacePrivateCertificates( void FakeNearbyShareCertificateStorage::ReplacePrivateCertificates(
const std::vector<NearbySharePrivateCertificate>& private_certificates) { const std::vector<NearbySharePrivateCertificate>& private_certificates) {
replace_private_certificates_calls_.push_back(private_certificates); private_certificates_ = private_certificates;
} }
void FakeNearbyShareCertificateStorage::ReplacePublicCertificates( void FakeNearbyShareCertificateStorage::ReplacePublicCertificates(
......
...@@ -95,6 +95,31 @@ class FakeNearbyShareCertificateStorage : public NearbyShareCertificateStorage { ...@@ -95,6 +95,31 @@ class FakeNearbyShareCertificateStorage : public NearbyShareCertificateStorage {
FakeNearbyShareCertificateStorage(); FakeNearbyShareCertificateStorage();
~FakeNearbyShareCertificateStorage() override; ~FakeNearbyShareCertificateStorage() override;
// NearbyShareCertificateStorage:
std::vector<std::string> GetPublicCertificateIds() const override;
void GetPublicCertificates(PublicCertificateCallback callback) override;
base::Optional<std::vector<NearbySharePrivateCertificate>>
GetPrivateCertificates() const override;
base::Optional<base::Time> NextPrivateCertificateExpirationTime()
const override;
base::Optional<base::Time> NextPublicCertificateExpirationTime()
const override;
void ReplacePrivateCertificates(
const std::vector<NearbySharePrivateCertificate>& private_certificates)
override;
void ReplacePublicCertificates(
const std::vector<nearbyshare::proto::PublicCertificate>&
public_certificates,
ResultCallback callback) override;
void AddPublicCertificates(
const std::vector<nearbyshare::proto::PublicCertificate>&
public_certificates,
ResultCallback callback) override;
void RemoveExpiredPublicCertificates(base::Time now,
ResultCallback callback) override;
void ClearPrivateCertificates() override;
void ClearPublicCertificates(ResultCallback callback) override;
void SetPublicCertificateIds(const std::vector<std::string>& ids); void SetPublicCertificateIds(const std::vector<std::string>& ids);
void SetPrivateCertificates( void SetPrivateCertificates(
base::Optional<std::vector<NearbySharePrivateCertificate>> base::Optional<std::vector<NearbySharePrivateCertificate>>
...@@ -106,11 +131,6 @@ class FakeNearbyShareCertificateStorage : public NearbyShareCertificateStorage { ...@@ -106,11 +131,6 @@ class FakeNearbyShareCertificateStorage : public NearbyShareCertificateStorage {
return get_public_certificates_callbacks_; return get_public_certificates_callbacks_;
} }
std::vector<std::vector<NearbySharePrivateCertificate>>&
replace_private_certificates_calls() {
return replace_private_certificates_calls_;
}
std::vector<ReplacePublicCertificatesCall>& std::vector<ReplacePublicCertificatesCall>&
replace_public_certificates_calls() { replace_public_certificates_calls() {
return replace_public_certificates_calls_; return replace_public_certificates_calls_;
...@@ -134,31 +154,6 @@ class FakeNearbyShareCertificateStorage : public NearbyShareCertificateStorage { ...@@ -134,31 +154,6 @@ class FakeNearbyShareCertificateStorage : public NearbyShareCertificateStorage {
} }
private: private:
// NearbyShareCertificateStorage:
std::vector<std::string> GetPublicCertificateIds() const override;
void GetPublicCertificates(PublicCertificateCallback callback) override;
base::Optional<std::vector<NearbySharePrivateCertificate>>
GetPrivateCertificates() const override;
base::Optional<base::Time> NextPrivateCertificateExpirationTime()
const override;
base::Optional<base::Time> NextPublicCertificateExpirationTime()
const override;
void ReplacePrivateCertificates(
const std::vector<NearbySharePrivateCertificate>& private_certificates)
override;
void ReplacePublicCertificates(
const std::vector<nearbyshare::proto::PublicCertificate>&
public_certificates,
ResultCallback callback) override;
void AddPublicCertificates(
const std::vector<nearbyshare::proto::PublicCertificate>&
public_certificates,
ResultCallback callback) override;
void RemoveExpiredPublicCertificates(base::Time now,
ResultCallback callback) override;
void ClearPrivateCertificates() override;
void ClearPublicCertificates(ResultCallback callback) override;
size_t num_clear_private_certificates_calls_ = 0; size_t num_clear_private_certificates_calls_ = 0;
base::Optional<base::Time> next_private_certificate_expiration_time_; base::Optional<base::Time> next_private_certificate_expiration_time_;
base::Optional<base::Time> next_public_certificate_expiration_time_; base::Optional<base::Time> next_public_certificate_expiration_time_;
...@@ -166,8 +161,6 @@ class FakeNearbyShareCertificateStorage : public NearbyShareCertificateStorage { ...@@ -166,8 +161,6 @@ class FakeNearbyShareCertificateStorage : public NearbyShareCertificateStorage {
base::Optional<std::vector<NearbySharePrivateCertificate>> base::Optional<std::vector<NearbySharePrivateCertificate>>
private_certificates_; private_certificates_;
std::vector<PublicCertificateCallback> get_public_certificates_callbacks_; std::vector<PublicCertificateCallback> get_public_certificates_callbacks_;
std::vector<std::vector<NearbySharePrivateCertificate>>
replace_private_certificates_calls_;
std::vector<ReplacePublicCertificatesCall> replace_public_certificates_calls_; std::vector<ReplacePublicCertificatesCall> replace_public_certificates_calls_;
std::vector<AddPublicCertificatesCall> add_public_certificates_calls_; std::vector<AddPublicCertificatesCall> add_public_certificates_calls_;
std::vector<RemoveExpiredPublicCertificatesCall> std::vector<RemoveExpiredPublicCertificatesCall>
......
...@@ -28,10 +28,9 @@ void NearbyShareCertificateManager::Stop() { ...@@ -28,10 +28,9 @@ void NearbyShareCertificateManager::Stop() {
OnStop(); OnStop();
} }
void NearbyShareCertificateManager::NotifyPublicCertificatesDownloaded( void NearbyShareCertificateManager::NotifyPublicCertificatesDownloaded() {
bool new_certs_added) {
for (auto& observer : observers_) for (auto& observer : observers_)
observer.OnPublicCertificatesDownloaded(new_certs_added); observer.OnPublicCertificatesDownloaded();
} }
void NearbyShareCertificateManager::NotifyPrivateCertificatesChanged() { void NearbyShareCertificateManager::NotifyPrivateCertificatesChanged() {
......
...@@ -30,7 +30,7 @@ class NearbyShareCertificateManager { ...@@ -30,7 +30,7 @@ class NearbyShareCertificateManager {
public: public:
class Observer : public base::CheckedObserver { class Observer : public base::CheckedObserver {
public: public:
virtual void OnPublicCertificatesDownloaded(bool new_certs_added) = 0; virtual void OnPublicCertificatesDownloaded() = 0;
virtual void OnPrivateCertificatesChanged() = 0; virtual void OnPrivateCertificatesChanged() = 0;
}; };
...@@ -80,7 +80,7 @@ class NearbyShareCertificateManager { ...@@ -80,7 +80,7 @@ class NearbyShareCertificateManager {
virtual void OnStart() = 0; virtual void OnStart() = 0;
virtual void OnStop() = 0; virtual void OnStop() = 0;
void NotifyPublicCertificatesDownloaded(bool new_certs_added); void NotifyPublicCertificatesDownloaded();
void NotifyPrivateCertificatesChanged(); void NotifyPrivateCertificatesChanged();
private: private:
......
...@@ -4,8 +4,12 @@ ...@@ -4,8 +4,12 @@
#include "chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.h" #include "chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.h"
#include <array>
#include <string>
#include "base/bind.h" #include "base/bind.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/notreached.h" #include "base/notreached.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
...@@ -23,11 +27,18 @@ ...@@ -23,11 +27,18 @@
#include "chrome/browser/nearby_sharing/scheduling/nearby_share_scheduler_factory.h" #include "chrome/browser/nearby_sharing/scheduling/nearby_share_scheduler_factory.h"
#include "components/leveldb_proto/public/proto_database_provider.h" #include "components/leveldb_proto/public/proto_database_provider.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/public/cpp/bluetooth_address.h"
namespace { namespace {
const char kDeviceIdPrefix[] = "users/me/devices/"; const char kDeviceIdPrefix[] = "users/me/devices/";
constexpr std::array<NearbyShareVisibility, 2> kVisibilities = {
NearbyShareVisibility::kAllContacts,
NearbyShareVisibility::kSelectedContacts};
void TryDecryptPublicCertificates( void TryDecryptPublicCertificates(
const NearbyShareEncryptedMetadataKey& encrypted_metadata_key, const NearbyShareEncryptedMetadataKey& encrypted_metadata_key,
NearbyShareCertificateManager::CertDecryptedCallback callback, NearbyShareCertificateManager::CertDecryptedCallback callback,
...@@ -110,6 +121,31 @@ NearbyShareCertificateManagerImpl::NearbyShareCertificateManagerImpl( ...@@ -110,6 +121,31 @@ NearbyShareCertificateManagerImpl::NearbyShareCertificateManagerImpl(
pref_service_(pref_service), pref_service_(pref_service),
client_factory_(client_factory), client_factory_(client_factory),
clock_(clock), clock_(clock),
private_certificate_expiration_scheduler_(
NearbyShareSchedulerFactory::CreateExpirationScheduler(
base::BindRepeating(&NearbyShareCertificateManagerImpl::
NextPrivateCertificateExpirationTime,
base::Unretained(this)),
/*retry_failures=*/true,
/*require_connectivity=*/false,
prefs::
kNearbySharingSchedulerPrivateCertificateExpirationPrefName,
pref_service_,
base::BindRepeating(&NearbyShareCertificateManagerImpl::
OnPrivateCertificateExpiration,
base::Unretained(this)),
clock_)),
upload_local_device_certificates_scheduler_(
NearbyShareSchedulerFactory::CreateOnDemandScheduler(
/*retry_failures=*/true,
/*require_connectivity=*/true,
prefs::
kNearbySharingSchedulerUploadLocalDeviceCertificatesPrefName,
pref_service_,
base::BindRepeating(&NearbyShareCertificateManagerImpl::
OnLocalDeviceCertificateUploadRequest,
base::Unretained(this)),
clock_)),
download_public_certificates_scheduler_( download_public_certificates_scheduler_(
NearbyShareSchedulerFactory::CreatePeriodicScheduler( NearbyShareSchedulerFactory::CreatePeriodicScheduler(
kNearbySharePublicCertificateDownloadPeriod, kNearbySharePublicCertificateDownloadPeriod,
...@@ -126,16 +162,16 @@ NearbyShareCertificateManagerImpl::NearbyShareCertificateManagerImpl( ...@@ -126,16 +162,16 @@ NearbyShareCertificateManagerImpl::NearbyShareCertificateManagerImpl(
pref_service_, pref_service_,
proto_database_provider, proto_database_provider,
profile_path)) {} profile_path)) {}
NearbyShareCertificateManagerImpl::~NearbyShareCertificateManagerImpl() = NearbyShareCertificateManagerImpl::~NearbyShareCertificateManagerImpl() =
default; default;
NearbySharePrivateCertificate NearbySharePrivateCertificate
NearbyShareCertificateManagerImpl::GetValidPrivateCertificate( NearbyShareCertificateManagerImpl::GetValidPrivateCertificate(
NearbyShareVisibility visibility) { NearbyShareVisibility visibility) {
base::Optional<std::vector<NearbySharePrivateCertificate>> certs = std::vector<NearbySharePrivateCertificate> certs =
cert_store_->GetPrivateCertificates(); *cert_store_->GetPrivateCertificates();
DCHECK(certs); for (auto& cert : certs) {
for (auto& cert : *certs) {
if (IsNearbyShareCertificateWithinValidityPeriod( if (IsNearbyShareCertificateWithinValidityPeriod(
clock_->Now(), cert.not_before(), cert.not_after(), clock_->Now(), cert.not_before(), cert.not_after(),
/*use_public_certificate_tolerance=*/false) && /*use_public_certificate_tolerance=*/false) &&
...@@ -171,6 +207,159 @@ void NearbyShareCertificateManagerImpl::DownloadPublicCertificates() { ...@@ -171,6 +207,159 @@ void NearbyShareCertificateManagerImpl::DownloadPublicCertificates() {
download_public_certificates_scheduler_->MakeImmediateRequest(); download_public_certificates_scheduler_->MakeImmediateRequest();
} }
void NearbyShareCertificateManagerImpl::OnStart() {
private_certificate_expiration_scheduler_->Start();
upload_local_device_certificates_scheduler_->Start();
download_public_certificates_scheduler_->Start();
}
void NearbyShareCertificateManagerImpl::OnStop() {
private_certificate_expiration_scheduler_->Stop();
upload_local_device_certificates_scheduler_->Stop();
download_public_certificates_scheduler_->Stop();
}
base::Time
NearbyShareCertificateManagerImpl::NextPrivateCertificateExpirationTime() {
// If no private certificates are present, return the minimum time to trigger
// an immediate refresh.
return cert_store_->NextPrivateCertificateExpirationTime().value_or(
base::Time::Min());
}
void NearbyShareCertificateManagerImpl::OnPrivateCertificateExpiration() {
NS_LOG(VERBOSE)
<< __func__
<< ": Private certificate expiration detected; refreshing certificates.";
base::Time now = clock_->Now();
base::flat_map<NearbyShareVisibility, size_t> num_valid_certs;
base::flat_map<NearbyShareVisibility, base::Time> latest_not_after;
for (NearbyShareVisibility visibility : kVisibilities) {
num_valid_certs[visibility] = 0;
latest_not_after[visibility] = now;
}
// Remove all expired certificates.
std::vector<NearbySharePrivateCertificate> old_certs =
*cert_store_->GetPrivateCertificates();
std::vector<NearbySharePrivateCertificate> new_certs;
for (const NearbySharePrivateCertificate& cert : old_certs) {
if (IsNearbyShareCertificateExpired(
now, cert.not_after(),
/*use_public_certificate_tolerance=*/false)) {
continue;
}
++num_valid_certs[cert.visibility()];
latest_not_after[cert.visibility()] =
std::max(latest_not_after[cert.visibility()], cert.not_after());
new_certs.push_back(cert);
}
if (!old_certs.empty() && new_certs.size() == old_certs.size()) {
NS_LOG(VERBOSE) << __func__
<< ": All private certificates are still valid.";
private_certificate_expiration_scheduler_->HandleResult(/*success=*/true);
return;
}
device::BluetoothAdapterFactory::Get()->GetAdapter(base::BindOnce(
&NearbyShareCertificateManagerImpl::FinishPrivateCertificateRefresh,
weak_ptr_factory_.GetWeakPtr(), std::move(new_certs),
std::move(num_valid_certs), std::move(latest_not_after)));
}
void NearbyShareCertificateManagerImpl::FinishPrivateCertificateRefresh(
std::vector<NearbySharePrivateCertificate> new_certs,
base::flat_map<NearbyShareVisibility, size_t> num_valid_certs,
base::flat_map<NearbyShareVisibility, base::Time> latest_not_after,
scoped_refptr<device::BluetoothAdapter> bluetooth_adapter) {
nearbyshare::proto::EncryptedMetadata metadata;
base::Optional<std::string> device_name =
local_device_data_manager_->GetDeviceName();
if (!device_name) {
NS_LOG(WARNING)
<< __func__
<< ": Cannot create private certificates; missing device name.";
private_certificate_expiration_scheduler_->HandleResult(/*success=*/false);
return;
}
metadata.set_device_name(*device_name);
base::Optional<std::string> full_name =
local_device_data_manager_->GetFullName();
base::Optional<std::string> icon_url =
local_device_data_manager_->GetIconUrl();
if (full_name) {
metadata.set_full_name(*full_name);
}
if (icon_url) {
metadata.set_icon_url(*icon_url);
}
std::array<uint8_t, 6> bytes;
if (bluetooth_adapter &&
device::ParseBluetoothAddress(bluetooth_adapter->GetAddress(), bytes)) {
metadata.set_bluetooth_mac_address(std::string(bytes.begin(), bytes.end()));
} else {
NS_LOG(WARNING) << __func__
<< ": No valid Bluetooth MAC available during private "
<< "certificate creation.";
// TODO(https://crbug.com/1122641): Decide the best way to handle
// missing/invalid Bluetooth MAC addresses. Also, log a metric to track how
// often this happens.
}
NS_LOG(VERBOSE)
<< __func__ << ": Creating "
<< kNearbyShareNumPrivateCertificates -
num_valid_certs[NearbyShareVisibility::kAllContacts]
<< " all-contacts visibility and "
<< kNearbyShareNumPrivateCertificates -
num_valid_certs[NearbyShareVisibility::kSelectedContacts]
<< " selected-contacts visibility private certificates.";
// Add new certificates if necessary. Each visibility should have
// kNearbyShareNumPrivateCertificates.
for (NearbyShareVisibility visibility : kVisibilities) {
while (num_valid_certs[visibility] < kNearbyShareNumPrivateCertificates) {
new_certs.emplace_back(
visibility, /*not_before=*/latest_not_after[visibility], metadata);
++num_valid_certs[visibility];
latest_not_after[visibility] = new_certs.back().not_after();
}
}
cert_store_->ReplacePrivateCertificates(new_certs);
NotifyPrivateCertificatesChanged();
private_certificate_expiration_scheduler_->HandleResult(/*success=*/true);
upload_local_device_certificates_scheduler_->MakeImmediateRequest();
}
void NearbyShareCertificateManagerImpl::
OnLocalDeviceCertificateUploadRequest() {
std::vector<nearbyshare::proto::PublicCertificate> public_certs;
std::vector<NearbySharePrivateCertificate> private_certs =
*cert_store_->GetPrivateCertificates();
for (const NearbySharePrivateCertificate& private_cert : private_certs) {
public_certs.push_back(*private_cert.ToPublicCertificate());
}
NS_LOG(VERBOSE) << __func__ << ": Uploading local device certificates.";
local_device_data_manager_->UploadCertificates(
std::move(public_certs),
base::BindOnce(&NearbyShareCertificateManagerImpl::
OnLocalDeviceCertificateUploadFinished,
weak_ptr_factory_.GetWeakPtr()));
}
void NearbyShareCertificateManagerImpl::OnLocalDeviceCertificateUploadFinished(
bool success) {
NS_LOG(VERBOSE) << __func__ << ": Upload of local device certificates "
<< (success ? "succeeded" : "failed.");
upload_local_device_certificates_scheduler_->HandleResult(success);
}
void NearbyShareCertificateManagerImpl::OnDownloadPublicCertificatesRequest( void NearbyShareCertificateManagerImpl::OnDownloadPublicCertificatesRequest(
base::Optional<std::string> page_token) { base::Optional<std::string> page_token) {
DCHECK(!client_); DCHECK(!client_);
...@@ -242,6 +431,7 @@ void NearbyShareCertificateManagerImpl::FinishDownloadPublicCertificates( ...@@ -242,6 +431,7 @@ void NearbyShareCertificateManagerImpl::FinishDownloadPublicCertificates(
NS_LOG(VERBOSE) NS_LOG(VERBOSE)
<< __func__ << __func__
<< ": Public certificates successfully downloaded and stored."; << ": Public certificates successfully downloaded and stored.";
NotifyPublicCertificatesDownloaded();
} else if (http_result == NearbyShareHttpResult::kSuccess) { } else if (http_result == NearbyShareHttpResult::kSuccess) {
NS_LOG(ERROR) << __func__ << ": Public certificates not stored."; NS_LOG(ERROR) << __func__ << ": Public certificates not stored.";
} else { } else {
...@@ -252,11 +442,3 @@ void NearbyShareCertificateManagerImpl::FinishDownloadPublicCertificates( ...@@ -252,11 +442,3 @@ void NearbyShareCertificateManagerImpl::FinishDownloadPublicCertificates(
RecordResultMetrics(http_result); RecordResultMetrics(http_result);
download_public_certificates_scheduler_->HandleResult(success); download_public_certificates_scheduler_->HandleResult(success);
} }
void NearbyShareCertificateManagerImpl::OnStart() {
download_public_certificates_scheduler_->Start();
}
void NearbyShareCertificateManagerImpl::OnStop() {
download_public_certificates_scheduler_->Stop();
}
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include "base/containers/span.h" #include "base/containers/span.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/time/clock.h" #include "base/time/clock.h"
#include "base/time/default_clock.h" #include "base/time/default_clock.h"
...@@ -27,6 +29,10 @@ class NearbyShareLocalDeviceDataManager; ...@@ -27,6 +29,10 @@ class NearbyShareLocalDeviceDataManager;
class NearbyShareScheduler; class NearbyShareScheduler;
class PrefService; class PrefService;
namespace device {
class BluetoothAdapter;
} // namespace device
namespace leveldb_proto { namespace leveldb_proto {
class ProtoDatabaseProvider; class ProtoDatabaseProvider;
} // namespace leveldb_proto } // namespace leveldb_proto
...@@ -37,7 +43,16 @@ class ListPublicCertificatesResponse; ...@@ -37,7 +43,16 @@ class ListPublicCertificatesResponse;
} // namespace proto } // namespace proto
} // namespace nearbyshare } // namespace nearbyshare
// TODO(nohle): Add description after class is fully implemented. // An implementation of the NearbyShareCertificateManager that handles
// 1) creating, storing, and uploading local device certificates, as well as
// removing expired/revoked local device certificates;
// 2) downloading, storing, and decrypting public certificates from trusted
// contacts, as well as removing expired public certificates.
//
// TODO(https://crbug.com/1121443): Add the following if we remove
// GetValidPrivateCertificate() and perform all private certificate crypto
// operations internally: "This implementation also provides the high-level
// interface for performing cryptographic operations related to certificates."
class NearbyShareCertificateManagerImpl : public NearbyShareCertificateManager { class NearbyShareCertificateManagerImpl : public NearbyShareCertificateManager {
public: public:
class Factory { class Factory {
...@@ -89,6 +104,20 @@ class NearbyShareCertificateManagerImpl : public NearbyShareCertificateManager { ...@@ -89,6 +104,20 @@ class NearbyShareCertificateManagerImpl : public NearbyShareCertificateManager {
void OnStart() override; void OnStart() override;
void OnStop() override; void OnStop() override;
// Removes expired privates certificates, ensures that at least
// kNearbyShareNumPrivateCertificates are present for each visibility with
// contiguous validity periods, and uploads any changes to the Nearby Share
// server.
base::Time NextPrivateCertificateExpirationTime();
void OnPrivateCertificateExpiration();
void FinishPrivateCertificateRefresh(
std::vector<NearbySharePrivateCertificate> new_certs,
base::flat_map<NearbyShareVisibility, size_t> num_valid_certs,
base::flat_map<NearbyShareVisibility, base::Time> latest_not_after,
scoped_refptr<device::BluetoothAdapter> bluetooth_adapter);
void OnLocalDeviceCertificateUploadRequest();
void OnLocalDeviceCertificateUploadFinished(bool success);
void OnDownloadPublicCertificatesRequest( void OnDownloadPublicCertificatesRequest(
base::Optional<std::string> page_token); base::Optional<std::string> page_token);
void OnRpcSuccess( void OnRpcSuccess(
...@@ -103,9 +132,15 @@ class NearbyShareCertificateManagerImpl : public NearbyShareCertificateManager { ...@@ -103,9 +132,15 @@ class NearbyShareCertificateManagerImpl : public NearbyShareCertificateManager {
PrefService* pref_service_ = nullptr; PrefService* pref_service_ = nullptr;
NearbyShareClientFactory* client_factory_ = nullptr; NearbyShareClientFactory* client_factory_ = nullptr;
base::Clock* clock_ = nullptr; base::Clock* clock_ = nullptr;
std::unique_ptr<NearbyShareScheduler>
private_certificate_expiration_scheduler_;
std::unique_ptr<NearbyShareScheduler>
upload_local_device_certificates_scheduler_;
std::unique_ptr<NearbyShareScheduler> download_public_certificates_scheduler_; std::unique_ptr<NearbyShareScheduler> download_public_certificates_scheduler_;
std::unique_ptr<NearbyShareCertificateStorage> cert_store_; std::unique_ptr<NearbyShareCertificateStorage> cert_store_;
std::unique_ptr<NearbyShareClient> client_; std::unique_ptr<NearbyShareClient> client_;
base::WeakPtrFactory<NearbyShareCertificateManagerImpl> weak_ptr_factory_{
this};
}; };
#endif // CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_NEARBY_SHARE_CERTIFICATE_MANAGER_IMPL_H_ #endif // CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_NEARBY_SHARE_CERTIFICATE_MANAGER_IMPL_H_
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/time/time.h" #include "base/time/time.h"
#include "chrome/browser/nearby_sharing/certificates/constants.h" #include "chrome/browser/nearby_sharing/certificates/constants.h"
#include "chrome/browser/nearby_sharing/certificates/fake_nearby_share_certificate_storage.h" #include "chrome/browser/nearby_sharing/certificates/fake_nearby_share_certificate_storage.h"
#include "chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager.h"
#include "chrome/browser/nearby_sharing/certificates/test_util.h" #include "chrome/browser/nearby_sharing/certificates/test_util.h"
#include "chrome/browser/nearby_sharing/client/fake_nearby_share_client.h" #include "chrome/browser/nearby_sharing/client/fake_nearby_share_client.h"
#include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h" #include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h"
...@@ -15,6 +16,8 @@ ...@@ -15,6 +16,8 @@
#include "chrome/browser/nearby_sharing/scheduling/fake_nearby_share_scheduler_factory.h" #include "chrome/browser/nearby_sharing/scheduling/fake_nearby_share_scheduler_factory.h"
#include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h" #include "components/prefs/testing_pref_service.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace { namespace {
...@@ -37,11 +40,14 @@ void CaptureDecryptedPublicCertificateCallback( ...@@ -37,11 +40,14 @@ void CaptureDecryptedPublicCertificateCallback(
} // namespace } // namespace
class NearbyShareCertificateManagerImplTest : public ::testing::Test { class NearbyShareCertificateManagerImplTest
: public ::testing::Test,
public NearbyShareCertificateManager::Observer {
public: public:
NearbyShareCertificateManagerImplTest() { NearbyShareCertificateManagerImplTest() {
local_device_data_manager_ = local_device_data_manager_ =
std::make_unique<FakeNearbyShareLocalDeviceDataManager>(); std::make_unique<FakeNearbyShareLocalDeviceDataManager>();
local_device_data_manager_->SetId(kDeviceId);
pref_service_ = std::make_unique<TestingPrefServiceSimple>(); pref_service_ = std::make_unique<TestingPrefServiceSimple>();
pref_service_->registry()->RegisterDictionaryPref( pref_service_->registry()->RegisterDictionaryPref(
...@@ -55,8 +61,21 @@ class NearbyShareCertificateManagerImplTest : public ::testing::Test { ...@@ -55,8 +61,21 @@ class NearbyShareCertificateManagerImplTest : public ::testing::Test {
local_device_data_manager_.get(), pref_service_.get(), local_device_data_manager_.get(), pref_service_.get(),
/*proto_database_provider=*/nullptr, base::FilePath(), &client_factory_, /*proto_database_provider=*/nullptr, base::FilePath(), &client_factory_,
&clock_); &clock_);
cert_man_->AddObserver(this);
scheduler_ = private_cert_exp_scheduler_ =
scheduler_factory_.pref_name_to_expiration_instance()
.find(
prefs::
kNearbySharingSchedulerPrivateCertificateExpirationPrefName)
->second.fake_scheduler;
upload_scheduler_ =
scheduler_factory_.pref_name_to_on_demand_instance()
.find(
prefs::
kNearbySharingSchedulerUploadLocalDeviceCertificatesPrefName)
->second.fake_scheduler;
download_scheduler_ =
scheduler_factory_.pref_name_to_periodic_instance() scheduler_factory_.pref_name_to_periodic_instance()
.find(prefs:: .find(prefs::
kNearbySharingSchedulerDownloadPublicCertificatesPrefName) kNearbySharingSchedulerDownloadPublicCertificatesPrefName)
...@@ -65,15 +84,35 @@ class NearbyShareCertificateManagerImplTest : public ::testing::Test { ...@@ -65,15 +84,35 @@ class NearbyShareCertificateManagerImplTest : public ::testing::Test {
PopulatePrivateCertificates(); PopulatePrivateCertificates();
PopulatePublicCertificates(); PopulatePublicCertificates();
mock_adapter_ =
base::MakeRefCounted<testing::NiceMock<device::MockBluetoothAdapter>>();
ON_CALL(*mock_adapter_, GetAddress()).WillByDefault([this] {
return bluetooth_mac_address_;
});
device::BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter_);
} }
~NearbyShareCertificateManagerImplTest() override = default; ~NearbyShareCertificateManagerImplTest() override = default;
void TearDown() override { void TearDown() override {
cert_man_->RemoveObserver(this);
NearbyShareSchedulerFactory::SetFactoryForTesting(nullptr); NearbyShareSchedulerFactory::SetFactoryForTesting(nullptr);
NearbyShareCertificateStorageImpl::Factory::SetFactoryForTesting(nullptr); NearbyShareCertificateStorageImpl::Factory::SetFactoryForTesting(nullptr);
} }
void SetBluetoothMacAddress(const std::string& bluetooth_mac_address) {
bluetooth_mac_address_ = bluetooth_mac_address;
}
// NearbyShareCertificateManager::Observer:
void OnPublicCertificatesDownloaded() override {
++num_public_certs_downloaded_notifications_;
}
void OnPrivateCertificatesChanged() override {
++num_private_certs_changed_notifications_;
}
protected: protected:
void GetPublicCertificatesCallback( void GetPublicCertificatesCallback(
bool success, bool success,
...@@ -87,22 +126,110 @@ class NearbyShareCertificateManagerImplTest : public ::testing::Test { ...@@ -87,22 +126,110 @@ class NearbyShareCertificateManagerImplTest : public ::testing::Test {
std::move(callback).Run(success, std::move(pub_certs)); std::move(callback).Run(success, std::move(pub_certs));
} }
void HandlePrivateCertificateRefresh(bool expect_private_cert_refresh,
bool expected_success) {
if (expect_private_cert_refresh)
private_cert_exp_scheduler_->InvokeRequestCallback();
EXPECT_EQ(expect_private_cert_refresh ? 1u : 0u,
private_cert_exp_scheduler_->handled_results().size());
if (expect_private_cert_refresh) {
EXPECT_EQ(expected_success,
private_cert_exp_scheduler_->handled_results().back());
}
EXPECT_EQ(expect_private_cert_refresh && expected_success ? 1u : 0u,
num_private_certs_changed_notifications_);
EXPECT_EQ(expect_private_cert_refresh && expected_success ? 1u : 0u,
upload_scheduler_->num_immediate_requests());
}
void VerifyPrivateCertificates(
const nearbyshare::proto::EncryptedMetadata& expected_metadata) {
// Expect a full set of certificates for both all-contacts and
// selected-contacts
std::vector<NearbySharePrivateCertificate> certs =
*cert_store_->GetPrivateCertificates();
EXPECT_EQ(2 * kNearbyShareNumPrivateCertificates, certs.size());
base::Time min_not_before_all_contacts = base::Time::Max();
base::Time min_not_before_selected_contacts = base::Time::Max();
base::Time max_not_after_all_contacts = base::Time::Min();
base::Time max_not_after_selected_contacts = base::Time::Min();
for (const auto& cert : certs) {
EXPECT_EQ(cert.not_after() - cert.not_before(),
kNearbyShareCertificateValidityPeriod);
switch (cert.visibility()) {
case NearbyShareVisibility::kAllContacts:
min_not_before_all_contacts =
std::min(min_not_before_all_contacts, cert.not_before());
max_not_after_all_contacts =
std::max(max_not_after_all_contacts, cert.not_after());
break;
case NearbyShareVisibility::kSelectedContacts:
min_not_before_selected_contacts =
std::min(min_not_before_selected_contacts, cert.not_before());
max_not_after_selected_contacts =
std::max(max_not_after_selected_contacts, cert.not_after());
break;
default:
NOTREACHED();
break;
}
// Verify metadata.
EXPECT_EQ(expected_metadata.SerializeAsString(),
cert.unencrypted_metadata().SerializeAsString());
}
// Verify contiguous validity periods
EXPECT_EQ(kNearbyShareNumPrivateCertificates *
kNearbyShareCertificateValidityPeriod,
max_not_after_all_contacts - min_not_before_all_contacts);
EXPECT_EQ(
kNearbyShareNumPrivateCertificates *
kNearbyShareCertificateValidityPeriod,
max_not_after_selected_contacts - min_not_before_selected_contacts);
}
void RunUpload(bool success) {
size_t initial_num_upload_calls =
local_device_data_manager_->upload_certificates_calls().size();
upload_scheduler_->InvokeRequestCallback();
EXPECT_EQ(initial_num_upload_calls + 1,
local_device_data_manager_->upload_certificates_calls().size());
EXPECT_EQ(2 * kNearbyShareNumPrivateCertificates,
local_device_data_manager_->upload_certificates_calls()
.back()
.certificates.size());
size_t initial_num_handled_results =
upload_scheduler_->handled_results().size();
std::move(
local_device_data_manager_->upload_certificates_calls().back().callback)
.Run(success);
EXPECT_EQ(initial_num_handled_results + 1,
upload_scheduler_->handled_results().size());
EXPECT_EQ(success, upload_scheduler_->handled_results().back());
}
// Test downloading public certificates with or without errors. The RPC is // Test downloading public certificates with or without errors. The RPC is
// paginated, and |num_pages| will be simulated. If |rpc_fail| is not nullopt // paginated, and |num_pages| will be simulated. If |rpc_fail| is not
// or store_fail is true, then those respective failures will be simulated on // nullopt or store_fail is true, then those respective failures will be
// the last page. // simulated on the last page.
void DownloadPublicCertificatesFlow( void DownloadPublicCertificatesFlow(
size_t num_pages, size_t num_pages,
base::Optional<NearbyShareHttpError> rpc_fail, base::Optional<NearbyShareHttpError> rpc_fail,
bool store_fail) { bool store_fail) {
size_t prev_num_results = scheduler_->handled_results().size(); size_t prev_num_results = download_scheduler_->handled_results().size();
cert_store_->SetPublicCertificateIds(kPublicCertificateIds); cert_store_->SetPublicCertificateIds(kPublicCertificateIds);
local_device_data_manager_->SetId(kDeviceId);
cert_man_->Start(); cert_man_->Start();
scheduler_->InvokeRequestCallback(); download_scheduler_->InvokeRequestCallback();
cert_man_->Stop(); cert_man_->Stop();
size_t initial_num_notifications =
num_public_certs_downloaded_notifications_;
std::string page_token; std::string page_token;
for (size_t page_number = 0; page_number < num_pages; ++page_number) { for (size_t page_number = 0; page_number < num_pages; ++page_number) {
bool last_page = page_number == num_pages - 1; bool last_page = page_number == num_pages - 1;
...@@ -125,11 +252,16 @@ class NearbyShareCertificateManagerImplTest : public ::testing::Test { ...@@ -125,11 +252,16 @@ class NearbyShareCertificateManagerImplTest : public ::testing::Test {
auto& add_cert_call = cert_store_->add_public_certificates_calls().back(); auto& add_cert_call = cert_store_->add_public_certificates_calls().back();
CheckStorageAddCertificates(add_cert_call); CheckStorageAddCertificates(add_cert_call);
std::move(add_cert_call.callback) std::move(add_cert_call.callback)
.Run(/*success=*/!(last_page && store_fail)); .Run(/*success=*/!(last_page && store_fail));
} }
ASSERT_EQ(scheduler_->handled_results().size(), prev_num_results + 1); ASSERT_EQ(download_scheduler_->handled_results().size(),
EXPECT_EQ(scheduler_->handled_results().back(), !rpc_fail && !store_fail); prev_num_results + 1);
bool success = !rpc_fail && !store_fail;
EXPECT_EQ(download_scheduler_->handled_results().back(), success);
EXPECT_EQ(initial_num_notifications + (success ? 1u : 0u),
num_public_certs_downloaded_notifications_);
} }
void CheckRpcRequest( void CheckRpcRequest(
...@@ -172,7 +304,7 @@ class NearbyShareCertificateManagerImplTest : public ::testing::Test { ...@@ -172,7 +304,7 @@ class NearbyShareCertificateManagerImplTest : public ::testing::Test {
void PopulatePrivateCertificates() { void PopulatePrivateCertificates() {
private_certificates_.clear(); private_certificates_.clear();
auto& metadata = GetNearbyShareTestMetadata(); const auto& metadata = GetNearbyShareTestMetadata();
for (auto visibility : {NearbyShareVisibility::kAllContacts, for (auto visibility : {NearbyShareVisibility::kAllContacts,
NearbyShareVisibility::kSelectedContacts}) { NearbyShareVisibility::kSelectedContacts}) {
private_certificates_.emplace_back(visibility, t0, metadata); private_certificates_.emplace_back(visibility, t0, metadata);
...@@ -201,7 +333,13 @@ class NearbyShareCertificateManagerImplTest : public ::testing::Test { ...@@ -201,7 +333,13 @@ class NearbyShareCertificateManagerImplTest : public ::testing::Test {
} }
FakeNearbyShareCertificateStorage* cert_store_; FakeNearbyShareCertificateStorage* cert_store_;
FakeNearbyShareScheduler* scheduler_; FakeNearbyShareScheduler* private_cert_exp_scheduler_;
FakeNearbyShareScheduler* upload_scheduler_;
FakeNearbyShareScheduler* download_scheduler_;
std::string bluetooth_mac_address_ = kTestUnparsedBluetoothMacAddress;
scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>> mock_adapter_;
size_t num_public_certs_downloaded_notifications_ = 0;
size_t num_private_certs_changed_notifications_ = 0;
std::vector<NearbySharePrivateCertificate> private_certificates_; std::vector<NearbySharePrivateCertificate> private_certificates_;
std::vector<nearbyshare::proto::PublicCertificate> public_certificates_; std::vector<nearbyshare::proto::PublicCertificate> public_certificates_;
std::vector<NearbyShareEncryptedMetadataKey> metadata_encryption_keys_; std::vector<NearbyShareEncryptedMetadataKey> metadata_encryption_keys_;
...@@ -277,9 +415,10 @@ TEST_F(NearbyShareCertificateManagerImplTest, ...@@ -277,9 +415,10 @@ TEST_F(NearbyShareCertificateManagerImplTest,
TEST_F(NearbyShareCertificateManagerImplTest, TEST_F(NearbyShareCertificateManagerImplTest,
DownloadPublicCertificatesImmediateRequest) { DownloadPublicCertificatesImmediateRequest) {
size_t prev_num_requests = scheduler_->num_immediate_requests(); size_t prev_num_requests = download_scheduler_->num_immediate_requests();
cert_man_->DownloadPublicCertificates(); cert_man_->DownloadPublicCertificates();
EXPECT_EQ(scheduler_->num_immediate_requests(), prev_num_requests + 1); EXPECT_EQ(download_scheduler_->num_immediate_requests(),
prev_num_requests + 1);
} }
TEST_F(NearbyShareCertificateManagerImplTest, TEST_F(NearbyShareCertificateManagerImplTest,
...@@ -300,3 +439,156 @@ TEST_F(NearbyShareCertificateManagerImplTest, ...@@ -300,3 +439,156 @@ TEST_F(NearbyShareCertificateManagerImplTest,
DownloadPublicCertificatesFlow(/*num_pages=*/2, /*rpc_fail=*/base::nullopt, DownloadPublicCertificatesFlow(/*num_pages=*/2, /*rpc_fail=*/base::nullopt,
/*store_fail=*/true); /*store_fail=*/true);
} }
TEST_F(NearbyShareCertificateManagerImplTest,
RefreshPrivateCertificates_ValidCertificates) {
clock_.SetNow(t0);
cert_store_->SetPrivateCertificates(private_certificates_);
local_device_data_manager_->SetDeviceName(
GetNearbyShareTestMetadata().device_name());
local_device_data_manager_->SetFullName(
GetNearbyShareTestMetadata().full_name());
local_device_data_manager_->SetIconUrl(
GetNearbyShareTestMetadata().icon_url());
SetBluetoothMacAddress(kTestUnparsedBluetoothMacAddress);
cert_man_->Start();
HandlePrivateCertificateRefresh(/*expect_private_cert_refresh=*/false,
/*expected_success=*/true);
VerifyPrivateCertificates(/*expected_metadata=*/GetNearbyShareTestMetadata());
}
TEST_F(NearbyShareCertificateManagerImplTest,
RefreshPrivateCertificates_NoCertificates_UploadSuccess) {
clock_.SetNow(t0);
cert_store_->SetPrivateCertificates(
std::vector<NearbySharePrivateCertificate>());
local_device_data_manager_->SetDeviceName(
GetNearbyShareTestMetadata().device_name());
local_device_data_manager_->SetFullName(
GetNearbyShareTestMetadata().full_name());
local_device_data_manager_->SetIconUrl(
GetNearbyShareTestMetadata().icon_url());
SetBluetoothMacAddress(kTestUnparsedBluetoothMacAddress);
cert_man_->Start();
HandlePrivateCertificateRefresh(/*expect_private_cert_refresh=*/true,
/*expected_success=*/true);
RunUpload(/*success=*/true);
VerifyPrivateCertificates(/*expected_metadata=*/GetNearbyShareTestMetadata());
}
TEST_F(NearbyShareCertificateManagerImplTest,
RefreshPrivateCertificates_NoCertificates_UploadFailure) {
clock_.SetNow(t0);
cert_store_->SetPrivateCertificates(
std::vector<NearbySharePrivateCertificate>());
local_device_data_manager_->SetDeviceName(
GetNearbyShareTestMetadata().device_name());
local_device_data_manager_->SetFullName(
GetNearbyShareTestMetadata().full_name());
local_device_data_manager_->SetIconUrl(
GetNearbyShareTestMetadata().icon_url());
SetBluetoothMacAddress(kTestUnparsedBluetoothMacAddress);
cert_man_->Start();
HandlePrivateCertificateRefresh(/*expect_private_cert_refresh=*/true,
/*expected_success=*/true);
RunUpload(/*success=*/false);
VerifyPrivateCertificates(/*expected_metadata=*/GetNearbyShareTestMetadata());
}
TEST_F(NearbyShareCertificateManagerImplTest,
RefreshPrivateCertificates_ExpiredCertificate) {
// First certificates are expired;
clock_.SetNow(t0 + kNearbyShareCertificateValidityPeriod * 1.5);
cert_store_->SetPrivateCertificates(private_certificates_);
local_device_data_manager_->SetDeviceName(
GetNearbyShareTestMetadata().device_name());
local_device_data_manager_->SetFullName(
GetNearbyShareTestMetadata().full_name());
local_device_data_manager_->SetIconUrl(
GetNearbyShareTestMetadata().icon_url());
SetBluetoothMacAddress(kTestUnparsedBluetoothMacAddress);
cert_man_->Start();
HandlePrivateCertificateRefresh(/*expect_private_cert_refresh=*/true,
/*expected_success=*/true);
RunUpload(/*success=*/true);
VerifyPrivateCertificates(/*expected_metadata=*/GetNearbyShareTestMetadata());
}
TEST_F(NearbyShareCertificateManagerImplTest,
RefreshPrivateCertificates_InvalidDeviceName) {
clock_.SetNow(t0);
cert_store_->SetPrivateCertificates(
std::vector<NearbySharePrivateCertificate>());
// Device name is missing in local device data manager.
local_device_data_manager_->SetFullName(
GetNearbyShareTestMetadata().full_name());
local_device_data_manager_->SetIconUrl(
GetNearbyShareTestMetadata().icon_url());
SetBluetoothMacAddress(kTestUnparsedBluetoothMacAddress);
cert_man_->Start();
// Expect failure because a device name is required.
HandlePrivateCertificateRefresh(/*expect_private_cert_refresh=*/true,
/*expected_success=*/false);
}
TEST_F(NearbyShareCertificateManagerImplTest,
RefreshPrivateCertificates_InvalidBluetoothMacAddress) {
clock_.SetNow(t0);
cert_store_->SetPrivateCertificates(
std::vector<NearbySharePrivateCertificate>());
// The bluetooth adapter returns an invalid Bluetooth MAC address.
local_device_data_manager_->SetDeviceName(
GetNearbyShareTestMetadata().device_name());
local_device_data_manager_->SetFullName(
GetNearbyShareTestMetadata().full_name());
local_device_data_manager_->SetIconUrl(
GetNearbyShareTestMetadata().icon_url());
SetBluetoothMacAddress("invalid_mac_address");
cert_man_->Start();
HandlePrivateCertificateRefresh(/*expect_private_cert_refresh=*/true,
/*expected_success=*/true);
RunUpload(/*success=*/true);
// The MAC address is not set.
nearbyshare::proto::EncryptedMetadata metadata = GetNearbyShareTestMetadata();
metadata.clear_bluetooth_mac_address();
VerifyPrivateCertificates(/*expected_metadata=*/metadata);
}
TEST_F(NearbyShareCertificateManagerImplTest,
RefreshPrivateCertificates_MissingFullNameAndIconUrl) {
clock_.SetNow(t0);
cert_store_->SetPrivateCertificates(
std::vector<NearbySharePrivateCertificate>());
// Full name and icon URL are missing in local device data manager.
local_device_data_manager_->SetDeviceName(
GetNearbyShareTestMetadata().device_name());
SetBluetoothMacAddress(kTestUnparsedBluetoothMacAddress);
cert_man_->Start();
HandlePrivateCertificateRefresh(/*expect_private_cert_refresh=*/true,
/*expected_success=*/true);
RunUpload(/*success=*/true);
// The full name and icon URL are not set.
nearbyshare::proto::EncryptedMetadata metadata = GetNearbyShareTestMetadata();
metadata.clear_full_name();
metadata.clear_icon_url();
VerifyPrivateCertificates(/*expected_metadata=*/metadata);
}
...@@ -248,7 +248,7 @@ std::vector<uint8_t> NearbySharePrivateCertificate::HashAuthenticationToken( ...@@ -248,7 +248,7 @@ std::vector<uint8_t> NearbySharePrivateCertificate::HashAuthenticationToken(
} }
base::Optional<nearbyshare::proto::PublicCertificate> base::Optional<nearbyshare::proto::PublicCertificate>
NearbySharePrivateCertificate::ToPublicCertificate() { NearbySharePrivateCertificate::ToPublicCertificate() const {
std::vector<uint8_t> public_key; std::vector<uint8_t> public_key;
if (!key_pair_->ExportPublicKey(&public_key)) { if (!key_pair_->ExportPublicKey(&public_key)) {
NS_LOG(ERROR) << "Failed to export public key."; NS_LOG(ERROR) << "Failed to export public key.";
...@@ -423,7 +423,7 @@ NearbySharePrivateCertificate::GenerateUnusedSalt() { ...@@ -423,7 +423,7 @@ NearbySharePrivateCertificate::GenerateUnusedSalt() {
} }
base::Optional<std::vector<uint8_t>> base::Optional<std::vector<uint8_t>>
NearbySharePrivateCertificate::EncryptMetadata() { NearbySharePrivateCertificate::EncryptMetadata() const {
// Init() keeps a reference to the input key, so that reference must outlive // Init() keeps a reference to the input key, so that reference must outlive
// the lifetime of |aead|. // the lifetime of |aead|.
std::vector<uint8_t> derived_key = DeriveNearbyShareKey( std::vector<uint8_t> derived_key = DeriveNearbyShareKey(
......
...@@ -96,7 +96,8 @@ class NearbySharePrivateCertificate { ...@@ -96,7 +96,8 @@ class NearbySharePrivateCertificate {
// Converts this private certificate to a public certificate proto that can be // Converts this private certificate to a public certificate proto that can be
// shared with select contacts. Returns base::nullopt if the conversion was // shared with select contacts. Returns base::nullopt if the conversion was
// unsuccessful. // unsuccessful.
base::Optional<nearbyshare::proto::PublicCertificate> ToPublicCertificate(); base::Optional<nearbyshare::proto::PublicCertificate> ToPublicCertificate()
const;
// Converts this private certificate to a dictionary value for storage // Converts this private certificate to a dictionary value for storage
// in Prefs. // in Prefs.
...@@ -120,7 +121,7 @@ class NearbySharePrivateCertificate { ...@@ -120,7 +121,7 @@ class NearbySharePrivateCertificate {
// Encrypts |unencrypted_metadata_| with the |metadata_encryption_key_|, using // Encrypts |unencrypted_metadata_| with the |metadata_encryption_key_|, using
// the |secret_key_| as salt. // the |secret_key_| as salt.
base::Optional<std::vector<uint8_t>> EncryptMetadata(); base::Optional<std::vector<uint8_t>> EncryptMetadata() const;
// Specifies which contacts can receive the public certificate corresponding // Specifies which contacts can receive the public certificate corresponding
// to this private certificate. // to this private certificate.
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "chrome/browser/nearby_sharing/certificates/constants.h" #include "chrome/browser/nearby_sharing/certificates/constants.h"
#include "chrome/browser/nearby_sharing/certificates/nearby_share_visibility.h" #include "chrome/browser/nearby_sharing/certificates/nearby_share_visibility.h"
#include "chrome/browser/nearby_sharing/proto/timestamp.pb.h" #include "chrome/browser/nearby_sharing/proto/timestamp.pb.h"
#include "device/bluetooth/public/cpp/bluetooth_address.h"
namespace { namespace {
...@@ -80,12 +81,11 @@ const uint8_t kTestEncryptedMetadataKey[] = {0x52, 0x0e, 0x7e, 0x6b, 0x8e, ...@@ -80,12 +81,11 @@ const uint8_t kTestEncryptedMetadataKey[] = {0x52, 0x0e, 0x7e, 0x6b, 0x8e,
const uint8_t kTestEncryptedMetadata[] = { const uint8_t kTestEncryptedMetadata[] = {
0x4d, 0x59, 0x5d, 0xb6, 0xac, 0x70, 0x00, 0x8f, 0x32, 0x9d, 0x0d, 0xcf, 0x4d, 0x59, 0x5d, 0xb6, 0xac, 0x70, 0x00, 0x8f, 0x32, 0x9d, 0x0d, 0xcf,
0xc3, 0x8b, 0x01, 0x19, 0x1d, 0xad, 0x2e, 0xb4, 0x62, 0xec, 0xf3, 0xa5, 0xc3, 0x8b, 0x01, 0x19, 0x1d, 0xad, 0x2e, 0xb4, 0x62, 0xec, 0xf3, 0xa5,
0xe4, 0x89, 0x51, 0x37, 0x0d, 0x78, 0xad, 0x9d, 0x2e, 0xe5, 0x99, 0xc6, 0xe4, 0x89, 0x51, 0x37, 0x0d, 0x78, 0xad, 0x9d, 0x2e, 0xe5, 0x99, 0xd5,
0xdb, 0x14, 0x65, 0x50, 0xf9, 0x25, 0xf3, 0x34, 0xec, 0xea, 0x55, 0xda, 0xf7, 0x1d, 0x71, 0x47, 0xef, 0x33,
0x3d, 0x97, 0x08, 0xf1, 0x0b, 0x67, 0x9b, 0x2b, 0x54,
// tag // tag
0xbf, 0x2e, 0x98, 0x10, 0x4f, 0x0b, 0xde, 0x17, 0xd0, 0xf6, 0xcf, 0xfd, 0x63, 0x47, 0xae, 0xb0, 0xdf, 0x67, 0x07, 0x16, 0x70, 0x97, 0x3d, 0x8f,
0x43, 0xe5, 0x46, 0xc2}; 0xc8, 0xe6, 0x61, 0xc0};
// Plaintext "sample" (from RFC 6979 A.2.5). // Plaintext "sample" (from RFC 6979 A.2.5).
const uint8_t kTestPayloadToSign[] = {0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65}; const uint8_t kTestPayloadToSign[] = {0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65};
...@@ -122,8 +122,11 @@ const int64_t kTestValidityOffsetMillis = 1800000; // 30 minutes ...@@ -122,8 +122,11 @@ const int64_t kTestValidityOffsetMillis = 1800000; // 30 minutes
} // namespace } // namespace
// Do not change. Values align with kTestEncryptedMetadata.
const char kTestDeviceName[] = "device_name";
const char kTestMetadataFullName[] = "full_name"; const char kTestMetadataFullName[] = "full_name";
const char kTestMetadataIconUrl[] = "icon_url"; const char kTestMetadataIconUrl[] = "icon_url";
const char kTestUnparsedBluetoothMacAddress[] = "4E:65:61:72:62:79";
std::unique_ptr<crypto::ECPrivateKey> GetNearbyShareTestP256KeyPair() { std::unique_ptr<crypto::ECPrivateKey> GetNearbyShareTestP256KeyPair() {
return crypto::ECPrivateKey::CreateFromPrivateKeyInfo(kTestPrivateKeyBytes); return crypto::ECPrivateKey::CreateFromPrivateKeyInfo(kTestPrivateKeyBytes);
...@@ -193,11 +196,14 @@ base::TimeDelta GetNearbyShareTestValidityOffset() { ...@@ -193,11 +196,14 @@ base::TimeDelta GetNearbyShareTestValidityOffset() {
const nearbyshare::proto::EncryptedMetadata& GetNearbyShareTestMetadata() { const nearbyshare::proto::EncryptedMetadata& GetNearbyShareTestMetadata() {
static const base::NoDestructor<nearbyshare::proto::EncryptedMetadata> static const base::NoDestructor<nearbyshare::proto::EncryptedMetadata>
metadata([] { metadata([] {
std::array<uint8_t, 6> bytes;
device::ParseBluetoothAddress(kTestUnparsedBluetoothMacAddress, bytes);
nearbyshare::proto::EncryptedMetadata metadata; nearbyshare::proto::EncryptedMetadata metadata;
metadata.set_device_name("device_name"); metadata.set_device_name(kTestDeviceName);
metadata.set_full_name(kTestMetadataFullName); metadata.set_full_name(kTestMetadataFullName);
metadata.set_icon_url(kTestMetadataIconUrl); metadata.set_icon_url(kTestMetadataIconUrl);
metadata.set_bluetooth_mac_address("bluetooth_mac_address"); metadata.set_bluetooth_mac_address(bytes.data(), 6u);
return metadata; return metadata;
}()); }());
return *metadata; return *metadata;
......
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
extern const char kTestMetadataFullName[]; extern const char kTestMetadataFullName[];
extern const char kTestMetadataIconUrl[]; extern const char kTestMetadataIconUrl[];
// Test Bluetooth MAC address in the format "XX:XX:XX:XX:XX:XX".
extern const char kTestUnparsedBluetoothMacAddress[];
std::unique_ptr<crypto::ECPrivateKey> GetNearbyShareTestP256KeyPair(); std::unique_ptr<crypto::ECPrivateKey> GetNearbyShareTestP256KeyPair();
const std::vector<uint8_t>& GetNearbyShareTestP256PublicKey(); const std::vector<uint8_t>& GetNearbyShareTestP256PublicKey();
......
...@@ -28,18 +28,24 @@ const char kNearbySharingFullNamePrefName[] = "nearby_sharing.full_name"; ...@@ -28,18 +28,24 @@ const char kNearbySharingFullNamePrefName[] = "nearby_sharing.full_name";
const char kNearbySharingIconUrlPrefName[] = "nearby_sharing.icon_url"; const char kNearbySharingIconUrlPrefName[] = "nearby_sharing.icon_url";
const char kNearbySharingOnboardingDismissedTimePrefName[] = const char kNearbySharingOnboardingDismissedTimePrefName[] =
"nearby_sharing.onboarding_dismissed_time"; "nearby_sharing.onboarding_dismissed_time";
const char kNearbySharingPublicCertificateExpirationDictPrefName[] =
"nearbyshare.public_certificate_expiration_dict";
const char kNearbySharingPrivateCertificateListPrefName[] =
"nearbyshare.private_certificate_list";
const char kNearbySharingSchedulerContactDownloadPrefName[] = const char kNearbySharingSchedulerContactDownloadPrefName[] =
"nearby_sharing.scheduler.contact_download"; "nearby_sharing.scheduler.contact_download";
const char kNearbySharingSchedulerContactUploadPrefName[] = const char kNearbySharingSchedulerContactUploadPrefName[] =
"nearby_sharing.scheduler.contact_upload"; "nearby_sharing.scheduler.contact_upload";
const char kNearbySharingSchedulerDownloadDeviceDataPrefName[] = const char kNearbySharingSchedulerDownloadDeviceDataPrefName[] =
"nearby_sharing.scheduler.download_device_data"; "nearby_sharing.scheduler.download_device_data";
const char kNearbySharingPublicCertificateExpirationDictPrefName[] =
"nearbyshare.public_certificate_expiration_dict";
const char kNearbySharingPrivateCertificateListPrefName[] =
"nearbyshare.private_certificate_list";
const char kNearbySharingSchedulerDownloadPublicCertificatesPrefName[] = const char kNearbySharingSchedulerDownloadPublicCertificatesPrefName[] =
"nearby_sharing.scheduler.download_public_certificates"; "nearby_sharing.scheduler.download_public_certificates";
const char kNearbySharingSchedulerPrivateCertificateExpirationPrefName[] =
"nearby_sharing.scheduler.private_certificate_expiration";
const char kNearbySharingSchedulerUploadDeviceNamePrefName[] =
"nearby_sharing.scheduler.upload_device_name";
const char kNearbySharingSchedulerUploadLocalDeviceCertificatesPrefName[] =
"nearby_sharing.scheduler.upload_local_device_certificates";
} // namespace prefs } // namespace prefs
...@@ -65,12 +71,6 @@ void RegisterNearbySharingPrefs(PrefRegistrySimple* registry) { ...@@ -65,12 +71,6 @@ void RegisterNearbySharingPrefs(PrefRegistrySimple* registry) {
/*default_value=*/std::string()); /*default_value=*/std::string());
registry->RegisterStringPref(prefs::kNearbySharingIconUrlPrefName, registry->RegisterStringPref(prefs::kNearbySharingIconUrlPrefName,
/*default_value=*/std::string()); /*default_value=*/std::string());
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerContactDownloadPrefName);
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerContactUploadPrefName);
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerDownloadDeviceDataPrefName);
registry->RegisterTimePref( registry->RegisterTimePref(
prefs::kNearbySharingOnboardingDismissedTimePrefName, prefs::kNearbySharingOnboardingDismissedTimePrefName,
/*default_value=*/base::Time()); /*default_value=*/base::Time());
...@@ -78,8 +78,20 @@ void RegisterNearbySharingPrefs(PrefRegistrySimple* registry) { ...@@ -78,8 +78,20 @@ void RegisterNearbySharingPrefs(PrefRegistrySimple* registry) {
prefs::kNearbySharingPublicCertificateExpirationDictPrefName); prefs::kNearbySharingPublicCertificateExpirationDictPrefName);
registry->RegisterListPref( registry->RegisterListPref(
prefs::kNearbySharingPrivateCertificateListPrefName); prefs::kNearbySharingPrivateCertificateListPrefName);
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerContactDownloadPrefName);
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerContactUploadPrefName);
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerDownloadDeviceDataPrefName);
registry->RegisterDictionaryPref( registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerDownloadPublicCertificatesPrefName); prefs::kNearbySharingSchedulerDownloadPublicCertificatesPrefName);
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerPrivateCertificateExpirationPrefName);
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerUploadDeviceNamePrefName);
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerUploadLocalDeviceCertificatesPrefName);
} }
void RegisterNearbySharingLocalPrefs(PrefRegistrySimple* local_state) { void RegisterNearbySharingLocalPrefs(PrefRegistrySimple* local_state) {
......
...@@ -19,12 +19,16 @@ extern const char kNearbySharingEnabledPrefName[]; ...@@ -19,12 +19,16 @@ extern const char kNearbySharingEnabledPrefName[];
extern const char kNearbySharingFullNamePrefName[]; extern const char kNearbySharingFullNamePrefName[];
extern const char kNearbySharingIconUrlPrefName[]; extern const char kNearbySharingIconUrlPrefName[];
extern const char kNearbySharingOnboardingDismissedTimePrefName[]; extern const char kNearbySharingOnboardingDismissedTimePrefName[];
extern const char kNearbySharingPrivateCertificateListPrefName[];
extern const char kNearbySharingPublicCertificateExpirationDictPrefName[];
extern const char kNearbySharingSchedulerContactDownloadPrefName[]; extern const char kNearbySharingSchedulerContactDownloadPrefName[];
extern const char kNearbySharingSchedulerContactUploadPrefName[]; extern const char kNearbySharingSchedulerContactUploadPrefName[];
extern const char kNearbySharingSchedulerDownloadDeviceDataPrefName[]; extern const char kNearbySharingSchedulerDownloadDeviceDataPrefName[];
extern const char kNearbySharingPublicCertificateExpirationDictPrefName[];
extern const char kNearbySharingPrivateCertificateListPrefName[];
extern const char kNearbySharingSchedulerDownloadPublicCertificatesPrefName[]; extern const char kNearbySharingSchedulerDownloadPublicCertificatesPrefName[];
extern const char kNearbySharingSchedulerPrivateCertificateExpirationPrefName[];
extern const char kNearbySharingSchedulerUploadDeviceNamePrefName[];
extern const char
kNearbySharingSchedulerUploadLocalDeviceCertificatesPrefName[];
} // namespace prefs } // namespace prefs
......
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