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") {
"//components/leveldb_proto",
"//components/prefs",
"//crypto",
"//device/bluetooth",
]
}
......@@ -59,6 +60,7 @@ source_set("test_support") {
"//components/leveldb_proto",
"//components/prefs",
"//crypto",
"//device/bluetooth/public/cpp",
]
}
......@@ -87,6 +89,8 @@ source_set("unit_tests") {
"//components/leveldb_proto:test_support",
"//components/prefs:test_support",
"//crypto",
"//device/bluetooth",
"//device/bluetooth:mocks",
"//testing/gtest",
]
}
......@@ -99,7 +99,7 @@ FakeNearbyShareCertificateStorage::NextPublicCertificateExpirationTime() const {
void FakeNearbyShareCertificateStorage::ReplacePrivateCertificates(
const std::vector<NearbySharePrivateCertificate>& private_certificates) {
replace_private_certificates_calls_.push_back(private_certificates);
private_certificates_ = private_certificates;
}
void FakeNearbyShareCertificateStorage::ReplacePublicCertificates(
......
......@@ -95,6 +95,31 @@ class FakeNearbyShareCertificateStorage : public NearbyShareCertificateStorage {
FakeNearbyShareCertificateStorage();
~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 SetPrivateCertificates(
base::Optional<std::vector<NearbySharePrivateCertificate>>
......@@ -106,11 +131,6 @@ class FakeNearbyShareCertificateStorage : public NearbyShareCertificateStorage {
return get_public_certificates_callbacks_;
}
std::vector<std::vector<NearbySharePrivateCertificate>>&
replace_private_certificates_calls() {
return replace_private_certificates_calls_;
}
std::vector<ReplacePublicCertificatesCall>&
replace_public_certificates_calls() {
return replace_public_certificates_calls_;
......@@ -134,31 +154,6 @@ class FakeNearbyShareCertificateStorage : public NearbyShareCertificateStorage {
}
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;
base::Optional<base::Time> next_private_certificate_expiration_time_;
base::Optional<base::Time> next_public_certificate_expiration_time_;
......@@ -166,8 +161,6 @@ class FakeNearbyShareCertificateStorage : public NearbyShareCertificateStorage {
base::Optional<std::vector<NearbySharePrivateCertificate>>
private_certificates_;
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<AddPublicCertificatesCall> add_public_certificates_calls_;
std::vector<RemoveExpiredPublicCertificatesCall>
......
......@@ -28,10 +28,9 @@ void NearbyShareCertificateManager::Stop() {
OnStop();
}
void NearbyShareCertificateManager::NotifyPublicCertificatesDownloaded(
bool new_certs_added) {
void NearbyShareCertificateManager::NotifyPublicCertificatesDownloaded() {
for (auto& observer : observers_)
observer.OnPublicCertificatesDownloaded(new_certs_added);
observer.OnPublicCertificatesDownloaded();
}
void NearbyShareCertificateManager::NotifyPrivateCertificatesChanged() {
......
......@@ -30,7 +30,7 @@ class NearbyShareCertificateManager {
public:
class Observer : public base::CheckedObserver {
public:
virtual void OnPublicCertificatesDownloaded(bool new_certs_added) = 0;
virtual void OnPublicCertificatesDownloaded() = 0;
virtual void OnPrivateCertificatesChanged() = 0;
};
......@@ -80,7 +80,7 @@ class NearbyShareCertificateManager {
virtual void OnStart() = 0;
virtual void OnStop() = 0;
void NotifyPublicCertificatesDownloaded(bool new_certs_added);
void NotifyPublicCertificatesDownloaded();
void NotifyPrivateCertificatesChanged();
private:
......
......@@ -10,6 +10,8 @@
#include "base/containers/span.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/time/clock.h"
#include "base/time/default_clock.h"
......@@ -27,6 +29,10 @@ class NearbyShareLocalDeviceDataManager;
class NearbyShareScheduler;
class PrefService;
namespace device {
class BluetoothAdapter;
} // namespace device
namespace leveldb_proto {
class ProtoDatabaseProvider;
} // namespace leveldb_proto
......@@ -37,7 +43,16 @@ class ListPublicCertificatesResponse;
} // namespace proto
} // 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 {
public:
class Factory {
......@@ -89,6 +104,20 @@ class NearbyShareCertificateManagerImpl : public NearbyShareCertificateManager {
void OnStart() 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(
base::Optional<std::string> page_token);
void OnRpcSuccess(
......@@ -103,9 +132,15 @@ class NearbyShareCertificateManagerImpl : public NearbyShareCertificateManager {
PrefService* pref_service_ = nullptr;
NearbyShareClientFactory* client_factory_ = 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<NearbyShareCertificateStorage> cert_store_;
std::unique_ptr<NearbyShareClient> client_;
base::WeakPtrFactory<NearbyShareCertificateManagerImpl> weak_ptr_factory_{
this};
};
#endif // CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_NEARBY_SHARE_CERTIFICATE_MANAGER_IMPL_H_
......@@ -248,7 +248,7 @@ std::vector<uint8_t> NearbySharePrivateCertificate::HashAuthenticationToken(
}
base::Optional<nearbyshare::proto::PublicCertificate>
NearbySharePrivateCertificate::ToPublicCertificate() {
NearbySharePrivateCertificate::ToPublicCertificate() const {
std::vector<uint8_t> public_key;
if (!key_pair_->ExportPublicKey(&public_key)) {
NS_LOG(ERROR) << "Failed to export public key.";
......@@ -423,7 +423,7 @@ NearbySharePrivateCertificate::GenerateUnusedSalt() {
}
base::Optional<std::vector<uint8_t>>
NearbySharePrivateCertificate::EncryptMetadata() {
NearbySharePrivateCertificate::EncryptMetadata() const {
// Init() keeps a reference to the input key, so that reference must outlive
// the lifetime of |aead|.
std::vector<uint8_t> derived_key = DeriveNearbyShareKey(
......
......@@ -96,7 +96,8 @@ class NearbySharePrivateCertificate {
// Converts this private certificate to a public certificate proto that can be
// shared with select contacts. Returns base::nullopt if the conversion was
// unsuccessful.
base::Optional<nearbyshare::proto::PublicCertificate> ToPublicCertificate();
base::Optional<nearbyshare::proto::PublicCertificate> ToPublicCertificate()
const;
// Converts this private certificate to a dictionary value for storage
// in Prefs.
......@@ -120,7 +121,7 @@ class NearbySharePrivateCertificate {
// Encrypts |unencrypted_metadata_| with the |metadata_encryption_key_|, using
// 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
// to this private certificate.
......
......@@ -10,6 +10,7 @@
#include "chrome/browser/nearby_sharing/certificates/constants.h"
#include "chrome/browser/nearby_sharing/certificates/nearby_share_visibility.h"
#include "chrome/browser/nearby_sharing/proto/timestamp.pb.h"
#include "device/bluetooth/public/cpp/bluetooth_address.h"
namespace {
......@@ -80,12 +81,11 @@ const uint8_t kTestEncryptedMetadataKey[] = {0x52, 0x0e, 0x7e, 0x6b, 0x8e,
const uint8_t kTestEncryptedMetadata[] = {
0x4d, 0x59, 0x5d, 0xb6, 0xac, 0x70, 0x00, 0x8f, 0x32, 0x9d, 0x0d, 0xcf,
0xc3, 0x8b, 0x01, 0x19, 0x1d, 0xad, 0x2e, 0xb4, 0x62, 0xec, 0xf3, 0xa5,
0xe4, 0x89, 0x51, 0x37, 0x0d, 0x78, 0xad, 0x9d, 0x2e, 0xe5, 0x99, 0xc6,
0xdb, 0x14, 0x65, 0x50, 0xf9, 0x25, 0xf3, 0x34, 0xec, 0xea, 0x55, 0xda,
0x3d, 0x97, 0x08, 0xf1, 0x0b, 0x67, 0x9b, 0x2b, 0x54,
0xe4, 0x89, 0x51, 0x37, 0x0d, 0x78, 0xad, 0x9d, 0x2e, 0xe5, 0x99, 0xd5,
0xf7, 0x1d, 0x71, 0x47, 0xef, 0x33,
// tag
0xbf, 0x2e, 0x98, 0x10, 0x4f, 0x0b, 0xde, 0x17, 0xd0, 0xf6, 0xcf, 0xfd,
0x43, 0xe5, 0x46, 0xc2};
0x63, 0x47, 0xae, 0xb0, 0xdf, 0x67, 0x07, 0x16, 0x70, 0x97, 0x3d, 0x8f,
0xc8, 0xe6, 0x61, 0xc0};
// Plaintext "sample" (from RFC 6979 A.2.5).
const uint8_t kTestPayloadToSign[] = {0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65};
......@@ -122,8 +122,11 @@ const int64_t kTestValidityOffsetMillis = 1800000; // 30 minutes
} // namespace
// Do not change. Values align with kTestEncryptedMetadata.
const char kTestDeviceName[] = "device_name";
const char kTestMetadataFullName[] = "full_name";
const char kTestMetadataIconUrl[] = "icon_url";
const char kTestUnparsedBluetoothMacAddress[] = "4E:65:61:72:62:79";
std::unique_ptr<crypto::ECPrivateKey> GetNearbyShareTestP256KeyPair() {
return crypto::ECPrivateKey::CreateFromPrivateKeyInfo(kTestPrivateKeyBytes);
......@@ -193,11 +196,14 @@ base::TimeDelta GetNearbyShareTestValidityOffset() {
const nearbyshare::proto::EncryptedMetadata& GetNearbyShareTestMetadata() {
static const base::NoDestructor<nearbyshare::proto::EncryptedMetadata>
metadata([] {
std::array<uint8_t, 6> bytes;
device::ParseBluetoothAddress(kTestUnparsedBluetoothMacAddress, bytes);
nearbyshare::proto::EncryptedMetadata metadata;
metadata.set_device_name("device_name");
metadata.set_device_name(kTestDeviceName);
metadata.set_full_name(kTestMetadataFullName);
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;
......
......@@ -20,6 +20,9 @@
extern const char kTestMetadataFullName[];
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();
const std::vector<uint8_t>& GetNearbyShareTestP256PublicKey();
......
......@@ -28,18 +28,24 @@ const char kNearbySharingFullNamePrefName[] = "nearby_sharing.full_name";
const char kNearbySharingIconUrlPrefName[] = "nearby_sharing.icon_url";
const char kNearbySharingOnboardingDismissedTimePrefName[] =
"nearby_sharing.onboarding_dismissed_time";
const char kNearbySharingPublicCertificateExpirationDictPrefName[] =
"nearbyshare.public_certificate_expiration_dict";
const char kNearbySharingPrivateCertificateListPrefName[] =
"nearbyshare.private_certificate_list";
const char kNearbySharingSchedulerContactDownloadPrefName[] =
"nearby_sharing.scheduler.contact_download";
const char kNearbySharingSchedulerContactUploadPrefName[] =
"nearby_sharing.scheduler.contact_upload";
const char kNearbySharingSchedulerDownloadDeviceDataPrefName[] =
"nearby_sharing.scheduler.download_device_data";
const char kNearbySharingPublicCertificateExpirationDictPrefName[] =
"nearbyshare.public_certificate_expiration_dict";
const char kNearbySharingPrivateCertificateListPrefName[] =
"nearbyshare.private_certificate_list";
const char kNearbySharingSchedulerDownloadPublicCertificatesPrefName[] =
"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
......@@ -65,12 +71,6 @@ void RegisterNearbySharingPrefs(PrefRegistrySimple* registry) {
/*default_value=*/std::string());
registry->RegisterStringPref(prefs::kNearbySharingIconUrlPrefName,
/*default_value=*/std::string());
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerContactDownloadPrefName);
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerContactUploadPrefName);
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerDownloadDeviceDataPrefName);
registry->RegisterTimePref(
prefs::kNearbySharingOnboardingDismissedTimePrefName,
/*default_value=*/base::Time());
......@@ -78,8 +78,20 @@ void RegisterNearbySharingPrefs(PrefRegistrySimple* registry) {
prefs::kNearbySharingPublicCertificateExpirationDictPrefName);
registry->RegisterListPref(
prefs::kNearbySharingPrivateCertificateListPrefName);
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerContactDownloadPrefName);
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerContactUploadPrefName);
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerDownloadDeviceDataPrefName);
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerDownloadPublicCertificatesPrefName);
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerPrivateCertificateExpirationPrefName);
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerUploadDeviceNamePrefName);
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerUploadLocalDeviceCertificatesPrefName);
}
void RegisterNearbySharingLocalPrefs(PrefRegistrySimple* local_state) {
......
......@@ -19,12 +19,16 @@ extern const char kNearbySharingEnabledPrefName[];
extern const char kNearbySharingFullNamePrefName[];
extern const char kNearbySharingIconUrlPrefName[];
extern const char kNearbySharingOnboardingDismissedTimePrefName[];
extern const char kNearbySharingPrivateCertificateListPrefName[];
extern const char kNearbySharingPublicCertificateExpirationDictPrefName[];
extern const char kNearbySharingSchedulerContactDownloadPrefName[];
extern const char kNearbySharingSchedulerContactUploadPrefName[];
extern const char kNearbySharingSchedulerDownloadDeviceDataPrefName[];
extern const char kNearbySharingPublicCertificateExpirationDictPrefName[];
extern const char kNearbySharingPrivateCertificateListPrefName[];
extern const char kNearbySharingSchedulerDownloadPublicCertificatesPrefName[];
extern const char kNearbySharingSchedulerPrivateCertificateExpirationPrefName[];
extern const char kNearbySharingSchedulerUploadDeviceNamePrefName[];
extern const char
kNearbySharingSchedulerUploadLocalDeviceCertificatesPrefName[];
} // 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