0

[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:
Juliet Levesque
2021-08-17 20:06:20 +00:00
committed by Chromium LUCI CQ
parent 8136871bf0
commit 2a8c8e5f24
15 changed files with 318 additions and 124 deletions

@ -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