Add initial pairing in scalable seeker

PiperOrigin-RevId: 541034178
This commit is contained in:
Janusz Sobczak
2023-06-16 16:14:14 -07:00
committed by Copybara-Service
parent 4914cbc2f9
commit 20acd4eeb9
10 changed files with 284 additions and 33 deletions
+2
View File
@@ -55,6 +55,7 @@ cc_library(
"//fastpair:__subpackages__",
],
deps = [
":fake_gatt_callbacks",
":message_stream",
"//fastpair/common",
"//internal/platform:base",
@@ -87,6 +88,7 @@ cc_library(
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
],
)
+18 -9
View File
@@ -21,6 +21,7 @@
#include "absl/container/flat_hash_map.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/escaping.h"
#include "internal/platform/ble_v2.h"
#include "internal/platform/future.h"
@@ -43,14 +44,22 @@ class FakeGattCallbacks {
// characteristic
absl::StatusOr<std::string> read_value =
absl::FailedPreconditionError("characteristic not set");
absl::AnyInvocable<absl::Status(absl::string_view)> write_callback =
[&](absl::string_view data) {
write_value.Set(std::string(data));
return write_result;
};
absl::AnyInvocable<absl::StatusOr<std::string>()> read_callback = [&]() {
absl::AnyInvocable<absl::Status(absl::string_view)> write_callback;
absl::AnyInvocable<absl::StatusOr<std::string>()> read_callback;
absl::Status WriteCallback(absl::string_view data) {
if (write_callback) {
return write_callback(data);
}
write_value.Set(std::string(data));
return write_result;
}
absl::StatusOr<std::string> ReadCallback() {
if (read_callback) {
return read_callback();
}
return read_value;
};
}
};
BleV2Medium::ServerGattConnectionCallback GetGattCallback() {
@@ -65,7 +74,7 @@ class FakeGattCallbacks {
callback(absl::NotFoundError("characteristic not found"));
return;
}
callback(it->second.read_callback());
callback(it->second.ReadCallback());
},
.on_characteristic_write_cb =
[&](const api::ble_v2::BlePeripheral& remote_device,
@@ -78,7 +87,7 @@ class FakeGattCallbacks {
callback(absl::NotFoundError("characteristic not found"));
return;
}
callback(it->second.write_callback(data));
callback(it->second.WriteCallback(data));
}};
}
+119 -9
View File
@@ -18,7 +18,9 @@
#include "absl/status/status.h"
#include "absl/strings/escaping.h"
#include "absl/strings/numbers.h"
#include "fastpair/common/constant.h"
#include "internal/platform/medium_environment.h"
#include <openssl/base.h>
#include <openssl/bn.h>
#include <openssl/ec_key.h>
@@ -28,6 +30,10 @@ namespace fastpair {
namespace {
constexpr uint8_t kKeyBasedPairingResponseCode = 1;
constexpr uint8_t kSeekerPasskeyResponseCode = 2;
constexpr uint8_t kProviderPasskeyResponseCode = 3;
static EC_POINT *load_public_key(absl::string_view public_key) {
CHECK_EQ(public_key.size(), kPublicKeyByteSize);
BN_CTX *bn_ctx;
@@ -129,22 +135,22 @@ void FakeProvider::LoadAntiSpoofingKey(absl::string_view private_key,
}
std::string FakeProvider::DecryptKbpRequest(absl::string_view request) {
NEARBY_LOGS(INFO) << "Encrypted KBP request "
<< absl::BytesToHexString(request);
NEARBY_LOGS(VERBOSE) << "Encrypted KBP request "
<< absl::BytesToHexString(request);
CHECK_EQ(request.size(), kEncryptedDataByteSize + kPublicKeyByteSize);
absl::string_view encrypted = request.substr(0, kEncryptedDataByteSize);
absl::string_view remote_public_key =
request.substr(kEncryptedDataByteSize, kPublicKeyByteSize);
std::string shared_secret = CreateSharedSecret(remote_public_key);
std::string decrypted = Aes128Decrypt(encrypted, shared_secret);
NEARBY_LOGS(INFO) << "Decrypted KBP request "
<< absl::BytesToHexString(decrypted);
account_key_ = shared_secret;
NEARBY_LOGS(VERBOSE) << "Decrypted KBP request "
<< absl::BytesToHexString(decrypted);
shared_secret_ = shared_secret;
return decrypted;
}
std::string FakeProvider::Encrypt(absl::string_view data) {
return Aes128Encrypt(data, account_key_);
return Aes128Encrypt(data, shared_secret_);
}
std::string FakeProvider::GenSec256r1Secret(
@@ -199,9 +205,9 @@ std::string FakeProvider::CreateSharedSecret(
Crypto::Sha256(secret).AsStringView().substr(0, kAccountKeySize));
}
void FakeProvider::StartGattServer(
BleV2Medium::ServerGattConnectionCallback callback) {
gatt_server_ = ble_.StartGattServer(std::move(callback));
void FakeProvider::StartGattServer(FakeGattCallbacks *fake_gatt_callbacks) {
fake_gatt_callbacks_ = fake_gatt_callbacks;
gatt_server_ = ble_.StartGattServer(fake_gatt_callbacks_->GetGattCallback());
}
absl::Status FakeProvider::NotifyKeyBasedPairing(ByteArray response) {
@@ -211,8 +217,16 @@ absl::Status FakeProvider::NotifyKeyBasedPairing(ByteArray response) {
false, response);
}
absl::Status FakeProvider::NotifyPasskey(ByteArray response) {
CHECK_NE(gatt_server_, nullptr);
CHECK(passkey_characteristic_.has_value());
return gatt_server_->NotifyCharacteristicChanged(*passkey_characteristic_,
false, response);
}
void FakeProvider::StartDiscoverableAdvertisement(absl::string_view model_id) {
advertising_ = true;
model_id_ = model_id;
ble_v1_.StartAdvertising(std::string(kServiceID),
ByteArray(absl::HexStringToBytes(model_id)),
std::string(kFastPairServiceUuid));
@@ -225,5 +239,101 @@ void FakeProvider::StopAdvertising() {
}
}
void FakeProvider::SetKeyBasedPairingCallback() {
CHECK_NE(fake_gatt_callbacks_, nullptr);
CHECK(key_based_characteristic_.has_value());
fake_gatt_callbacks_->characteristics_[*key_based_characteristic_]
.write_callback = [this](absl::string_view request) {
NEARBY_LOGS(VERBOSE) << "Encrypted request: "
<< absl::BytesToHexString(request);
std::string decrypted_request = DecryptKbpRequest(request);
NEARBY_LOGS(VERBOSE) << "KBP decrypted request "
<< absl::BytesToHexString(decrypted_request);
fake_gatt_callbacks_->characteristics_[*key_based_characteristic_]
.write_value.Set(std::string(decrypted_request));
std::string response;
response.push_back(kKeyBasedPairingResponseCode);
response.append(GetMacAddressAsBytes());
response.resize(kEncryptedDataByteSize, 0);
absl::Status status = NotifyKeyBasedPairing(ByteArray(Encrypt(response)));
NEARBY_LOGS(VERBOSE) << "KBP notify result: " << status;
return absl::OkStatus();
};
}
void FakeProvider::SetPasskeyCallback() {
CHECK_NE(fake_gatt_callbacks_, nullptr);
CHECK(passkey_characteristic_.has_value());
fake_gatt_callbacks_->characteristics_[*passkey_characteristic_]
.write_callback = [this](absl::string_view request) {
NEARBY_LOGS(VERBOSE) << "Passkey Encrypted request: "
<< absl::BytesToHexString(request);
std::string decrypted = Aes128Decrypt(request, shared_secret_);
NEARBY_LOGS(VERBOSE) << "Passkey decrypted request "
<< absl::BytesToHexString(decrypted);
fake_gatt_callbacks_->characteristics_[*passkey_characteristic_]
.write_value.Set(std::string(decrypted));
if (decrypted[0] != kSeekerPasskeyResponseCode) {
return absl::InvalidArgumentError(
absl::StrFormat("Invalid passkey response code: 0x%x", decrypted[0]));
}
std::string response;
response.push_back(kProviderPasskeyResponseCode);
response.push_back(pass_key_ >> 16);
response.push_back(pass_key_ >> 8);
response.push_back(pass_key_);
response.resize(kEncryptedDataByteSize, 0);
absl::Status status = NotifyPasskey(ByteArray(Encrypt(response)));
NEARBY_LOGS(VERBOSE) << "Passkey notify result: " << status;
return absl::OkStatus();
};
}
void FakeProvider::SetAccountkeyCallback() {
CHECK_NE(fake_gatt_callbacks_, nullptr);
CHECK(accountkey_characteristic_.has_value());
fake_gatt_callbacks_->characteristics_[*accountkey_characteristic_]
.write_callback = [this](absl::string_view request) {
NEARBY_LOGS(VERBOSE) << "Account key encrypted request: "
<< absl::BytesToHexString(request);
std::string decrypted = Aes128Decrypt(request, shared_secret_);
NEARBY_LOGS(VERBOSE) << "Account key decrypted request "
<< absl::BytesToHexString(decrypted);
fake_gatt_callbacks_->characteristics_[*accountkey_characteristic_]
.write_value.Set(std::string(decrypted));
account_key_ = AccountKey(decrypted);
return absl::OkStatus();
};
}
void FakeProvider::ConfigurePairingContext(absl::string_view pass_key) {
api::PairingParams pairing_params;
pairing_params.pairing_type =
api::PairingParams::PairingType::kConfirmPasskey;
pairing_params.passkey = pass_key;
auto device = MediumEnvironment::Instance().FindBluetoothDevice(
provider_medium_.GetMacAddress());
CHECK_NE(device, nullptr);
MediumEnvironment::Instance().ConfigBluetoothPairingContext(device,
pairing_params);
CHECK(absl::SimpleAtoi(pass_key, &pass_key_));
}
void FakeProvider::PrepareForInitialPairing(
PairingConfig config, FakeGattCallbacks *fake_gatt_callbacks) {
LoadAntiSpoofingKey(config.private_key, config.public_key);
StartGattServer(fake_gatt_callbacks);
InsertCorrectGattCharacteristics();
SetKeyBasedPairingCallback();
SetPasskeyCallback();
SetAccountkeyCallback();
provider_adapter_.SetScanMode(
BluetoothAdapter::ScanMode::kConnectableDiscoverable);
ConfigurePairingContext(config.pass_key);
StartDiscoverableAdvertisement(config.model_id);
}
} // namespace fastpair
} // namespace nearby
+32 -4
View File
@@ -28,8 +28,10 @@
#include "absl/strings/escaping.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "fastpair/common/account_key.h"
#include "fastpair/common/constant.h"
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/message_stream/fake_gatt_callbacks.h"
#include "fastpair/message_stream/message.h"
#include "internal/platform/ble.h"
#include "internal/platform/ble_v2.h"
@@ -71,8 +73,18 @@ class FakeProvider {
public:
using KeyBasedPairingCallback =
absl::AnyInvocable<std::string(absl::string_view)>;
struct PairingConfig {
std::string private_key; // binary, private Anti-Spoofing Key
std::string public_key; // binary, public Anti-Spoofing Key
std::string model_id;
std::string pass_key;
};
~FakeProvider() { Shutdown(); }
// Sets the fake provider up for initial pairing
void PrepareForInitialPairing(PairingConfig config,
FakeGattCallbacks* fake_gatt_callbacks);
void Shutdown() {
StopAdvertising();
provider_thread_.Shutdown();
@@ -151,25 +163,31 @@ class FakeProvider {
BluetoothUtils::FromString(provider_adapter_.GetMacAddress()));
}
void StartGattServer(BleV2Medium::ServerGattConnectionCallback callback);
void StartGattServer(FakeGattCallbacks* fake_gatt_callbacks);
void InsertCorrectGattCharacteristics() {
CHECK_NE(fake_gatt_callbacks_, nullptr);
key_based_characteristic_ = gatt_server_->CreateCharacteristic(
kFastPairServiceUuid, kKeyBasedCharacteristicUuidV2, permissions_,
properties_);
CHECK(key_based_characteristic_.has_value());
fake_gatt_callbacks_->characteristics_[*key_based_characteristic_]
.write_result = absl::OkStatus();
passkey_characteristic_ = gatt_server_->CreateCharacteristic(
kFastPairServiceUuid, kPasskeyCharacteristicUuidV2, permissions_,
properties_);
CHECK(passkey_characteristic_.has_value());
fake_gatt_callbacks_->characteristics_[*passkey_characteristic_]
.write_result = absl::OkStatus();
accountkey_characteristic_ = gatt_server_->CreateCharacteristic(
kFastPairServiceUuid, kAccountKeyCharacteristicUuidV2, permissions_,
properties_);
CHECK(accountkey_characteristic_.has_value());
fake_gatt_callbacks_->characteristics_[*accountkey_characteristic_]
.write_result = absl::OkStatus();
}
void LoadAntiSpoofingKey(absl::string_view private_key,
@@ -179,14 +197,20 @@ class FakeProvider {
std::string Encrypt(absl::string_view data);
absl::Status NotifyKeyBasedPairing(ByteArray response);
absl::Status NotifyPasskey(ByteArray response);
void StartDiscoverableAdvertisement(absl::string_view model_id);
void StopAdvertising();
void ConfigurePairingContext(absl::string_view pass_key);
AccountKey& GetAccountKey() { return account_key_; }
std::optional<GattCharacteristic> key_based_characteristic_;
std::optional<GattCharacteristic> passkey_characteristic_;
std::optional<GattCharacteristic> accountkey_characteristic_;
private:
void SetKeyBasedPairingCallback();
void SetPasskeyCallback();
void SetAccountkeyCallback();
std::string GenSec256r1Secret(absl::string_view remote_party_public_key);
std::string CreateSharedSecret(absl::string_view remote_public_key);
BluetoothAdapter provider_adapter_;
@@ -201,8 +225,12 @@ class FakeProvider {
Permission permissions_ = Permission::kWrite;
std::unique_ptr<EVP_PKEY, void (*)(EVP_PKEY*)> anti_spoofing_key_{
nullptr, EVP_PKEY_free};
std::string account_key_;
std::string shared_secret_;
SingleThreadExecutor provider_thread_;
std::string model_id_;
FakeGattCallbacks* fake_gatt_callbacks_ = nullptr;
unsigned int pass_key_;
AccountKey account_key_;
};
} // namespace fastpair