From 1f02913a2c6d7b880de5c82599a03e865ce6a015 Mon Sep 17 00:00:00 2001 From: Vincent Coubard Date: Wed, 11 Apr 2018 14:18:42 +0100 Subject: [PATCH 1/3] BLE: Add Gap privacy interfaces. This commit adds API to enable and configure the device privacy. It deprecates address random types present in Gap::AddressType as these types are not appropriate for scan reports, connection initiation and the connection event. Now user should use the function Gap::getRandomAddressType to find the type of a random address. The function gap::setAddress is deprecated as it is not portable and can colide with privacy. --- features/FEATURE_BLE/ble/BLEProtocol.h | 33 +++ features/FEATURE_BLE/ble/BLETypes.h | 18 ++ features/FEATURE_BLE/ble/Gap.h | 294 ++++++++++++++++++++++++- features/FEATURE_BLE/source/Gap.cpp | 36 +++ 4 files changed, 375 insertions(+), 6 deletions(-) create mode 100644 features/FEATURE_BLE/source/Gap.cpp diff --git a/features/FEATURE_BLE/ble/BLEProtocol.h b/features/FEATURE_BLE/ble/BLEProtocol.h index 4fdcb59bc5c..79e3357bec1 100644 --- a/features/FEATURE_BLE/ble/BLEProtocol.h +++ b/features/FEATURE_BLE/ble/BLEProtocol.h @@ -59,18 +59,51 @@ namespace BLEProtocol { */ PUBLIC = 0, + /** + * Random address. + * + * Use Gap::getRandomAddressType to retrieve the type of the random + * address. + */ + RANDOM, + + /** + * A Public address used as a device identity address. + */ + PUBLIC_IDENTITY, + + /** + * A Random static address used as a device identity address. + */ + RANDOM_STATIC_IDENTITY, + /** * Random static device address. + * + * @deprecated This enumeration value is not relevant anymore. + * Advertising reporting and the connection procedure should rely + * on RANDOM instead. Use Gap::getRandomAddressType to retrieve the + * type of the random address. */ RANDOM_STATIC, /** * Private resolvable device address. + * + * @deprecated This enumeration value is not relevant anymore. + * Advertising reporting and the connection procedure should rely + * on RANDOM instead. Use Gap::getRandomAddressType to retrieve the + * type of the random address. */ RANDOM_PRIVATE_RESOLVABLE, /** * Private non-resolvable device address. + * + * @deprecated This enumeration value is not relevant anymore. + * Advertising reporting and the connection procedure should rely + * on RANDOM instead. Use Gap::getRandomAddressType to retrieve the + * type of the random address. */ RANDOM_PRIVATE_NON_RESOLVABLE }; diff --git a/features/FEATURE_BLE/ble/BLETypes.h b/features/FEATURE_BLE/ble/BLETypes.h index a5ece317577..41e4c99f131 100644 --- a/features/FEATURE_BLE/ble/BLETypes.h +++ b/features/FEATURE_BLE/ble/BLETypes.h @@ -442,6 +442,24 @@ struct address_t : public byte_array_t<6> { } }; +/** + * Type that describes a random device address type. + */ +struct random_address_type_t : SafeEnum { + /** struct scoped enum wrapped by the class */ + enum type { + STATIC, /**< Random static device address. */ + NON_RESOLVABLE_PRIVATE, /**< Random non resolvable private address. */ + RESOLVABLE_PRIVATE /**< Random resolvable private address. */ + }; + + /** + * Construct a new instance of random_address_type_t. + */ + random_address_type_t(type value) : + SafeEnum(value) { } +}; + } // namespace ble /** diff --git a/features/FEATURE_BLE/ble/Gap.h b/features/FEATURE_BLE/ble/Gap.h index d42c5826fc5..095c1c8bc24 100644 --- a/features/FEATURE_BLE/ble/Gap.h +++ b/features/FEATURE_BLE/ble/Gap.h @@ -294,6 +294,9 @@ class Gap { */ enum DeprecatedAddressType_t { ADDR_TYPE_PUBLIC = BLEProtocol::AddressType::PUBLIC, + ADDR_TYPE_RANDOM = BLEProtocol::AddressType::RANDOM, + ADDR_TYPE_PUBLIC_IDENTITY = BLEProtocol::AddressType::PUBLIC_IDENTITY, + ADDR_TYPE_RANDOM_STATIC_IDENTITY = BLEProtocol::AddressType::RANDOM_STATIC_IDENTITY, ADDR_TYPE_RANDOM_STATIC = BLEProtocol::AddressType::RANDOM_STATIC, ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE = BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE, ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE = BLEProtocol::AddressType::RANDOM_PRIVATE_NON_RESOLVABLE @@ -353,6 +356,12 @@ class Gap { * disconnection reason to be transmitted to the peer. */ enum DisconnectionReason_t { + + /** + * GAP or GATT failed to authenticate the peer. + */ + AUTHENTICATION_FAILLURE = 0x05, + /** * The connection timed out. * @@ -496,6 +505,11 @@ class Gap { */ typedef ble::connection_handle_t Handle_t; + /** + * Enumeration of random address types. + */ + typedef ble::random_address_type_t RandomAddressType_t; + /** * Parameters of a BLE connection. */ @@ -610,7 +624,10 @@ class Gap { const uint8_t *advertisingData; /** - * Type of the address received + * Type of the address received. + * + * @note This value should be used in the connect function to establish + * a connection with the peer that has sent this advertisement packet. */ AddressType_t addressType; }; @@ -667,6 +684,20 @@ class Gap { */ const ConnectionParams_t *connectionParams; + /** + * Resolvable address used by the peer. + * + * @note All bytes of the address are set to 0 if not applicable + */ + BLEProtocol::AddressBytes_t peerResolvableAddr; + + /** + * resolvable address of the local device. + * + * @note All bytes of the address are set to 0 if not applicable + */ + BLEProtocol::AddressBytes_t localResolvableAddr; + /** * Construct an instance of ConnectionCallbackParams_t. * @@ -677,6 +708,8 @@ class Gap { * @param[in] ownAddrTypeIn Value to assign to ownAddrType. * @param[in] ownAddrIn Value to assign to ownAddr. * @param[in] connectionParamsIn Value to assign to connectionParams. + * @param[in] peerResolvableAddrIn Value to assign to peerResolvableAddr. + * @param[in] localResolvableAddrIn Value to assign to localResolvableAddr. * * @note Constructor is not meant to be called by user code. * The BLE API vendor code generates ConnectionCallbackParams_t. @@ -688,17 +721,28 @@ class Gap { const uint8_t *peerAddrIn, BLEProtocol::AddressType_t ownAddrTypeIn, const uint8_t *ownAddrIn, - const ConnectionParams_t *connectionParamsIn + const ConnectionParams_t *connectionParamsIn, + const uint8_t *peerResolvableAddrIn = NULL, + const uint8_t *localResolvableAddrIn = NULL ) : handle(handleIn), role(roleIn), peerAddrType(peerAddrTypeIn), peerAddr(), ownAddrType(ownAddrTypeIn), ownAddr(), - connectionParams(connectionParamsIn) + connectionParams(connectionParamsIn), + peerResolvableAddr(), + localResolvableAddr() { memcpy(peerAddr, peerAddrIn, ADDR_LEN); memcpy(ownAddr, ownAddrIn, ADDR_LEN); + if (peerResolvableAddrIn) { + memcpy(peerResolvableAddr, peerResolvableAddrIn, ADDR_LEN); + } + + if (localResolvableAddrIn) { + memcpy(localResolvableAddr, localResolvableAddrIn, ADDR_LEN); + } } }; @@ -736,6 +780,107 @@ class Gap { {} }; + /** + * Privacy Configuration of the peripheral role. + * + * @note This configuration also apply to the broadcaster role configuration. + */ + struct PeripheralPrivacyConfiguration_t { + /** + * Indicates if non resolvable random address should be used when the + * peripheral advertise non connectable packets. + * + * Resolvable random address continue to be used for connectable packets. + */ + bool use_non_resolvable_random_address; + + /** + * Resolution strategy of initiator resolvable addresses when a + * connection request is received. + */ + enum ResolutionStrategy { + /** + * Do not resolve the address of the initiator and accept the + * connection request. + */ + DO_NOT_RESOLVE, + + /** + * If a bond is present in the secure database and the address + * resolution fail then reject the connection request with the error + * code AUTHENTICATION_FAILLURE. + */ + REJECT_NON_RESOLVED_ADDRESS, + + /** + * Perform the pairing procedure if the initiator resolvable + * address failed the resolution process. + */ + PERFORM_PAIRING_PROCEDURE, + + /** + * Perform the authentication procedure if the initiator resolvable + * address failed the resolution process. + */ + PERFORM_AUTHENTICATION_PROCEDURE + }; + + /** + * Connection strategy to use when a connection request contains a + * private resolvable address. + */ + ResolutionStrategy resolution_strategy; + }; + + /** + * Privacy Configuration of the central role. + * + * @note This configuration encompass the observer role configuration. + */ + struct CentralPrivacyConfiguration_t { + /** + * Indicates if non resolvable random address should be used when the + * central or observer sends scan request packets. + * + * Resolvable random address continue to be used for connection requests. + */ + bool use_non_resolvable_random_address; + + + /** + * Resolution strategy of resolvable addresses received in advertising + * packets. + */ + enum ResolutionStrategy { + /** + * Do not resolve the address received in advertising packets. + */ + DO_NOT_RESOLVE, + + /** + * Resolve the resolvable addresses in the advertising packet and + * forward advertising packet to the application independently of + * the address resolution procedure result. + */ + RESOLVE_AND_FORWARD, + + /** + * Filter out packets containing a resolvable that cannot be resolved + * by this device. + * + * @note Filtering is applied if the local device contains at least + * one bond. + */ + RESOLVE_AND_FILTER + }; + + /** + * Resolution strategy applied to advertising packets received by the + * local device. + */ + ResolutionStrategy resolution_strategy; + }; + /** * Number of microseconds in 1.25 milliseconds. */ @@ -844,8 +989,29 @@ class Gap { * @note Some implementation may refuse to set a new PUBLIC address. * @note Random static address set does not change. * + * @deprecated Starting with mbed-os-5.9.0 this function is deprecated and + * address management is delegated to implementation. Implementations may or + * may not continue to support this function. Compliance with the Bluetooth + * specification and unification of behaviour between implementations are + * the key reasons behind this change: + * - Many implementations does not allow replacement of the public + * address. Therefore programs relying on this function are not portable + * across BLE implementations. + * - The Bluetooth specification forbid replacement of the random static + * address; this address can be set once and only once: at startup. + * Depending on the underlying implementation the random address may or + * may not have been set automatically at startup; therefore update of the + * Random Static address after ble initialisation may be a fault. As a + * result calls to this function were not portable. + * Furthermore replacement of the random static address silently + * invalidates the bond stored in the secure database. + * @return BLE_ERROR_NONE on success. */ + MBED_DEPRECATED_SINCE( + "mbed-os-5.9.0", + "Non portable API, use enablePrivacy to enable use of private addresses" + ) virtual ble_error_t setAddress( BLEProtocol::AddressType_t type, const BLEProtocol::AddressBytes_t address @@ -865,6 +1031,9 @@ class Gap { * @param[out] typeP Type of the current address set. * @param[out] address Value of the current address. * + * @note If privacy is enabled the device address may be unavailable to + * application code. + * * @return BLE_ERROR_NONE on success. */ virtual ble_error_t getAddress( @@ -880,6 +1049,22 @@ class Gap { return BLE_ERROR_NOT_IMPLEMENTED; } + /** + * Return the type of a random address. + * + * @param[in] address The random address to retrieve the type from. The # + * address must be ordered in little endian. + * + * @param[out] addressType Type of the address to fill. + * + * @return BLE_ERROR_NONE in case of success or BLE_ERROR_INVALID_PARAM if + * the address in input was not identifiable as a random address. + */ + static ble_error_t getRandomAddressType( + BLEProtocol::AddressBytes_t address, + RandomAddressType_t& addressType + ); + /** * Get the minimum advertising interval in milliseconds, which can be used * for connectable advertising types. @@ -1955,6 +2140,97 @@ class Gap { return BLE_ERROR_NOT_IMPLEMENTED; } + /** + * Enable or disable privacy mode of the local device. + * + * When privacy is enabled, the system use private addresses while it scans, + * advertises or initiate a connection. The device private address is + * renewed every 15 minutes. + * + * @par Configuration + * + * The privacy feature can be configured with the help of the functions + * setPeripheralPrivacyConfiguration and setCentralPrivacyConfiguration + * which respectively set the privacy configuration of the peripheral and + * central role. + * + * @par Default configuration of peripheral role + * + * By default private resolvable address are used for all procedures; + * including advertisement of non connectable packets. Connection request + * from an unknown initiator with a private resolvable address triggers the + * pairing procedure. + * + * @par Default configuration of central role + * + * By default private resolvable address are used for all procedures; + * including active scanning. Address present in advertisement packet are + * resolved and advertisement packets are forwarded to the application + * even if the advertiser private address is unknown. + * + * @param enable[in] Should be set to true to enable the privacy mode and false + * to disable it. + * + * @return BLE_ERROR_NONE in case of success or an appropriate error code. + */ + virtual ble_error_t enablePrivacy(bool enable) { + return BLE_ERROR_NOT_IMPLEMENTED; + } + + /** + * Set the privacy configuration used by the peripheral role. + * + * @param[in] configuration The configuration to set. + * + * @return BLE_ERROR_NONE in case of success or an appropriate error code. + */ + virtual ble_error_t setPeripheralPrivacyConfiguration( + const PeripheralPrivacyConfiguration_t &configuration + ) { + return BLE_ERROR_NOT_IMPLEMENTED; + } + + /** + * Get the privacy configuration used by the peripheral role. + * + * @param[out] configuration The variable filled with the current + * configuration. + * + * @return BLE_ERROR_NONE in case of success or an appropriate error code. + */ + virtual ble_error_t getPeripheralPrivacyConfiguration( + PeripheralPrivacyConfiguration_t &configuration + ) { + return BLE_ERROR_NOT_IMPLEMENTED; + } + + /** + * Set the privacy configuration used by the central role. + * + * @param[in] configuration The configuration to set. + * + * @return BLE_ERROR_NONE in case of success or an appropriate error code. + */ + virtual ble_error_t setCentralPrivacyConfiguration( + const CentralPrivacyConfiguration_t &configuration + ) { + return BLE_ERROR_NOT_IMPLEMENTED; + } + + /** + * Get the privacy configuration used by the central role. + * + * @param[out] configuration The variable filled with the current + * configuration. + * + * @return BLE_ERROR_NONE in case of success or an appropriate error code. + */ + virtual ble_error_t getCentralPrivacyConfiguration( + CentralPrivacyConfiguration_t &configuration + ) { + return BLE_ERROR_NOT_IMPLEMENTED; + } + private: /** * Set the advertising data and scan response in the vendor subsytem. @@ -2285,6 +2561,8 @@ class Gap { * connection. * @param[in] ownAddr Address this device uses for this connection. * @param[in] connectionParams Parameters of the connection. + * @param[in] peerResolvableAddr Resolvable address used by the peer. + * @param[in] localResolvableAddr resolvable address used by the local device. */ void processConnectionEvent( Handle_t handle, @@ -2293,7 +2571,9 @@ class Gap { const BLEProtocol::AddressBytes_t peerAddr, BLEProtocol::AddressType_t ownAddrType, const BLEProtocol::AddressBytes_t ownAddr, - const ConnectionParams_t *connectionParams + const ConnectionParams_t *connectionParams, + const uint8_t *peerResolvableAddr = NULL, + const uint8_t *localResolvableAddr = NULL ) { /* Update Gap state */ state.advertising = 0; @@ -2307,7 +2587,9 @@ class Gap { peerAddr, ownAddrType, ownAddr, - connectionParams + connectionParams, + peerResolvableAddr, + localResolvableAddr ); connectionCallChain.call(&callbackParams); @@ -2357,7 +2639,7 @@ class Gap { GapAdvertisingParams::AdvertisingType_t type, uint8_t advertisingDataLen, const uint8_t *advertisingData, - BLEProtocol::AddressType_t addressType = BLEProtocol::AddressType::RANDOM_STATIC + BLEProtocol::AddressType_t addressType = BLEProtocol::AddressType::RANDOM ) { // FIXME: remove default parameter for addressType when ST shield is merged; // this has been added to mitigate the lack of dependency management in diff --git a/features/FEATURE_BLE/source/Gap.cpp b/features/FEATURE_BLE/source/Gap.cpp new file mode 100644 index 00000000000..c25be9fd4eb --- /dev/null +++ b/features/FEATURE_BLE/source/Gap.cpp @@ -0,0 +1,36 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ble/Gap.h" + +ble_error_t Gap::getRandomAddressType(BLEProtocol::AddressBytes_t address, RandomAddressType_t& type) +{ + // see section Device address in Bluetooth Link Layer specification + // (Vol 6 - Part B) + switch (address[5] >> 6) { + case 0x03: + type = RandomAddressType_t::STATIC; + return BLE_ERROR_NONE; + case 0x00: + type = RandomAddressType_t::NON_RESOLVABLE_PRIVATE; + return BLE_ERROR_NONE; + case 0x02: + type = RandomAddressType_t::RESOLVABLE_PRIVATE; + return BLE_ERROR_NONE; + default: + return BLE_ERROR_INVALID_PARAM; + } +} From 2811e0086850a3dd5d51316944dddc773256028a Mon Sep 17 00:00:00 2001 From: Vincent Coubard Date: Thu, 12 Apr 2018 10:37:13 +0100 Subject: [PATCH 2/3] BLE: Fix Gap privacy related documentation --- features/FEATURE_BLE/ble/Gap.h | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/features/FEATURE_BLE/ble/Gap.h b/features/FEATURE_BLE/ble/Gap.h index 095c1c8bc24..c87f82774d1 100644 --- a/features/FEATURE_BLE/ble/Gap.h +++ b/features/FEATURE_BLE/ble/Gap.h @@ -360,7 +360,7 @@ class Gap { /** * GAP or GATT failed to authenticate the peer. */ - AUTHENTICATION_FAILLURE = 0x05, + AUTHENTICATION_FAILURE = 0x05, /** * The connection timed out. @@ -783,19 +783,19 @@ class Gap { /** * Privacy Configuration of the peripheral role. * - * @note This configuration also apply to the broadcaster role configuration. + * @note This configuration also applies to the broadcaster role configuration. */ struct PeripheralPrivacyConfiguration_t { /** * Indicates if non resolvable random address should be used when the - * peripheral advertise non connectable packets. + * peripheral advertises non connectable packets. * - * Resolvable random address continue to be used for connectable packets. + * Resolvable random address continues to be used for connectable packets. */ bool use_non_resolvable_random_address; /** - * Resolution strategy of initiator resolvable addresses when a + * Resolution strategy for initiator resolvable addresses when a * connection request is received. */ enum ResolutionStrategy { @@ -835,7 +835,8 @@ class Gap { /** * Privacy Configuration of the central role. * - * @note This configuration encompass the observer role configuration. + * @note This configuration is also used when the local device operates as + * an observer. */ struct CentralPrivacyConfiguration_t { /** @@ -994,9 +995,9 @@ class Gap { * may not continue to support this function. Compliance with the Bluetooth * specification and unification of behaviour between implementations are * the key reasons behind this change: - * - Many implementations does not allow replacement of the public - * address. Therefore programs relying on this function are not portable - * across BLE implementations. + * - Many implementations do not allow changing of the public address. + * Therefore programs relying on this function are not portable across BLE + * implementations. * - The Bluetooth specification forbid replacement of the random static * address; this address can be set once and only once: at startup. * Depending on the underlying implementation the random address may or @@ -1052,7 +1053,7 @@ class Gap { /** * Return the type of a random address. * - * @param[in] address The random address to retrieve the type from. The # + * @param[in] address The random address to retrieve the type from. The * address must be ordered in little endian. * * @param[out] addressType Type of the address to fill. @@ -1062,7 +1063,7 @@ class Gap { */ static ble_error_t getRandomAddressType( BLEProtocol::AddressBytes_t address, - RandomAddressType_t& addressType + RandomAddressType_t* addressType ); /** @@ -2156,20 +2157,20 @@ class Gap { * * @par Default configuration of peripheral role * - * By default private resolvable address are used for all procedures; + * By default private resolvable addresses are used for all procedures; * including advertisement of non connectable packets. Connection request * from an unknown initiator with a private resolvable address triggers the * pairing procedure. * * @par Default configuration of central role * - * By default private resolvable address are used for all procedures; - * including active scanning. Address present in advertisement packet are + * By default private resolvable addresses are used for all procedures; + * including active scanning. Addresses present in advertisement packet are * resolved and advertisement packets are forwarded to the application * even if the advertiser private address is unknown. * - * @param enable[in] Should be set to true to enable the privacy mode and false - * to disable it. + * @param enable[in] Should be set to true to enable the privacy mode and + * false to disable it. * * @return BLE_ERROR_NONE in case of success or an appropriate error code. */ From 90c85955ad1615a3c9584e9519d60b35dc19fe56 Mon Sep 17 00:00:00 2001 From: Vincent Coubard Date: Thu, 12 Apr 2018 11:04:44 +0100 Subject: [PATCH 3/3] BLE: Fix GAP privacy related signatures. --- features/FEATURE_BLE/ble/Gap.h | 8 ++++---- features/FEATURE_BLE/source/Gap.cpp | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/features/FEATURE_BLE/ble/Gap.h b/features/FEATURE_BLE/ble/Gap.h index c87f82774d1..17abea4441d 100644 --- a/features/FEATURE_BLE/ble/Gap.h +++ b/features/FEATURE_BLE/ble/Gap.h @@ -2186,7 +2186,7 @@ class Gap { * @return BLE_ERROR_NONE in case of success or an appropriate error code. */ virtual ble_error_t setPeripheralPrivacyConfiguration( - const PeripheralPrivacyConfiguration_t &configuration + const PeripheralPrivacyConfiguration_t *configuration ) { return BLE_ERROR_NOT_IMPLEMENTED; } @@ -2200,7 +2200,7 @@ class Gap { * @return BLE_ERROR_NONE in case of success or an appropriate error code. */ virtual ble_error_t getPeripheralPrivacyConfiguration( - PeripheralPrivacyConfiguration_t &configuration + PeripheralPrivacyConfiguration_t *configuration ) { return BLE_ERROR_NOT_IMPLEMENTED; } @@ -2213,7 +2213,7 @@ class Gap { * @return BLE_ERROR_NONE in case of success or an appropriate error code. */ virtual ble_error_t setCentralPrivacyConfiguration( - const CentralPrivacyConfiguration_t &configuration + const CentralPrivacyConfiguration_t *configuration ) { return BLE_ERROR_NOT_IMPLEMENTED; } @@ -2227,7 +2227,7 @@ class Gap { * @return BLE_ERROR_NONE in case of success or an appropriate error code. */ virtual ble_error_t getCentralPrivacyConfiguration( - CentralPrivacyConfiguration_t &configuration + CentralPrivacyConfiguration_t *configuration ) { return BLE_ERROR_NOT_IMPLEMENTED; } diff --git a/features/FEATURE_BLE/source/Gap.cpp b/features/FEATURE_BLE/source/Gap.cpp index c25be9fd4eb..3793c0c46c3 100644 --- a/features/FEATURE_BLE/source/Gap.cpp +++ b/features/FEATURE_BLE/source/Gap.cpp @@ -16,8 +16,10 @@ #include "ble/Gap.h" -ble_error_t Gap::getRandomAddressType(BLEProtocol::AddressBytes_t address, RandomAddressType_t& type) -{ +ble_error_t Gap::getRandomAddressType( + BLEProtocol::AddressBytes_t address, + RandomAddressType_t* type +) { // see section Device address in Bluetooth Link Layer specification // (Vol 6 - Part B) switch (address[5] >> 6) {