[Fast Pair] Connect Fast Pair Data Encryptor to pairing process.
Adds Fast Pair Data Encryptor to the Fast Pair Gatt Service Client through the Fast Pair Pairer. Change-Id: I5648f1c034751155fad72fc390e6577e8695ff7f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3094716 Commit-Queue: Juliet Levesque <julietlevesque@google.com> Reviewed-by: Shane Fitzpatrick <shanefitz@google.com> Cr-Commit-Position: refs/heads/master@{#912709}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
8136871bf0
commit
2a8c8e5f24
ash/quick_pair
common
pairing
BUILD.gn
fast_pair
fake_fast_pair_gatt_service_client.ccfake_fast_pair_gatt_service_client.hfast_pair_data_encryptor.hfast_pair_data_encryptor_impl.ccfast_pair_data_encryptor_impl.hfast_pair_gatt_service_client.hfast_pair_gatt_service_client_impl.ccfast_pair_gatt_service_client_impl.hfast_pair_gatt_service_client_unittest.ccfast_pair_pairer.ccfast_pair_pairer.hfast_pair_pairer_unittest.cc
@ -18,6 +18,9 @@ std::ostream& operator<<(std::ostream& stream, PairFailure failure) {
|
||||
case PairFailure::kGattServiceDiscoveryTimeout:
|
||||
stream << "[Timed out while starting discovery of GATT service]";
|
||||
break;
|
||||
case PairFailure::kDataEncryptorRetrieval:
|
||||
stream << "[Failed to retrieve the data encryptor]";
|
||||
break;
|
||||
case PairFailure::kKeyBasedPairingCharacteristicDiscovery:
|
||||
stream << "[Failed to find the Key-based pairing GATT characteristic]";
|
||||
break;
|
||||
|
@ -18,41 +18,43 @@ enum class PairFailure {
|
||||
kGattServiceDiscovery = 1,
|
||||
// Timed out while starting discovery of GATT service.
|
||||
kGattServiceDiscoveryTimeout = 2,
|
||||
// Failed to retrieve the data encryptor.
|
||||
kDataEncryptorRetrieval = 3,
|
||||
// Failed to find the Key-based pairing GATT characteristic.
|
||||
kKeyBasedPairingCharacteristicDiscovery = 3,
|
||||
kKeyBasedPairingCharacteristicDiscovery = 4,
|
||||
// Failed to find the Passkey GATT characteristic.
|
||||
kPasskeyCharacteristicDiscovery = 4,
|
||||
kPasskeyCharacteristicDiscovery = 5,
|
||||
// Failed to find the Account Key GATT characteristic.
|
||||
kAccountKeyCharacteristicDiscovery = 5,
|
||||
kAccountKeyCharacteristicDiscovery = 6,
|
||||
// Failed to start a notify session on the Key-based pairing GATT
|
||||
// characteristic.
|
||||
kKeyBasedPairingCharacteristicNotifySession = 6,
|
||||
kKeyBasedPairingCharacteristicNotifySession = 7,
|
||||
// Failed to start a notify session on the Passkey GATT characteristic.
|
||||
kPasskeyCharacteristicNotifySession = 7,
|
||||
kPasskeyCharacteristicNotifySession = 8,
|
||||
// Timed out while waiting to start a notify session on the Key-based pairing
|
||||
// GATT characteristic.
|
||||
kKeyBasedPairingCharacteristicNotifySessionTimeout = 8,
|
||||
kKeyBasedPairingCharacteristicNotifySessionTimeout = 9,
|
||||
// / Timed out while waiting to start a notify session on the Passkey GATT
|
||||
// characteristic.
|
||||
kPasskeyCharacteristicNotifySessionTimeout = 9,
|
||||
kPasskeyCharacteristicNotifySessionTimeout = 10,
|
||||
// Failed to write to the Key-based pairing GATT characteristic.
|
||||
kKeyBasedPairingCharacteristicWrite = 10,
|
||||
kKeyBasedPairingCharacteristicWrite = 11,
|
||||
// Failed to write to the Passkey GATT characteristic.
|
||||
kPasskeyPairingCharacteristicWrite = 11,
|
||||
kPasskeyPairingCharacteristicWrite = 12,
|
||||
// Timed out while waiting for the Key-based Pairing response.
|
||||
kKeyBasedPairingResponseTimeout = 12,
|
||||
kKeyBasedPairingResponseTimeout = 13,
|
||||
// Timed out while waiting for the Passkey response.
|
||||
kPasskeyResponseTimeout = 13,
|
||||
kPasskeyResponseTimeout = 14,
|
||||
// Incorrect Key-based response message type.
|
||||
kIncorrectKeyBasedPairingResponseType = 14,
|
||||
kIncorrectKeyBasedPairingResponseType = 15,
|
||||
// Incorrect Passkey response message type.
|
||||
kIncorrectPasskeyResponseType = 15,
|
||||
kIncorrectPasskeyResponseType = 16,
|
||||
// Passkeys did not match.
|
||||
kPasskeyMismatch = 16,
|
||||
kPasskeyMismatch = 17,
|
||||
// Failed to bond to discovered device.
|
||||
kPairingConnect = 17,
|
||||
kPairingConnect = 18,
|
||||
// Failed to bond to device via public address.
|
||||
kAddressConnect = 18,
|
||||
kAddressConnect = 19,
|
||||
};
|
||||
|
||||
COMPONENT_EXPORT(QUICK_PAIR_COMMON)
|
||||
|
@ -11,8 +11,9 @@ source_set("pairing") {
|
||||
sources = [
|
||||
"fast_pair/fake_fast_pair_gatt_service_client.cc",
|
||||
"fast_pair/fake_fast_pair_gatt_service_client.h",
|
||||
"fast_pair/fast_pair_data_encryptor.cc",
|
||||
"fast_pair/fast_pair_data_encryptor.h",
|
||||
"fast_pair/fast_pair_data_encryptor_impl.cc",
|
||||
"fast_pair/fast_pair_data_encryptor_impl.h",
|
||||
"fast_pair/fast_pair_encryption.cc",
|
||||
"fast_pair/fast_pair_encryption.h",
|
||||
"fast_pair/fast_pair_gatt_service_client.h",
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "ash/quick_pair/pairing/fast_pair/fake_fast_pair_gatt_service_client.h"
|
||||
#include "ash/quick_pair/common/logging.h"
|
||||
#include "ash/quick_pair/pairing/fast_pair/fast_pair_data_encryptor.h"
|
||||
#include "base/callback_helpers.h"
|
||||
#include "device/bluetooth/bluetooth_adapter.h"
|
||||
#include "device/bluetooth/bluetooth_device.h"
|
||||
@ -35,6 +36,7 @@ void FakeFastPairGattServiceClient::WriteRequestAsync(
|
||||
uint8_t flags,
|
||||
const std::string& provider_address,
|
||||
const std::string& seekers_address,
|
||||
FastPairDataEncryptor* fast_pair_data_encryptor,
|
||||
base::OnceCallback<void(std::vector<uint8_t>, absl::optional<PairFailure>)>
|
||||
write_response_callback) {
|
||||
key_based_write_response_callback_ = std::move(write_response_callback);
|
||||
|
@ -20,6 +20,8 @@ class BluetoothDevice;
|
||||
namespace ash {
|
||||
namespace quick_pair {
|
||||
|
||||
class FastPairDataEncryptor;
|
||||
|
||||
// This class fakes FastPairGattServiceClient and permits setting which
|
||||
// PairFailure, if any, is run with the callback.
|
||||
class FakeFastPairGattServiceClient : public FastPairGattServiceClient {
|
||||
@ -37,6 +39,7 @@ class FakeFastPairGattServiceClient : public FastPairGattServiceClient {
|
||||
uint8_t flags,
|
||||
const std::string& provider_address,
|
||||
const std::string& seekers_address,
|
||||
FastPairDataEncryptor* fast_pair_data_encryptor,
|
||||
base::OnceCallback<void(std::vector<uint8_t>,
|
||||
absl::optional<PairFailure>)>
|
||||
write_response_callback) override;
|
||||
|
@ -10,13 +10,6 @@
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "ash/quick_pair/common/device.h"
|
||||
#include "ash/quick_pair/pairing/fast_pair/fast_pair_key_pair.h"
|
||||
#include "ash/quick_pair/repository/fast_pair/device_metadata.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kBlockSizeBytes = 16;
|
||||
@ -25,47 +18,18 @@ constexpr int kBlockSizeBytes = 16;
|
||||
|
||||
namespace ash {
|
||||
namespace quick_pair {
|
||||
namespace fast_pair_encryption {
|
||||
|
||||
// Holds a secret key for a device and has methods to encrypt bytes, decrypt
|
||||
// response and decrypt passkey.
|
||||
class FastPairDataEncryptor {
|
||||
public:
|
||||
class Factory {
|
||||
public:
|
||||
static void CreateAsync(
|
||||
scoped_refptr<Device> device,
|
||||
base::OnceCallback<void(std::unique_ptr<FastPairDataEncryptor>)>
|
||||
on_get_instance_callback);
|
||||
// Encrypts bytes with the stored secret key.
|
||||
virtual const std::array<uint8_t, kBlockSizeBytes> EncryptBytes(
|
||||
const std::array<uint8_t, kBlockSizeBytes>& bytes_to_encrypt) = 0;
|
||||
|
||||
private:
|
||||
static void DeviceMetadataRetrieved(
|
||||
scoped_refptr<Device> device,
|
||||
base::OnceCallback<void(std::unique_ptr<FastPairDataEncryptor>)>
|
||||
on_get_instance_callback,
|
||||
DeviceMetadata* device_metadata);
|
||||
};
|
||||
|
||||
const std::array<uint8_t, kBlockSizeBytes> EncryptBytes(
|
||||
const std::array<uint8_t, kBlockSizeBytes>& bytes_to_encrypt);
|
||||
|
||||
~FastPairDataEncryptor();
|
||||
|
||||
protected:
|
||||
FastPairDataEncryptor(const KeyPair& key_pair);
|
||||
FastPairDataEncryptor(const FastPairDataEncryptor&) = delete;
|
||||
FastPairDataEncryptor& operator=(const FastPairDataEncryptor&) = delete;
|
||||
|
||||
private:
|
||||
std::array<uint8_t, kPrivateKeyByteSize> secret_key_;
|
||||
|
||||
// The public key is only required during initial pairing and optional during
|
||||
// communication with paired devices.
|
||||
absl::optional<std::array<uint8_t, kPublicKeyByteSize>> public_key_ =
|
||||
absl::nullopt;
|
||||
virtual ~FastPairDataEncryptor() = default;
|
||||
};
|
||||
|
||||
} // namespace fast_pair_encryption
|
||||
} // namespace quick_pair
|
||||
} // namespace ash
|
||||
|
||||
|
@ -2,32 +2,54 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "ash/quick_pair/pairing/fast_pair/fast_pair_data_encryptor.h"
|
||||
#include "ash/quick_pair/pairing/fast_pair/fast_pair_data_encryptor_impl.h"
|
||||
|
||||
#include "ash/quick_pair/common/logging.h"
|
||||
#include "ash/quick_pair/pairing/fast_pair/fast_pair_encryption.h"
|
||||
#include "ash/quick_pair/proto/fastpair.pb.h"
|
||||
#include "ash/quick_pair/repository/fast_pair/device_metadata.h"
|
||||
#include "ash/quick_pair/repository/fast_pair_repository.h"
|
||||
#include "base/base64.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
|
||||
namespace ash {
|
||||
namespace quick_pair {
|
||||
namespace fast_pair_encryption {
|
||||
|
||||
namespace {
|
||||
|
||||
// static
|
||||
void FastPairDataEncryptor::Factory::CreateAsync(
|
||||
FastPairDataEncryptorImpl::Factory* g_test_factory_ = nullptr;
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
void FastPairDataEncryptorImpl::Factory::SetFactoryForTesting(
|
||||
Factory* g_test_factory) {
|
||||
g_test_factory_ = g_test_factory;
|
||||
}
|
||||
|
||||
FastPairDataEncryptorImpl::Factory::~Factory() = default;
|
||||
|
||||
// static
|
||||
void FastPairDataEncryptorImpl::Factory::CreateAsync(
|
||||
scoped_refptr<Device> device,
|
||||
base::OnceCallback<void(std::unique_ptr<FastPairDataEncryptor>)>
|
||||
on_get_instance_callback) {
|
||||
if (g_test_factory_) {
|
||||
g_test_factory_->CreateInstance(std::move(device),
|
||||
std::move(on_get_instance_callback));
|
||||
return;
|
||||
}
|
||||
|
||||
FastPairRepository::Get()->GetDeviceMetadata(
|
||||
device->metadata_id,
|
||||
base::BindOnce(&FastPairDataEncryptor::Factory::DeviceMetadataRetrieved,
|
||||
std::move(device), std::move(on_get_instance_callback)));
|
||||
base::BindOnce(
|
||||
&FastPairDataEncryptorImpl::Factory::DeviceMetadataRetrieved,
|
||||
std::move(device), std::move(on_get_instance_callback)));
|
||||
}
|
||||
|
||||
// static
|
||||
void FastPairDataEncryptor::Factory::DeviceMetadataRetrieved(
|
||||
void FastPairDataEncryptorImpl::Factory::DeviceMetadataRetrieved(
|
||||
scoped_refptr<Device> device,
|
||||
base::OnceCallback<void(std::unique_ptr<FastPairDataEncryptor>)>
|
||||
on_get_instance_callback,
|
||||
@ -41,22 +63,24 @@ void FastPairDataEncryptor::Factory::DeviceMetadataRetrieved(
|
||||
device_metadata->device.anti_spoofing_key_pair().public_key();
|
||||
std::string decoded_key;
|
||||
base::Base64Decode(public_anti_spoofing_key, &decoded_key);
|
||||
KeyPair key_pair = GenerateKeysWithEcdhKeyAgreement(decoded_key);
|
||||
std::unique_ptr<FastPairDataEncryptor> data_encryptor =
|
||||
base::WrapUnique(new FastPairDataEncryptor(key_pair));
|
||||
fast_pair_encryption::KeyPair key_pair =
|
||||
fast_pair_encryption::GenerateKeysWithEcdhKeyAgreement(decoded_key);
|
||||
std::unique_ptr<FastPairDataEncryptorImpl> data_encryptor =
|
||||
base::WrapUnique(new FastPairDataEncryptorImpl(key_pair));
|
||||
std::move(on_get_instance_callback).Run(std::move(data_encryptor));
|
||||
}
|
||||
|
||||
FastPairDataEncryptor::FastPairDataEncryptor(const KeyPair& key_pair)
|
||||
FastPairDataEncryptorImpl::FastPairDataEncryptorImpl(
|
||||
const fast_pair_encryption::KeyPair& key_pair)
|
||||
: secret_key_(key_pair.private_key), public_key_(key_pair.public_key) {}
|
||||
|
||||
FastPairDataEncryptor::~FastPairDataEncryptor() = default;
|
||||
FastPairDataEncryptorImpl::~FastPairDataEncryptorImpl() = default;
|
||||
|
||||
const std::array<uint8_t, kBlockSizeBytes> FastPairDataEncryptor::EncryptBytes(
|
||||
const std::array<uint8_t, kBlockSizeBytes>
|
||||
FastPairDataEncryptorImpl::EncryptBytes(
|
||||
const std::array<uint8_t, kBlockSizeBytes>& bytes_to_encrypt) {
|
||||
return fast_pair_encryption::EncryptBytes(secret_key_, bytes_to_encrypt);
|
||||
}
|
||||
|
||||
} // namespace fast_pair_encryption
|
||||
} // namespace quick_pair
|
||||
} // namespace ash
|
@ -0,0 +1,76 @@
|
||||
// Copyright 2021 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 ASH_QUICK_PAIR_PAIRING_FAST_PAIR_FAST_PAIR_DATA_ENCRYPTOR_IMPL_H_
|
||||
#define ASH_QUICK_PAIR_PAIRING_FAST_PAIR_FAST_PAIR_DATA_ENCRYPTOR_IMPL_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "ash/quick_pair/common/device.h"
|
||||
#include "ash/quick_pair/pairing/fast_pair/fast_pair_data_encryptor.h"
|
||||
#include "ash/quick_pair/pairing/fast_pair/fast_pair_key_pair.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
|
||||
namespace ash {
|
||||
namespace quick_pair {
|
||||
|
||||
struct DeviceMetadata;
|
||||
|
||||
// Holds a secret key for a device and has methods to encrypt bytes, decrypt
|
||||
// response and decrypt passkey.
|
||||
class FastPairDataEncryptorImpl : public FastPairDataEncryptor {
|
||||
public:
|
||||
class Factory {
|
||||
public:
|
||||
static void CreateAsync(
|
||||
scoped_refptr<Device> device,
|
||||
base::OnceCallback<void(std::unique_ptr<FastPairDataEncryptor>)>
|
||||
on_get_instance_callback);
|
||||
|
||||
static void SetFactoryForTesting(Factory* test_factory);
|
||||
|
||||
protected:
|
||||
virtual ~Factory();
|
||||
virtual void CreateInstance(
|
||||
scoped_refptr<Device> device,
|
||||
base::OnceCallback<void(std::unique_ptr<FastPairDataEncryptor>)>
|
||||
on_get_instance_callback) = 0;
|
||||
|
||||
private:
|
||||
static void DeviceMetadataRetrieved(
|
||||
scoped_refptr<Device> device,
|
||||
base::OnceCallback<void(std::unique_ptr<FastPairDataEncryptor>)>
|
||||
on_get_instance_callback,
|
||||
DeviceMetadata* device_metadata);
|
||||
};
|
||||
|
||||
const std::array<uint8_t, kBlockSizeBytes> EncryptBytes(
|
||||
const std::array<uint8_t, kBlockSizeBytes>& bytes_to_encrypt) override;
|
||||
|
||||
~FastPairDataEncryptorImpl() override;
|
||||
|
||||
protected:
|
||||
FastPairDataEncryptorImpl(const fast_pair_encryption::KeyPair& key_pair);
|
||||
FastPairDataEncryptorImpl(const FastPairDataEncryptorImpl&) = delete;
|
||||
FastPairDataEncryptorImpl& operator=(const FastPairDataEncryptorImpl&) =
|
||||
delete;
|
||||
|
||||
private:
|
||||
std::array<uint8_t, kPrivateKeyByteSize> secret_key_;
|
||||
|
||||
// The public key is only required during initial pairing and optional during
|
||||
// communication with paired devices.
|
||||
absl::optional<std::array<uint8_t, kPublicKeyByteSize>> public_key_ =
|
||||
absl::nullopt;
|
||||
};
|
||||
|
||||
} // namespace quick_pair
|
||||
} // namespace ash
|
||||
|
||||
#endif // ASH_QUICK_PAIR_PAIRING_FAST_PAIR_FAST_PAIR_DATA_ENCRYPTOR_IMPL_H_
|
@ -10,6 +10,8 @@
|
||||
namespace ash {
|
||||
namespace quick_pair {
|
||||
|
||||
class FastPairDataEncryptor;
|
||||
|
||||
// This class is responsible for connecting to the Fast Pair GATT service for a
|
||||
// device and invoking a callback when ready, or when an error is discovered
|
||||
// during initialization.
|
||||
@ -27,6 +29,7 @@ class FastPairGattServiceClient : public device::BluetoothAdapter::Observer {
|
||||
uint8_t flags,
|
||||
const std::string& provider_address,
|
||||
const std::string& seekers_address,
|
||||
FastPairDataEncryptor* fast_pair_data_encryptor,
|
||||
base::OnceCallback<void(std::vector<uint8_t>,
|
||||
absl::optional<PairFailure>)>
|
||||
write_response_callback) = 0;
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "ash/quick_pair/common/constants.h"
|
||||
#include "ash/quick_pair/common/logging.h"
|
||||
#include "ash/quick_pair/pairing/fast_pair/fast_pair_data_encryptor.h"
|
||||
#include "base/time/time.h"
|
||||
#include "device/bluetooth/bluetooth_device.h"
|
||||
#include "device/bluetooth/bluetooth_gatt_connection.h"
|
||||
@ -28,11 +29,8 @@ const device::BluetoothUUID kAccountKeyCharacteristicUuidV1("1236");
|
||||
const device::BluetoothUUID kAccountKeyCharacteristicUuidV2(
|
||||
"FE2C1236-8366-4814-8EB0-01DE32100BEA");
|
||||
|
||||
constexpr uint8_t kBlockByteSize = 16;
|
||||
constexpr uint8_t kRequestSaltByteSize = 3;
|
||||
constexpr uint8_t kProviderAddressStartIndex = 2;
|
||||
constexpr uint8_t kSeekerAddressStartIndex = 8;
|
||||
constexpr uint8_t kRequestSaltStartIndex = 13;
|
||||
constexpr uint8_t kSeekerPasskey = 0x02;
|
||||
|
||||
constexpr base::TimeDelta kGattOperationTimeout =
|
||||
@ -306,27 +304,32 @@ FastPairGattServiceClientImpl::gatt_service() {
|
||||
return gatt_service_;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> FastPairGattServiceClientImpl::CreateRequest(
|
||||
const std::array<uint8_t, kBlockByteSize>
|
||||
FastPairGattServiceClientImpl::CreateRequest(
|
||||
uint8_t message_type,
|
||||
uint8_t flags,
|
||||
const std::string& provider_address,
|
||||
const std::string& seekers_address) {
|
||||
std::vector<uint8_t> data_to_write(kBlockByteSize);
|
||||
// We can't use a std::array to start with because RAND_bytes only takes in
|
||||
// C-style arrays, so we will convert at the end.
|
||||
uint8_t data_to_write[kBlockByteSize];
|
||||
RAND_bytes(data_to_write, kBlockByteSize);
|
||||
|
||||
data_to_write[0] = message_type;
|
||||
data_to_write[1] = flags;
|
||||
|
||||
std::copy(provider_address.begin(), provider_address.end(),
|
||||
data_to_write.begin() + kProviderAddressStartIndex);
|
||||
std::begin(data_to_write) + kProviderAddressStartIndex);
|
||||
|
||||
// Seekers address can be empty, in which we would just have the bytes be
|
||||
// the salt.
|
||||
std::copy(seekers_address.begin(), seekers_address.end(),
|
||||
data_to_write.begin() + kSeekerAddressStartIndex);
|
||||
std::begin(data_to_write) + kSeekerAddressStartIndex);
|
||||
|
||||
uint8_t salt[kRequestSaltByteSize];
|
||||
RAND_bytes(salt, kRequestSaltByteSize);
|
||||
std::copy(std::begin(salt), std::end(salt),
|
||||
data_to_write.begin() + kRequestSaltStartIndex);
|
||||
|
||||
return data_to_write;
|
||||
std::array<uint8_t, kBlockByteSize> std_data_to_write;
|
||||
std::move(std::begin(data_to_write), std::end(data_to_write),
|
||||
std_data_to_write.begin());
|
||||
return std_data_to_write;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> FastPairGattServiceClientImpl::CreatePasskeyBlock(
|
||||
@ -351,10 +354,12 @@ void FastPairGattServiceClientImpl::WriteRequestAsync(
|
||||
uint8_t flags,
|
||||
const std::string& provider_address,
|
||||
const std::string& seekers_address,
|
||||
FastPairDataEncryptor* fast_pair_data_encryptor,
|
||||
base::OnceCallback<void(std::vector<uint8_t>, absl::optional<PairFailure>)>
|
||||
write_response_callback) {
|
||||
DCHECK(is_initialized_);
|
||||
DCHECK(!key_based_write_response_callback_);
|
||||
DCHECK(fast_pair_data_encryptor);
|
||||
|
||||
key_based_write_response_callback_ = std::move(write_response_callback);
|
||||
|
||||
@ -369,8 +374,12 @@ void FastPairGattServiceClientImpl::WriteRequestAsync(
|
||||
weak_ptr_factory_.GetWeakPtr(),
|
||||
PairFailure::kKeyBasedPairingResponseTimeout));
|
||||
|
||||
const std::array<uint8_t, kBlockSizeBytes> data_to_write =
|
||||
fast_pair_data_encryptor->EncryptBytes(CreateRequest(
|
||||
message_type, flags, provider_address, seekers_address));
|
||||
|
||||
key_based_characteristic_->WriteRemoteCharacteristic(
|
||||
CreateRequest(message_type, flags, provider_address, seekers_address),
|
||||
std::vector<uint8_t>(data_to_write.begin(), data_to_write.end()),
|
||||
device::BluetoothRemoteGattCharacteristic::WriteType::kWithResponse,
|
||||
base::BindOnce(&FastPairGattServiceClientImpl::OnWriteRequest,
|
||||
weak_ptr_factory_.GetWeakPtr()),
|
||||
|
@ -30,9 +30,17 @@ class BluetoothRemoteGattService;
|
||||
|
||||
} // namespace device
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kBlockByteSize = 16;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace ash {
|
||||
namespace quick_pair {
|
||||
|
||||
class FastPairDataEncryptor;
|
||||
|
||||
// This class is responsible for connecting to the Fast Pair GATT service for a
|
||||
// device and invoking a callback when ready, or when an error is discovered
|
||||
// during initialization.
|
||||
@ -67,6 +75,7 @@ class FastPairGattServiceClientImpl : public FastPairGattServiceClient {
|
||||
uint8_t flags,
|
||||
const std::string& provider_address,
|
||||
const std::string& seekers_address,
|
||||
FastPairDataEncryptor* fast_pair_data_encryptor,
|
||||
base::OnceCallback<void(std::vector<uint8_t>,
|
||||
absl::optional<PairFailure>)>
|
||||
write_response_callback) override;
|
||||
@ -88,10 +97,11 @@ class FastPairGattServiceClientImpl : public FastPairGattServiceClient {
|
||||
const FastPairGattServiceClientImpl&) = delete;
|
||||
|
||||
// Creates a data vector based on parameter information.
|
||||
std::vector<uint8_t> CreateRequest(uint8_t message_type,
|
||||
uint8_t flags,
|
||||
const std::string& provider_address,
|
||||
const std::string& seekers_address);
|
||||
const std::array<uint8_t, kBlockByteSize> CreateRequest(
|
||||
uint8_t message_type,
|
||||
uint8_t flags,
|
||||
const std::string& provider_address,
|
||||
const std::string& seekers_address);
|
||||
std::vector<uint8_t> CreatePasskeyBlock(uint8_t message_type,
|
||||
uint32_t passkey);
|
||||
|
||||
|
@ -54,8 +54,6 @@ const device::BluetoothUUID kAccountKeyCharacteristicUuid1("1236");
|
||||
const device::BluetoothUUID kAccountKeyCharacteristicUuid2(
|
||||
"FE2C1236-8366-4814-8EB0-01DE32100BEA");
|
||||
|
||||
const uint8_t kMessageType = 0x00;
|
||||
const uint8_t kFlags = 0x00;
|
||||
const std::string kProviderAddress = "abcde";
|
||||
const std::string kSeekersAddress = "abcde";
|
||||
const std::vector<uint8_t>& kTestWriteResponse{0x01, 0x03, 0x02, 0x01, 0x02};
|
||||
@ -414,11 +412,6 @@ class FastPairGattServiceClientTest : public testing::Test {
|
||||
}
|
||||
|
||||
void WriteRequestToKeyBased() {
|
||||
gatt_service_client_->WriteRequestAsync(
|
||||
kMessageType, kFlags, kProviderAddress, kSeekersAddress,
|
||||
base::BindRepeating(&::ash::quick_pair::FastPairGattServiceClientTest::
|
||||
WriteTestCallback,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void WriteRequestToPasskey() {
|
||||
@ -565,38 +558,12 @@ TEST_F(FastPairGattServiceClientTest, KeyBasedStartNotifyTimeout) {
|
||||
}
|
||||
|
||||
TEST_F(FastPairGattServiceClientTest, WriteKeyBasedRequest) {
|
||||
SuccessfulGattConnectionSetUp();
|
||||
NotifyGattDiscoveryCompleteForService();
|
||||
EXPECT_EQ(GetInitializedCallbackResult(), absl::nullopt);
|
||||
EXPECT_TRUE(ServiceIsSet());
|
||||
WriteRequestToKeyBased();
|
||||
TriggerKeyBasedGattChanged();
|
||||
EXPECT_EQ(GetWriteCallbackResult(), absl::nullopt);
|
||||
}
|
||||
|
||||
TEST_F(FastPairGattServiceClientTest, WriteKeyBasedRequestError) {
|
||||
SetKeyBasedWriteError();
|
||||
SuccessfulGattConnectionSetUp();
|
||||
NotifyGattDiscoveryCompleteForService();
|
||||
EXPECT_EQ(GetInitializedCallbackResult(), absl::nullopt);
|
||||
EXPECT_TRUE(ServiceIsSet());
|
||||
WriteRequestToKeyBased();
|
||||
TriggerKeyBasedGattChanged();
|
||||
EXPECT_EQ(GetWriteCallbackResult(),
|
||||
PairFailure::kKeyBasedPairingCharacteristicWrite);
|
||||
}
|
||||
|
||||
TEST_F(FastPairGattServiceClientTest, WriteKeyBasedRequestTimeout) {
|
||||
SetWriteRequestTimeout();
|
||||
SuccessfulGattConnectionSetUp();
|
||||
NotifyGattDiscoveryCompleteForService();
|
||||
EXPECT_EQ(GetInitializedCallbackResult(), absl::nullopt);
|
||||
EXPECT_TRUE(ServiceIsSet());
|
||||
WriteRequestToKeyBased();
|
||||
TriggerKeyBasedGattChanged();
|
||||
EXPECT_TRUE(ServiceIsSet());
|
||||
EXPECT_EQ(GetWriteCallbackResult(),
|
||||
PairFailure::kKeyBasedPairingResponseTimeout);
|
||||
}
|
||||
|
||||
TEST_F(FastPairGattServiceClientTest, WritePasskeyRequest) {
|
||||
|
@ -8,10 +8,18 @@
|
||||
#include "ash/quick_pair/common/device.h"
|
||||
#include "ash/quick_pair/common/logging.h"
|
||||
#include "ash/quick_pair/common/pair_failure.h"
|
||||
#include "ash/quick_pair/pairing/fast_pair/fast_pair_data_encryptor.h"
|
||||
#include "ash/quick_pair/pairing/fast_pair/fast_pair_data_encryptor_impl.h"
|
||||
#include "ash/quick_pair/pairing/fast_pair/fast_pair_gatt_service_client_impl.h"
|
||||
#include "base/callback.h"
|
||||
#include "device/bluetooth/bluetooth_adapter.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kProviderAddressSize = 6;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace ash {
|
||||
namespace quick_pair {
|
||||
|
||||
@ -46,8 +54,35 @@ void FastPairPairer::OnGattClientInitializedCallback(
|
||||
return;
|
||||
}
|
||||
|
||||
QP_LOG(VERBOSE) << "Fast Pair GATT service client initialization successful.";
|
||||
FastPairDataEncryptorImpl::Factory::CreateAsync(
|
||||
device_, base::BindOnce(&FastPairPairer::OnDataEncryptorCreateAsync,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void FastPairPairer::OnDataEncryptorCreateAsync(
|
||||
std::unique_ptr<FastPairDataEncryptor> fast_pair_data_encryptor) {
|
||||
if (!fast_pair_data_encryptor) {
|
||||
QP_LOG(WARNING) << "Fast Pair Data Encryptor failed to be created.";
|
||||
std::move(pair_failed_callback_)
|
||||
.Run(device_, PairFailure::kDataEncryptorRetrieval);
|
||||
return;
|
||||
}
|
||||
fast_pair_data_encryptor_ = std::move(fast_pair_data_encryptor);
|
||||
QP_LOG(VERBOSE) << "Fast Pair GATT service client initialization successful.";
|
||||
|
||||
DCHECK(!device_->address.empty());
|
||||
DCHECK(device_->address.size() == kProviderAddressSize);
|
||||
fast_pair_gatt_service_client_->WriteRequestAsync(
|
||||
/*message_type=*/0x00,
|
||||
/*flags=*/0x00,
|
||||
/*provider_address=*/device_->address,
|
||||
/*seekers_address=*/"", fast_pair_data_encryptor_.get(),
|
||||
base::BindOnce(&FastPairPairer::OnWriteResponse,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void FastPairPairer::OnWriteResponse(std::vector<uint8_t> response_bytes,
|
||||
absl::optional<PairFailure> failure) {}
|
||||
|
||||
} // namespace quick_pair
|
||||
} // namespace ash
|
||||
|
@ -24,6 +24,7 @@ namespace quick_pair {
|
||||
struct Device;
|
||||
enum class AccountKeyFailure;
|
||||
enum class PairFailure;
|
||||
class FastPairDataEncryptor;
|
||||
|
||||
// A FastPairPairer instance is responsible for the pairing procedure to a
|
||||
// single device. Pairing begins on instantiation.
|
||||
@ -46,8 +47,19 @@ class FastPairPairer {
|
||||
~FastPairPairer();
|
||||
|
||||
private:
|
||||
// FastPairGattServiceClientImpl::Factory::Create callback
|
||||
void OnGattClientInitializedCallback(absl::optional<PairFailure> failure);
|
||||
|
||||
// FastPairDataEncryptor::Factory::CreateAsync callback
|
||||
// Once the data encryptor is created, triggers a WriteRequestAsync in the
|
||||
// client to be encrypted with the DataEncryptor and written to the device.
|
||||
void OnDataEncryptorCreateAsync(
|
||||
std::unique_ptr<FastPairDataEncryptor> fast_pair_data_encryptor);
|
||||
|
||||
// FastPairGattServiceClient::WriteRequest callback
|
||||
void OnWriteResponse(std::vector<uint8_t> response_bytes,
|
||||
absl::optional<PairFailure> failure);
|
||||
|
||||
scoped_refptr<device::BluetoothAdapter> adapter_;
|
||||
scoped_refptr<Device> device_;
|
||||
base::OnceCallback<void(scoped_refptr<Device>)> paired_callback_;
|
||||
@ -56,6 +68,7 @@ class FastPairPairer {
|
||||
base::OnceCallback<void(scoped_refptr<Device>, AccountKeyFailure)>
|
||||
account_key_failure_callback_;
|
||||
base::OnceCallback<void(scoped_refptr<Device>)> pairing_procedure_complete_;
|
||||
std::unique_ptr<FastPairDataEncryptor> fast_pair_data_encryptor_;
|
||||
std::unique_ptr<FastPairGattServiceClient> fast_pair_gatt_service_client_;
|
||||
base::WeakPtrFactory<FastPairPairer> weak_ptr_factory_{this};
|
||||
};
|
||||
|
@ -11,14 +11,18 @@
|
||||
#include "ash/quick_pair/common/pair_failure.h"
|
||||
#include "ash/quick_pair/common/protocol.h"
|
||||
#include "ash/quick_pair/pairing/fast_pair/fake_fast_pair_gatt_service_client.h"
|
||||
#include "ash/quick_pair/pairing/fast_pair/fast_pair_data_encryptor.h"
|
||||
#include "ash/quick_pair/pairing/fast_pair/fast_pair_data_encryptor_impl.h"
|
||||
#include "ash/quick_pair/pairing/fast_pair/fast_pair_gatt_service_client.h"
|
||||
#include "ash/quick_pair/pairing/fast_pair/fast_pair_gatt_service_client_impl.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "base/test/mock_callback.h"
|
||||
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
|
||||
#include "device/bluetooth/test/mock_bluetooth_device.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
#include "third_party/boringssl/src/include/openssl/rand.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@ -57,10 +61,51 @@ class FakeBluetoothAdapter
|
||||
namespace ash {
|
||||
namespace quick_pair {
|
||||
|
||||
class FakeFastPairDataEncryptor : public FastPairDataEncryptor {
|
||||
public:
|
||||
const std::array<uint8_t, kBlockSizeBytes> EncryptBytes(
|
||||
const std::array<uint8_t, kBlockSizeBytes>& bytes_to_encrypt) override {
|
||||
// Return random bytes for testing since we are just testing the retrieval
|
||||
// of the encryptor.
|
||||
uint8_t data_to_write[kBlockByteSize];
|
||||
RAND_bytes(data_to_write, kBlockByteSize);
|
||||
std::array<uint8_t, kBlockByteSize> std_data_to_write;
|
||||
std::move(std::begin(data_to_write), std::end(data_to_write),
|
||||
std_data_to_write.begin());
|
||||
return std_data_to_write;
|
||||
}
|
||||
|
||||
FakeFastPairDataEncryptor() = default;
|
||||
~FakeFastPairDataEncryptor() override = default;
|
||||
};
|
||||
|
||||
class FakeFastPairDataEncryptorImplFactory
|
||||
: public FastPairDataEncryptorImpl::Factory {
|
||||
public:
|
||||
void CreateInstance(
|
||||
scoped_refptr<Device> device,
|
||||
base::OnceCallback<void(std::unique_ptr<FastPairDataEncryptor>)>
|
||||
on_get_instance_callback) override {
|
||||
if (!successful_retrieval_) {
|
||||
std::move(on_get_instance_callback).Run(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<FastPairDataEncryptor> data_encryptor =
|
||||
base::WrapUnique(new FakeFastPairDataEncryptor());
|
||||
}
|
||||
|
||||
~FakeFastPairDataEncryptorImplFactory() override = default;
|
||||
|
||||
void SetFailedRetrieval() { successful_retrieval_ = false; }
|
||||
|
||||
private:
|
||||
bool successful_retrieval_ = true;
|
||||
};
|
||||
|
||||
class FakeFastPairGattServiceClientImplFactory
|
||||
: public FastPairGattServiceClientImpl::Factory {
|
||||
public:
|
||||
FakeFastPairGattServiceClientImplFactory() = default;
|
||||
~FakeFastPairGattServiceClientImplFactory() override = default;
|
||||
|
||||
FakeFastPairGattServiceClient* fake_fast_pair_gatt_service_client() {
|
||||
@ -87,7 +132,7 @@ class FakeFastPairGattServiceClientImplFactory
|
||||
|
||||
class FastPairPairerTest : public testing::Test {
|
||||
public:
|
||||
void SetUp() override {
|
||||
void SuccessfulDataEncryptorSetUp() {
|
||||
device_ = base::MakeRefCounted<Device>(kMetadataId, kAddress,
|
||||
Protocol::kFastPair);
|
||||
adapter_ = base::MakeRefCounted<FakeBluetoothAdapter>();
|
||||
@ -103,6 +148,32 @@ class FastPairPairerTest : public testing::Test {
|
||||
|
||||
FastPairGattServiceClientImpl::Factory::SetFactoryForTesting(
|
||||
&fast_pair_gatt_service_factory_);
|
||||
|
||||
FastPairDataEncryptorImpl::Factory::SetFactoryForTesting(
|
||||
&fast_pair_data_encryptor_factory);
|
||||
}
|
||||
|
||||
void FailedDataEncryptorSetUp() {
|
||||
device_ = base::MakeRefCounted<Device>(kMetadataId, kAddress,
|
||||
Protocol::kFastPair);
|
||||
adapter_ = base::MakeRefCounted<FakeBluetoothAdapter>();
|
||||
|
||||
// Need to add a matching mock device to the bluetooth adapter with the
|
||||
// same address to mock the relationship between Device and
|
||||
// device::BluetoothDevice.
|
||||
mock_device_ =
|
||||
std::make_unique<testing::NiceMock<device::MockBluetoothDevice>>(
|
||||
adapter_.get(), 0, kDeviceName, kAddress, /*paired=*/true,
|
||||
/*connected*/ false);
|
||||
adapter_->AddMockDevice(std::move(mock_device_));
|
||||
|
||||
FastPairGattServiceClientImpl::Factory::SetFactoryForTesting(
|
||||
&fast_pair_gatt_service_factory_);
|
||||
|
||||
fast_pair_data_encryptor_factory.SetFailedRetrieval();
|
||||
|
||||
FastPairDataEncryptorImpl::Factory::SetFactoryForTesting(
|
||||
&fast_pair_data_encryptor_factory);
|
||||
}
|
||||
|
||||
void RunOnGattClientInitializedCallback(
|
||||
@ -133,20 +204,31 @@ class FastPairPairerTest : public testing::Test {
|
||||
base::MockCallback<base::OnceCallback<void(scoped_refptr<Device>)>>
|
||||
pairing_procedure_complete_;
|
||||
FakeFastPairGattServiceClientImplFactory fast_pair_gatt_service_factory_;
|
||||
FakeFastPairDataEncryptorImplFactory fast_pair_data_encryptor_factory;
|
||||
std::unique_ptr<FastPairPairer> pairer_;
|
||||
};
|
||||
|
||||
TEST_F(FastPairPairerTest, NoCallbackIsInvokedOnGattSuccess) {
|
||||
SuccessfulDataEncryptorSetUp();
|
||||
EXPECT_CALL(pair_failed_callback_, Run).Times(0);
|
||||
CreatePairer();
|
||||
RunOnGattClientInitializedCallback();
|
||||
}
|
||||
|
||||
TEST_F(FastPairPairerTest, PairFailedCallbackIsInvokedOnGattFailure) {
|
||||
SuccessfulDataEncryptorSetUp();
|
||||
EXPECT_CALL(pair_failed_callback_, Run);
|
||||
CreatePairer();
|
||||
RunOnGattClientInitializedCallback(PairFailure::kCreateGattConnection);
|
||||
}
|
||||
|
||||
TEST_F(FastPairPairerTest,
|
||||
PairFailedCallbackIsInvokedOnEncryptorRetrievalFailure) {
|
||||
FailedDataEncryptorSetUp();
|
||||
EXPECT_CALL(pair_failed_callback_, Run);
|
||||
CreatePairer();
|
||||
RunOnGattClientInitializedCallback();
|
||||
}
|
||||
|
||||
} // namespace quick_pair
|
||||
} // namespace ash
|
||||
|
Reference in New Issue
Block a user