Update embedded SDK

New features:
* Smart Audio Source Switching.
* Fast Pair for BLE-only devices.
* Two byte salt size for improved security.

Other changes:
* Added optional encryption modules based on mbedtls.
* Fixed build issues.
* More verbose and readable logs.
This commit is contained in:
Janusz Sobczak
2022-12-20 10:50:13 -08:00
parent 3dbf10eb66
commit f643f7a466
28 changed files with 4094 additions and 533 deletions
+166
View File
@@ -17,6 +17,172 @@
#include "nearby_fp_client.h"
#include "nearby_platform_audio.h"
static const nearby_platform_AudioCallbacks* callbacks;
static bool multipoint = false;
static uint8_t switching_preference_flags = 0;
static uint64_t switch_active_peer_address = 0;
static uint8_t switch_active_flags = 0;
static uint64_t switch_active_preferred_audio_source = 0;
static uint64_t switch_back_peer_address = 0;
static uint8_t switch_back_flags = 0;
static uint64_t notify_peer_address = 0;
static uint8_t notify_flags = 0;
static uint64_t drop_peer_address = 0;
static uint8_t drop_flags = 0;
static uint64_t active_peer_address = 0;
bool nearby_platform_GetEarbudRightStatus() { return false; }
bool nearby_platform_GetEarbudLeftStatus() { return false; }
unsigned int nearby_platform_GetAudioConnectionState() {
return NEARBY_PLATFORM_CONNECTION_STATE_A2DP_WITH_AVRCP;
}
bool nearby_platform_OnHead() { return true; }
// Returns true if the device can accept another audio connection without
// dropping any of the existing connections.
bool nearby_platform_CanAcceptConnection() { return false; }
// When the device is in focus mode, connection switching is not allowed
bool nearby_platform_InFocusMode() { return false; }
// Returns true if the current connection is auto-recconnected, meaning it is
// not connected by the user. For multi-point connections, returns true if any
// of the existing connections is auto-reconnected.
bool nearby_platform_AutoReconnected() { return false; }
// Sets a bit in the |bitmap| for every connected peer. The bit stays cleared
// for bonded but not connected peers. The order change is acceptable if it is
// unavoidable, e.g. when users factory reset the headset or when the bonded
// device count reaches the upper limit.
// |length| is the |bitmap| length on input in bytes and used space on output.
// For example, if there are 5 bonded devices, then |length| should be set to 1.
void nearby_platform_GetConnectionBitmap(uint8_t* bitmap, size_t* length) {
if (*length > 0) {
bitmap[0] = 0x09;
*length = 1;
}
}
bool nearby_platform_IsSassOn() { return true; }
bool nearby_platform_IsMultipointConfigurable() { return true; }
bool nearby_platform_IsMultipointOn() { return multipoint; }
bool nearby_platform_IsOnHeadDetectionSupported() { return true; }
bool nearby_platform_IsOnHeadDetectionEnabled() { return false; }
nearby_platform_status nearby_platform_SetMultipoint(uint64_t peer_address,
bool enable) {
multipoint = enable;
return kNearbyStatusOK;
}
nearby_platform_status nearby_platform_SetSwitchingPreference(uint8_t flags) {
switching_preference_flags = flags;
return kNearbyStatusOK;
}
// Gets switching preference flags
uint8_t nearby_platform_GetSwitchingPreference() {
return switching_preference_flags;
}
nearby_platform_status nearby_platform_SwitchActiveAudioSource(
uint64_t peer_address, uint8_t flags, uint64_t preferred_audio_source) {
switch_active_peer_address = peer_address;
switch_active_flags = flags;
switch_active_preferred_audio_source = preferred_audio_source;
return kNearbyStatusOK;
}
nearby_platform_status nearby_platform_SwitchBackAudioSource(
uint64_t peer_address, uint8_t flags) {
switch_back_peer_address = peer_address;
switch_back_flags = flags;
return kNearbyStatusOK;
}
nearby_platform_status nearby_platform_NotifySassInitiatedConnection(
uint64_t peer_address, uint8_t flags) {
notify_peer_address = peer_address;
notify_flags = flags;
return kNearbyStatusOK;
}
nearby_platform_status nearby_platform_SetDropConnectionTarget(
uint64_t peer_address, uint8_t flags) {
drop_peer_address = peer_address;
drop_flags = flags;
return kNearbyStatusOK;
}
uint64_t nearby_platform_GetActiveAudioSource() { return active_peer_address; }
void nearby_test_fakes_SetActiveAudioSource(uint64_t peer_address) {
active_peer_address = peer_address;
}
// Initializes Audio module
nearby_platform_status nearby_platform_AudioInit(
const nearby_platform_AudioCallbacks* audio_interface) {
multipoint = false;
switching_preference_flags = 0;
switch_active_peer_address = 0;
switch_active_flags = 0;
switch_active_preferred_audio_source = 0;
switch_back_peer_address = 0;
switch_back_flags = 0;
notify_peer_address = 0;
notify_flags = 0;
drop_peer_address = 0;
drop_flags = 0;
callbacks = audio_interface;
return kNearbyStatusOK;
}
uint64_t nearby_test_fakes_GetSassSwitchActiveSourcePeerAddress() {
return switch_active_peer_address;
}
uint8_t nearby_test_fakes_GetSassSwitchActiveSourceFlags() {
return switch_active_flags;
}
uint64_t nearby_test_fakes_GetSassSwitchActiveSourcePreferredAudioSource() {
return switch_active_preferred_audio_source;
}
uint64_t nearby_test_fakes_GetSassSwitchBackPeerAddress() {
return switch_back_peer_address;
}
uint8_t nearby_test_fakes_GetSassSwitchBackFlags() { return switch_back_flags; }
uint64_t nearby_test_fakes_GetSassNotifyInitiatedConnectionPeerAddress() {
return notify_peer_address;
}
uint8_t nearby_test_fakes_GetSassNotifyInitiatedConnectionFlags() {
return notify_flags;
}
uint64_t nearby_test_fakes_GetSassDropConnectionTargetPeerAddress() {
return drop_peer_address;
}
uint8_t nearby_test_fakes_GetSassDropConnectionTargetFlags() {
return drop_flags;
}
void nearby_test_fakes_SassMultipointSwitch(uint8_t reason,
uint64_t peer_address,
const char* name) {
callbacks->on_multipoint_switch_event(reason, peer_address, name);
}
+4 -1
View File
@@ -16,12 +16,13 @@
#include "nearby.h"
#include "nearby_platform_battery.h"
static nearby_platform_BatteryInfo test_battery_info = {
constexpr nearby_platform_BatteryInfo kDefaultBatteryInfo = {
.is_charging = true,
.right_bud_battery_level = 80,
.left_bud_battery_level = 85,
.charging_case_battery_level = 90,
.remaining_time_minutes = 100};
static nearby_platform_BatteryInfo test_battery_info = kDefaultBatteryInfo;
static nearby_platform_status get_battery_info_result = kNearbyStatusOK;
static const nearby_platform_BatteryInterface* battery_interface;
@@ -58,5 +59,7 @@ void nearby_test_fakes_SetGetBatteryInfoResult(nearby_platform_status status) {
nearby_platform_status nearby_platform_BatteryInit(
nearby_platform_BatteryInterface* callbacks) {
battery_interface = callbacks;
test_battery_info = kDefaultBatteryInfo;
get_battery_info_result = kNearbyStatusOK;
return kNearbyStatusOK;
}
+13
View File
@@ -30,6 +30,8 @@ static const nearby_platform_BleInterface* ble_interface;
static std::map<nearby_fp_Characteristic, std::vector<uint8_t>> notifications;
static std::vector<uint8_t> advertisement;
static nearby_fp_AvertisementInterval interval;
constexpr int32_t kDefaultPsm = -1;
static int32_t psm = kDefaultPsm;
std::map<nearby_fp_Characteristic, std::vector<uint8_t>>&
nearby_test_fakes_GetGattNotifications() {
@@ -83,6 +85,8 @@ nearby_platform_status nearby_platform_SetAdvertisement(
return kNearbyStatusOK;
}
int32_t nearby_platform_GetMessageStreamPsm() { return psm; }
// Initializes BLE
nearby_platform_status nearby_platform_BleInit(
const nearby_platform_BleInterface* callbacks) {
@@ -91,9 +95,12 @@ nearby_platform_status nearby_platform_BleInit(
advertisement.clear();
interval = kDisabled;
ble_address = kDefaultBleAddress;
psm = kDefaultPsm;
return kNearbyStatusOK;
}
void nearby_test_fakes_SetPsm(int32_t value) { psm = value; }
std::vector<uint8_t>& nearby_test_fakes_GetAdvertisement() {
return advertisement;
}
@@ -125,3 +132,9 @@ nearby_platform_status nearby_fp_fakes_ReceiveAdditionalData(
return ble_interface->on_gatt_write(peer_address, kAdditionalData, request,
length);
}
nearby_platform_status nearby_fp_fakes_GattReadMessageStreamPsm(
uint8_t* output, size_t* length) {
return ble_interface->on_gatt_read(peer_address, kMessageStreamPsm, output,
length);
}
+24 -4
View File
@@ -13,6 +13,7 @@
// limitations under the License.
#include <cstring>
#include <map>
#include <vector>
#include "nearby_platform_bt.h"
@@ -20,13 +21,16 @@
static const uint32_t kFastPairId = 0x101112;
static const int8_t kTxLevel = 33;
static const uint64_t kPublicAddress = 0xA0A1A2A3A4A5;
// No secondary identity address by default.
static const uint64_t kSecondaryPublicAddress = 0;
static const uint32_t kLocalPasskey = 123456;
static uint32_t remote_passkey;
static uint64_t remote_address;
static uint64_t paired_peer_address;
static std::vector<uint8_t> rfcomm_output;
static std::map<uint64_t, std::vector<uint8_t>> rfcomm_outputs;
static std::vector<char> device_name;
static bool pairing_mode = false;
static uint64_t secondary_public_address = kSecondaryPublicAddress;
static const nearby_platform_BtInterface* bt_interface;
// Returns Fast Pair Model Id.
@@ -37,6 +41,10 @@ int8_t nearby_platform_GetTxLevel() { return kTxLevel; }
// Returns public BR/EDR address
uint64_t nearby_platform_GetPublicAddress() { return kPublicAddress; }
uint64_t nearby_platform_GetSecondaryPublicAddress() {
return secondary_public_address;
}
// Returns passkey used during pairing
uint32_t nearby_platfrom_GetPairingPassKey() { return kLocalPasskey; }
@@ -71,6 +79,8 @@ nearby_platform_status nearby_platform_BtInit(
remote_passkey = 0;
paired_peer_address = 0;
pairing_mode = false;
secondary_public_address = kSecondaryPublicAddress;
rfcomm_outputs.clear();
return kNearbyStatusOK;
}
@@ -85,6 +95,10 @@ void nearby_test_fakes_SimulatePairing(uint64_t peer_address) {
}
}
void nearby_test_fakes_SetSecondaryPublicAddress(uint64_t address) {
secondary_public_address = address;
}
uint64_t nearby_test_fakes_GetPairedDevice() { return paired_peer_address; }
void nearby_test_fakes_DevicePaired(uint64_t peer_address) {
@@ -94,14 +108,20 @@ void nearby_test_fakes_DevicePaired(uint64_t peer_address) {
nearby_platform_status nearby_platform_SendMessageStream(uint64_t peer_address,
const uint8_t* message,
size_t length) {
rfcomm_outputs.emplace(peer_address, std::vector<uint8_t>());
auto rfcomm_output = rfcomm_outputs.find(peer_address);
for (int i = 0; i < length; i++) {
rfcomm_output.push_back(message[i]);
rfcomm_output->second.push_back(message[i]);
}
return kNearbyStatusOK;
}
std::vector<uint8_t>& nearby_test_fakes_GetRfcommOutput(uint64_t peer_address) {
return rfcomm_outputs[peer_address];
}
std::vector<uint8_t>& nearby_test_fakes_GetRfcommOutput() {
return rfcomm_output;
return nearby_test_fakes_GetRfcommOutput(paired_peer_address);
}
nearby_platform_status nearby_platform_SetDeviceName(const char* name) {
@@ -128,7 +148,7 @@ void nearby_test_fakes_SetInPairingMode(bool in_pairing_mode) {
pairing_mode = in_pairing_mode;
}
#ifdef NEARBY_FP_MESSAGE_STREAM
#if NEARBY_FP_MESSAGE_STREAM
void nearby_test_fakes_MessageStreamConnected(uint64_t peer_address) {
bt_interface->on_message_stream_connected(peer_address);
}
+79 -15
View File
@@ -25,14 +25,19 @@
void nearby_test_fakes_SetRandomNumber(unsigned int value);
void nearby_test_fakes_SetRandomNumberSequence(std::vector<uint8_t>& value);
void nearby_test_fakes_SetAccountKeys(const uint8_t* input, size_t length);
std::vector<uint8_t> nearby_test_fakes_GetRawAccountKeys();
nearby_platform_status nearby_test_fakes_GattReadModelId(uint8_t* output,
size_t* length);
#ifdef MBEDTLS_FOR_SSL
extern "C" {
#endif
nearby_platform_status nearby_test_fakes_SetAntiSpoofingKey(
const uint8_t private_key[32], const uint8_t public_key[64]);
#ifdef MBEDTLS_FOR_SSL
}
#endif
nearby_platform_status nearby_test_fakes_GenSec256r1Secret(
const uint8_t remote_party_public_key[64], uint8_t secret[32]);
@@ -60,41 +65,79 @@ nearby_platform_status nearby_fp_fakes_ReceiveAccountKeyWrite(
const uint8_t* request, size_t length);
nearby_platform_status nearby_fp_fakes_ReceiveAdditionalData(
const uint8_t* request, size_t length);
nearby_platform_status nearby_fp_fakes_GattReadMessageStreamPsm(uint8_t* output,
size_t* length);
uint64_t nearby_test_fakes_GetPairingRequestAddress();
uint32_t nearby_test_fakes_GetRemotePasskey();
uint64_t nearby_test_fakes_GetPairedDevice();
void nearby_test_fakes_DevicePaired(uint64_t peer_address);
class AccountKeyPair {
public:
AccountKeyPair(uint64_t bt_address, const std::vector<uint8_t>& account_key)
: address_(bt_address), account_key_(account_key) {}
AccountKeyPair(uint64_t bt_address, const uint8_t* account_key)
: address_(bt_address),
account_key_(account_key, account_key + ACCOUNT_KEY_SIZE_BYTES) {}
uint64_t address_;
std::vector<uint8_t> account_key_;
};
struct RawAccountKeyList {
uint8_t num_keys;
nearby_platform_AccountKeyInfo key[NEARBY_MAX_ACCOUNT_KEYS];
};
class AccountKeyList {
public:
explicit AccountKeyList(const std::vector<uint8_t>& raw_values) {
if (raw_values.size() == 0) return;
int key_count = raw_values[0];
for (int i = 0; i < key_count; i++) {
const uint8_t* p = raw_values.data() + 1 + (i * ACCOUNT_KEY_SIZE_BYTES);
keys_.emplace_back(std::vector<uint8_t>(p, p + ACCOUNT_KEY_SIZE_BYTES));
const RawAccountKeyList* list =
reinterpret_cast<const RawAccountKeyList*>(raw_values.data());
if (!list) return;
for (size_t i = 0; i < list->num_keys; i++) {
uint64_t address = 0;
#ifdef NEARBY_FP_ENABLE_SASS
address = list->key[i].peer_address;
#endif /* NEARBY_FP_ENABLE_SASS */
key_pairs_.emplace_back(
address, std::vector<uint8_t>(
list->key[i].account_key,
list->key[i].account_key + ACCOUNT_KEY_SIZE_BYTES));
}
}
explicit AccountKeyList(const std::vector<AccountKeyPair>& key_pairs)
: key_pairs_(key_pairs) {}
size_t size() { return keys_.size(); }
size_t size() { return key_pairs_.size(); }
std::vector<std::vector<uint8_t>>& GetKeys() { return keys_; }
std::vector<uint8_t> GetKey(int index) {
return key_pairs_[index].account_key_;
}
std::vector<uint8_t> GetRawFormat() {
std::vector<uint8_t> result;
result.push_back(size());
for (auto& key : keys_) {
for (auto& v : key) {
result.push_back(v);
RawAccountKeyList account_keys;
account_keys.num_keys = size();
for (size_t i = 0; i < size(); i++) {
#ifdef NEARBY_FP_ENABLE_SASS
account_keys.key[i].peer_address = key_pairs_[i].address_;
#endif /* NEARBY_FP_ENABLE_SASS */
for (size_t j = 0; j < key_pairs_[i].account_key_.size(); j++) {
account_keys.key[i].account_key[j] = key_pairs_[i].account_key_[j];
}
}
return result;
uint8_t* p = reinterpret_cast<uint8_t*>(&account_keys);
return std::vector<uint8_t>(p, p + sizeof(account_keys));
}
private:
std::vector<std::vector<uint8_t>> keys_;
std::vector<AccountKeyPair> key_pairs_;
};
void nearby_test_fakes_SetAccountKeys(const uint8_t* input, size_t length);
void nearby_test_fakes_SetAccountKeys(
std::vector<AccountKeyPair>& account_key_pairs);
void nearby_test_fakes_SetAccountKeys(AccountKeyList& keys);
AccountKeyList nearby_test_fakes_GetAccountKeys();
@@ -112,6 +155,7 @@ void nearby_test_fakes_BatteryTime(uint16_t battery_time);
void nearby_test_fakes_SetGetBatteryInfoResult(nearby_platform_status status);
std::vector<uint8_t>& nearby_test_fakes_GetRfcommOutput();
std::vector<uint8_t>& nearby_test_fakes_GetRfcommOutput(uint64_t peer_address);
void nearby_test_fakes_MessageStreamConnected(uint64_t peer_address);
@@ -130,5 +174,25 @@ void nearby_test_fakes_SetInPairingMode(bool in_pairing_mode);
uint8_t nearby_test_fakes_GetRingCommand(void);
uint16_t nearby_test_fakes_GetRingTimeout(void);
uint64_t nearby_test_fakes_GetSassSwitchActiveSourcePeerAddress();
uint8_t nearby_test_fakes_GetSassSwitchActiveSourceFlags();
uint64_t nearby_test_fakes_GetSassSwitchActiveSourcePreferredAudioSource();
uint64_t nearby_test_fakes_GetSassSwitchBackPeerAddress();
uint8_t nearby_test_fakes_GetSassSwitchBackFlags();
uint64_t nearby_test_fakes_GetSassNotifyInitiatedConnectionPeerAddress();
uint8_t nearby_test_fakes_GetSassNotifyInitiatedConnectionFlags();
uint64_t nearby_test_fakes_GetSassDropConnectionTargetPeerAddress();
uint8_t nearby_test_fakes_GetSassDropConnectionTargetFlags();
void nearby_test_fakes_SassMultipointSwitch(uint8_t reason,
uint64_t peer_address,
const char* name);
#ifdef NEARBY_FP_ENABLE_SASS
void nearby_test_fakes_SetActiveAudioSource(uint64_t peer_address);
#endif /* NEARBY_FP_ENABLE_SASS */
void nearby_test_fakes_SetPsm(int32_t value);
void nearby_test_fakes_SetSecondaryPublicAddress(uint64_t address);
#endif /* NEARBY_TEST_FAKES_H */
@@ -51,6 +51,12 @@ nearby_platform_status nearby_platform_PersistenceInit() {
return kNearbyStatusOK;
}
void nearby_test_fakes_SetAccountKeys(
std::vector<AccountKeyPair>& account_key_pairs) {
AccountKeyList list(account_key_pairs);
nearby_test_fakes_SetAccountKeys(list);
}
void nearby_test_fakes_SetAccountKeys(const uint8_t* input, size_t length) {
storage[kStoredKeyAccountKeyList].assign(input, input + length);
}
+32 -19
View File
@@ -28,9 +28,13 @@
#include "fakes.h"
#include "nearby_platform_se.h"
#pragma GCC diagnostic ignored "-Wunused-function"
static unsigned int random_value = 0;
static std::queue<uint8_t> random_sequence;
static uint8_t private_key_store[32];
static std::unique_ptr<EVP_PKEY, void (*)(EVP_PKEY *)> anti_spoofing_key(
NULL, EVP_PKEY_free);
@@ -54,7 +58,7 @@ uint8_t nearby_platform_Rand() {
}
}
#ifdef NEARBY_FP_ENABLE_ADDITIONAL_DATA
#ifndef NEARBY_PLATFORM_USE_MBEDTLS
static SHA256_CTX sha256_context;
nearby_platform_status nearby_platform_Sha256Start() {
@@ -72,7 +76,6 @@ nearby_platform_status nearby_platform_Sha256Finish(uint8_t out[32]) {
SHA256_Final(out, &sha256_context);
return kNearbyStatusOK;
}
#endif /* NEARBY_FP_ENABLE_ADDITIONAL_DATA */
// Encrypts a data block with AES128 in ECB mode.
nearby_platform_status nearby_platform_Aes128Encrypt(const uint8_t input[16],
@@ -102,6 +105,7 @@ nearby_platform_status nearby_platform_Aes128Decrypt(const uint8_t input[16],
int output_length = 16;
EVP_DecryptInit(ctx, EVP_aes_128_ecb(), key, NULL);
EVP_CIPHER_CTX_set_padding(ctx, 0);
if (1 !=
EVP_DecryptUpdate(ctx, output, &output_length, input, input_length)) {
@@ -111,6 +115,7 @@ nearby_platform_status nearby_platform_Aes128Decrypt(const uint8_t input[16],
EVP_CIPHER_CTX_free(ctx);
return kNearbyStatusOK;
}
#endif /* NEARBY_PLATFORM_USE_MBEDTLS */
static EC_POINT *load_public_key(const uint8_t public_key[64]) {
BN_CTX *bn_ctx;
@@ -132,6 +137,16 @@ static EC_POINT *load_public_key(const uint8_t public_key[64]) {
return point;
}
static BIGNUM *load_private_key(const uint8_t private_key[32]) {
uint8_t buffer[37];
buffer[0] = buffer[1] = buffer[2] = 0;
buffer[3] = 33;
buffer[4] = 0;
memcpy(buffer + 5, private_key, 32);
return BN_mpi2bn(buffer, sizeof(buffer), NULL);
}
#ifdef NEARBY_PLATFORM_HAS_SE
// Generates a shared sec256p1 secret using remote party public key and this
// device's private key.
nearby_platform_status nearby_platform_GenSec256r1Secret(
@@ -177,16 +192,9 @@ nearby_platform_status nearby_platform_GenSec256r1Secret(
EC_POINT_free(peer_point);
EVP_PKEY_free(peerkey);
std::cout << "Secret: " << ArrayToString(secret, 32) << std::endl;
return kNearbyStatusOK;
}
// Initializes secure element module
nearby_platform_status nearby_platform_SecureElementInit() {
random_value = 0;
random_sequence = std::queue<uint8_t>();
return kNearbyStatusOK;
}
#endif /* NEARBY_PLATFORM_HAS_SE */
void nearby_test_fakes_SetRandomNumber(unsigned int value) {
random_value = value;
@@ -196,15 +204,6 @@ void nearby_test_fakes_SetRandomNumberSequence(std::vector<uint8_t> &value) {
for (auto &v : value) random_sequence.push(v);
}
static BIGNUM *load_private_key(const uint8_t private_key[32]) {
uint8_t buffer[37];
buffer[0] = buffer[1] = buffer[2] = 0;
buffer[3] = 33;
buffer[4] = 0;
memcpy(buffer + 5, private_key, 32);
return BN_mpi2bn(buffer, sizeof(buffer), NULL);
}
nearby_platform_status nearby_test_fakes_SetAntiSpoofingKey(
const uint8_t private_key[32], const uint8_t public_key[64]) {
EC_KEY *key;
@@ -224,6 +223,9 @@ nearby_platform_status nearby_test_fakes_SetAntiSpoofingKey(
anti_spoofing_key.reset(EVP_PKEY_new());
if (1 != EVP_PKEY_assign_EC_KEY(anti_spoofing_key.get(), key))
return kNearbyStatusError;
memcpy(private_key_store, private_key, 32);
BN_free(prv);
EC_POINT_free(pub);
return kNearbyStatusOK;
@@ -247,3 +249,14 @@ nearby_platform_status nearby_test_fakes_Aes128Encrypt(
const uint8_t key[AES_MESSAGE_SIZE_BYTES]) {
return nearby_platform_Aes128Encrypt(input, output, key);
}
const uint8_t *nearby_platform_GetAntiSpoofingPrivateKey() {
return private_key_store;
}
// Initializes secure element module
nearby_platform_status nearby_platform_SecureElementInit() {
random_value = 0;
random_sequence = std::queue<uint8_t>();
return kNearbyStatusOK;
}