mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #6932 from paul-szczepanek-arm/security-manager-dev
BLE privacy, signing, persistent security databasepull/7011/head
commit
791620c428
|
@ -86,3 +86,5 @@ tags
|
|||
|
||||
# Visual Studio Code
|
||||
.vscode/
|
||||
|
||||
features/FEATURE_BLE/targets/TARGET_CORDIO/stack_backup/
|
||||
|
|
|
@ -17,8 +17,11 @@
|
|||
#ifndef BLE_ARRAY_VIEW_H_
|
||||
#define BLE_ARRAY_VIEW_H_
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "platform/mbed_assert.h"
|
||||
|
||||
/**
|
||||
* @addtogroup ble
|
||||
|
@ -33,11 +36,18 @@
|
|||
|
||||
namespace ble {
|
||||
|
||||
/**
|
||||
* Special value for the Size parameter of ArrayView.
|
||||
* If the type use this value then the size of the array is stored in the object
|
||||
* at runtime.
|
||||
*/
|
||||
#define ARRAY_VIEW_DYNAMIC_SIZE -1
|
||||
|
||||
/**
|
||||
* Immutable view to an array.
|
||||
*
|
||||
* Array views encapsulate the pointer to an array and its size into a single
|
||||
* object; however, it does not manage the lifetime of the array viewed.
|
||||
* object or type; however, it does not manage the lifetime of the array viewed.
|
||||
* You can use instances of ArrayView to replace the traditional pair of pointer
|
||||
* and size arguments in function calls.
|
||||
*
|
||||
|
@ -48,20 +58,28 @@ namespace ble {
|
|||
* @note You can create ArrayView instances with the help of the function
|
||||
* template make_ArrayView() and make_const_ArrayView().
|
||||
*
|
||||
* @note ArrayView<T, Size> objects can be implicitly converted to ArrayView<T>
|
||||
* objects where required.
|
||||
*
|
||||
* @tparam T type of objects held by the array.
|
||||
* @tparam Size The size of the array viewed. The default value
|
||||
* ARRAY_VIEW_DYNAMIC_SIZE is special as it allows construction of ArrayView
|
||||
* objects of any size (set at runtime).
|
||||
*/
|
||||
template<typename T>
|
||||
template<typename T, ptrdiff_t Size = ARRAY_VIEW_DYNAMIC_SIZE>
|
||||
struct ArrayView {
|
||||
|
||||
MBED_STATIC_ASSERT(Size >= 0, "Invalid size for an ArrayView");
|
||||
|
||||
/**
|
||||
* Construct a view to an empty array.
|
||||
*
|
||||
* @post a call to size() will return 0, and data() will return NULL.
|
||||
*/
|
||||
ArrayView() : _array(0), _size(0) { }
|
||||
ArrayView() : _array(NULL) { }
|
||||
|
||||
/**
|
||||
* Construct an array view from a pointer to a buffer and its size.
|
||||
* Construct an array view from a pointer to a buffer.
|
||||
*
|
||||
* @param array_ptr Pointer to the array data
|
||||
* @param array_size Number of elements of T present in the array.
|
||||
|
@ -70,7 +88,9 @@ struct ArrayView {
|
|||
* array_tpr.
|
||||
*/
|
||||
ArrayView(T* array_ptr, size_t array_size) :
|
||||
_array(array_ptr), _size(array_size) { }
|
||||
_array(array_ptr) {
|
||||
MBED_ASSERT(array_size >= (size_t) Size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an array view from the reference to an array.
|
||||
|
@ -82,9 +102,8 @@ struct ArrayView {
|
|||
* @post a call to size() will return Size, and data() will return
|
||||
* a pointer to elements.
|
||||
*/
|
||||
template<size_t Size>
|
||||
ArrayView(T (&elements)[Size]):
|
||||
_array(elements), _size(Size) { }
|
||||
_array(elements) { }
|
||||
|
||||
/**
|
||||
* Return the size of the array viewed.
|
||||
|
@ -93,7 +112,7 @@ struct ArrayView {
|
|||
*/
|
||||
size_t size() const
|
||||
{
|
||||
return _size;
|
||||
return _array ? Size : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -144,40 +163,115 @@ struct ArrayView {
|
|||
return _array;
|
||||
}
|
||||
|
||||
private:
|
||||
T* const _array;
|
||||
};
|
||||
|
||||
/**
|
||||
* ArrayView specialisation that handle dynamic array size.
|
||||
*/
|
||||
template<typename T>
|
||||
struct ArrayView<T, ARRAY_VIEW_DYNAMIC_SIZE> {
|
||||
|
||||
/**
|
||||
* Equality operator.
|
||||
* Construct a view to an empty array.
|
||||
*
|
||||
* @param lhs Left hand side of the binary operation.
|
||||
* @param rhs Right hand side of the binary operation.
|
||||
*
|
||||
* @return True if arrays in input have the same size and the same content
|
||||
* and false otherwise.
|
||||
* @post a call to size() will return 0, and data() will return NULL.
|
||||
*/
|
||||
friend bool operator==(const ArrayView& lhs, const ArrayView& rhs)
|
||||
ArrayView() : _array(0), _size(0) { }
|
||||
|
||||
/**
|
||||
* Construct an array view from a pointer to a buffer and its size.
|
||||
*
|
||||
* @param array_ptr Pointer to the array data
|
||||
* @param array_size Number of elements of T present in the array.
|
||||
*
|
||||
* @post a call to size() will return array_size and data() will return
|
||||
* array_tpr.
|
||||
*/
|
||||
ArrayView(T* array_ptr, size_t array_size) :
|
||||
_array(array_ptr), _size(array_size) { }
|
||||
|
||||
/**
|
||||
* Construct an array view from the reference to an array.
|
||||
*
|
||||
* @param elements Reference to the array viewed.
|
||||
*
|
||||
* @tparam Size Number of elements of T presents in the array.
|
||||
*
|
||||
* @post a call to size() will return Size, and data() will return
|
||||
* a pointer to elements.
|
||||
*/
|
||||
template<size_t Size>
|
||||
ArrayView(T (&elements)[Size]):
|
||||
_array(elements), _size(Size) { }
|
||||
|
||||
|
||||
/**
|
||||
* Construct a ArrayView object with a dynamic size from an ArrayView object
|
||||
* with a static size.
|
||||
* @param other The ArrayView object used to construct this.
|
||||
*/
|
||||
template<size_t Size>
|
||||
ArrayView(ArrayView<T, Size> other):
|
||||
_array(other.data()), _size(other.size()) { }
|
||||
|
||||
/**
|
||||
* Return the size of the array viewed.
|
||||
*
|
||||
* @return The number of elements present in the array viewed.
|
||||
*/
|
||||
size_t size() const
|
||||
{
|
||||
if (lhs.size() != rhs.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lhs.data() == rhs.data()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return memcmp(lhs.data(), rhs.data(), lhs.size()) == 0;
|
||||
return _size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not equal operator
|
||||
* Access to a mutable element of the array.
|
||||
*
|
||||
* @param lhs Left hand side of the binary operation.
|
||||
* @param rhs Right hand side of the binary operation.
|
||||
* @param index Element index to access.
|
||||
*
|
||||
* @return True if arrays in input do not have the same size or the same
|
||||
* content and false otherwise.
|
||||
* @return A reference to the element at the index specified in input.
|
||||
*
|
||||
* @pre index shall be less than size().
|
||||
*/
|
||||
friend bool operator!=(const ArrayView& lhs, const ArrayView& rhs)
|
||||
T& operator[](size_t index)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
return _array[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Access to an immutable element of the array.
|
||||
*
|
||||
* @param index Element index to access.
|
||||
*
|
||||
* @return A const reference to the element at the index specified in input.
|
||||
*
|
||||
* @pre index shall be less than size().
|
||||
*/
|
||||
const T& operator[](size_t index) const
|
||||
{
|
||||
return _array[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw pointer to the array.
|
||||
*
|
||||
* @return The raw pointer to the array.
|
||||
*/
|
||||
T* data()
|
||||
{
|
||||
return _array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw const pointer to the array.
|
||||
*
|
||||
* @return The raw pointer to the array.
|
||||
*/
|
||||
const T* data() const
|
||||
{
|
||||
return _array;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -186,6 +280,45 @@ private:
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* Equality operator.
|
||||
*
|
||||
* @param lhs Left hand side of the binary operation.
|
||||
* @param rhs Right hand side of the binary operation.
|
||||
*
|
||||
* @return True if arrays in input have the same size and the same content
|
||||
* and false otherwise.
|
||||
*/
|
||||
template<typename T, ptrdiff_t LhsSize, ptrdiff_t RhsSize>
|
||||
bool operator==(const ArrayView<T, LhsSize>& lhs, const ArrayView<T, LhsSize>& rhs)
|
||||
{
|
||||
if (lhs.size() != rhs.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lhs.data() == rhs.data()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return std::equal(lhs.data(), lhs.data() + lhs.size(), rhs.data());
|
||||
}
|
||||
|
||||
/**
|
||||
* Not equal operator
|
||||
*
|
||||
* @param lhs Left hand side of the binary operation.
|
||||
* @param rhs Right hand side of the binary operation.
|
||||
*
|
||||
* @return True if arrays in input do not have the same size or the same
|
||||
* content and false otherwise.
|
||||
*/
|
||||
template<typename T, ptrdiff_t LhsSize, ptrdiff_t RhsSize>
|
||||
bool operator!=(const ArrayView<T, LhsSize>& lhs, const ArrayView<T, LhsSize>& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate an array view from a reference to a C/C++ array.
|
||||
*
|
||||
|
@ -200,9 +333,28 @@ private:
|
|||
* created 'inline'.
|
||||
*/
|
||||
template<typename T, size_t Size>
|
||||
ArrayView<T> make_ArrayView(T (&elements)[Size])
|
||||
ArrayView<T, Size> make_ArrayView(T (&elements)[Size])
|
||||
{
|
||||
return ArrayView<T>(elements);
|
||||
return ArrayView<T, Size>(elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an array view from a pointer to a C/C++ array.
|
||||
*
|
||||
* @tparam Size Number of items held in elements.
|
||||
* @tparam T Type of elements held in elements.
|
||||
*
|
||||
* @param elements The reference to the array viewed.
|
||||
*
|
||||
* @return The ArrayView to elements.
|
||||
*
|
||||
* @note This helper avoids the typing of template parameter when ArrayView is
|
||||
* created 'inline'.
|
||||
*/
|
||||
template<size_t Size, typename T>
|
||||
ArrayView<T, Size> make_ArrayView(T* elements)
|
||||
{
|
||||
return ArrayView<T, Size>(elements, Size);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -237,9 +389,28 @@ ArrayView<T> make_ArrayView(T* array_ptr, size_t array_size)
|
|||
* created 'inline'.
|
||||
*/
|
||||
template<typename T, size_t Size>
|
||||
ArrayView<const T> make_const_ArrayView(T (&elements)[Size])
|
||||
ArrayView<const T, Size> make_const_ArrayView(T (&elements)[Size])
|
||||
{
|
||||
return ArrayView<const T>(elements);
|
||||
return ArrayView<const T, Size>(elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a const array view from a pointer to a C/C++ array.
|
||||
*
|
||||
* @tparam Size Number of items held in elements.
|
||||
* @tparam T Type of elements held in elements.
|
||||
*
|
||||
* @param elements The reference to the array viewed.
|
||||
*
|
||||
* @return The ArrayView to elements.
|
||||
*
|
||||
* @note This helper avoids the typing of template parameter when ArrayView is
|
||||
* created 'inline'.
|
||||
*/
|
||||
template<size_t Size, typename T>
|
||||
ArrayView<const T, Size> make_const_ArrayView(const T* elements)
|
||||
{
|
||||
return ArrayView<const T, Size>(elements, Size);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -457,9 +457,7 @@ public:
|
|||
ble_error_t setAddress(
|
||||
BLEProtocol::AddressType_t type,
|
||||
const BLEProtocol::AddressBytes_t address
|
||||
) {
|
||||
return gap().setAddress(type, address);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Fetch the Bluetooth Low Energy MAC address and type.
|
||||
|
@ -1009,9 +1007,7 @@ public:
|
|||
ble_error_t connect(const BLEProtocol::AddressBytes_t peerAddr,
|
||||
BLEProtocol::AddressType_t peerAddrType = BLEProtocol::AddressType::RANDOM_STATIC,
|
||||
const Gap::ConnectionParams_t *connectionParams = NULL,
|
||||
const GapScanningParams *scanParams = NULL) {
|
||||
return gap().connect(peerAddr, peerAddrType, connectionParams, scanParams);
|
||||
}
|
||||
const GapScanningParams *scanParams = NULL);
|
||||
|
||||
/**
|
||||
* This call initiates the disconnection procedure, and its completion is
|
||||
|
@ -1045,9 +1041,7 @@ public:
|
|||
* connection.
|
||||
*/
|
||||
MBED_DEPRECATED("Use ble.gap().disconnect(...)")
|
||||
ble_error_t disconnect(Gap::DisconnectionReason_t reason) {
|
||||
return gap().disconnect(reason);
|
||||
}
|
||||
ble_error_t disconnect(Gap::DisconnectionReason_t reason);
|
||||
|
||||
/**
|
||||
* Returns the current Gap state of the device using a bitmask that
|
||||
|
|
|
@ -61,16 +61,31 @@ namespace BLEProtocol {
|
|||
|
||||
/**
|
||||
* 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
|
||||
};
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "ble/SafeEnum.h"
|
||||
#include "ble/ArrayView.h"
|
||||
|
||||
/**
|
||||
* @addtogroup ble
|
||||
|
@ -128,7 +129,8 @@ struct link_encryption_t : SafeEnum<link_encryption_t, uint8_t> {
|
|||
NOT_ENCRYPTED, /**< The link is not secured. */
|
||||
ENCRYPTION_IN_PROGRESS, /**< Link security is being established. */
|
||||
ENCRYPTED, /**< The link is secure. */
|
||||
ENCRYPTED_WITH_MITM /**< The link is secure and authenticated. */
|
||||
ENCRYPTED_WITH_MITM, /**< The link is secure and authenticated. */
|
||||
ENCRYPTED_WITH_SC_AND_MITM /**< The link is secure and authenticated with a secure connection key. */
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -261,8 +263,34 @@ private:
|
|||
uint8_t ascii[PASSKEY_LEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if every byte is equal to zero
|
||||
*/
|
||||
template <class byte_array_class>
|
||||
bool is_all_zeros(byte_array_class &byte_array) {
|
||||
for (size_t i = 0; i < byte_array.size(); i++) {
|
||||
if (byte_array[i] != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zero out all bytes
|
||||
*/
|
||||
template <class byte_array_class>
|
||||
void set_all_zeros(byte_array_class &byte_array) {
|
||||
memset(&byte_array[0], 0x00, byte_array.size());
|
||||
}
|
||||
|
||||
template <size_t array_size>
|
||||
struct byte_array_t {
|
||||
/**
|
||||
* Size of the array; accessible at compile time.
|
||||
*/
|
||||
static const size_t size_ = array_size;
|
||||
|
||||
/**
|
||||
* Default to all zeroes
|
||||
*/
|
||||
|
@ -306,7 +334,14 @@ struct byte_array_t {
|
|||
/**
|
||||
* Subscript operator to access data content
|
||||
*/
|
||||
uint8_t& operator[](uint8_t i) {
|
||||
uint8_t& operator[](size_t i) {
|
||||
return _value[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscript operator to access data content
|
||||
*/
|
||||
uint8_t operator[](size_t i) const {
|
||||
return _value[i];
|
||||
}
|
||||
|
||||
|
@ -320,7 +355,7 @@ struct byte_array_t {
|
|||
/**
|
||||
* Return the pointer to the buffer holding data.
|
||||
*/
|
||||
uint8_t* buffer() {
|
||||
uint8_t* data() {
|
||||
return _value;
|
||||
}
|
||||
|
||||
|
@ -335,6 +370,32 @@ protected:
|
|||
uint8_t _value[array_size];
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct a fixed size ArrayView from a byte_array_t.
|
||||
*
|
||||
* @param src byte_array_t to create a view from.
|
||||
*
|
||||
* @return An ArrayView to @p src.
|
||||
*/
|
||||
template<size_t Size>
|
||||
ArrayView<uint8_t, Size> make_ArrayView(byte_array_t<Size>& src)
|
||||
{
|
||||
return ArrayView<uint8_t, Size>(src.data(), src.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a fixed size ArrayView from a const byte_array_t.
|
||||
*
|
||||
* @param src byte_array_t to create a view from.
|
||||
*
|
||||
* @return An ArrayView to @p src.
|
||||
*/
|
||||
template<size_t Size>
|
||||
ArrayView<const uint8_t, Size> make_const_ArrayView(const byte_array_t<Size>& src)
|
||||
{
|
||||
return ArrayView<const uint8_t, Size>(src.data(), src.size());
|
||||
}
|
||||
|
||||
/** 128 bit keys used by paired devices */
|
||||
typedef byte_array_t<16> irk_t;
|
||||
typedef byte_array_t<16> csrk_t;
|
||||
|
@ -358,15 +419,18 @@ typedef byte_array_t<32> public_key_coord_t;
|
|||
/** Diffie-Hellman key */
|
||||
typedef byte_array_t<32> dhkey_t;
|
||||
|
||||
/** counter for signed data writes done by GattClient */
|
||||
typedef uint32_t sign_count_t;
|
||||
|
||||
/**
|
||||
* MAC address data type.
|
||||
*/
|
||||
struct address_t : public byte_array_t<6> {
|
||||
/**
|
||||
* Create an invalid mac address, equal to FF:FF:FF:FF:FF:FF
|
||||
* Create an invalid mac address, equal to 00:00:00:00:00:00
|
||||
*/
|
||||
address_t() {
|
||||
memset(_value, 0xFF, sizeof(_value));
|
||||
memset(_value, 0x00, sizeof(_value));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -379,6 +443,135 @@ struct address_t : public byte_array_t<6> {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Type that describes a random device address type.
|
||||
*/
|
||||
struct random_address_type_t : SafeEnum<random_address_type_t, uint8_t> {
|
||||
/** 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<random_address_type_t, uint8_t>(value) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* Security requirement that can be attached to an attribute operation.
|
||||
*/
|
||||
struct att_security_requirement_t : SafeEnum<att_security_requirement_t, uint8_t> {
|
||||
/**
|
||||
* Number of bits required to store the value.
|
||||
*
|
||||
* This value can be used to define a bitfield that host a value of this
|
||||
* enum.
|
||||
*/
|
||||
static const uint8_t size = 2;
|
||||
|
||||
/** struct scoped enum wrapped by the class */
|
||||
enum type {
|
||||
/**
|
||||
* The operation does not have security requirements.
|
||||
*
|
||||
* It is equivalent to: SecurityMode 1 level 1: No authentication, no
|
||||
* encryption and no signing required.
|
||||
*
|
||||
* @note This security mode is not applicable for signed operation.
|
||||
*
|
||||
* @note Equivalent to SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK.
|
||||
*/
|
||||
NONE,
|
||||
|
||||
/**
|
||||
* The operation requires security and there's no requirement towards
|
||||
* peer authentication.
|
||||
*
|
||||
* @note Security can be achieved either by signing messages or
|
||||
* encrypting the link.
|
||||
*
|
||||
* @note Signing is only applicable for signed write operations.
|
||||
*
|
||||
* @note Equivalent to SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM
|
||||
* or SecurityManager::SECURITY_MODE_SIGNED_NO_MITM.
|
||||
*/
|
||||
UNAUTHENTICATED,
|
||||
|
||||
/**
|
||||
* The operation requires security and the peer must be authenticated.
|
||||
*
|
||||
* @note Security can be achieved either by signing messages or
|
||||
* encrypting the link.
|
||||
*
|
||||
* @note Equivalent to SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM
|
||||
* or SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM.
|
||||
*/
|
||||
AUTHENTICATED,
|
||||
|
||||
/**
|
||||
* The operation require encryption with an authenticated peer that
|
||||
* paired using secure connection pairing.
|
||||
*
|
||||
* @note This security mode is not applicable for signed operation;
|
||||
* security is achieved with link encryption.
|
||||
*/
|
||||
SC_AUTHENTICATED
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct a new instance of att_security_requirement_t.
|
||||
*/
|
||||
att_security_requirement_t(type value) :
|
||||
SafeEnum<att_security_requirement_t, uint8_t>(value) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* Type that describes a peer device address type.
|
||||
*/
|
||||
struct peer_address_type_t :SafeEnum<peer_address_type_t, uint8_t> {
|
||||
/** struct scoped enum wrapped by the class */
|
||||
enum type {
|
||||
/**
|
||||
* Public device address.
|
||||
*/
|
||||
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
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct a new instance of peer_address_type_t.
|
||||
*/
|
||||
peer_address_type_t(type value) :
|
||||
SafeEnum<peer_address_type_t, uint8_t>(value) { }
|
||||
|
||||
/**
|
||||
* Default initialization of peer_address_type_t.
|
||||
*/
|
||||
peer_address_type_t() :
|
||||
SafeEnum<peer_address_type_t, uint8_t>(PUBLIC) { }
|
||||
};
|
||||
|
||||
} // namespace ble
|
||||
|
||||
/**
|
||||
|
|
|
@ -121,6 +121,27 @@ class GapAdvertisingData;
|
|||
* gap.startAdvertising();
|
||||
* @endcode
|
||||
*
|
||||
* @par Privacy
|
||||
*
|
||||
* Privacy is a feature that allows a device to avoid being tracked by other
|
||||
* (untrusted) devices. The device achieves it by periodically generating a
|
||||
* new random address. The random address may be a resolvable random address,
|
||||
* enabling trusted devices to recognise it as belonging to the same
|
||||
* device. These trusted devices receive an Identity Resolution Key (IRK)
|
||||
* during pairing. This is handled by the SecurityManager and relies on the
|
||||
* other device accepting and storing the IRK.
|
||||
*
|
||||
* Privacy needs to be enabled by calling enablePrivacy() after having
|
||||
* initialised the SecurityManager since privacy requires SecurityManager
|
||||
* to handle IRKs. The behaviour of privacy enabled devices is set by
|
||||
* using setCentralPrivacyConfiguration() which specifies what the device
|
||||
* should be with devices using random addresses. Random addresses
|
||||
* generated by privacy enabled device can be of two types: resolvable
|
||||
* (by devices who have the IRK) and unresolvable. Unresolvable addresses
|
||||
* can't be used for connecting and connectable advertising therefore a
|
||||
* resolvable one will be used for these regardless of the privacy
|
||||
* configuration.
|
||||
*
|
||||
* @par Scanning
|
||||
*
|
||||
* Scanning consist of listening for peer advertising packets. From a scan, a
|
||||
|
@ -353,6 +374,12 @@ public:
|
|||
* disconnection reason to be transmitted to the peer.
|
||||
*/
|
||||
enum DisconnectionReason_t {
|
||||
|
||||
/**
|
||||
* GAP or GATT failed to authenticate the peer.
|
||||
*/
|
||||
AUTHENTICATION_FAILURE = 0x05,
|
||||
|
||||
/**
|
||||
* The connection timed out.
|
||||
*
|
||||
|
@ -496,6 +523,16 @@ public:
|
|||
*/
|
||||
typedef ble::connection_handle_t Handle_t;
|
||||
|
||||
/**
|
||||
* Enumeration of random address types.
|
||||
*/
|
||||
typedef ble::random_address_type_t RandomAddressType_t;
|
||||
|
||||
/**
|
||||
* Enumeration of peer address types
|
||||
*/
|
||||
typedef ble::peer_address_type_t PeerAddressType_t;
|
||||
|
||||
/**
|
||||
* Parameters of a BLE connection.
|
||||
*/
|
||||
|
@ -579,6 +616,11 @@ public:
|
|||
* startScan().
|
||||
*/
|
||||
struct AdvertisementCallbackParams_t {
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
AdvertisementCallbackParams_t();
|
||||
|
||||
/**
|
||||
* BLE address of the device that has advertised the packet.
|
||||
*/
|
||||
|
@ -610,9 +652,28 @@ public:
|
|||
const uint8_t *advertisingData;
|
||||
|
||||
/**
|
||||
* Type of the address received
|
||||
* Type of the address received.
|
||||
*
|
||||
* @deprecated AddressType_t do not carry enough information to be used
|
||||
* when privacy is enabled. Use peerAddressType instead.
|
||||
*
|
||||
* @note This value should be used in the connect function to establish
|
||||
* a connection with the peer that has sent this advertisement packet.
|
||||
*/
|
||||
MBED_DEPRECATED_SINCE(
|
||||
"mbed-os-5.9.0",
|
||||
"addressType won't work in connect when privacy is enabled; please"
|
||||
"use peerAddrType"
|
||||
)
|
||||
AddressType_t addressType;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
PeerAddressType_t peerAddrType;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -644,7 +705,15 @@ public:
|
|||
|
||||
/**
|
||||
* Type of the address the peer uses.
|
||||
*
|
||||
* @deprecated The type BLEProtocol::AddressType_t is not suitable when
|
||||
* privacy is enabled. Use peerAddressType instead.
|
||||
*/
|
||||
MBED_DEPRECATED_SINCE(
|
||||
"mbed-os-5.9",
|
||||
"The type BLEProtocol::AddressType_t is not suitable when privacy is "
|
||||
"enabled. Use peerAddressType instead."
|
||||
)
|
||||
BLEProtocol::AddressType_t peerAddrType;
|
||||
|
||||
/**
|
||||
|
@ -659,7 +728,18 @@ public:
|
|||
|
||||
/**
|
||||
* Address of the local device.
|
||||
*
|
||||
* @deprecated The local address used for the connection may not be known,
|
||||
* Therefore this field is not reliable.
|
||||
*
|
||||
* @note All bytes of the address are set to 0 if not applicable
|
||||
*/
|
||||
MBED_DEPRECATED_SINCE(
|
||||
"mbed-os-5.9",
|
||||
"A Bluetooth controller is not supposed to return the address it used"
|
||||
"to connect. With privacy enabled the controller address may be unknown"
|
||||
"to the host. There is no replacement for this deprecation."
|
||||
)
|
||||
BLEProtocol::AddressBytes_t ownAddr;
|
||||
|
||||
/**
|
||||
|
@ -667,6 +747,53 @@ public:
|
|||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Type of the address the peer uses.
|
||||
*/
|
||||
PeerAddressType_t peerAddressType;
|
||||
|
||||
/**
|
||||
* Construct an instance of ConnectionCallbackParams_t.
|
||||
*
|
||||
* @param[in] handleIn Value to assign to handle.
|
||||
* @param[in] roleIn Value to assign to role.
|
||||
* @param[in] peerAddrTypeIn Value to assign to peerAddrType.
|
||||
* @param[in] peerAddrIn Value to assign to peerAddr.
|
||||
* @param[in] ownAddrTypeIn Value to assign to ownAddrType.
|
||||
* @param[in] ownAddrIn Value to assign to ownAddr. This may be NULL.
|
||||
* @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.
|
||||
*/
|
||||
ConnectionCallbackParams_t(
|
||||
Handle_t handleIn,
|
||||
Role_t roleIn,
|
||||
PeerAddressType_t peerAddrTypeIn,
|
||||
const uint8_t *peerAddrIn,
|
||||
BLEProtocol::AddressType_t ownAddrTypeIn,
|
||||
const uint8_t *ownAddrIn,
|
||||
const ConnectionParams_t *connectionParamsIn,
|
||||
const uint8_t *peerResolvableAddrIn = NULL,
|
||||
const uint8_t *localResolvableAddrIn = NULL
|
||||
);
|
||||
|
||||
/**
|
||||
* Construct an instance of ConnectionCallbackParams_t.
|
||||
*
|
||||
|
@ -677,10 +804,21 @@ public:
|
|||
* @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.
|
||||
*
|
||||
* @deprecated The type BLEProtocol::AddressType_t is not suitable when
|
||||
* privacy is enabled. Use the constructor that accepts a
|
||||
* PeerAddressType_t instead.
|
||||
*/
|
||||
MBED_DEPRECATED_SINCE(
|
||||
"mbed-os-5.9.0",
|
||||
"The type BLEProtocol::AddressType_t is not suitable when privacy is "
|
||||
"enabled. Use the constructor that accepts a PeerAddressType_t instead."
|
||||
)
|
||||
ConnectionCallbackParams_t(
|
||||
Handle_t handleIn,
|
||||
Role_t roleIn,
|
||||
|
@ -688,18 +826,18 @@ public:
|
|||
const uint8_t *peerAddrIn,
|
||||
BLEProtocol::AddressType_t ownAddrTypeIn,
|
||||
const uint8_t *ownAddrIn,
|
||||
const ConnectionParams_t *connectionParamsIn
|
||||
) : handle(handleIn),
|
||||
role(roleIn),
|
||||
peerAddrType(peerAddrTypeIn),
|
||||
peerAddr(),
|
||||
ownAddrType(ownAddrTypeIn),
|
||||
ownAddr(),
|
||||
connectionParams(connectionParamsIn)
|
||||
{
|
||||
memcpy(peerAddr, peerAddrIn, ADDR_LEN);
|
||||
memcpy(ownAddr, ownAddrIn, ADDR_LEN);
|
||||
}
|
||||
const ConnectionParams_t *connectionParamsIn,
|
||||
const uint8_t *peerResolvableAddrIn = NULL,
|
||||
const uint8_t *localResolvableAddrIn = NULL
|
||||
);
|
||||
|
||||
private:
|
||||
void constructor_helper(
|
||||
const uint8_t *peerAddrIn,
|
||||
const uint8_t *ownAddrIn,
|
||||
const uint8_t *peerResolvableAddrIn,
|
||||
const uint8_t *localResolvableAddrIn
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -736,11 +874,119 @@ public:
|
|||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* Privacy Configuration of the peripheral role.
|
||||
*
|
||||
* @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 advertises non connectable packets.
|
||||
*
|
||||
* Resolvable random address continues to be used for connectable packets.
|
||||
*/
|
||||
bool use_non_resolvable_random_address;
|
||||
|
||||
/**
|
||||
* Resolution strategy for 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 is also used when the local device operates as
|
||||
* an observer.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
static const uint16_t UNIT_1_25_MS = 1250;
|
||||
|
||||
static const PeripheralPrivacyConfiguration_t
|
||||
default_peripheral_privacy_configuration;
|
||||
|
||||
static const CentralPrivacyConfiguration_t
|
||||
default_central_privacy_configuration;
|
||||
|
||||
/**
|
||||
* Convert milliseconds into 1.25ms units.
|
||||
*
|
||||
|
@ -844,8 +1090,29 @@ public:
|
|||
* @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 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
|
||||
* 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 +1132,9 @@ public:
|
|||
* @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 +1150,22 @@ public:
|
|||
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(
|
||||
const BLEProtocol::AddressBytes_t address,
|
||||
RandomAddressType_t* addressType
|
||||
);
|
||||
|
||||
/**
|
||||
* Get the minimum advertising interval in milliseconds, which can be used
|
||||
* for connectable advertising types.
|
||||
|
@ -956,7 +1242,8 @@ public:
|
|||
* emitted to handlers that have been registered with onConnection().
|
||||
*
|
||||
* @param[in] peerAddr MAC address of the peer. It must be in LSB format.
|
||||
* @param[in] peerAddrType Address type of the peer.
|
||||
* @param[in] peerAddrType Address type of the peer. It is usually obtained
|
||||
* from advertising frames.
|
||||
* @param[in] connectionParams Connection parameters to use.
|
||||
* @param[in] scanParams Scan parameters used to find the peer.
|
||||
*
|
||||
|
@ -964,6 +1251,47 @@ public:
|
|||
* successfully. The connectionCallChain (if set) is invoked upon
|
||||
* a connection event.
|
||||
*/
|
||||
virtual ble_error_t connect(
|
||||
const BLEProtocol::AddressBytes_t peerAddr,
|
||||
PeerAddressType_t peerAddrType,
|
||||
const ConnectionParams_t *connectionParams,
|
||||
const GapScanningParams *scanParams
|
||||
) {
|
||||
/* Avoid compiler warnings about unused variables. */
|
||||
(void)peerAddr;
|
||||
(void)peerAddrType;
|
||||
(void)connectionParams;
|
||||
(void)scanParams;
|
||||
|
||||
/* Requesting action from porter(s): override this API if this capability
|
||||
is supported. */
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate a connection to a peer.
|
||||
*
|
||||
* Once the connection is established, a ConnectionCallbackParams_t event is
|
||||
* emitted to handlers that have been registered with onConnection().
|
||||
*
|
||||
* @param[in] peerAddr MAC address of the peer. It must be in LSB format.
|
||||
* @param[in] peerAddrType Address type of the peer.
|
||||
* @param[in] connectionParams Connection parameters to use.
|
||||
* @param[in] scanParams Scan parameters used to find the peer.
|
||||
*
|
||||
* @deprecated BLEProtocol::AddressType_t is not able to to carry accurate
|
||||
* meaning when privacy is in use. Please Uses the connect overload that
|
||||
* accept a PeerAddressType_t as the peer address type.
|
||||
*
|
||||
* @return BLE_ERROR_NONE if connection establishment procedure is started
|
||||
* successfully. The connectionCallChain (if set) is invoked upon
|
||||
* a connection event.
|
||||
*/
|
||||
MBED_DEPRECATED_SINCE(
|
||||
"mbed-os-5.9.0",
|
||||
"This function won't work if privacy is enabled; You must use the overload "
|
||||
"accepting PeerAddressType_t."
|
||||
)
|
||||
virtual ble_error_t connect(
|
||||
const BLEProtocol::AddressBytes_t peerAddr,
|
||||
BLEProtocol::AddressType_t peerAddrType,
|
||||
|
@ -1001,15 +1329,7 @@ public:
|
|||
DeprecatedAddressType_t peerAddrType,
|
||||
const ConnectionParams_t *connectionParams,
|
||||
const GapScanningParams *scanParams
|
||||
) {
|
||||
return connect(
|
||||
peerAddr,
|
||||
(BLEProtocol::AddressType_t)
|
||||
peerAddrType,
|
||||
connectionParams,
|
||||
scanParams
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Initiate a disconnection procedure.
|
||||
|
@ -1955,6 +2275,97 @@ public:
|
|||
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 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 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[in] enable 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.
|
||||
|
@ -2271,6 +2682,36 @@ protected:
|
|||
|
||||
/* Entry points for the underlying stack to report events back to the user. */
|
||||
public:
|
||||
/**
|
||||
* Notify all registered connection event handlers of a connection event.
|
||||
*
|
||||
* @attention This function is meant to be called from the BLE stack specific
|
||||
* implementation when a connection event occurs.
|
||||
*
|
||||
* @param[in] handle Handle of the new connection.
|
||||
* @param[in] role Role of this BLE device in the connection.
|
||||
* @param[in] peerAddrType Address type of the connected peer.
|
||||
* @param[in] peerAddr Address of the connected peer.
|
||||
* @param[in] ownAddrType Address type this device uses for this
|
||||
* connection.
|
||||
* @param[in] ownAddr Address this device uses for this connection. This
|
||||
* parameter may be NULL if the local address is not available.
|
||||
* @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,
|
||||
Role_t role,
|
||||
PeerAddressType_t peerAddrType,
|
||||
const BLEProtocol::AddressBytes_t peerAddr,
|
||||
BLEProtocol::AddressType_t ownAddrType,
|
||||
const BLEProtocol::AddressBytes_t ownAddr,
|
||||
const ConnectionParams_t *connectionParams,
|
||||
const uint8_t *peerResolvableAddr = NULL,
|
||||
const uint8_t *localResolvableAddr = NULL
|
||||
);
|
||||
|
||||
/**
|
||||
* Notify all registered connection event handlers of a connection event.
|
||||
*
|
||||
|
@ -2285,7 +2726,18 @@ public:
|
|||
* 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.
|
||||
*
|
||||
* @deprecated The type BLEProtocol::AddressType_t is not suitable when
|
||||
* privacy is enabled. Use the overload that accepts a PeerAddressType_t
|
||||
* instead.
|
||||
*/
|
||||
MBED_DEPRECATED_SINCE(
|
||||
"mbed-os-5.9.0",
|
||||
"The type BLEProtocol::AddressType_t is not suitable when privacy is "
|
||||
"enabled. Use the overload that accepts a PeerAddressType_t instead."
|
||||
)
|
||||
void processConnectionEvent(
|
||||
Handle_t handle,
|
||||
Role_t role,
|
||||
|
@ -2293,25 +2745,10 @@ public:
|
|||
const BLEProtocol::AddressBytes_t peerAddr,
|
||||
BLEProtocol::AddressType_t ownAddrType,
|
||||
const BLEProtocol::AddressBytes_t ownAddr,
|
||||
const ConnectionParams_t *connectionParams
|
||||
) {
|
||||
/* Update Gap state */
|
||||
state.advertising = 0;
|
||||
state.connected = 1;
|
||||
++connectionCount;
|
||||
|
||||
ConnectionCallbackParams_t callbackParams(
|
||||
handle,
|
||||
role,
|
||||
peerAddrType,
|
||||
peerAddr,
|
||||
ownAddrType,
|
||||
ownAddr,
|
||||
connectionParams
|
||||
);
|
||||
|
||||
connectionCallChain.call(&callbackParams);
|
||||
}
|
||||
const ConnectionParams_t *connectionParams,
|
||||
const uint8_t *peerResolvableAddr = NULL,
|
||||
const uint8_t *localResolvableAddr = NULL
|
||||
);
|
||||
|
||||
/**
|
||||
* Notify all registered disconnection event handlers of a disconnection event.
|
||||
|
@ -2348,7 +2785,8 @@ public:
|
|||
* @param[in] type Advertising type of the packet.
|
||||
* @param[in] advertisingDataLen Length of the advertisement data received.
|
||||
* @param[in] advertisingData Pointer to the advertisement packet's data.
|
||||
* @param[in] addressType Type of the address of the peer that has emitted the packet.
|
||||
* @param[in] addressType Type of the address of the peer that has emitted
|
||||
* the packet.
|
||||
*/
|
||||
void processAdvertisementReport(
|
||||
const BLEProtocol::AddressBytes_t peerAddr,
|
||||
|
@ -2357,22 +2795,43 @@ public:
|
|||
GapAdvertisingParams::AdvertisingType_t type,
|
||||
uint8_t advertisingDataLen,
|
||||
const uint8_t *advertisingData,
|
||||
BLEProtocol::AddressType_t addressType = BLEProtocol::AddressType::RANDOM_STATIC
|
||||
) {
|
||||
// FIXME: remove default parameter for addressType when ST shield is merged;
|
||||
// this has been added to mitigate the lack of dependency management in
|
||||
// testing jobs ....
|
||||
PeerAddressType_t addressType
|
||||
);
|
||||
|
||||
AdvertisementCallbackParams_t params;
|
||||
memcpy(params.peerAddr, peerAddr, ADDR_LEN);
|
||||
params.rssi = rssi;
|
||||
params.isScanResponse = isScanResponse;
|
||||
params.type = type;
|
||||
params.advertisingDataLen = advertisingDataLen;
|
||||
params.advertisingData = advertisingData;
|
||||
params.addressType = addressType;
|
||||
onAdvertisementReport.call(¶ms);
|
||||
}
|
||||
/**
|
||||
* Forward a received advertising packet to all registered event handlers
|
||||
* listening for scanned packet events.
|
||||
*
|
||||
* @attention This function is meant to be called from the BLE stack specific
|
||||
* implementation when a disconnection event occurs.
|
||||
*
|
||||
* @param[in] peerAddr Address of the peer that has emitted the packet.
|
||||
* @param[in] rssi Value of the RSSI measured for the received packet.
|
||||
* @param[in] isScanResponse If true, then the packet is a response to a scan
|
||||
* request.
|
||||
* @param[in] type Advertising type of the packet.
|
||||
* @param[in] advertisingDataLen Length of the advertisement data received.
|
||||
* @param[in] advertisingData Pointer to the advertisement packet's data.
|
||||
* @param[in] addressType Type of the address of the peer that has emitted the packet.
|
||||
*
|
||||
* @deprecated The type BLEProtocol::AddressType_t is not suitable when
|
||||
* privacy is enabled. Use the overload that accepts a PeerAddressType_t
|
||||
* instead.
|
||||
*/
|
||||
MBED_DEPRECATED_SINCE(
|
||||
"mbed-os-5.9.0",
|
||||
"The type BLEProtocol::AddressType_t is not suitable when privacy is "
|
||||
"enabled. Use the overload that accepts a PeerAddressType_t instead."
|
||||
)
|
||||
void processAdvertisementReport(
|
||||
const BLEProtocol::AddressBytes_t peerAddr,
|
||||
int8_t rssi,
|
||||
bool isScanResponse,
|
||||
GapAdvertisingParams::AdvertisingType_t type,
|
||||
uint8_t advertisingDataLen,
|
||||
const uint8_t *advertisingData,
|
||||
BLEProtocol::AddressType_t addressType = BLEProtocol::AddressType::RANDOM_STATIC
|
||||
);
|
||||
|
||||
/**
|
||||
* Notify the occurrence of a timeout event to all registered timeout events
|
||||
|
|
|
@ -72,6 +72,9 @@ public:
|
|||
static const Handle_t INVALID_HANDLE = 0x0000;
|
||||
|
||||
public:
|
||||
|
||||
typedef ble::att_security_requirement_t Security_t;
|
||||
|
||||
/**
|
||||
* Construct an attribute.
|
||||
*
|
||||
|
@ -102,6 +105,9 @@ public:
|
|||
* true // variable length
|
||||
* );
|
||||
* @endcode
|
||||
*
|
||||
* @note By default, read and write operations are allowed and does not
|
||||
* require any security.
|
||||
*/
|
||||
GattAttribute(
|
||||
const UUID &uuid,
|
||||
|
@ -113,8 +119,12 @@ public:
|
|||
_valuePtr(valuePtr),
|
||||
_lenMax(maxLen),
|
||||
_len(len),
|
||||
_handle(),
|
||||
_hasVariableLen(hasVariableLen),
|
||||
_handle() {
|
||||
_read_allowed(true),
|
||||
_read_security(Security_t::NONE),
|
||||
_write_allowed(true),
|
||||
_write_security(Security_t::NONE) {
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -209,6 +219,78 @@ public:
|
|||
return _hasVariableLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow or disallow read operation from a client.
|
||||
* @param allow_read Read is allowed if true.
|
||||
*/
|
||||
void allowRead(bool allow_read)
|
||||
{
|
||||
_read_allowed = allow_read;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate if a client is allowed to read the attribute.
|
||||
* @return true if a client is allowed to read the attribute.
|
||||
*/
|
||||
bool isReadAllowed(void) const
|
||||
{
|
||||
return _read_allowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the security requirements of the read operations.
|
||||
* @param requirement The security level required by the read operations.
|
||||
*/
|
||||
void setReadSecurityRequirement(Security_t requirement)
|
||||
{
|
||||
_read_security = requirement.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the security level required by read operations.
|
||||
* @return The security level of the read operations.
|
||||
*/
|
||||
Security_t getReadSecurityRequirement() const
|
||||
{
|
||||
return static_cast<Security_t::type>(_read_security);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow or disallow write operation from a client.
|
||||
* @param allow_write Write is allowed if true.
|
||||
*/
|
||||
void allowWrite(bool allow_write)
|
||||
{
|
||||
_write_allowed = allow_write;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate if a client is allowed to write the attribute.
|
||||
* @return true if a client is allowed to write the attribute.
|
||||
*/
|
||||
bool isWriteAllowed(void) const
|
||||
{
|
||||
return _write_allowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the security requirements of the write operations.
|
||||
* @param requirement The security level required by the write operations.
|
||||
*/
|
||||
void setWriteSecurityRequirement(Security_t requirement)
|
||||
{
|
||||
_write_security = requirement.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the security level required by write operations.
|
||||
* @return The security level of the write operations.
|
||||
*/
|
||||
Security_t getWriteSecurityRequirement() const
|
||||
{
|
||||
return static_cast<Security_t::type>(_write_security);
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Characteristic's UUID.
|
||||
|
@ -230,15 +312,35 @@ private:
|
|||
*/
|
||||
uint16_t _len;
|
||||
|
||||
/**
|
||||
* The attribute's handle in the ATT table.
|
||||
*/
|
||||
Handle_t _handle;
|
||||
|
||||
/**
|
||||
* Whether the length of the value can change throughout time.
|
||||
*/
|
||||
bool _hasVariableLen;
|
||||
|
||||
/**
|
||||
* The attribute's handle in the ATT table.
|
||||
* Whether read is allowed or not.
|
||||
*/
|
||||
Handle_t _handle;
|
||||
uint8_t _read_allowed:1;
|
||||
|
||||
/**
|
||||
* Security applied to the read operation.
|
||||
*/
|
||||
uint8_t _read_security: Security_t::size;
|
||||
|
||||
/**
|
||||
* Whether write is allowed or not.
|
||||
*/
|
||||
uint8_t _write_allowed:1;
|
||||
|
||||
/**
|
||||
* Security applied to the write operation.
|
||||
*/
|
||||
uint8_t _write_security: Security_t::size;
|
||||
|
||||
private:
|
||||
/* Disallow copy and assignment. */
|
||||
|
|
|
@ -73,24 +73,23 @@
|
|||
* of the characteristic. Clients use this handle to interact with the
|
||||
* characteristic. This handle is used locally in GattServer APIs.
|
||||
*
|
||||
* @par Security requirements
|
||||
*
|
||||
* Verification of security requirements happens whenever a client request to
|
||||
* read the characteristic; write it or even register to its updates. Different
|
||||
* requirements may be defined for these three type of operation. As an example:
|
||||
* it is possible to define a characteristic that do not require security to be
|
||||
* read and require an authenticated link to be written.
|
||||
*
|
||||
* By default all security requirements are set to att_security_requirement_t::NONE
|
||||
* except if the characteristic supports signed write; in such case the security
|
||||
* requirement for write operations is set to att_security_requirement_t::UNAUTHENTICATED.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Representation of a GattServer characteristic.
|
||||
*
|
||||
* A characteristic is a typed value used in a service. It contains a set of
|
||||
* properties that define client operations supported by the characteristic.
|
||||
* A characteristic may also include descriptors; a descriptor exposes
|
||||
* metainformation associated to a characteristic, such as the unit of its value,
|
||||
* its human readable name or a control point attribute that allows the client to
|
||||
* subscribe to the characteristic notifications.
|
||||
*
|
||||
* The GattCharacteristic class allows application code to construct
|
||||
* and monitor characteristics presents in a GattServer.
|
||||
* @note If a peer uses an operation that is not set in the characteristic
|
||||
* properties then the request request is discarded regardless of the security
|
||||
* requirements and current security level. The only exception being signed
|
||||
* write: signed write are converted into regular write without response if
|
||||
* the link is encrypted.
|
||||
*/
|
||||
class GattCharacteristic {
|
||||
public:
|
||||
|
@ -1276,9 +1275,40 @@ public:
|
|||
* defines additional characteristic properties.
|
||||
*/
|
||||
BLE_GATT_CHAR_PROPERTIES_EXTENDED_PROPERTIES = 0x80
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Indicates if the properties has at least one of the writable flags.
|
||||
*
|
||||
* @param[in] properties The properties to inspect.
|
||||
*
|
||||
* @return True if the properties set at least one of the writable flags and
|
||||
* false otherwise.
|
||||
*/
|
||||
static bool isWritable(uint8_t properties)
|
||||
{
|
||||
const uint8_t writable =
|
||||
BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE |
|
||||
BLE_GATT_CHAR_PROPERTIES_WRITE |
|
||||
BLE_GATT_CHAR_PROPERTIES_AUTHENTICATED_SIGNED_WRITES;
|
||||
|
||||
return properties & writable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the properties is readable.
|
||||
*
|
||||
* @param[in] properties The properties to inspect.
|
||||
*
|
||||
* @return True if the properties has its readable flag set and false
|
||||
* otherwise.
|
||||
*/
|
||||
static bool isReadable(uint8_t properties)
|
||||
{
|
||||
const uint8_t readable = BLE_GATT_CHAR_PROPERTIES_READ;
|
||||
return properties & readable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Value of a Characteristic Presentation Format descriptor.
|
||||
*
|
||||
|
@ -1327,6 +1357,11 @@ public:
|
|||
|
||||
};
|
||||
|
||||
/**
|
||||
* Security level applied to GATT operations.
|
||||
*/
|
||||
typedef ble::att_security_requirement_t SecurityRequirement_t;
|
||||
|
||||
/**
|
||||
* @brief Constructs a new GattCharacteristic.
|
||||
*
|
||||
|
@ -1371,13 +1406,21 @@ public:
|
|||
bool hasVariableLen = true
|
||||
) : _valueAttribute(uuid, valuePtr, len, maxLen, hasVariableLen),
|
||||
_properties(props),
|
||||
_requiredSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK),
|
||||
_descriptors(descriptors),
|
||||
_descriptorCount(numDescriptors),
|
||||
enabledReadAuthorization(false),
|
||||
enabledWriteAuthorization(false),
|
||||
readAuthorizationCallback(),
|
||||
writeAuthorizationCallback() {
|
||||
writeAuthorizationCallback(),
|
||||
_update_security(SecurityRequirement_t::NONE) {
|
||||
_valueAttribute.allowWrite(isWritable(_properties));
|
||||
_valueAttribute.allowRead(isReadable(_properties));
|
||||
|
||||
// signed writes requires at least an unauthenticated CSRK or an
|
||||
// unauthenticated ltk if the link is encrypted.
|
||||
if (_properties & BLE_GATT_CHAR_PROPERTIES_AUTHENTICATED_SIGNED_WRITES) {
|
||||
_valueAttribute.setWriteSecurityRequirement(
|
||||
SecurityRequirement_t::UNAUTHENTICATED
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -1387,10 +1430,120 @@ public:
|
|||
*
|
||||
* @param[in] securityMode Can be one of encryption or signing, with or
|
||||
* without protection for man in the middle attacks (MITM).
|
||||
*
|
||||
* @deprecated Fine grained security check has been added to with mbed OS
|
||||
* 5.9. It is possible to set independently security requirements for read,
|
||||
* write and update operations. In the meantime SecurityManager::SecurityMode_t
|
||||
* is not used anymore to represent security requirements as it maps
|
||||
* incorrectly the Bluetooth standard.
|
||||
*/
|
||||
MBED_DEPRECATED_SINCE(
|
||||
"mbed-os-5.9",
|
||||
"Use setWriteSecurityRequirements, setReadSecurityRequirements and "
|
||||
"setUpdateSecurityRequirements"
|
||||
)
|
||||
void requireSecurity(SecurityManager::SecurityMode_t securityMode)
|
||||
{
|
||||
_requiredSecurity = securityMode;
|
||||
SecurityRequirement_t sec_requirements = SecurityModeToAttSecurity(securityMode);
|
||||
|
||||
_valueAttribute.setReadSecurityRequirement(sec_requirements);
|
||||
_valueAttribute.setWriteSecurityRequirement(sec_requirements);
|
||||
_update_security = sec_requirements.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all security requirements of the characteristic.
|
||||
*
|
||||
* @param read_security The security requirement of the read operations.
|
||||
* @param write_security The security requirement of write operations.
|
||||
* @param update_security The security requirement of update operations.
|
||||
*/
|
||||
void setSecurityRequirements(
|
||||
SecurityRequirement_t read_security,
|
||||
SecurityRequirement_t write_security,
|
||||
SecurityRequirement_t update_security
|
||||
) {
|
||||
setReadSecurityRequirement(read_security);
|
||||
setWriteSecurityRequirement(write_security);
|
||||
setUpdateSecurityRequirement(update_security);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the security of the read operation.
|
||||
*
|
||||
* @param[in] security The security requirement of the read operation.
|
||||
*/
|
||||
void setReadSecurityRequirement(SecurityRequirement_t security)
|
||||
{
|
||||
_valueAttribute.setReadSecurityRequirement(security);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the security requirement of the read operation.
|
||||
*
|
||||
* @return The security requirement of the read operation.
|
||||
*/
|
||||
SecurityRequirement_t getReadSecurityRequirement() const
|
||||
{
|
||||
return _valueAttribute.getReadSecurityRequirement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the security requirement of the write operations.
|
||||
*
|
||||
* @note If the signed write flag is set in the characteristic properties
|
||||
* then the security requirement applied to write operation must be either
|
||||
* AUTHENTICATED or UNAUTHENTICATED. Security requirements NONE and
|
||||
* SC_AUTHENTICATED are not applicable to signing operation.
|
||||
*
|
||||
* @param[in] security The security requirement of write operations.
|
||||
*/
|
||||
void setWriteSecurityRequirement(SecurityRequirement_t security)
|
||||
{
|
||||
MBED_ASSERT(
|
||||
((_properties & BLE_GATT_CHAR_PROPERTIES_AUTHENTICATED_SIGNED_WRITES) &&
|
||||
((security == SecurityRequirement_t::NONE) ||
|
||||
(security == SecurityRequirement_t::SC_AUTHENTICATED))) == false
|
||||
);
|
||||
_valueAttribute.setWriteSecurityRequirement(security);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the security requirement of write operations.
|
||||
*
|
||||
* @return The security requirement of write operations.
|
||||
*/
|
||||
SecurityRequirement_t getWriteSecurityRequirement() const
|
||||
{
|
||||
return _valueAttribute.getWriteSecurityRequirement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the security requirement of update operations.
|
||||
*
|
||||
* @note This security requirement is also applied to the write operation of
|
||||
* the Client Characteristic Configuration Descriptor.
|
||||
*
|
||||
* @param[in] security The security requirement that must be met to send
|
||||
* updates and accept write of the CCCD.
|
||||
*/
|
||||
void setUpdateSecurityRequirement(SecurityRequirement_t security)
|
||||
{
|
||||
_update_security = security.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the security requirement of update operations.
|
||||
*
|
||||
* @note This security requirement is also applied to the write operation of
|
||||
* the Client Characteristic Configuration Descriptor.
|
||||
*
|
||||
* @return The security requirement that must be met to send updates and
|
||||
* accept write of the CCCD.
|
||||
*/
|
||||
SecurityRequirement_t getUpdateSecurityRequirement() const
|
||||
{
|
||||
return static_cast<SecurityRequirement_t::type>(_update_security);
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -1407,7 +1560,6 @@ public:
|
|||
void (*callback)(GattWriteAuthCallbackParams *)
|
||||
) {
|
||||
writeAuthorizationCallback.attach(callback);
|
||||
enabledWriteAuthorization = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1428,7 +1580,6 @@ public:
|
|||
void (T::*member)(GattWriteAuthCallbackParams *)
|
||||
) {
|
||||
writeAuthorizationCallback.attach(object, member);
|
||||
enabledWriteAuthorization = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1445,7 +1596,6 @@ public:
|
|||
void (*callback)(GattReadAuthCallbackParams *)
|
||||
) {
|
||||
readAuthorizationCallback.attach(callback);
|
||||
enabledReadAuthorization = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1467,7 +1617,6 @@ public:
|
|||
void (T::*member)(GattReadAuthCallbackParams *)
|
||||
) {
|
||||
readAuthorizationCallback.attach(object, member);
|
||||
enabledReadAuthorization = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1580,10 +1729,54 @@ public:
|
|||
* Get the characteristic's required security.
|
||||
*
|
||||
* @return The characteristic's required security.
|
||||
*
|
||||
* @deprecated Fine grained security check has been added to with mbed OS
|
||||
* 5.9. It is possible to set independently security requirements for read,
|
||||
* write and update operations. In the meantime SecurityManager::SecurityMode_t
|
||||
* is not used anymore to represent security requirements as it maps
|
||||
* incorrectly the Bluetooth standard.
|
||||
*/
|
||||
MBED_DEPRECATED_SINCE(
|
||||
"mbed-os-5.9",
|
||||
"Use getWriteSecurityRequirements, getReadSecurityRequirements and "
|
||||
"getUpdateSecurityRequirements"
|
||||
)
|
||||
SecurityManager::SecurityMode_t getRequiredSecurity() const
|
||||
{
|
||||
return _requiredSecurity;
|
||||
SecurityRequirement_t max_sec = std::max(
|
||||
std::max(
|
||||
getReadSecurityRequirement(),
|
||||
getWriteSecurityRequirement()
|
||||
),
|
||||
getUpdateSecurityRequirement()
|
||||
);
|
||||
|
||||
bool needs_signing =
|
||||
_properties & BLE_GATT_CHAR_PROPERTIES_AUTHENTICATED_SIGNED_WRITES;
|
||||
|
||||
switch(max_sec.value()) {
|
||||
case SecurityRequirement_t::NONE:
|
||||
MBED_ASSERT(needs_signing == false);
|
||||
return SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK;
|
||||
|
||||
case SecurityRequirement_t::UNAUTHENTICATED:
|
||||
return (needs_signing) ?
|
||||
SecurityManager::SECURITY_MODE_SIGNED_NO_MITM :
|
||||
SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM;
|
||||
|
||||
case SecurityRequirement_t::AUTHENTICATED:
|
||||
return (needs_signing) ?
|
||||
SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM :
|
||||
SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM;
|
||||
|
||||
case SecurityRequirement_t::SC_AUTHENTICATED:
|
||||
MBED_ASSERT(needs_signing == false);
|
||||
// fallback to encryption with MITM
|
||||
return SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM;
|
||||
default:
|
||||
MBED_ASSERT(false);
|
||||
return SecurityManager::SECURITY_MODE_NO_ACCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1606,7 +1799,7 @@ public:
|
|||
*/
|
||||
bool isReadAuthorizationEnabled() const
|
||||
{
|
||||
return enabledReadAuthorization;
|
||||
return readAuthorizationCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1619,7 +1812,7 @@ public:
|
|||
*/
|
||||
bool isWriteAuthorizationEnabled() const
|
||||
{
|
||||
return enabledWriteAuthorization;
|
||||
return writeAuthorizationCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1640,6 +1833,39 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Loosely convert a SecurityManager::SecurityMode_t into a
|
||||
* SecurityRequirement_t.
|
||||
*
|
||||
* @param[in] mode The security mode to convert
|
||||
*
|
||||
* @return The security requirement equivalent to the security mode in input.
|
||||
*/
|
||||
SecurityRequirement_t SecurityModeToAttSecurity(
|
||||
SecurityManager::SecurityMode_t mode
|
||||
) {
|
||||
switch(mode) {
|
||||
case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK:
|
||||
case SecurityManager::SECURITY_MODE_NO_ACCESS:
|
||||
// assuming access is managed by property and orthogonal to
|
||||
// security mode ...
|
||||
return SecurityRequirement_t::NONE;
|
||||
|
||||
case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM:
|
||||
case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM:
|
||||
return SecurityRequirement_t::UNAUTHENTICATED;
|
||||
|
||||
case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM:
|
||||
case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM:
|
||||
return SecurityRequirement_t::AUTHENTICATED;
|
||||
|
||||
default:
|
||||
// should not happens; makes the compiler happy.
|
||||
return SecurityRequirement_t::NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute that contains the actual value of this characteristic.
|
||||
*/
|
||||
|
@ -1651,11 +1877,6 @@ private:
|
|||
*/
|
||||
uint8_t _properties;
|
||||
|
||||
/**
|
||||
* The characteristic's required security.
|
||||
*/
|
||||
SecurityManager::SecurityMode_t _requiredSecurity;
|
||||
|
||||
/**
|
||||
* The characteristic's descriptor attributes.
|
||||
*/
|
||||
|
@ -1666,16 +1887,6 @@ private:
|
|||
*/
|
||||
uint8_t _descriptorCount;
|
||||
|
||||
/**
|
||||
* Whether read authorization is enabled.
|
||||
*/
|
||||
bool enabledReadAuthorization;
|
||||
|
||||
/**
|
||||
* Whether write authorization is enabled.
|
||||
*/
|
||||
bool enabledWriteAuthorization;
|
||||
|
||||
/**
|
||||
* The registered callback handler for read authorization reply.
|
||||
*/
|
||||
|
@ -1688,6 +1899,14 @@ private:
|
|||
FunctionPointerWithContext<GattWriteAuthCallbackParams *>
|
||||
writeAuthorizationCallback;
|
||||
|
||||
/**
|
||||
* Security requirements of update operations.
|
||||
*
|
||||
* The peer must meet the security requirement to enable, disable and
|
||||
* receive updates
|
||||
*/
|
||||
uint8_t _update_security: SecurityRequirement_t::size;
|
||||
|
||||
private:
|
||||
/* Disallow copy and assignment. */
|
||||
GattCharacteristic(const GattCharacteristic &);
|
||||
|
|
|
@ -116,6 +116,15 @@ public:
|
|||
* The server does not acknowledge the status of the operation.
|
||||
*/
|
||||
GATT_OP_WRITE_CMD = 0x02,
|
||||
|
||||
/**
|
||||
* Signed Write command.
|
||||
*
|
||||
* It is used to request the server to write the value of an attribute
|
||||
* using a signed packet. The server does not acknowledge the status
|
||||
* of the operation.
|
||||
*/
|
||||
GATT_OP_SIGNED_WRITE_CMD = 0x03
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -139,6 +139,57 @@ struct SafeEnum {
|
|||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Less than operator for SafeEnum instances.
|
||||
*
|
||||
* @param lhs left hand side of the comparison
|
||||
* @param rhs right hand side of the comparison
|
||||
*
|
||||
* @return true if the inner value of lhs is less than rhs and false otherwise.
|
||||
*/
|
||||
friend bool operator<(SafeEnum lhs, SafeEnum rhs) {
|
||||
return lhs.value() < rhs.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Less than or equal to operator for SafeEnum instances.
|
||||
*
|
||||
* @param lhs left hand side of the comparison
|
||||
* @param rhs right hand side of the comparison
|
||||
*
|
||||
* @return true if the inner value of lhs is less than or equal to rhs and
|
||||
* false otherwise.
|
||||
*/
|
||||
friend bool operator<=(SafeEnum lhs, SafeEnum rhs) {
|
||||
return lhs.value() < rhs.value() || lhs == rhs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Greater than operator for SafeEnum instances.
|
||||
*
|
||||
* @param lhs left hand side of the comparison
|
||||
* @param rhs right hand side of the comparison
|
||||
*
|
||||
* @return true if the inner value of lhs is greater than rhs; false
|
||||
* otherwise.
|
||||
*/
|
||||
friend bool operator>(SafeEnum lhs, SafeEnum rhs) {
|
||||
return !(lhs <= rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Greater than or equal to operator for SafeEnum instances.
|
||||
*
|
||||
* @param lhs left hand side of the comparison
|
||||
* @param rhs right hand side of the comparison
|
||||
*
|
||||
* @return true if the inner value of lhs is greater than or equal to rhs;
|
||||
* false otherwise.
|
||||
*/
|
||||
friend bool operator>=(SafeEnum lhs, SafeEnum rhs) {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicit access to the inner value of the SafeEnum instance.
|
||||
*/
|
||||
|
|
|
@ -31,7 +31,9 @@
|
|||
* and/or exchanging keys used for the current connection. Bonding means saving this information so that
|
||||
* it can later be used after reconnecting without having to pair again. This saves time and power.
|
||||
*
|
||||
* There are many ways to provide these at different levels of security depending on your requirements
|
||||
* @par Paring
|
||||
*
|
||||
* There are several ways to provide different levels of security during pairing depending on your requirements
|
||||
* and the facilities provided by the application. The process starts with initialising the SecurityManager
|
||||
* with default options for new connections. Some settings can later be changed per link or globally.
|
||||
*
|
||||
|
@ -43,6 +45,8 @@
|
|||
* You can change the IO capabilities after initialisation with setIoCapability(). This will take effect
|
||||
* for all subsequent pairings.
|
||||
*
|
||||
* @par Out of Band data used in pairing
|
||||
*
|
||||
* Sharing this information through IO capabilities means user interaction which limits the degree of
|
||||
* protection due to the limit of the amount of data that we can expect the user to transfer. Another
|
||||
* solution is using OOB (out of band) communication to transfer this data instead which can send much
|
||||
|
@ -57,7 +61,27 @@
|
|||
* it. If either side doesn't support it Legacy Pairing will be used. This is an older standard of pairing.
|
||||
* If higher security is required legacy pairing can be disabled by calling allowLegacyPairing(false);
|
||||
*
|
||||
* \par How to use
|
||||
* @par Signing
|
||||
*
|
||||
* Applications may require a level of security providing confidence that data transfers are coming
|
||||
* from a trusted source. This can be achieved by encrypting the link which also provides added confidentiality.
|
||||
* Encryption is a good choice when a device stays connected but introduces latency due to the need of encrypting the
|
||||
* link if the device only connects periodically to transfer data. If confidentiality is not required data GATT
|
||||
* server may allow writes to happen over an unencrypted link but authenticated by a signature present in each packet.
|
||||
* This signature relies on having sent a signing key to the peer during pairing prior to sending any signed packets.
|
||||
*
|
||||
* @par Persistence of Security information
|
||||
*
|
||||
* Security Manager stores all the data required for its operation on active links. Depending on resources
|
||||
* available on the device it will also attempt to store data for disconnected devices which have bonded to be
|
||||
* reused when reconnected.
|
||||
*
|
||||
* If the application has initialised a filesystem and the Security Manager has been provided with a
|
||||
* filepath during the init() call it may also provide data persistence across resets. This must be enabled by
|
||||
* calling preserveBondingStateOnReset(). Persistence is not guaranteed and may fail if abnormally terminated.
|
||||
* The Security Manager may also fall back to a non-persistent implementation if the resources are too limited.
|
||||
*
|
||||
* @par How to use
|
||||
*
|
||||
* First thing you need to do is to initialise the manager by calling init() with your chosen settings.
|
||||
*
|
||||
|
@ -87,7 +111,7 @@
|
|||
* accetPairing() or cancelPairing(). The result will be communicated on both peers through an event calling
|
||||
* pairingResult() in the EventHandler.
|
||||
*
|
||||
* \par Sequence diagrams
|
||||
* @par Sequence diagrams
|
||||
*
|
||||
* Sequence diagram "Just Works" pairing
|
||||
*
|
||||
|
@ -103,7 +127,7 @@
|
|||
* | | |<---[pairing complete]----->| | |
|
||||
* |<- pairingResult() <---------------| |----------------> pairingResult() -->|
|
||||
* | | | | | |
|
||||
* \endverbatim
|
||||
* @endverbatim
|
||||
*
|
||||
* @note the requestPairing() call isn't required to trigger pairing. Pairing will also be triggered
|
||||
* if you request encryption and authentication and no bonding information is available. The sequence will
|
||||
|
@ -121,7 +145,7 @@
|
|||
* | | |<-[encryption established]->| | |
|
||||
* |<- linkEncryptionResult() <--------| |---------> linkEncryptionResult() -->|
|
||||
* | | | | | |
|
||||
* \endverbatim
|
||||
* @endverbatim
|
||||
*
|
||||
* @note if bonding information is not available, pairing will be triggered
|
||||
*
|
||||
|
@ -149,7 +173,7 @@
|
|||
* | | |<---[pairing complete]----->| | |
|
||||
* |<- pairingResult() <---------------| |----------------> pairingResult() -->|
|
||||
* | | | | | |
|
||||
* \endverbatim
|
||||
* @endverbatim
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -417,6 +441,9 @@ public:
|
|||
* support out-of-band exchanges of security data.
|
||||
* @param[in] passkey To specify a static passkey.
|
||||
* @param[in] signing Generate and distribute signing key during pairing
|
||||
* @param[in] dbFilepath Path to the file used to store keys in the filesystem,
|
||||
* if NULL keys will be only stored in memory
|
||||
*
|
||||
*
|
||||
* @return BLE_ERROR_NONE on success.
|
||||
*/
|
||||
|
@ -424,16 +451,34 @@ public:
|
|||
bool requireMITM = true,
|
||||
SecurityIOCapabilities_t iocaps = IO_CAPS_NONE,
|
||||
const Passkey_t passkey = NULL,
|
||||
bool signing = true) {
|
||||
bool signing = true,
|
||||
const char *dbFilepath = NULL) {
|
||||
/* Avoid compiler warnings about unused variables. */
|
||||
(void)enableBonding;
|
||||
(void)requireMITM;
|
||||
(void)iocaps;
|
||||
(void)passkey;
|
||||
(void)dbFilepath;
|
||||
|
||||
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the file used for the security database. If path is invalid or a NULL is passed
|
||||
* keys will only be stored in memory.
|
||||
*
|
||||
* @note This operation is only allowed with no active connections.
|
||||
*
|
||||
* @param[in] dbFilepath Path to the file used to store keys in the filesystem,
|
||||
* if NULL keys will be only stored in memory
|
||||
*
|
||||
* @return BLE_ERROR_NONE on success.
|
||||
*/
|
||||
virtual ble_error_t setDatabaseFilepath(const char *dbFilepath = NULL) {
|
||||
(void)dbFilepath;
|
||||
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all registered onShutdown callbacks that the SecurityManager is
|
||||
* about to be shutdown and clear all SecurityManager state of the
|
||||
|
@ -736,13 +781,47 @@ public:
|
|||
//
|
||||
|
||||
/**
|
||||
* Enable OOB data usage during paring.
|
||||
* Generate OOB data with the given address. If Secure Connections is supported this will
|
||||
* also generate Secure Connections OOB data on top of legacy pairing OOB data. This can be used
|
||||
* to generate such data before the connection takes place.
|
||||
*
|
||||
* In this model the OOB exchange takes place before the devices connect. Devices should establish
|
||||
* communication over another channel and exchange the OOB data. The address provided will be used
|
||||
* by the peer to associate the received data with the address of the device it will then connect
|
||||
* to over BLE.
|
||||
*
|
||||
* @param[in] address The local address you will use in the connection using this OOB data. This
|
||||
* address will be returned along with the rest of the OOB data when generation
|
||||
* is complete. Using an invalid address is illegal.
|
||||
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
|
||||
*/
|
||||
virtual ble_error_t generateOOB(const ble::address_t *address) {
|
||||
/* Avoid compiler warnings about unused variables */
|
||||
(void) address;
|
||||
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable OOB data usage during paring. If Secure Connections is supported enabling useOOB will
|
||||
* generate Secure Connections OOB data through oobGenerated() on top of legacy pairing OOB data.
|
||||
*
|
||||
* You do not have to call this function to return received OOB data. Use legacyPairingOobReceived
|
||||
* or oobReceived to hand it in. This will allow the stack to use it if possible. You only need to
|
||||
* call this function to attempt legacy OOB data exchange after pairing start and to inform
|
||||
* the stack OOB data does not provide MITM protection (by default it is set to provide this).
|
||||
*
|
||||
* In this model the OOB exchange takes places after the devices have connected but possibly
|
||||
* prior to pairing. For secure connections pairing must not be started until after the OOB
|
||||
* data has been sent and/or received. The address in the OOB data generated will match
|
||||
* the original address used to establish the connection and will be used by the peer to
|
||||
* identify which connection the OOB data belongs to.
|
||||
*
|
||||
* @param[in] connectionHandle Handle to identify the connection.
|
||||
* @param[in] useOOB If set to true, authenticate using OOB data.
|
||||
* @param[in] OOBProvidesMITM If set to true keys exchanged during pairing using OOB data
|
||||
* will provide MITM protection. This indicates that the form
|
||||
* of exchange used by the OOB data itself provides MITM protection.
|
||||
* will provide Man-in-the-Middle protection. This indicates that
|
||||
* the form of exchange used by the OOB data itself provides MITM
|
||||
* protection.
|
||||
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
|
||||
*/
|
||||
virtual ble_error_t setOOBDataUsage(ble::connection_handle_t connectionHandle, bool useOOB, bool OOBProvidesMITM = true) {
|
||||
|
@ -933,15 +1012,31 @@ public:
|
|||
*/
|
||||
ble_error_t getLinkSecurity(ble::connection_handle_t connectionHandle, LinkSecurityStatus_t *securityStatus) {
|
||||
ble::link_encryption_t encryption(ble::link_encryption_t::NOT_ENCRYPTED);
|
||||
ble_error_t status = getLinkEncryption(connectionHandle, &encryption);
|
||||
/* legacy support limits the return values */
|
||||
if (encryption.value() == ble::link_encryption_t::ENCRYPTED_WITH_MITM) {
|
||||
*securityStatus = ENCRYPTED;
|
||||
} else {
|
||||
*securityStatus = (LinkSecurityStatus_t)encryption.value();
|
||||
ble_error_t err = getLinkEncryption(connectionHandle, &encryption);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return status;
|
||||
switch (encryption.value()) {
|
||||
case ble::link_encryption_t::NOT_ENCRYPTED:
|
||||
*securityStatus = NOT_ENCRYPTED;
|
||||
break;
|
||||
case ble::link_encryption_t::ENCRYPTION_IN_PROGRESS:
|
||||
*securityStatus = ENCRYPTION_IN_PROGRESS;
|
||||
break;
|
||||
case ble::link_encryption_t::ENCRYPTED:
|
||||
case ble::link_encryption_t::ENCRYPTED_WITH_MITM:
|
||||
case ble::link_encryption_t::ENCRYPTED_WITH_SC_AND_MITM:
|
||||
*securityStatus = ENCRYPTED;
|
||||
break;
|
||||
default:
|
||||
// should never happen
|
||||
MBED_ASSERT(false);
|
||||
*securityStatus = NOT_ENCRYPTED;
|
||||
break;
|
||||
}
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1045,7 +1140,10 @@ private:
|
|||
SecurityManager::SecurityMode_t securityMode;
|
||||
if (result == ble::link_encryption_t::ENCRYPTED) {
|
||||
securityMode = SECURITY_MODE_ENCRYPTION_NO_MITM;
|
||||
} else if (result == ble::link_encryption_t::ENCRYPTED_WITH_MITM) {
|
||||
} else if (
|
||||
result == ble::link_encryption_t::ENCRYPTED_WITH_MITM ||
|
||||
result == ble::link_encryption_t::ENCRYPTED_WITH_SC_AND_MITM
|
||||
) {
|
||||
securityMode = SECURITY_MODE_ENCRYPTION_WITH_MITM;
|
||||
} else {
|
||||
securityMode = SECURITY_MODE_ENCRYPTION_OPEN_LINK;
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
#ifndef GENERIC_FILE_SECURITY_DB_H_
|
||||
#define GENERIC_FILE_SECURITY_DB_H_
|
||||
|
||||
#include "SecurityDb.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace ble {
|
||||
namespace generic {
|
||||
|
||||
/** Filesystem implementation */
|
||||
class FileSecurityDb : public SecurityDb {
|
||||
private:
|
||||
|
||||
struct entry_t {
|
||||
SecurityDistributionFlags_t flags;
|
||||
sign_count_t peer_sign_counter;
|
||||
size_t file_offset;
|
||||
};
|
||||
|
||||
static const size_t MAX_ENTRIES = 5;
|
||||
|
||||
static entry_t* as_entry(entry_handle_t db_handle) {
|
||||
return reinterpret_cast<entry_t*>(db_handle);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void db_read(T *value, long int offset) {
|
||||
fseek(_db_file, offset, SEEK_SET);
|
||||
fread(value, sizeof(T), 1, _db_file);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void db_write(T *value, long int offset) {
|
||||
fseek(_db_file, offset, SEEK_SET);
|
||||
fwrite(value, sizeof(T), 1, _db_file);
|
||||
}
|
||||
|
||||
public:
|
||||
FileSecurityDb(FILE *db_file);
|
||||
virtual ~FileSecurityDb();
|
||||
|
||||
/**
|
||||
* Validates or creates a file for the security database.
|
||||
* @param db_path path to the file
|
||||
* @return FILE handle open and ready for use by the database or NULL if unavailable
|
||||
*/
|
||||
static FILE* open_db_file(const char *db_path);
|
||||
|
||||
virtual SecurityDistributionFlags_t* get_distribution_flags(
|
||||
entry_handle_t db_handle
|
||||
);
|
||||
|
||||
|
||||
/* local keys */
|
||||
|
||||
/* set */
|
||||
virtual void set_entry_local_ltk(
|
||||
entry_handle_t db_handle,
|
||||
const ltk_t <k
|
||||
);
|
||||
|
||||
virtual void set_entry_local_ediv_rand(
|
||||
entry_handle_t db_handle,
|
||||
const ediv_t &ediv,
|
||||
const rand_t &rand
|
||||
);
|
||||
|
||||
/* peer's keys */
|
||||
|
||||
/* set */
|
||||
|
||||
virtual void set_entry_peer_ltk(
|
||||
entry_handle_t db_handle,
|
||||
const ltk_t <k
|
||||
);
|
||||
|
||||
virtual void set_entry_peer_ediv_rand(
|
||||
entry_handle_t db_handle,
|
||||
const ediv_t &ediv,
|
||||
const rand_t &rand
|
||||
);
|
||||
|
||||
virtual void set_entry_peer_irk(
|
||||
entry_handle_t db_handle,
|
||||
const irk_t &irk
|
||||
);
|
||||
|
||||
virtual void set_entry_peer_bdaddr(
|
||||
entry_handle_t db_handle,
|
||||
bool address_is_public,
|
||||
const address_t &peer_address
|
||||
);
|
||||
|
||||
virtual void set_entry_peer_csrk(
|
||||
entry_handle_t db_handle,
|
||||
const csrk_t &csrk
|
||||
);
|
||||
|
||||
virtual void set_entry_peer_sign_counter(
|
||||
entry_handle_t db_handle,
|
||||
sign_count_t sign_counter
|
||||
);
|
||||
|
||||
/* saving and loading from nvm */
|
||||
|
||||
virtual void restore();
|
||||
|
||||
virtual void sync(entry_handle_t db_handle);
|
||||
|
||||
virtual void set_restore(bool reload);
|
||||
|
||||
private:
|
||||
virtual uint8_t get_entry_count();
|
||||
|
||||
virtual SecurityDistributionFlags_t* get_entry_handle_by_index(uint8_t index);
|
||||
|
||||
virtual void reset_entry(entry_handle_t db_handle);
|
||||
|
||||
virtual SecurityEntryIdentity_t* read_in_entry_peer_identity(entry_handle_t db_handle);
|
||||
virtual SecurityEntryKeys_t* read_in_entry_peer_keys(entry_handle_t db_handle);
|
||||
virtual SecurityEntryKeys_t* read_in_entry_local_keys(entry_handle_t db_handle);
|
||||
virtual SecurityEntrySigning_t* read_in_entry_peer_signing(entry_handle_t db_handle);
|
||||
|
||||
/**
|
||||
* Zero the db file.
|
||||
* @param db_file filehandle for file to erase
|
||||
* @return filehandle when successful, otherwise NULL
|
||||
*/
|
||||
static FILE* erase_db_file(FILE* db_file);
|
||||
|
||||
private:
|
||||
entry_t _entries[MAX_ENTRIES];
|
||||
FILE *_db_file;
|
||||
uint8_t _buffer[sizeof(SecurityEntryKeys_t)];
|
||||
};
|
||||
|
||||
} /* namespace pal */
|
||||
} /* namespace ble */
|
||||
|
||||
#endif /*GENERIC_FILE_SECURITY_DB_H_*/
|
|
@ -23,6 +23,7 @@
|
|||
#include "ble/BLEProtocol.h"
|
||||
#include "ble/Gap.h"
|
||||
#include "ble/pal/PalGap.h"
|
||||
#include "ble/pal/PalSecurityManager.h"
|
||||
#include "ble/pal/GapEvents.h"
|
||||
#include "ble/pal/GapTypes.h"
|
||||
#include "ble/BLETypes.h"
|
||||
|
@ -55,11 +56,15 @@ public:
|
|||
*
|
||||
* @param generic_access_service Platform abstraction instance managing
|
||||
* the GATT generic access service.
|
||||
*
|
||||
* @param pal_sm Security Manager Platform abstraction instance containing the base
|
||||
* Security Manager primitives.
|
||||
*/
|
||||
GenericGap(
|
||||
pal::EventQueue &event_queue,
|
||||
pal::Gap &pal_gap,
|
||||
pal::GenericAccessService &generic_access_service
|
||||
pal::GenericAccessService &generic_access_service,
|
||||
pal::SecurityManager &pal_sm
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -108,6 +113,16 @@ public:
|
|||
*/
|
||||
virtual ble_error_t stopScan();
|
||||
|
||||
/**
|
||||
* @see Gap::connect
|
||||
*/
|
||||
virtual ble_error_t connect(
|
||||
const BLEProtocol::AddressBytes_t peerAddr,
|
||||
PeerAddressType_t peerAddrType,
|
||||
const ConnectionParams_t *connectionParams,
|
||||
const GapScanningParams *scanParams
|
||||
);
|
||||
|
||||
/**
|
||||
* @see Gap::connect
|
||||
*/
|
||||
|
@ -233,6 +248,39 @@ public:
|
|||
*/
|
||||
virtual ble_error_t initRadioNotification(void);
|
||||
|
||||
/**
|
||||
* @see Gap::enablePrivacy
|
||||
*/
|
||||
virtual ble_error_t enablePrivacy(bool enable);
|
||||
|
||||
/**
|
||||
* @see Gap::setPeripheralPrivacyConfiguration
|
||||
*/
|
||||
virtual ble_error_t setPeripheralPrivacyConfiguration(
|
||||
const PeripheralPrivacyConfiguration_t *configuration
|
||||
);
|
||||
|
||||
/**
|
||||
* @see Gap::getPeripheralPrivacyConfiguration
|
||||
*/
|
||||
virtual ble_error_t getPeripheralPrivacyConfiguration(
|
||||
PeripheralPrivacyConfiguration_t *configuration
|
||||
);
|
||||
|
||||
/**
|
||||
* @see Gap::setCentralPrivacyConfiguration
|
||||
*/
|
||||
virtual ble_error_t setCentralPrivacyConfiguration(
|
||||
const CentralPrivacyConfiguration_t *configuration
|
||||
);
|
||||
|
||||
/**
|
||||
* @see Gap::getCentralPrivacyConfiguration
|
||||
*/
|
||||
virtual ble_error_t getCentralPrivacyConfiguration(
|
||||
CentralPrivacyConfiguration_t *configuration
|
||||
);
|
||||
|
||||
/**
|
||||
* @see Gap::setAdvertisingData
|
||||
*/
|
||||
|
@ -257,11 +305,13 @@ public:
|
|||
void processConnectionEvent(
|
||||
Handle_t handle,
|
||||
Role_t role,
|
||||
BLEProtocol::AddressType_t peerAddrType,
|
||||
peer_address_type_t peerAddrType,
|
||||
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,
|
||||
const uint8_t *localResolvableAddr
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -302,21 +352,45 @@ private:
|
|||
|
||||
void on_unexpected_error(const pal::GapUnexpectedErrorEvent &e);
|
||||
|
||||
pal::own_address_type_t get_own_address_type();
|
||||
enum AddressUseType_t {
|
||||
CENTRAL_CONNECTION,
|
||||
CENTRAL_SCAN,
|
||||
PERIPHERAL_CONNECTABLE,
|
||||
PERIPHERAL_NON_CONNECTABLE
|
||||
};
|
||||
|
||||
pal::own_address_type_t get_own_address_type(AddressUseType_t address_use_type);
|
||||
|
||||
bool initialize_whitelist() const;
|
||||
|
||||
ble_error_t update_address_resolution_setting();
|
||||
|
||||
void set_random_address_rotation(bool enable);
|
||||
|
||||
void update_random_address();
|
||||
|
||||
void on_address_rotation_timeout();
|
||||
|
||||
pal::EventQueue& _event_queue;
|
||||
pal::Gap &_pal_gap;
|
||||
pal::GenericAccessService &_gap_service;
|
||||
pal::SecurityManager &_pal_sm;
|
||||
BLEProtocol::AddressType_t _address_type;
|
||||
ble::address_t _address;
|
||||
pal::initiator_policy_t _initiator_policy_mode;
|
||||
pal::scanning_filter_policy_t _scanning_filter_policy;
|
||||
pal::advertising_filter_policy_t _advertising_filter_policy;
|
||||
mutable Whitelist_t _whitelist;
|
||||
|
||||
bool _privacy_enabled;
|
||||
PeripheralPrivacyConfiguration_t _peripheral_privacy_configuration;
|
||||
CentralPrivacyConfiguration_t _central_privacy_configuration;
|
||||
ble::address_t _random_static_identity_address;
|
||||
bool _random_address_rotating;
|
||||
|
||||
mbed::Timeout _advertising_timeout;
|
||||
mbed::Timeout _scan_timeout;
|
||||
mbed::Ticker _address_rotation_ticker;
|
||||
pal::ConnectionEventMonitor::EventHandler *_connection_event_handler;
|
||||
};
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <algorithm>
|
||||
#include "ble/GattClient.h"
|
||||
#include "ble/pal/PalGattClient.h"
|
||||
#include "ble/pal/SigningEventMonitor.h"
|
||||
|
||||
// IMPORTANT: private header. Not part of the public interface.
|
||||
|
||||
|
@ -31,7 +32,8 @@ namespace generic {
|
|||
* It requires a pal::GattClient injected at construction site.
|
||||
* @attention: Not part of the public interface of BLE API.
|
||||
*/
|
||||
class GenericGattClient : public GattClient {
|
||||
class GenericGattClient : public GattClient,
|
||||
public pal::SigningEventMonitor {
|
||||
public:
|
||||
/**
|
||||
* Create a GenericGattClient from a pal::GattClient
|
||||
|
@ -114,6 +116,11 @@ public:
|
|||
*/
|
||||
virtual ble_error_t reset(void);
|
||||
|
||||
/**
|
||||
* @see ble::pal::SigningEventMonitor::set_signing_event_handler
|
||||
*/
|
||||
virtual void set_signing_event_handler(pal::SigningEventMonitor::EventHandler *signing_event_handler);
|
||||
|
||||
private:
|
||||
struct ProcedureControlBlock;
|
||||
struct DiscoveryControlBlock;
|
||||
|
@ -136,6 +143,7 @@ private:
|
|||
|
||||
pal::GattClient* const _pal_client;
|
||||
ServiceDiscovery::TerminationCallback_t _termination_callback;
|
||||
pal::SigningEventMonitor::EventHandler* _signing_event_handler;
|
||||
mutable ProcedureControlBlock* control_blocks;
|
||||
bool _is_reseting;
|
||||
};
|
||||
|
|
|
@ -19,11 +19,13 @@
|
|||
|
||||
#include "ble/pal/GapTypes.h"
|
||||
#include "ble/BLETypes.h"
|
||||
#include "ble/pal/SecurityDb.h"
|
||||
#include "ble/generic/SecurityDb.h"
|
||||
#include "platform/Callback.h"
|
||||
#include "ble/pal/ConnectionEventMonitor.h"
|
||||
#include "ble/pal/SigningEventMonitor.h"
|
||||
#include "ble/generic/GenericGap.h"
|
||||
#include "ble/pal/PalSecurityManager.h"
|
||||
#include "ble/ArrayView.h"
|
||||
|
||||
namespace ble {
|
||||
namespace generic {
|
||||
|
@ -32,10 +34,9 @@ typedef SecurityManager::SecurityIOCapabilities_t SecurityIOCapabilities_t;
|
|||
|
||||
class GenericSecurityManager : public SecurityManager,
|
||||
public pal::SecurityManager::EventHandler,
|
||||
public pal::ConnectionEventMonitor::EventHandler {
|
||||
public pal::ConnectionEventMonitor::EventHandler,
|
||||
public pal::SigningEventMonitor::EventHandler {
|
||||
public:
|
||||
typedef ble::pal::SecurityDistributionFlags_t SecurityDistributionFlags_t;
|
||||
typedef ble::pal::SecurityEntryKeys_t SecurityEntryKeys_t;
|
||||
|
||||
/* implements SecurityManager */
|
||||
|
||||
|
@ -48,9 +49,12 @@ public:
|
|||
bool mitm = true,
|
||||
SecurityIOCapabilities_t iocaps = IO_CAPS_NONE,
|
||||
const Passkey_t passkey = NULL,
|
||||
bool signing = true
|
||||
bool signing = true,
|
||||
const char* db_path = NULL
|
||||
);
|
||||
|
||||
virtual ble_error_t setDatabaseFilepath(const char *db_path = NULL);
|
||||
|
||||
virtual ble_error_t reset();
|
||||
|
||||
virtual ble_error_t preserveBondingStateOnReset(
|
||||
|
@ -192,6 +196,10 @@ public:
|
|||
// MITM
|
||||
//
|
||||
|
||||
virtual ble_error_t generateOOB(
|
||||
const address_t *address
|
||||
);
|
||||
|
||||
virtual ble_error_t setOOBDataUsage(
|
||||
connection_handle_t connection,
|
||||
bool useOOB,
|
||||
|
@ -229,18 +237,27 @@ public:
|
|||
public:
|
||||
GenericSecurityManager(
|
||||
pal::SecurityManager &palImpl,
|
||||
pal::SecurityDb &dbImpl,
|
||||
pal::ConnectionEventMonitor &connMonitorImpl
|
||||
pal::ConnectionEventMonitor &connMonitorImpl,
|
||||
pal::SigningEventMonitor &signingMonitorImpl
|
||||
) : _pal(palImpl),
|
||||
_db(dbImpl),
|
||||
_connection_monitor(connMonitorImpl),
|
||||
_signing_monitor(signingMonitorImpl),
|
||||
_db(NULL),
|
||||
_default_authentication(0),
|
||||
_default_key_distribution(pal::KeyDistribution::KEY_DISTRIBUTION_ALL),
|
||||
_pairing_authorisation_required(false),
|
||||
_legacy_pairing_allowed(true),
|
||||
_master_sends_keys(false),
|
||||
_public_keys_generated(false) {
|
||||
_master_sends_keys(false) {
|
||||
_pal.set_event_handler(this);
|
||||
|
||||
/* We create a fake value for oob to allow creation of the next oob which needs
|
||||
* the last process to finish first before restarting (this is to simplify checking).
|
||||
* This fake value will not be used as the oob address is currently invalid */
|
||||
_oob_local_random[0] = 1;
|
||||
}
|
||||
|
||||
~GenericSecurityManager() {
|
||||
delete _db;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -248,6 +265,22 @@ public:
|
|||
//
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Initialise the database, if database already exists it will close it and open the new one.
|
||||
*
|
||||
* @param db_path path to file to store secure db
|
||||
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
|
||||
*/
|
||||
ble_error_t init_database(const char *db_path = NULL);
|
||||
|
||||
/**
|
||||
* Generate identity list based on the database of IRK and apply it to the resolving list.
|
||||
*
|
||||
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
|
||||
*/
|
||||
ble_error_t init_resolving_list();
|
||||
|
||||
/**
|
||||
* Generate the CSRK if needed.
|
||||
*
|
||||
|
@ -295,7 +328,7 @@ private:
|
|||
* @param[in] entryKeys security entry containing keys.
|
||||
*/
|
||||
void enable_encryption_cb(
|
||||
pal::SecurityDb::entry_handle_t entry,
|
||||
SecurityDb::entry_handle_t entry,
|
||||
const SecurityEntryKeys_t* entryKeys
|
||||
);
|
||||
|
||||
|
@ -306,7 +339,7 @@ private:
|
|||
* @param[in] entryKeys security entry containing keys.
|
||||
*/
|
||||
void set_ltk_cb(
|
||||
pal::SecurityDb::entry_handle_t entry,
|
||||
SecurityDb::entry_handle_t entry,
|
||||
const SecurityEntryKeys_t* entryKeys
|
||||
);
|
||||
|
||||
|
@ -314,23 +347,23 @@ private:
|
|||
* Returns the CSRK for the connection. Called by the security db.
|
||||
*
|
||||
* @param[in] connectionHandle Handle to identify the connection.
|
||||
* @param[in] entryKeys security entry containing keys.
|
||||
* @param[in] signing connection signature resolving key and counter.
|
||||
*/
|
||||
void return_csrk_cb(
|
||||
pal::SecurityDb::entry_handle_t connection,
|
||||
const csrk_t *csrk
|
||||
SecurityDb::entry_handle_t connection,
|
||||
const SecurityEntrySigning_t *signing
|
||||
);
|
||||
|
||||
#if defined(MBEDTLS_CMAC_C)
|
||||
/**
|
||||
* Generate local OOB data to be sent to the application which sends it to the peer.
|
||||
* Set the peer CSRK for the connection. Called by the security db.
|
||||
*
|
||||
* @param[in] connectionHandle Handle to identify the connection.
|
||||
* @param[in] signing connection signature resolving key and counter.
|
||||
*/
|
||||
void generate_secure_connections_oob(
|
||||
connection_handle_t connection
|
||||
void set_peer_csrk_cb(
|
||||
SecurityDb::entry_handle_t connection,
|
||||
const SecurityEntrySigning_t *signing
|
||||
);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Updates the entry for the connection with OOB data presence.
|
||||
|
@ -341,26 +374,6 @@ private:
|
|||
connection_handle_t connection
|
||||
);
|
||||
|
||||
#if defined(MBEDTLS_CMAC_C)
|
||||
/**
|
||||
* Calculate the confirmation value for secure connections OOB data based
|
||||
* on local public key and a random number.
|
||||
* @see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part H - 2.2.6
|
||||
|
||||
* @param[in] U public key x component
|
||||
* @param[in] V public key y component
|
||||
* @param[in] X random number
|
||||
* @param[out] confirm confirmation value
|
||||
* @return true if cryptography functioned worked
|
||||
*/
|
||||
static bool crypto_toolbox_f4(
|
||||
const public_key_coord_t &U,
|
||||
const public_key_coord_t &V,
|
||||
const oob_lesc_value_t &X,
|
||||
oob_confirm_t &confirm
|
||||
);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Set the MITM protection setting on the database entry
|
||||
*
|
||||
|
@ -386,7 +399,7 @@ private:
|
|||
virtual void on_connected(
|
||||
connection_handle_t connection,
|
||||
Gap::Role_t role,
|
||||
BLEProtocol::AddressType_t peer_address_type,
|
||||
peer_address_type_t peer_address_type,
|
||||
const BLEProtocol::AddressBytes_t peer_address,
|
||||
BLEProtocol::AddressType_t local_address_type,
|
||||
const BLEProtocol::AddressBytes_t local_address,
|
||||
|
@ -406,25 +419,32 @@ private:
|
|||
);
|
||||
|
||||
/**
|
||||
* Inform the security manager of a new connection.
|
||||
*
|
||||
* @param[in] params information about the new connection.
|
||||
* Callback invoked by the secure DB when an identity entry has been
|
||||
* retrieved.
|
||||
* @param entry Handle of the entry.
|
||||
* @param identity The identity associated with the entry; may be NULL.
|
||||
*/
|
||||
void connection_callback(
|
||||
const Gap::ConnectionCallbackParams_t* params
|
||||
void on_security_entry_retrieved(
|
||||
SecurityDb::entry_handle_t entry,
|
||||
const SecurityEntryIdentity_t* identity
|
||||
);
|
||||
|
||||
/**
|
||||
* Inform the security manager that a connection ended.
|
||||
* Callback invoked by the secure DB when the identity list has been
|
||||
* retrieved.
|
||||
*
|
||||
* @param[in] params handle and reason of the disconnection.
|
||||
* @param identity View to the array passed to the secure DB. It contains
|
||||
* identity entries retrieved.
|
||||
*
|
||||
* @param count Number of identities entries retrieved.
|
||||
*/
|
||||
void disconnection_callback(
|
||||
const Gap::DisconnectionCallbackParams_t* params
|
||||
void on_identity_list_retrieved(
|
||||
ble::ArrayView<SecurityEntryIdentity_t>& identity_list,
|
||||
size_t count
|
||||
);
|
||||
|
||||
private:
|
||||
struct ControlBlock_t : public pal::SecurityDistributionFlags_t {
|
||||
struct ControlBlock_t {
|
||||
ControlBlock_t();
|
||||
|
||||
pal::KeyDistribution get_initiator_key_distribution() {
|
||||
|
@ -441,7 +461,7 @@ private:
|
|||
};
|
||||
|
||||
connection_handle_t connection;
|
||||
pal::SecurityDb::entry_handle_t db_entry;
|
||||
SecurityDb::entry_handle_t db_entry;
|
||||
|
||||
address_t local_address; /**< address used for connection, possibly different from identity */
|
||||
|
||||
|
@ -465,11 +485,25 @@ private:
|
|||
uint8_t attempt_oob:1;
|
||||
uint8_t oob_mitm_protection:1;
|
||||
uint8_t oob_present:1;
|
||||
uint8_t legacy_pairing_oob_request_pending:1;
|
||||
|
||||
uint8_t csrk_failures:2;
|
||||
};
|
||||
|
||||
pal::SecurityManager &_pal;
|
||||
pal::SecurityDb &_db;
|
||||
pal::ConnectionEventMonitor &_connection_monitor;
|
||||
pal::SigningEventMonitor &_signing_monitor;
|
||||
|
||||
SecurityDb *_db;
|
||||
|
||||
/* OOB data */
|
||||
address_t _oob_local_address;
|
||||
address_t _oob_peer_address;
|
||||
oob_lesc_value_t _oob_peer_random;
|
||||
oob_confirm_t _oob_peer_confirm;
|
||||
oob_lesc_value_t _oob_local_random;
|
||||
address_t _oob_temporary_key_creator_address; /**< device which generated and sent the TK */
|
||||
oob_tk_t _oob_temporary_key; /**< used for legacy pairing */
|
||||
|
||||
pal::AuthenticationMask _default_authentication;
|
||||
pal::KeyDistribution _default_key_distribution;
|
||||
|
@ -477,13 +511,6 @@ private:
|
|||
bool _pairing_authorisation_required;
|
||||
bool _legacy_pairing_allowed;
|
||||
bool _master_sends_keys;
|
||||
bool _public_keys_generated;
|
||||
|
||||
/** There is always only one OOB data set stored at a time */
|
||||
address_t _peer_sc_oob_address;
|
||||
oob_lesc_value_t _peer_sc_oob_random;
|
||||
oob_confirm_t _peer_sc_oob_confirm;
|
||||
oob_lesc_value_t _local_sc_oob_random;
|
||||
|
||||
static const size_t MAX_CONTROL_BLOCKS = 5;
|
||||
ControlBlock_t _control_blocks[MAX_CONTROL_BLOCKS];
|
||||
|
@ -533,6 +560,23 @@ public:
|
|||
connection_handle_t connection
|
||||
);
|
||||
|
||||
/** @copydoc ble::pal::SecurityManager::on_signed_write_received
|
||||
*/
|
||||
virtual void on_signed_write_received(
|
||||
connection_handle_t connection,
|
||||
uint32_t sign_coutner
|
||||
);
|
||||
|
||||
/** @copydoc ble::pal::SecurityManager::on_signed_write_verification_failure
|
||||
*/
|
||||
virtual void on_signed_write_verification_failure(
|
||||
connection_handle_t connection
|
||||
);
|
||||
|
||||
/** @copydoc ble::pal::SecurityManager::on_signed_write
|
||||
*/
|
||||
virtual void on_signed_write();
|
||||
|
||||
/** @copydoc ble::pal::SecurityManager::on_slave_security_request
|
||||
*/
|
||||
virtual void on_slave_security_request(
|
||||
|
@ -587,31 +631,29 @@ public:
|
|||
connection_handle_t connection
|
||||
);
|
||||
|
||||
/** @copydoc ble::pal::SecurityManager::on_secure_connections_oob_request
|
||||
*/
|
||||
virtual void on_secure_connections_oob_request(
|
||||
connection_handle_t connection
|
||||
);
|
||||
|
||||
/** @copydoc ble::pal::SecurityManager::on_legacy_pairing_oob_request
|
||||
*/
|
||||
virtual void on_legacy_pairing_oob_request(
|
||||
connection_handle_t connection
|
||||
);
|
||||
|
||||
/** @copydoc ble::pal::SecurityManager::on_oob_data_verification_request
|
||||
/** @copydoc ble::pal::SecurityManager::on_secure_connections_oob_generated
|
||||
*/
|
||||
virtual void on_oob_data_verification_request(
|
||||
connection_handle_t connection,
|
||||
const public_key_coord_t &peer_public_key_x,
|
||||
const public_key_coord_t &peer_public_key_y
|
||||
virtual void on_secure_connections_oob_generated(
|
||||
const oob_lesc_value_t &random,
|
||||
const oob_confirm_t &confirm
|
||||
);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Keys
|
||||
//
|
||||
|
||||
/** @copydoc ble::pal::SecurityManager::on_public_key_generated
|
||||
*/
|
||||
virtual void on_public_key_generated(
|
||||
const public_key_coord_t &public_key_x,
|
||||
const public_key_coord_t &public_key_y
|
||||
);
|
||||
|
||||
/** @copydoc ble::pal::SecurityManager::on_secure_connections_ltk_generated
|
||||
*/
|
||||
virtual void on_secure_connections_ltk_generated(
|
||||
|
@ -695,7 +737,7 @@ public:
|
|||
|
||||
ControlBlock_t* get_control_block(const address_t &peer_address);
|
||||
|
||||
ControlBlock_t* get_control_block(pal::SecurityDb::entry_handle_t db_entry);
|
||||
ControlBlock_t* get_control_block(SecurityDb::entry_handle_t db_entry);
|
||||
|
||||
void release_control_block(ControlBlock_t* entry);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
#ifndef GENERIC_MEMORY_SECURITY_DB_H_
|
||||
#define GENERIC_MEMORY_SECURITY_DB_H_
|
||||
|
||||
#include "SecurityDb.h"
|
||||
|
||||
namespace ble {
|
||||
namespace generic {
|
||||
|
||||
/** Naive memory implementation for verification. */
|
||||
class MemorySecurityDb : public SecurityDb {
|
||||
private:
|
||||
struct entry_t {
|
||||
entry_t() { };
|
||||
SecurityDistributionFlags_t flags;
|
||||
SecurityEntryKeys_t local_keys;
|
||||
SecurityEntryKeys_t peer_keys;
|
||||
SecurityEntryIdentity_t peer_identity;
|
||||
SecurityEntrySigning_t peer_signing;
|
||||
};
|
||||
|
||||
static const size_t MAX_ENTRIES = 5;
|
||||
|
||||
static entry_t* as_entry(entry_handle_t db_handle)
|
||||
{
|
||||
return reinterpret_cast<entry_t*>(db_handle);
|
||||
}
|
||||
|
||||
public:
|
||||
MemorySecurityDb() : SecurityDb() { }
|
||||
virtual ~MemorySecurityDb() { }
|
||||
|
||||
virtual SecurityDistributionFlags_t* get_distribution_flags(
|
||||
entry_handle_t db_handle
|
||||
) {
|
||||
return reinterpret_cast<SecurityDistributionFlags_t*>(db_handle);
|
||||
}
|
||||
|
||||
/* local keys */
|
||||
|
||||
/* set */
|
||||
virtual void set_entry_local_ltk(
|
||||
entry_handle_t db_handle,
|
||||
const ltk_t <k
|
||||
) {
|
||||
entry_t *entry = as_entry(db_handle);
|
||||
if (entry) {
|
||||
entry->flags.ltk_sent = true;
|
||||
entry->local_keys.ltk = ltk;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_entry_local_ediv_rand(
|
||||
entry_handle_t db_handle,
|
||||
const ediv_t &ediv,
|
||||
const rand_t &rand
|
||||
) {
|
||||
entry_t *entry = as_entry(db_handle);
|
||||
if (entry) {
|
||||
entry->local_keys.ediv = ediv;
|
||||
entry->local_keys.rand = rand;
|
||||
}
|
||||
}
|
||||
|
||||
/* peer's keys */
|
||||
|
||||
/* set */
|
||||
|
||||
virtual void set_entry_peer_ltk(
|
||||
entry_handle_t db_handle,
|
||||
const ltk_t <k
|
||||
) {
|
||||
entry_t *entry = as_entry(db_handle);
|
||||
if (entry) {
|
||||
entry->peer_keys.ltk = ltk;
|
||||
entry->flags.ltk_stored = true;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_entry_peer_ediv_rand(
|
||||
entry_handle_t db_handle,
|
||||
const ediv_t &ediv,
|
||||
const rand_t &rand
|
||||
) {
|
||||
entry_t *entry = as_entry(db_handle);
|
||||
if (entry) {
|
||||
entry->peer_keys.ediv = ediv;
|
||||
entry->peer_keys.rand = rand;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_entry_peer_irk(
|
||||
entry_handle_t db_handle,
|
||||
const irk_t &irk
|
||||
) {
|
||||
entry_t *entry = as_entry(db_handle);
|
||||
if (entry) {
|
||||
entry->peer_identity.irk = irk;
|
||||
entry->flags.irk_stored = true;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_entry_peer_bdaddr(
|
||||
entry_handle_t db_handle,
|
||||
bool address_is_public,
|
||||
const address_t &peer_address
|
||||
) {
|
||||
entry_t *entry = as_entry(db_handle);
|
||||
if (entry) {
|
||||
entry->peer_identity.identity_address = peer_address;
|
||||
entry->peer_identity.identity_address_is_public = address_is_public;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_entry_peer_csrk(
|
||||
entry_handle_t db_handle,
|
||||
const csrk_t &csrk
|
||||
) {
|
||||
entry_t *entry = as_entry(db_handle);
|
||||
if (entry) {
|
||||
entry->flags.csrk_stored = true;
|
||||
entry->peer_signing.csrk = csrk;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_entry_peer_sign_counter(
|
||||
entry_handle_t db_handle,
|
||||
sign_count_t sign_counter
|
||||
) {
|
||||
entry_t *entry = as_entry(db_handle);
|
||||
if (entry) {
|
||||
entry->peer_signing.counter = sign_counter;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
virtual uint8_t get_entry_count() {
|
||||
return MAX_ENTRIES;
|
||||
}
|
||||
|
||||
virtual SecurityDistributionFlags_t* get_entry_handle_by_index(uint8_t index) {
|
||||
if (index < MAX_ENTRIES) {
|
||||
return &_entries[index].flags;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void reset_entry(entry_handle_t db_entry) {
|
||||
entry_t *entry = reinterpret_cast<entry_t*>(db_entry);
|
||||
*entry = entry_t();
|
||||
}
|
||||
|
||||
virtual SecurityEntryIdentity_t* read_in_entry_peer_identity(entry_handle_t db_entry) {
|
||||
entry_t *entry = reinterpret_cast<entry_t*>(db_entry);
|
||||
return &entry->peer_identity;
|
||||
};
|
||||
|
||||
virtual SecurityEntryKeys_t* read_in_entry_peer_keys(entry_handle_t db_entry) {
|
||||
entry_t *entry = reinterpret_cast<entry_t*>(db_entry);
|
||||
return &entry->peer_keys;
|
||||
};
|
||||
|
||||
virtual SecurityEntryKeys_t* read_in_entry_local_keys(entry_handle_t db_entry) {
|
||||
entry_t *entry = reinterpret_cast<entry_t*>(db_entry);
|
||||
return &entry->local_keys;
|
||||
};
|
||||
|
||||
virtual SecurityEntrySigning_t* read_in_entry_peer_signing(entry_handle_t db_entry) {
|
||||
entry_t *entry = reinterpret_cast<entry_t*>(db_entry);
|
||||
return &entry->peer_signing;
|
||||
};
|
||||
|
||||
private:
|
||||
entry_t _entries[MAX_ENTRIES];
|
||||
};
|
||||
|
||||
} /* namespace pal */
|
||||
} /* namespace ble */
|
||||
|
||||
#endif /*GENERIC_MEMORY_SECURITY_DB_H_*/
|
|
@ -0,0 +1,752 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
#ifndef GENERIC_SECURITY_MANAGER_DB_H__
|
||||
#define GENERIC_SECURITY_MANAGER_DB_H__
|
||||
|
||||
#include "platform/Callback.h"
|
||||
#include "ble/pal/GapTypes.h"
|
||||
#include "ble/BLETypes.h"
|
||||
#include "ble/Gap.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace ble {
|
||||
namespace generic {
|
||||
|
||||
|
||||
/**
|
||||
* Security flags associated with a bond.
|
||||
*/
|
||||
struct SecurityDistributionFlags_t {
|
||||
SecurityDistributionFlags_t() :
|
||||
peer_address(),
|
||||
encryption_key_size(0),
|
||||
peer_address_is_public(false),
|
||||
csrk_stored(false),
|
||||
ltk_stored(false),
|
||||
ltk_sent(false),
|
||||
irk_stored(false),
|
||||
csrk_mitm_protected(false),
|
||||
ltk_mitm_protected(false),
|
||||
secure_connections_paired(false),
|
||||
connected(false) {
|
||||
}
|
||||
|
||||
/** peer address */
|
||||
address_t peer_address;
|
||||
|
||||
/** encryption key size */
|
||||
uint8_t encryption_key_size;
|
||||
/** true if peer address is public, false if it's static random */
|
||||
uint8_t peer_address_is_public:1;
|
||||
|
||||
/** CSRK (Connection Signature Resolving Key) has been distributed and stored */
|
||||
uint8_t csrk_stored:1;
|
||||
/** LTK (Long Term Key) has been distributed and stored */
|
||||
uint8_t ltk_stored:1;
|
||||
uint8_t ltk_sent:1;
|
||||
/** the security entry has been distributed and stored */
|
||||
uint8_t irk_stored:1;
|
||||
|
||||
/** CSRK that is stored has MITM protection */
|
||||
uint8_t csrk_mitm_protected:1;
|
||||
/** LTK that is stored has MITM protection */
|
||||
uint8_t ltk_mitm_protected:1;
|
||||
/** the current pairing was done using Secure Connections */
|
||||
uint8_t secure_connections_paired:1;
|
||||
uint8_t connected:1;
|
||||
};
|
||||
|
||||
/** Long Term Key and data used to identify it */
|
||||
struct SecurityEntryKeys_t {
|
||||
/** Long Term Key */
|
||||
ltk_t ltk;
|
||||
/** EDIV (Encryption diversifier) used to identify LTK during legacy pairing */
|
||||
ediv_t ediv;
|
||||
/** Rand (random number) used to identify LTK during legacy pairing */
|
||||
rand_t rand;
|
||||
};
|
||||
|
||||
/** CSRK and sign counter used to verify messages */
|
||||
struct SecurityEntrySigning_t {
|
||||
SecurityEntrySigning_t() : counter(0) { };
|
||||
/** Signing key */
|
||||
csrk_t csrk;
|
||||
/** counter used to verify message to guard from replay attacks */
|
||||
sign_count_t counter;
|
||||
};
|
||||
|
||||
/** Data for resolving random resolvable addresses */
|
||||
struct SecurityEntryIdentity_t {
|
||||
/** identity address */
|
||||
address_t identity_address;
|
||||
/** Identity Resolving Key */
|
||||
irk_t irk;
|
||||
/** true if peer identity address is public, false if it's static random */
|
||||
uint8_t identity_address_is_public:1;
|
||||
};
|
||||
|
||||
/**
|
||||
* SecurityDb holds the state for active connections and bonded devices.
|
||||
* Keys can be stored in NVM and are returned via callbacks.
|
||||
* SecurityDb is responsible for serialising any requests and keeping
|
||||
* the store in a consistent state.
|
||||
* Active connections state must be returned immediately.
|
||||
*/
|
||||
class SecurityDb {
|
||||
public:
|
||||
/**
|
||||
* Opaque type representing a handle to a database entry.
|
||||
*/
|
||||
typedef void* entry_handle_t;
|
||||
|
||||
/* callbacks for asynchronous data retrieval from the security db */
|
||||
|
||||
typedef mbed::Callback<void(entry_handle_t, const SecurityEntryKeys_t*)>
|
||||
SecurityEntryKeysDbCb_t;
|
||||
typedef mbed::Callback<void(entry_handle_t, const SecurityEntrySigning_t*)>
|
||||
SecurityEntrySigningDbCb_t;
|
||||
typedef mbed::Callback<void(entry_handle_t, const SecurityEntryIdentity_t*)>
|
||||
SecurityEntryIdentityDbCb_t;
|
||||
typedef mbed::Callback<void(ArrayView<SecurityEntryIdentity_t>&, size_t count)>
|
||||
IdentitylistDbCb_t;
|
||||
typedef mbed::Callback<void(::Gap::Whitelist_t*)>
|
||||
WhitelistDbCb_t;
|
||||
|
||||
SecurityDb() : _local_sign_counter(0) { };
|
||||
virtual ~SecurityDb() { };
|
||||
|
||||
/**
|
||||
* Return immediately security flags associated to a db entry.
|
||||
*
|
||||
* @param[in] db_handle Entry of the database queried.
|
||||
* @return pointer to the flags or NULL if the entry do not have any
|
||||
* associated flags.
|
||||
*/
|
||||
virtual SecurityDistributionFlags_t* get_distribution_flags(
|
||||
entry_handle_t db_handle
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Set the distribution flags of a DB entry.
|
||||
*
|
||||
* @param[in] db_handle Entry of the database that will store the flags.
|
||||
* @param[in] flags Distribution flags to store in @p db_handle.
|
||||
*/
|
||||
virtual void set_distribution_flags(
|
||||
entry_handle_t db_handle,
|
||||
const SecurityDistributionFlags_t& new_flags
|
||||
) {
|
||||
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
|
||||
if (flags) {
|
||||
*flags = new_flags;
|
||||
}
|
||||
}
|
||||
|
||||
/* local keys */
|
||||
|
||||
/**
|
||||
* Retrieve stored LTK based on passed in EDIV and RAND values.
|
||||
*
|
||||
* @param[in] cb callback that will receive the LTK struct
|
||||
* @param[in] db_handle handle of the entry being queried.
|
||||
* @param[in] ediv one of the values used to identify the LTK
|
||||
* @param[in] rand one of the values used to identify the LTK
|
||||
*/
|
||||
virtual void get_entry_local_keys(
|
||||
SecurityEntryKeysDbCb_t cb,
|
||||
entry_handle_t db_handle,
|
||||
const ediv_t &ediv,
|
||||
const rand_t &rand
|
||||
) {
|
||||
SecurityEntryKeys_t* keys = read_in_entry_local_keys(db_handle);
|
||||
/* validate we have the correct key */
|
||||
if (keys && ediv == keys->ediv && rand == keys->rand) {
|
||||
cb(db_handle, keys);
|
||||
} else {
|
||||
cb(db_handle, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve stored LTK generated during secure connections pairing.
|
||||
*
|
||||
* @param[in] cb callback that will receive the LTK struct
|
||||
* @param[in] db_handle handle of the entry being queried.
|
||||
*/
|
||||
virtual void get_entry_local_keys(
|
||||
SecurityEntryKeysDbCb_t cb,
|
||||
entry_handle_t db_handle
|
||||
) {
|
||||
SecurityEntryKeys_t* keys = read_in_entry_local_keys(db_handle);
|
||||
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
|
||||
/* validate we have the correct key */
|
||||
if (flags && keys && flags->secure_connections_paired) {
|
||||
cb(db_handle, keys);
|
||||
} else {
|
||||
cb(db_handle, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save new local LTK for a connection.
|
||||
*
|
||||
* @param[in] db_handle handle of the entry being updated.
|
||||
* @param[in] ltk the new LTK, if the device is slave, this is the LTK that
|
||||
* will be used when link is encrypted
|
||||
*/
|
||||
virtual void set_entry_local_ltk(
|
||||
entry_handle_t db_handle,
|
||||
const ltk_t <k
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Update EDIV and RAND used to identify the LTK.
|
||||
*
|
||||
* @param[in] db_handle handle of the entry being updated.
|
||||
* @param[in] ediv new EDIV value
|
||||
* @param[in] rand new RAND value
|
||||
*/
|
||||
virtual void set_entry_local_ediv_rand(
|
||||
entry_handle_t db_handle,
|
||||
const ediv_t &ediv,
|
||||
const rand_t &rand
|
||||
) = 0;
|
||||
|
||||
/* peer's keys */
|
||||
|
||||
/**
|
||||
* Return asynchronously the peer signing key through a callback
|
||||
* so that signed packets can be verified.
|
||||
*
|
||||
* @param[in] cb callback which will receive the key
|
||||
* @param[in] db_handle handle of the entry being queried.
|
||||
*/
|
||||
virtual void get_entry_peer_csrk(
|
||||
SecurityEntrySigningDbCb_t cb,
|
||||
entry_handle_t db_handle
|
||||
) {
|
||||
SecurityEntrySigning_t* signing = read_in_entry_peer_signing(db_handle);
|
||||
cb(db_handle, signing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return asynchronously the peer encryption key through a callback
|
||||
* so that encryption can be enabled.
|
||||
*
|
||||
* @param[in] cb callback which will receive the key
|
||||
* @param[in] db_handle handle of the entry being queried.
|
||||
*/
|
||||
virtual void get_entry_peer_keys(
|
||||
SecurityEntryKeysDbCb_t cb,
|
||||
entry_handle_t db_handle
|
||||
) {
|
||||
SecurityEntryKeys_t* keys = read_in_entry_peer_keys(db_handle);
|
||||
cb(db_handle, keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save new LTK received from the peer.
|
||||
*
|
||||
* @param[in] db_handle handle of the entry being updated.
|
||||
* @param[in] ltk the new LTK, if the peer device is slave, this is the LTK
|
||||
* that will be used when link is encrypted
|
||||
*/
|
||||
virtual void set_entry_peer_ltk(
|
||||
entry_handle_t db_handle,
|
||||
const ltk_t <k
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Update EDIV and RAND used to identify the LTK sent by the peer.
|
||||
*
|
||||
* @param[in] db_handle handle of the entry being updated.
|
||||
* @param[in] ediv new EDIV value
|
||||
* @param[in] rand new RAND value
|
||||
*/
|
||||
virtual void set_entry_peer_ediv_rand(
|
||||
entry_handle_t db_handle,
|
||||
const ediv_t &ediv,
|
||||
const rand_t &rand
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Update IRK for this connection.
|
||||
*
|
||||
* @param[in] db_handle handle of the entry being updated.
|
||||
* @param[in] irk new IRK value
|
||||
*/
|
||||
virtual void set_entry_peer_irk(
|
||||
entry_handle_t db_handle,
|
||||
const irk_t &irk
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Update the identity address of the peer.
|
||||
*
|
||||
* @param[in] db_handle handle of the entry being updated.
|
||||
* @param[in] address_is_public is the identity address public or private
|
||||
* @param[in] peer_address the new address
|
||||
*/
|
||||
virtual void set_entry_peer_bdaddr(
|
||||
entry_handle_t db_handle,
|
||||
bool address_is_public,
|
||||
const address_t &peer_address
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Retrieve stored identity address and IRK.
|
||||
*
|
||||
* @param[in] cb callback that will receive the SecurityEntryIdentity_t struct
|
||||
* @param[in] db_handle handle of the entry being queried.
|
||||
*/
|
||||
virtual void get_entry_identity(
|
||||
SecurityEntryIdentityDbCb_t cb,
|
||||
entry_handle_t db_handle
|
||||
) {
|
||||
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
|
||||
if (flags && flags->irk_stored) {
|
||||
SecurityEntryIdentity_t* peer_identity = read_in_entry_peer_identity(db_handle);
|
||||
if (peer_identity) {
|
||||
cb(db_handle, peer_identity);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* avoid duplicate else */
|
||||
cb(db_handle, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously return the identity list stored in NVM through a callback.
|
||||
* Function takes ownership of the memory. The identity list and the
|
||||
* ownership will be returned in the callback.
|
||||
*
|
||||
* @param[in] cb callback that will receive the whitelist
|
||||
* @param[in] identity_list preallocated identity_list that will be filled
|
||||
* in.
|
||||
*/
|
||||
virtual void get_identity_list(
|
||||
IdentitylistDbCb_t cb,
|
||||
ArrayView<SecurityEntryIdentity_t>& identity_list
|
||||
) {
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < get_entry_count() && count < identity_list.size(); ++i) {
|
||||
|
||||
entry_handle_t db_handle = get_entry_handle_by_index(i);
|
||||
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
|
||||
|
||||
|
||||
if (flags && flags->irk_stored) {
|
||||
SecurityEntryIdentity_t* peer_identity = read_in_entry_peer_identity(db_handle);
|
||||
if (peer_identity) {
|
||||
identity_list[count] = *peer_identity;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cb(identity_list, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update peer signing key.
|
||||
*
|
||||
* @param[in] db_handle handle of the entry being updated.
|
||||
* @param[in] csrk new CSRK value
|
||||
*/
|
||||
virtual void set_entry_peer_csrk(
|
||||
entry_handle_t db_handle,
|
||||
const csrk_t &csrk
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Update peer signing counter.
|
||||
*
|
||||
* @param[in] db_handle handle of the entry being updated.
|
||||
* @param[in] sign_counter new signing counter value
|
||||
*/
|
||||
virtual void set_entry_peer_sign_counter(
|
||||
entry_handle_t db_handle,
|
||||
sign_count_t sign_counter
|
||||
) = 0;
|
||||
|
||||
/* local csrk */
|
||||
|
||||
/**
|
||||
* Return local signing key used for signing packets.
|
||||
*
|
||||
* @return pointer to local CSRK
|
||||
*/
|
||||
virtual const csrk_t* get_local_csrk() {
|
||||
return &_local_csrk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return local signing counter.
|
||||
*
|
||||
* @return signing counter
|
||||
*/
|
||||
virtual sign_count_t get_local_sign_counter() {
|
||||
return _local_sign_counter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update local signing key.
|
||||
*
|
||||
* @param[in] csrk new CSRK value
|
||||
*/
|
||||
virtual void set_local_csrk(
|
||||
const csrk_t &csrk
|
||||
) {
|
||||
_local_csrk = csrk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update local signing counter.
|
||||
*
|
||||
* @param[in] sign_counter new signing counter value
|
||||
*/
|
||||
virtual void set_local_sign_counter(
|
||||
sign_count_t sign_counter
|
||||
) {
|
||||
_local_sign_counter = sign_counter;
|
||||
}
|
||||
|
||||
/* list management */
|
||||
|
||||
/**
|
||||
* Open a database entry.
|
||||
*
|
||||
* While this entry is opened; it can be queried and updated with the help
|
||||
* of the database setter and getter functions.
|
||||
*
|
||||
* @param[in] peer_address_type type of address
|
||||
* @param[in] peer_address this address will be used to locate an existing
|
||||
* entry.
|
||||
*
|
||||
* @return A handle to the entry.
|
||||
*/
|
||||
virtual entry_handle_t open_entry(
|
||||
peer_address_type_t peer_address_type,
|
||||
const address_t &peer_address
|
||||
) {
|
||||
entry_handle_t db_handle = find_entry_by_peer_address(peer_address_type, peer_address);
|
||||
if (db_handle) {
|
||||
return db_handle;
|
||||
}
|
||||
|
||||
SecurityDistributionFlags_t* flags = get_free_entry_flags();
|
||||
if (flags) {
|
||||
const bool peer_address_public =
|
||||
(peer_address_type == peer_address_type_t::PUBLIC) ||
|
||||
(peer_address_type == peer_address_type_t::PUBLIC_IDENTITY);
|
||||
/* we need some address to store, so we store even random ones
|
||||
* this address will be used as an id, possibly replaced later
|
||||
* by identity address */
|
||||
flags->peer_address = peer_address;
|
||||
flags->peer_address_is_public = peer_address_public;
|
||||
return flags;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a database entry based on peer address.
|
||||
*
|
||||
* @param[in] peer_address_type type of address
|
||||
* @param[in] peer_address this address will be used to locate an existing entry.
|
||||
*
|
||||
* @return A handle to the entry.
|
||||
*/
|
||||
virtual entry_handle_t find_entry_by_peer_address(
|
||||
peer_address_type_t peer_address_type,
|
||||
const address_t &peer_address
|
||||
) {
|
||||
const bool peer_address_public =
|
||||
(peer_address_type == peer_address_type_t::PUBLIC) ||
|
||||
(peer_address_type == peer_address_type_t::PUBLIC_IDENTITY);
|
||||
|
||||
for (size_t i = 0; i < get_entry_count(); i++) {
|
||||
entry_handle_t db_handle = get_entry_handle_by_index(i);
|
||||
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
|
||||
|
||||
/* only look among disconnected entries */
|
||||
if (flags && !flags->connected) {
|
||||
if (peer_address_type == peer_address_type_t::PUBLIC_IDENTITY &&
|
||||
flags->irk_stored == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* lookup for connection address used during bonding */
|
||||
if (flags->peer_address == peer_address &&
|
||||
flags->peer_address_is_public == peer_address_public) {
|
||||
return flags;
|
||||
}
|
||||
|
||||
/* look for the identity address if stored */
|
||||
if (flags->irk_stored) {
|
||||
SecurityEntryIdentity_t* identity = read_in_entry_peer_identity(db_handle);
|
||||
|
||||
if (identity &&
|
||||
identity->identity_address == peer_address &&
|
||||
identity->identity_address_is_public == peer_address_public) {
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close a connection entry.
|
||||
*
|
||||
* @param[in] db_handle this handle will be freed up from the security db.
|
||||
*/
|
||||
virtual void close_entry(entry_handle_t db_handle) {
|
||||
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
|
||||
if (flags) {
|
||||
flags->connected = false;
|
||||
}
|
||||
sync(db_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove entry for this peer from NVM.
|
||||
*
|
||||
* @param[in] peer_address_type type of address
|
||||
* @param[in] peer_address this address will be used to locate an existing
|
||||
* entry.
|
||||
*
|
||||
* @return A handle to the entry.
|
||||
*/
|
||||
virtual void remove_entry(
|
||||
peer_address_type_t peer_address_type,
|
||||
const address_t &peer_address
|
||||
) {
|
||||
entry_handle_t db_handle = find_entry_by_peer_address(peer_address_type, peer_address);
|
||||
if (db_handle) {
|
||||
reset_entry(db_handle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all entries from the security DB.
|
||||
*/
|
||||
virtual void clear_entries() {
|
||||
for (size_t i = 0; i < get_entry_count(); i++) {
|
||||
entry_handle_t db_handle = get_entry_handle_by_index(i);
|
||||
reset_entry(db_handle);
|
||||
}
|
||||
_local_identity = SecurityEntryIdentity_t();
|
||||
_local_csrk = csrk_t();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously return the whitelist stored in NVM through a callback.
|
||||
* Function takes ownership of the memory. The whitelist and the ownership
|
||||
* will be returned in the callback.
|
||||
*
|
||||
* @param[in] cb callback that will receive the whitelist
|
||||
* @param[in] whitelist preallocated whitelist that will be filled in
|
||||
*/
|
||||
virtual void get_whitelist(
|
||||
WhitelistDbCb_t cb,
|
||||
::Gap::Whitelist_t *whitelist
|
||||
) {
|
||||
/*TODO: fill whitelist*/
|
||||
cb(whitelist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously return a whitelist through a callback, generated from the
|
||||
* bond table.
|
||||
*
|
||||
* @param[in] cb callback that will receive the whitelist
|
||||
* @param[in] whitelist preallocated whitelist that will be filled in
|
||||
*/
|
||||
virtual void generate_whitelist_from_bond_table(
|
||||
WhitelistDbCb_t cb,
|
||||
::Gap::Whitelist_t *whitelist
|
||||
) {
|
||||
for (size_t i = 0; i < get_entry_count() && i < whitelist->capacity; i++) {
|
||||
entry_handle_t db_handle = get_entry_handle_by_index(i);
|
||||
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
|
||||
|
||||
if (!flags) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flags->peer_address_is_public) {
|
||||
whitelist->addresses[i].type = BLEProtocol::AddressType::PUBLIC;
|
||||
} else {
|
||||
whitelist->addresses[i].type = BLEProtocol::AddressType::RANDOM_STATIC;
|
||||
}
|
||||
|
||||
SecurityEntryIdentity_t* identity = read_in_entry_peer_identity(db_handle);
|
||||
if (identity) {
|
||||
memcpy(
|
||||
whitelist->addresses[i].address,
|
||||
identity->identity_address.data(),
|
||||
sizeof(BLEProtocol::AddressBytes_t)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
cb(whitelist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the whitelist stored in NVM by replacing it with new one.
|
||||
*
|
||||
* @param[in] whitelist
|
||||
*/
|
||||
virtual void set_whitelist(const ::Gap::Whitelist_t &whitelist) { };
|
||||
|
||||
/**
|
||||
* Add a new entry to the whitelist in the NVM.
|
||||
*
|
||||
* @param[in] address new whitelist entry
|
||||
*/
|
||||
virtual void add_whitelist_entry(const address_t &address) { };
|
||||
|
||||
/**
|
||||
* Remove whitelist entry from NVM.
|
||||
*
|
||||
* @param[in] address entry to be removed
|
||||
*/
|
||||
virtual void remove_whitelist_entry(const address_t &address) { };
|
||||
|
||||
/**
|
||||
*Remove all whitelist entries stored in the NVM.
|
||||
*/
|
||||
virtual void clear_whitelist() { };
|
||||
|
||||
/* saving and loading from nvm */
|
||||
|
||||
/**
|
||||
* Read values from storage.
|
||||
*/
|
||||
virtual void restore() { };
|
||||
|
||||
/**
|
||||
* Flush all values which might be stored in memory into NVM.
|
||||
*/
|
||||
virtual void sync(entry_handle_t db_handle) { };
|
||||
|
||||
/**
|
||||
* Toggle whether values should be preserved across resets.
|
||||
*
|
||||
* @param[in] reload if true values will be preserved across resets.
|
||||
*/
|
||||
virtual void set_restore(bool reload) { };
|
||||
|
||||
private:
|
||||
/**
|
||||
* Get an entry for a new connection not present in the db yet. This will find a free entry
|
||||
* or use a disconnected entry by reseting all the stored information.
|
||||
* @return empty entry for the new connection
|
||||
*/
|
||||
virtual SecurityDistributionFlags_t* get_free_entry_flags() {
|
||||
/* get a free one if available */
|
||||
SecurityDistributionFlags_t* match = NULL;
|
||||
for (size_t i = 0; i < get_entry_count(); i++) {
|
||||
entry_handle_t db_handle = get_entry_handle_by_index(i);
|
||||
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
|
||||
|
||||
if (flags && !flags->connected) {
|
||||
/* we settle for any disconnected if we don't find an empty one */
|
||||
match = flags;
|
||||
if (!flags->csrk_stored
|
||||
&& !flags->ltk_stored
|
||||
&& !flags->ltk_sent
|
||||
&& !flags->irk_stored) {
|
||||
/* empty one found, stop looking*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
reset_entry(match);
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
/**
|
||||
* How many entries can be stored in the databes.
|
||||
* @return max number of entries
|
||||
*/
|
||||
virtual uint8_t get_entry_count() = 0;
|
||||
|
||||
/**
|
||||
* Return database entry based on its index.
|
||||
* @param index index from 0 to get_entry_count()
|
||||
* @return databse entry stored at index
|
||||
*/
|
||||
virtual SecurityDistributionFlags_t* get_entry_handle_by_index(uint8_t index) = 0;
|
||||
|
||||
/**
|
||||
* Delete all the information.
|
||||
* @param db_handle handle for the entry to be reset
|
||||
*/
|
||||
virtual void reset_entry(entry_handle_t db_handle) = 0;
|
||||
|
||||
/**
|
||||
* This will read in the requested information into a buffer that will remain valid
|
||||
* until another read_in call is made.
|
||||
* @param db_handle handle of the entry to be read
|
||||
* @return pointer to buffer holding the query result, NULL when not found
|
||||
*/
|
||||
virtual SecurityEntryIdentity_t* read_in_entry_peer_identity(entry_handle_t db_handle) = 0;
|
||||
|
||||
/**
|
||||
* This will read in the requested information into a buffer that will remain valid
|
||||
* until another read_in call is made.
|
||||
* @param db_handle handle of the entry to be read
|
||||
* @return pointer to buffer holding the query result, NULL when not found
|
||||
*/
|
||||
virtual SecurityEntryKeys_t* read_in_entry_peer_keys(entry_handle_t db_handle) = 0;
|
||||
|
||||
/**
|
||||
* This will read in the requested information into a buffer that will remain valid
|
||||
* until another read_in call is made.
|
||||
* @param db_handle handle of the entry to be read
|
||||
* @return pointer to buffer holding the query result, NULL when not found
|
||||
*/
|
||||
virtual SecurityEntryKeys_t* read_in_entry_local_keys(entry_handle_t db_handle) = 0;
|
||||
|
||||
/**
|
||||
* This will read in the requested information into a buffer that will remain valid
|
||||
* until another read_in call is made.
|
||||
* @param db_handle handle of the entry to be read
|
||||
* @return pointer to buffer holding the query result, NULL when not found
|
||||
*/
|
||||
virtual SecurityEntrySigning_t* read_in_entry_peer_signing(entry_handle_t db_handle) = 0;
|
||||
|
||||
protected:
|
||||
SecurityEntryIdentity_t _local_identity;
|
||||
csrk_t _local_csrk;
|
||||
sign_count_t _local_sign_counter;
|
||||
};
|
||||
|
||||
} /* namespace pal */
|
||||
} /* namespace ble */
|
||||
|
||||
#endif /*GENERIC_SECURITY_MANAGER_DB_H__*/
|
|
@ -48,11 +48,13 @@ public:
|
|||
* @param[in] local_address_type type of address of the local device.
|
||||
* @param[in] local_address Address of the local device that was used during connection.
|
||||
* @param[in] connection_params connection parameters like interval, latency and timeout.
|
||||
* @param[in] resolved_peer_address resolved address of the peer; may
|
||||
* be NULL.
|
||||
*/
|
||||
virtual void on_connected(
|
||||
connection_handle_t connection,
|
||||
::Gap::Role_t role,
|
||||
BLEProtocol::AddressType_t peer_address_type,
|
||||
ble::peer_address_type_t peer_address_type,
|
||||
const BLEProtocol::AddressBytes_t peer_address,
|
||||
BLEProtocol::AddressType_t local_address_type,
|
||||
const BLEProtocol::AddressBytes_t local_address,
|
||||
|
|
|
@ -140,7 +140,6 @@ struct GapConnectionCompleteEvent : public GapEvent {
|
|||
* @param supervision_timeout Supervision timeout of the connection. It
|
||||
* shall be in the range [0x000A : 0x0C80] where a unit represent 10ms.
|
||||
*
|
||||
* @note: See Bluetooth 5 Vol 2 PartE: 7.7.65.1 LE Connection Complete Event
|
||||
* @note: See Bluetooth 5 Vol 2 PartE: 7.7.65.10 LE Enhanced Connection
|
||||
* Complete Event
|
||||
*/
|
||||
|
@ -153,6 +152,69 @@ struct GapConnectionCompleteEvent : public GapEvent {
|
|||
uint16_t connection_interval,
|
||||
uint16_t connection_latency,
|
||||
uint16_t supervision_timeout
|
||||
) :
|
||||
GapEvent(GapEventType::CONNECTION_COMPLETE),
|
||||
status(status),
|
||||
connection_handle(connection_handle),
|
||||
role(role),
|
||||
peer_address_type(
|
||||
peer_address_type == advertising_peer_address_type_t::PUBLIC_ADDRESS ?
|
||||
peer_address_type_t::PUBLIC :
|
||||
peer_address_type_t::RANDOM
|
||||
),
|
||||
peer_address(peer_address),
|
||||
connection_interval(connection_interval),
|
||||
connection_latency(connection_latency),
|
||||
supervision_timeout(supervision_timeout),
|
||||
local_resolvable_private_address(),
|
||||
peer_resolvable_private_address() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new GapConnectionCompleteEvent.
|
||||
*
|
||||
* @param status Status of the operation: 0x00 in case of success otherwise
|
||||
* the error code associated with the failure.
|
||||
*
|
||||
* @param connection_handle handle of the connection created. This handle
|
||||
* will be used to address the connection in any connection oriented
|
||||
* operation.
|
||||
*
|
||||
* @param role Role of the LE subsystem in the connection.
|
||||
*
|
||||
* @param address_type Type of address used by the peer for this connection.
|
||||
*
|
||||
* @param address Address of the peer used to establish the connection.
|
||||
*
|
||||
* @param connection_interval Connection interval used on this connection.
|
||||
* It shall be in a range [0x0006 : 0x0C80]. A unit is equal to 1.25ms.
|
||||
*
|
||||
* @param connection_latency Number of connection events the slave can
|
||||
* drop.
|
||||
*
|
||||
* @param supervision_timeout Supervision timeout of the connection. It
|
||||
* shall be in the range [0x000A : 0x0C80] where a unit represent 10ms.
|
||||
*
|
||||
* @param local_resolvable_private_address Resolvable private address used
|
||||
* by the local device to establish the connection.
|
||||
*
|
||||
* @param peer_resolvable_private_address Resolvable private address used
|
||||
* by the peer to establish the connection.
|
||||
*
|
||||
* @note: See Bluetooth 5 Vol 2 PartE: 7.7.65.10 LE Enhanced Connection
|
||||
* Complete Event
|
||||
*/
|
||||
GapConnectionCompleteEvent(
|
||||
uint8_t status,
|
||||
connection_handle_t connection_handle,
|
||||
connection_role_t role,
|
||||
peer_address_type_t peer_address_type,
|
||||
const address_t& peer_address,
|
||||
uint16_t connection_interval,
|
||||
uint16_t connection_latency,
|
||||
uint16_t supervision_timeout,
|
||||
const address_t& local_resolvable_private_address,
|
||||
const address_t& peer_resolvable_private_address
|
||||
) :
|
||||
GapEvent(GapEventType::CONNECTION_COMPLETE),
|
||||
status(status),
|
||||
|
@ -162,9 +224,12 @@ struct GapConnectionCompleteEvent : public GapEvent {
|
|||
peer_address(peer_address),
|
||||
connection_interval(connection_interval),
|
||||
connection_latency(connection_latency),
|
||||
supervision_timeout(supervision_timeout) {
|
||||
supervision_timeout(supervision_timeout),
|
||||
local_resolvable_private_address(local_resolvable_private_address),
|
||||
peer_resolvable_private_address(peer_resolvable_private_address) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @param status Indicate if the connection succesfully completed or not:
|
||||
* - 0: Connection successfuly completed
|
||||
|
@ -188,7 +253,7 @@ struct GapConnectionCompleteEvent : public GapEvent {
|
|||
/**
|
||||
* Peer address type.
|
||||
*/
|
||||
const advertising_peer_address_type_t peer_address_type;
|
||||
const peer_address_type_t peer_address_type;
|
||||
|
||||
/**
|
||||
* Peer address.
|
||||
|
@ -211,6 +276,18 @@ struct GapConnectionCompleteEvent : public GapEvent {
|
|||
* It shall be in the range [0x000A : 0x0C80] where a unit represent 10ms.
|
||||
*/
|
||||
const uint16_t supervision_timeout;
|
||||
|
||||
/**
|
||||
* Resolvable private address of the local device.
|
||||
* Set to all 0 if not available.
|
||||
*/
|
||||
const address_t local_resolvable_private_address;
|
||||
|
||||
/**
|
||||
* Resolvable private address of the peer.
|
||||
* Set to all 0 if not available. *
|
||||
*/
|
||||
const address_t peer_resolvable_private_address;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,372 +0,0 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
#ifndef PAL_MEMORY_SECURITY_DB_H_
|
||||
#define PAL_MEMORY_SECURITY_DB_H_
|
||||
|
||||
#include "SecurityDb.h"
|
||||
|
||||
namespace ble {
|
||||
namespace pal {
|
||||
|
||||
/** Naive memory implementation for verification. */
|
||||
class MemorySecurityDb : public SecurityDb {
|
||||
private:
|
||||
enum state_t {
|
||||
ENTRY_FREE,
|
||||
ENTRY_RESERVED,
|
||||
ENTRY_WRITTEN
|
||||
};
|
||||
|
||||
struct entry_t {
|
||||
entry_t() : state(ENTRY_FREE) { };
|
||||
SecurityDistributionFlags_t flags;
|
||||
SecurityEntryKeys_t peer_keys;
|
||||
SecurityEntryKeys_t local_keys;
|
||||
SecurityEntryIdentity_t peer_identity;
|
||||
csrk_t csrk;
|
||||
state_t state;
|
||||
};
|
||||
static const size_t MAX_ENTRIES = 5;
|
||||
|
||||
static entry_t* as_entry(entry_handle_t entry_handle)
|
||||
{
|
||||
return reinterpret_cast<entry_t*>(entry_handle);
|
||||
}
|
||||
|
||||
public:
|
||||
MemorySecurityDb() { };
|
||||
virtual ~MemorySecurityDb() { };
|
||||
|
||||
virtual const SecurityDistributionFlags_t* get_distribution_flags(
|
||||
entry_handle_t entry_handle
|
||||
) {
|
||||
entry_t* entry = as_entry(entry_handle);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &entry->flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the distribution flags of the DB entry
|
||||
*/
|
||||
virtual void set_distribution_flags(
|
||||
entry_handle_t entry_handle,
|
||||
const SecurityDistributionFlags_t& flags
|
||||
) {
|
||||
entry_t* entry = as_entry(entry_handle);
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
entry->state = ENTRY_WRITTEN;
|
||||
entry->flags = flags;
|
||||
}
|
||||
|
||||
/* local keys */
|
||||
|
||||
/* get */
|
||||
virtual void get_entry_local_keys(
|
||||
SecurityEntryKeysDbCb_t cb,
|
||||
entry_handle_t entry_handle,
|
||||
const ediv_t &ediv,
|
||||
const rand_t &rand
|
||||
) {
|
||||
entry_t* entry = as_entry(entry_handle);
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* validate we have the correct key */
|
||||
if (ediv == entry->local_keys.ediv && rand == entry->local_keys.rand) {
|
||||
cb(entry_handle, &entry->local_keys);
|
||||
} else {
|
||||
cb(entry_handle, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void get_entry_local_keys(
|
||||
SecurityEntryKeysDbCb_t cb,
|
||||
entry_handle_t entry_handle
|
||||
) {
|
||||
entry_t* entry = as_entry(entry_handle);
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* validate we have the correct key */
|
||||
if (entry->flags.secure_connections_paired) {
|
||||
cb(entry_handle, &entry->local_keys);
|
||||
} else {
|
||||
cb(entry_handle, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* set */
|
||||
virtual void set_entry_local_ltk(
|
||||
entry_handle_t entry_handle,
|
||||
const ltk_t <k
|
||||
) {
|
||||
entry_t *entry = as_entry(entry_handle);
|
||||
if (entry) {
|
||||
entry->state = ENTRY_WRITTEN;
|
||||
entry->local_keys.ltk = ltk;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_entry_local_ediv_rand(
|
||||
entry_handle_t entry_handle,
|
||||
const ediv_t &ediv,
|
||||
const rand_t &rand
|
||||
) {
|
||||
entry_t *entry = as_entry(entry_handle);
|
||||
if (entry) {
|
||||
entry->state = ENTRY_WRITTEN;
|
||||
entry->local_keys.ediv = ediv;
|
||||
entry->local_keys.rand = rand;
|
||||
}
|
||||
}
|
||||
|
||||
/* peer's keys */
|
||||
|
||||
/* get */
|
||||
virtual void get_entry_peer_csrk(
|
||||
SecurityEntryCsrkDbCb_t cb,
|
||||
entry_handle_t entry_handle
|
||||
) {
|
||||
csrk_t csrk;
|
||||
entry_t *entry = as_entry(entry_handle);
|
||||
if (entry) {
|
||||
csrk = entry->csrk;
|
||||
}
|
||||
cb(entry_handle, &csrk);
|
||||
}
|
||||
|
||||
virtual void get_entry_peer_keys(
|
||||
SecurityEntryKeysDbCb_t cb,
|
||||
entry_handle_t entry_handle
|
||||
) {
|
||||
SecurityEntryKeys_t *key = NULL;
|
||||
entry_t *entry = as_entry(entry_handle);
|
||||
if (entry) {
|
||||
key = &entry->peer_keys;
|
||||
}
|
||||
cb(entry_handle, key);
|
||||
}
|
||||
|
||||
/* set */
|
||||
|
||||
virtual void set_entry_peer_ltk(
|
||||
entry_handle_t entry_handle,
|
||||
const ltk_t <k
|
||||
) {
|
||||
entry_t *entry = as_entry(entry_handle);
|
||||
if (entry) {
|
||||
entry->state = ENTRY_WRITTEN;
|
||||
entry->peer_keys.ltk = ltk;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_entry_peer_ediv_rand(
|
||||
entry_handle_t entry_handle,
|
||||
const ediv_t &ediv,
|
||||
const rand_t &rand
|
||||
) {
|
||||
entry_t *entry = as_entry(entry_handle);
|
||||
if (entry) {
|
||||
entry->state = ENTRY_WRITTEN;
|
||||
entry->peer_keys.ediv = ediv;
|
||||
entry->peer_keys.rand = rand;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_entry_peer_irk(
|
||||
entry_handle_t entry_handle,
|
||||
const irk_t &irk
|
||||
) {
|
||||
entry_t *entry = as_entry(entry_handle);
|
||||
if (entry) {
|
||||
entry->state = ENTRY_WRITTEN;
|
||||
entry->peer_identity.irk = irk;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_entry_peer_bdaddr(
|
||||
entry_handle_t entry_handle,
|
||||
bool address_is_public,
|
||||
const address_t &peer_address
|
||||
) {
|
||||
entry_t *entry = as_entry(entry_handle);
|
||||
if (entry) {
|
||||
entry->state = ENTRY_WRITTEN;
|
||||
entry->peer_identity.identity_address = peer_address;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_entry_peer_csrk(
|
||||
entry_handle_t entry_handle,
|
||||
const csrk_t &csrk
|
||||
) {
|
||||
entry_t *entry = as_entry(entry_handle);
|
||||
if (entry) {
|
||||
entry->state = ENTRY_WRITTEN;
|
||||
entry->csrk = csrk;
|
||||
}
|
||||
}
|
||||
|
||||
/* local csrk */
|
||||
|
||||
virtual const csrk_t* get_local_csrk() {
|
||||
return &_local_csrk;
|
||||
}
|
||||
|
||||
virtual void set_local_csrk(const csrk_t &csrk) {
|
||||
_local_csrk = csrk;
|
||||
}
|
||||
|
||||
/* public key */
|
||||
|
||||
virtual const public_key_coord_t& get_public_key_x() {
|
||||
return _public_key_x;
|
||||
}
|
||||
|
||||
virtual const public_key_coord_t& get_public_key_y() {
|
||||
return _public_key_y;
|
||||
}
|
||||
|
||||
virtual void set_public_key(
|
||||
const public_key_coord_t &public_key_x,
|
||||
const public_key_coord_t &public_key_y
|
||||
) {
|
||||
_public_key_x = public_key_x;
|
||||
_public_key_y = public_key_y;
|
||||
}
|
||||
|
||||
/* list management */
|
||||
|
||||
virtual entry_handle_t open_entry(
|
||||
BLEProtocol::AddressType_t peer_address_type,
|
||||
const address_t &peer_address
|
||||
) {
|
||||
const bool peer_address_public =
|
||||
(peer_address_type == BLEProtocol::AddressType::PUBLIC);
|
||||
|
||||
for (size_t i = 0; i < MAX_ENTRIES; i++) {
|
||||
if (_entries[i].state == ENTRY_FREE) {
|
||||
continue;
|
||||
} else if (peer_address == _entries[i].peer_identity.identity_address
|
||||
&& _entries[i].flags.peer_address_is_public == peer_address_public) {
|
||||
return &_entries[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* if we din't find one grab the first disconnected slot*/
|
||||
for (size_t i = 0; i < MAX_ENTRIES; i++) {
|
||||
if (_entries[i].state == ENTRY_FREE) {
|
||||
_entries[i] = entry_t();
|
||||
_entries[i].flags.peer_address = peer_address;
|
||||
_entries[i].flags.peer_address_is_public = peer_address_public;
|
||||
_entries[i].state = ENTRY_RESERVED;
|
||||
return &_entries[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual void close_entry(entry_handle_t entry_handle)
|
||||
{
|
||||
entry_t *entry = as_entry(entry_handle);
|
||||
if (entry && entry->state == ENTRY_RESERVED) {
|
||||
entry->state = ENTRY_FREE;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void remove_entry(const address_t peer_identity_address)
|
||||
{
|
||||
for (size_t i = 0; i < MAX_ENTRIES; i++) {
|
||||
if (_entries[i].state == ENTRY_FREE) {
|
||||
continue;
|
||||
} else if (peer_identity_address == _entries[i].peer_identity.identity_address) {
|
||||
_entries[i] = entry_t();
|
||||
_entries[i].state = ENTRY_FREE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void clear_entries() {
|
||||
for (size_t i = 0; i < MAX_ENTRIES; i++) {
|
||||
_entries[i] = entry_t();
|
||||
}
|
||||
_local_identity = SecurityEntryIdentity_t();
|
||||
_local_csrk = csrk_t();
|
||||
}
|
||||
|
||||
virtual void get_whitelist(WhitelistDbCb_t cb, ::Gap::Whitelist_t *whitelist) {
|
||||
/*TODO: fill whitelist*/
|
||||
cb(whitelist);
|
||||
}
|
||||
|
||||
virtual void generate_whitelist_from_bond_table(WhitelistDbCb_t cb, ::Gap::Whitelist_t *whitelist) {
|
||||
for (size_t i = 0; i < MAX_ENTRIES && i < whitelist->capacity; i++) {
|
||||
if (_entries[i].flags.peer_address_is_public) {
|
||||
whitelist->addresses[i].type = BLEProtocol::AddressType::PUBLIC;
|
||||
} else {
|
||||
whitelist->addresses[i].type = BLEProtocol::AddressType::RANDOM_STATIC;
|
||||
}
|
||||
|
||||
memcpy(
|
||||
whitelist->addresses[i].address,
|
||||
_entries[i].peer_identity.identity_address.data(),
|
||||
sizeof(BLEProtocol::AddressBytes_t)
|
||||
);
|
||||
}
|
||||
|
||||
cb(whitelist);
|
||||
}
|
||||
|
||||
virtual void set_whitelist(const ::Gap::Whitelist_t &whitelist) { };
|
||||
|
||||
virtual void add_whitelist_entry(const address_t &address) { }
|
||||
|
||||
virtual void remove_whitelist_entry(const address_t &address) { }
|
||||
|
||||
virtual void clear_whitelist() { }
|
||||
|
||||
/* saving and loading from nvm */
|
||||
|
||||
virtual void restore() { }
|
||||
|
||||
virtual void sync() { }
|
||||
|
||||
virtual void set_restore(bool reload) { }
|
||||
|
||||
private:
|
||||
entry_t _entries[MAX_ENTRIES];
|
||||
SecurityEntryIdentity_t _local_identity;
|
||||
csrk_t _local_csrk;
|
||||
public_key_coord_t _public_key_x;
|
||||
public_key_coord_t _public_key_y;
|
||||
};
|
||||
|
||||
} /* namespace pal */
|
||||
} /* namespace ble */
|
||||
|
||||
#endif /*PAL_MEMORY_SECURITY_DB_H_*/
|
|
@ -649,6 +649,27 @@ struct Gap {
|
|||
disconnection_reason_t disconnection_reason
|
||||
) = 0;
|
||||
|
||||
/** Check if privacy feature is supported by implementation
|
||||
*
|
||||
* @return true if privacy is supported, false otherwise.
|
||||
*
|
||||
* @note: See Bluetooth 5 Vol 3 Part C: 10.7 Privacy feature.
|
||||
*/
|
||||
virtual bool is_privacy_supported() = 0;
|
||||
|
||||
/** Enable or disable private addresses resolution
|
||||
*
|
||||
* @param enable whether to enable private addresses resolution
|
||||
*
|
||||
* @return BLE_ERROR_NONE if the request has been successfully sent or the
|
||||
* appropriate error otherwise.
|
||||
*
|
||||
* @note: See Bluetooth 5 Vol 2 PartE: 7.8.44 LE Set Address Resolution Enable command.
|
||||
*/
|
||||
virtual ble_error_t set_address_resolution(
|
||||
bool enable
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Register a callback which will handle Gap events.
|
||||
*
|
||||
|
|
|
@ -27,10 +27,10 @@
|
|||
namespace ble {
|
||||
namespace pal {
|
||||
|
||||
typedef SecurityManager::SecurityCompletionStatus_t SecurityCompletionStatus_t;
|
||||
typedef SecurityManager::SecurityMode_t SecurityMode_t;
|
||||
typedef SecurityManager::LinkSecurityStatus_t LinkSecurityStatus_t;
|
||||
typedef SecurityManager::Keypress_t Keypress_t;
|
||||
typedef ::SecurityManager::SecurityCompletionStatus_t SecurityCompletionStatus_t;
|
||||
typedef ::SecurityManager::SecurityMode_t SecurityMode_t;
|
||||
typedef ::SecurityManager::LinkSecurityStatus_t LinkSecurityStatus_t;
|
||||
typedef ::SecurityManager::Keypress_t Keypress_t;
|
||||
|
||||
/**
|
||||
* Key distribution as required by the SMP with convenient setters and getters,
|
||||
|
@ -371,7 +371,18 @@ public:
|
|||
* Request OOB data from the user application.
|
||||
*
|
||||
* @param[in] connection connection handle
|
||||
* @note shall be followed by: pal::SecurityManager::legacy_pairing_oob_data_request_reply
|
||||
* @note shall be followed by: pal::SecurityManager::secure_connections_oob_request_reply
|
||||
* or a cancellation of the procedure.
|
||||
*/
|
||||
virtual void on_secure_connections_oob_request(
|
||||
connection_handle_t connection
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Request OOB data from the user application.
|
||||
*
|
||||
* @param[in] connection connection handle
|
||||
* @note shall be followed by: pal::SecurityManager::legacy_pairing_oob_request_reply
|
||||
* or a cancellation of the procedure.
|
||||
*/
|
||||
virtual void on_legacy_pairing_oob_request(
|
||||
|
@ -379,32 +390,23 @@ public:
|
|||
) = 0;
|
||||
|
||||
/**
|
||||
* Request OOB data to be verified against received public keys.
|
||||
* Send OOB data to the application for transport to the peer.
|
||||
*
|
||||
* @param[in] public_key_x newly generated public key (x coordinate)
|
||||
* @param[in] public_key_y newly generated public key (y coordinate)
|
||||
* @param[in] connection connection handle
|
||||
* @param[in] random random number used to generate the confirmation
|
||||
* @param[in] confirm confirmation value to be use for authentication
|
||||
* in secure connections pairing
|
||||
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
|
||||
*/
|
||||
virtual void on_oob_data_verification_request(
|
||||
connection_handle_t connection,
|
||||
const public_key_coord_t &peer_public_key_x,
|
||||
const public_key_coord_t &peer_public_key_y
|
||||
virtual void on_secure_connections_oob_generated(
|
||||
const oob_lesc_value_t &random,
|
||||
const oob_confirm_t &confirm
|
||||
) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Keys
|
||||
//
|
||||
|
||||
/**
|
||||
* Provide the local public key.
|
||||
*
|
||||
* @param[in] public_key_x newly generated public key (x coordinate)
|
||||
* @param[in] public_key_y newly generated public key (y coordinate)
|
||||
*/
|
||||
virtual void on_public_key_generated(
|
||||
const public_key_coord_t &public_key_x,
|
||||
const public_key_coord_t &public_key_y
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Store the results of key generation of the stage 2 of secure connections pairing
|
||||
* @see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part H - 2.3.5.6.5
|
||||
|
@ -542,21 +544,21 @@ public:
|
|||
/**
|
||||
* Initialise stack. Called before first use.
|
||||
*
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t initialize() = 0;
|
||||
|
||||
/**
|
||||
* Finalise all actions. Called before shutdown.
|
||||
*
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t terminate() = 0;
|
||||
|
||||
/**
|
||||
* Reset to same state as after initialize.
|
||||
*
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t reset() = 0;
|
||||
|
||||
|
@ -571,7 +573,7 @@ public:
|
|||
* @warning: The number of entries is considered fixed.
|
||||
*
|
||||
* @see BLUETOOTH SPECIFICATION Version 5.0 | Vol 2, Part E: 7.8.41
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual uint8_t read_resolving_list_capacity() = 0;
|
||||
|
||||
|
@ -582,7 +584,7 @@ public:
|
|||
* @param[in] peer_identity_address address of the device whose entry is to be added
|
||||
* @param[in] peer_irk peer identity resolving key
|
||||
* @see BLUETOOTH SPECIFICATION Version 5.0 | Vol 2, Part E: 7.8.38
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t add_device_to_resolving_list(
|
||||
advertising_peer_address_type_t peer_identity_address_type,
|
||||
|
@ -596,7 +598,7 @@ public:
|
|||
* @param[in] peer_identity_address_type public/private indicator
|
||||
* @param[in] peer_identity_address address of the device whose entry is to be removed
|
||||
* @see BLUETOOTH SPECIFICATION Version 5.0 | Vol 2, Part E: 7.8.39
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t remove_device_from_resolving_list(
|
||||
advertising_peer_address_type_t peer_identity_address_type,
|
||||
|
@ -607,7 +609,7 @@ public:
|
|||
* Remove all devices from the resolving list.
|
||||
*
|
||||
* @see BLUETOOTH SPECIFICATION Version 5.0 | Vol 2, Part E: 7.8.40
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t clear_resolving_list() = 0;
|
||||
|
||||
|
@ -624,7 +626,7 @@ public:
|
|||
* @param[in] initiator_dist key distribution
|
||||
* @param[in] responder_dist key distribution
|
||||
* @see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part H - 3.5.1
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t send_pairing_request(
|
||||
connection_handle_t connection,
|
||||
|
@ -643,7 +645,7 @@ public:
|
|||
* @param[in] authentication_requirements authentication requirements
|
||||
* @param[in] initiator_dist key distribution
|
||||
* @param[in] responder_dist key distribution
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t send_pairing_response(
|
||||
connection_handle_t connection,
|
||||
|
@ -659,7 +661,7 @@ public:
|
|||
* @param[in] connection connection handle
|
||||
* @param[in] reason pairing failure error
|
||||
* @see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part H - 3.5.5
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t cancel_pairing(
|
||||
connection_handle_t connection,
|
||||
|
@ -674,7 +676,7 @@ public:
|
|||
* Check if the Secure Connections feature is supported by the stack and controller.
|
||||
*
|
||||
* @param[out] enabled true if SC are supported
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t get_secure_connections_support(
|
||||
bool &enabled
|
||||
|
@ -684,7 +686,7 @@ public:
|
|||
* Set the IO capability that will be used during pairing feature exchange.
|
||||
*
|
||||
* @param[in] io_capability type of IO capabilities available on the local device
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t set_io_capability(
|
||||
io_capability_t io_capability
|
||||
|
@ -700,7 +702,7 @@ public:
|
|||
*
|
||||
* @param[in] connection connection handle
|
||||
* @param[in] timeout_in_10ms time measured in units of 10 milliseconds
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t set_authentication_timeout(
|
||||
connection_handle_t connection,
|
||||
|
@ -713,7 +715,7 @@ public:
|
|||
*
|
||||
* @param[in] connection connection handle
|
||||
* @param[out] timeout_in_10ms time measured in units of 10 milliseconds
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t get_authentication_timeout(
|
||||
connection_handle_t connection,
|
||||
|
@ -731,7 +733,7 @@ public:
|
|||
* required for pairing. This value shall be in the range
|
||||
* [min_encryption_key_size : 16].
|
||||
*
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t set_encryption_key_requirements(
|
||||
uint8_t min_encryption_key_size,
|
||||
|
@ -746,7 +748,7 @@ public:
|
|||
*
|
||||
* @param[in] connection connection handle
|
||||
* @param[in] authentication authentication requirements
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t slave_security_request(
|
||||
connection_handle_t connection,
|
||||
|
@ -767,7 +769,7 @@ public:
|
|||
* @param[in] ediv encryption diversifier from the peer
|
||||
* @param[in] rand random value from the peer
|
||||
* @param[in] mitm does the LTK have man in the middle protection
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t enable_encryption(
|
||||
connection_handle_t connection,
|
||||
|
@ -784,7 +786,7 @@ public:
|
|||
* @param[in] connection connection handle
|
||||
* @param[in] ltk long term key from the peer
|
||||
* @param[in] mitm does the LTK have man in the middle protection
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t enable_encryption(
|
||||
connection_handle_t connection,
|
||||
|
@ -798,7 +800,7 @@ public:
|
|||
*
|
||||
* @param[in] key encryption key
|
||||
* @param[in,out] data data to be encrypted, if successful contains the result
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t encrypt_data(
|
||||
const byte_array_t<16> &key,
|
||||
|
@ -824,7 +826,7 @@ public:
|
|||
* @param[in] ltk long term key
|
||||
* @param[in] mitm does the LTK have man in the middle protection
|
||||
* @param[in] secure_connections is this a secure_connections pairing
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t set_ltk(
|
||||
connection_handle_t connection,
|
||||
|
@ -837,7 +839,7 @@ public:
|
|||
* Inform the stack we don't have the LTK.
|
||||
*
|
||||
* @param[in] connection connection handle
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t set_ltk_not_found(
|
||||
connection_handle_t connection
|
||||
|
@ -847,7 +849,7 @@ public:
|
|||
* Set the local IRK.
|
||||
*
|
||||
* @param[in] irk identity resolution key
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t set_irk(
|
||||
const irk_t &irk
|
||||
|
@ -856,20 +858,32 @@ public:
|
|||
/**
|
||||
* Set the local CSRK.
|
||||
*
|
||||
* @param[in] csrk signing key
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @param[in] csrk local signing key
|
||||
* @param[in] sign_counter local signing counter
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t set_csrk(
|
||||
const csrk_t &csrk
|
||||
const csrk_t &csrk,
|
||||
sign_count_t sign_counter
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Generate the Public key. This will also generate the private key.
|
||||
* Public key will be returned as an event handler callback when it's ready.
|
||||
* Set the peer CSRK for particular connection.
|
||||
*
|
||||
* @param[in] connection connection handle
|
||||
* @param[in] csrk signing key
|
||||
* @param[in] authenticated is the CSRK authenticated
|
||||
* @param[in] sign_counter signing counter
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t generate_public_key() = 0;
|
||||
virtual ble_error_t set_peer_csrk(
|
||||
connection_handle_t connection,
|
||||
const csrk_t &csrk,
|
||||
bool authenticated,
|
||||
sign_count_t sign_counter
|
||||
) = 0;
|
||||
|
||||
virtual ble_error_t remove_peer_csrk(connection_handle_t connection) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Authentication
|
||||
|
@ -880,7 +894,7 @@ public:
|
|||
*
|
||||
* @param[out] random_data returns 8 octets of random data
|
||||
* @see BLUETOOTH SPECIFICATION Version 5.0 | Vol 2, Part H 2
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t get_random_data(
|
||||
byte_array_t<8> &random_data
|
||||
|
@ -908,7 +922,7 @@ public:
|
|||
* passkey is set to 0 then the security manager generates a random
|
||||
* passkey every time it calls SecurityManagerEvent::on_passkey_display.
|
||||
*
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t set_display_passkey(
|
||||
passkey_num_t passkey
|
||||
|
@ -917,7 +931,7 @@ public:
|
|||
/**
|
||||
* Reply to a passkey request received from the SecurityManagerEventHandler.
|
||||
*
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t passkey_request_reply(
|
||||
connection_handle_t connection,
|
||||
|
@ -925,13 +939,30 @@ public:
|
|||
) = 0;
|
||||
|
||||
/**
|
||||
* Reply to an oob data request received from the SecurityManagerEventHandler.
|
||||
* Reply to a Secure Connections oob data request received from the SecurityManagerEventHandler.
|
||||
*
|
||||
* @param[in] connection connection handle
|
||||
* @param[in] local_random local random number used for the last oob exchange
|
||||
* @param[in] peer_random random number used to generate the confirmation on peer
|
||||
* @param[in] peer_confirm confirmation value to be use for authentication
|
||||
* in secure connections pairing
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t secure_connections_oob_request_reply(
|
||||
connection_handle_t connection,
|
||||
const oob_lesc_value_t &local_random,
|
||||
const oob_lesc_value_t &peer_random,
|
||||
const oob_confirm_t &peer_confirm
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Reply to a legacy pairing oob data request received from the SecurityManagerEventHandler.
|
||||
*
|
||||
* @param[in] connection connection handle
|
||||
* @param[in] oob_data pointer to out of band data
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t legacy_pairing_oob_data_request_reply(
|
||||
virtual ble_error_t legacy_pairing_oob_request_reply(
|
||||
connection_handle_t connection,
|
||||
const oob_tk_t &oob_data
|
||||
) = 0;
|
||||
|
@ -942,7 +973,7 @@ public:
|
|||
*
|
||||
* @param[in] connection connection handle
|
||||
* @param[in] confirmation true if the user indicated the numbers match
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t confirmation_entered(
|
||||
connection_handle_t connection,
|
||||
|
@ -955,7 +986,7 @@ public:
|
|||
*
|
||||
* @param[in] connection connection handle
|
||||
* @param[in] keypress type of keypress event
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t send_keypress_notification(
|
||||
connection_handle_t connection,
|
||||
|
@ -963,21 +994,10 @@ public:
|
|||
) = 0;
|
||||
|
||||
/**
|
||||
* Notify the stack that the OOB data has been verified and supply the peer's random number.
|
||||
* If the verification failed this will not be called and cancel_pairing will be called instead.
|
||||
*
|
||||
* @param[in] connection connection handle
|
||||
* @param[in] local_random random number sent from the local device to be used in further
|
||||
* calculations by the stack, set to 0 if peer reported no OOB present
|
||||
* @param[in] peer_random random number from the peer to be used in further
|
||||
* calculations by the stack, set to 0 if no OOB data received
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* Generate local OOB data to be sent to the application which sends it to the peer.
|
||||
* @return BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t oob_data_verified(
|
||||
connection_handle_t connection,
|
||||
const oob_lesc_value_t &local_random,
|
||||
const oob_lesc_value_t &peer_random
|
||||
) = 0;
|
||||
virtual ble_error_t generate_secure_connections_oob() = 0;
|
||||
|
||||
/* Entry points for the underlying stack to report events back to the user. */
|
||||
public:
|
||||
|
|
|
@ -1,429 +0,0 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
#ifndef PAL_SECURITY_MANAGER_DB_H__
|
||||
#define PAL_SECURITY_MANAGER_DB_H__
|
||||
|
||||
#include "platform/Callback.h"
|
||||
#include "ble/pal/GapTypes.h"
|
||||
#include "ble/BLETypes.h"
|
||||
#include "ble/Gap.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace ble {
|
||||
namespace pal {
|
||||
|
||||
|
||||
/**
|
||||
* Security flags associated with a bond.
|
||||
*/
|
||||
struct SecurityDistributionFlags_t {
|
||||
SecurityDistributionFlags_t() :
|
||||
peer_address(),
|
||||
encryption_key_size(0),
|
||||
peer_address_is_public(false),
|
||||
local_address_is_public(false),
|
||||
csrk_stored(false),
|
||||
csrk_mitm_protected(false),
|
||||
ltk_stored(false),
|
||||
ltk_mitm_protected(false),
|
||||
secure_connections_paired(false) {
|
||||
}
|
||||
|
||||
/** peer address */
|
||||
address_t peer_address;
|
||||
|
||||
/** encryption key size */
|
||||
uint8_t encryption_key_size;
|
||||
/** true if peer address is public, false if it's static random */
|
||||
uint8_t peer_address_is_public:1;
|
||||
/** true if local address is public, false if it's static random */
|
||||
uint8_t local_address_is_public:1;
|
||||
|
||||
/** CSRK (Connection Signature Resolving Key) has been distributed and stored */
|
||||
uint8_t csrk_stored:1;
|
||||
/** CSRK that is stored has MITM protection */
|
||||
uint8_t csrk_mitm_protected:1;
|
||||
/** LTK (Long Term Key) has been distributed and stored */
|
||||
uint8_t ltk_stored:1;
|
||||
/** LTK that is stored has MITM protection */
|
||||
uint8_t ltk_mitm_protected:1;
|
||||
/** the current pairing was done using Secure Connections */
|
||||
uint8_t secure_connections_paired:1;
|
||||
};
|
||||
|
||||
/** Long Term Key and data used to identify it */
|
||||
struct SecurityEntryKeys_t {
|
||||
/** Long Term Key */
|
||||
ltk_t ltk;
|
||||
/** EDIV (Encryption diversifier) used to identify LTK during legacy pairing */
|
||||
ediv_t ediv;
|
||||
/** Rand (random number) used to identify LTK during legacy pairing */
|
||||
rand_t rand;
|
||||
};
|
||||
|
||||
/** Data for resolving random resolvable addresses */
|
||||
struct SecurityEntryIdentity_t {
|
||||
/** identity address */
|
||||
address_t identity_address;
|
||||
/** Identity Resolving Key */
|
||||
irk_t irk;
|
||||
};
|
||||
|
||||
/**
|
||||
* SecurityDb holds the state for active connections and bonded devices.
|
||||
* Keys can be stored in NVM and are returned via callbacks.
|
||||
* SecurityDb is responsible for serialising any requests and keeping
|
||||
* the store in a consistent state.
|
||||
* Active connections state must be returned immediately.
|
||||
*/
|
||||
class SecurityDb {
|
||||
public:
|
||||
/**
|
||||
* Opaque type representing a handle to a database entry.
|
||||
*/
|
||||
typedef void* entry_handle_t;
|
||||
|
||||
/* callbacks for asynchronous data retrieval from the security db */
|
||||
|
||||
typedef mbed::Callback<void(entry_handle_t, const SecurityEntryKeys_t*)>
|
||||
SecurityEntryKeysDbCb_t;
|
||||
typedef mbed::Callback<void(entry_handle_t, const csrk_t*)>
|
||||
SecurityEntryCsrkDbCb_t;
|
||||
typedef mbed::Callback<void(::Gap::Whitelist_t*)>
|
||||
WhitelistDbCb_t;
|
||||
|
||||
SecurityDb() { };
|
||||
virtual ~SecurityDb() { };
|
||||
|
||||
/**
|
||||
* Return immediately security flags associated to a db entry.
|
||||
*
|
||||
* @param[in] db_entry Entry of the database queried.
|
||||
* @return pointer to the flags or NULL if the entry do not have any
|
||||
* associated flags.
|
||||
*/
|
||||
virtual const SecurityDistributionFlags_t* get_distribution_flags(
|
||||
entry_handle_t db_entry
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Set the distribution flags of a DB entry.
|
||||
*
|
||||
* @param[in] db_entry Entry of the database that will store the flags.
|
||||
* @param[in] flags Distribution flags to store in @p db_entry.
|
||||
*/
|
||||
virtual void set_distribution_flags(
|
||||
entry_handle_t db_entry,
|
||||
const SecurityDistributionFlags_t& flags
|
||||
) = 0;
|
||||
|
||||
/* local keys */
|
||||
|
||||
/**
|
||||
* Retrieve stored LTK based on passed in EDIV and RAND values.
|
||||
*
|
||||
* @param[in] cb callback that will receive the LTK struct
|
||||
* @param[in] db_entry handle of the entry being queried.
|
||||
* @param[in] ediv one of the values used to identify the LTK
|
||||
* @param[in] rand one of the values used to identify the LTK
|
||||
*/
|
||||
virtual void get_entry_local_keys(
|
||||
SecurityEntryKeysDbCb_t cb,
|
||||
entry_handle_t db_entry,
|
||||
const ediv_t &ediv,
|
||||
const rand_t &rand
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Retrieve stored LTK generated during secure connections pairing.
|
||||
*
|
||||
* @param[in] cb callback that will receive the LTK struct
|
||||
* @param[in] db_entry handle of the entry being queried.
|
||||
*/
|
||||
virtual void get_entry_local_keys(
|
||||
SecurityEntryKeysDbCb_t cb,
|
||||
entry_handle_t db_entry
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Save new local LTK for a connection.
|
||||
*
|
||||
* @param[in] db_entry handle of the entry being updated.
|
||||
* @param[in] ltk the new LTK, if the device is slave, this is the LTK that
|
||||
* will be used when link is encrypted
|
||||
*/
|
||||
virtual void set_entry_local_ltk(
|
||||
entry_handle_t db_entry,
|
||||
const ltk_t <k
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Update EDIV and RAND used to identify the LTK.
|
||||
*
|
||||
* @param[in] db_entry handle of the entry being updated.
|
||||
* @param[in] ediv new EDIV value
|
||||
* @param[in] rand new RAND value
|
||||
*/
|
||||
virtual void set_entry_local_ediv_rand(
|
||||
entry_handle_t db_entry,
|
||||
const ediv_t &ediv,
|
||||
const rand_t &rand
|
||||
) = 0;
|
||||
|
||||
/* peer's keys */
|
||||
|
||||
/**
|
||||
* Return asynchronously the peer signing key through a callback
|
||||
* so that signed packets can be verified.
|
||||
*
|
||||
* @param[in] cb callback which will receive the key
|
||||
* @param[in] db_entry handle of the entry being queried.
|
||||
*/
|
||||
virtual void get_entry_peer_csrk(
|
||||
SecurityEntryCsrkDbCb_t cb,
|
||||
entry_handle_t db_entry
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Return asynchronously the peer encryption key through a callback
|
||||
* so that encryption can be enabled.
|
||||
*
|
||||
* @param[in] cb callback which will receive the key
|
||||
* @param[in] db_entry handle of the entry being queried.
|
||||
*/
|
||||
virtual void get_entry_peer_keys(
|
||||
SecurityEntryKeysDbCb_t cb,
|
||||
entry_handle_t db_entry
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Save new LTK received from the peer.
|
||||
*
|
||||
* @param[in] db_entry handle of the entry being updated.
|
||||
* @param[in] ltk the new LTK, if the peer device is slave, this is the LTK
|
||||
* that will be used when link is encrypted
|
||||
*/
|
||||
virtual void set_entry_peer_ltk(
|
||||
entry_handle_t db_entry,
|
||||
const ltk_t <k
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Update EDIV and RAND used to identify the LTK sent by the peer.
|
||||
*
|
||||
* @param[in] db_entry handle of the entry being updated.
|
||||
* @param[in] ediv new EDIV value
|
||||
* @param[in] rand new RAND value
|
||||
*/
|
||||
virtual void set_entry_peer_ediv_rand(
|
||||
entry_handle_t db_entry,
|
||||
const ediv_t &ediv,
|
||||
const rand_t &rand
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Update IRK for this connection.
|
||||
*
|
||||
* @param[in] db_entry handle of the entry being updated.
|
||||
* @param[in] irk new IRK value
|
||||
*/
|
||||
virtual void set_entry_peer_irk(
|
||||
entry_handle_t db_entry,
|
||||
const irk_t &irk
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Update the identity address of the peer.
|
||||
*
|
||||
* @param[in] db_entry handle of the entry being updated.
|
||||
* @param[in] address_is_public is the identity address public or private
|
||||
* @param[in] peer_address the new address
|
||||
*/
|
||||
virtual void set_entry_peer_bdaddr(
|
||||
entry_handle_t db_entry,
|
||||
bool address_is_public,
|
||||
const address_t &peer_address
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Update peer signing key.
|
||||
*
|
||||
* @param[in] db_entry handle of the entry being updated.
|
||||
* @param[in] csrk new CSRK value
|
||||
*/
|
||||
virtual void set_entry_peer_csrk(
|
||||
entry_handle_t db_entry,
|
||||
const csrk_t &csrk
|
||||
) = 0;
|
||||
|
||||
/* local csrk */
|
||||
|
||||
/**
|
||||
* Return local signing key used for signing packets.
|
||||
*
|
||||
* @return pointer to local CSRK
|
||||
*/
|
||||
virtual const csrk_t* get_local_csrk() = 0;
|
||||
|
||||
/**
|
||||
* Update local signing key.
|
||||
*
|
||||
* @param[in] csrk new CSRK value
|
||||
*/
|
||||
virtual void set_local_csrk(const csrk_t &csrk) = 0;
|
||||
|
||||
/* public keys */
|
||||
|
||||
/**
|
||||
* Return local public key.
|
||||
*
|
||||
* @return ref to x component of public key
|
||||
*/
|
||||
virtual const public_key_coord_t& get_public_key_x() = 0;
|
||||
|
||||
/**
|
||||
* Return local public key.
|
||||
*
|
||||
* @return ref to y component of public key
|
||||
*/
|
||||
virtual const public_key_coord_t& get_public_key_y() = 0;
|
||||
|
||||
/**
|
||||
* Set local public key.
|
||||
*
|
||||
* @param[in] public_key_x new public key value of the x coordinate
|
||||
* @param[in] public_key_y new public key value of the y coordinate
|
||||
*/
|
||||
virtual void set_public_key(
|
||||
const public_key_coord_t &public_key_x,
|
||||
const public_key_coord_t &public_key_y
|
||||
) = 0;
|
||||
|
||||
/* list management */
|
||||
|
||||
/**
|
||||
* Open a database entry.
|
||||
*
|
||||
* While this entry is opened; it can be queried and updated with the help
|
||||
* of the database setter and getter functions.
|
||||
*
|
||||
* @param[in] peer_address_type type of address
|
||||
* @param[in] peer_address this address will be used to locate an existing
|
||||
* entry.
|
||||
*
|
||||
* @return A handle to the entry.
|
||||
*/
|
||||
virtual entry_handle_t open_entry(
|
||||
BLEProtocol::AddressType_t peer_address_type,
|
||||
const address_t &peer_address
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Close a connection entry.
|
||||
*
|
||||
* @param[in] db_entry this handle will be freed up from the security db.
|
||||
*/
|
||||
virtual void close_entry(entry_handle_t db_entry) = 0;
|
||||
|
||||
/**
|
||||
* Remove entry for this peer from NVM.
|
||||
*
|
||||
* @param[in] peer_identity_address peer address that no longer needs NVM
|
||||
* storage.
|
||||
*/
|
||||
virtual void remove_entry(const address_t peer_identity_address) = 0;
|
||||
|
||||
/**
|
||||
* Remove all entries from the security DB.
|
||||
*/
|
||||
virtual void clear_entries() = 0;
|
||||
|
||||
/**
|
||||
* Asynchronously return the whitelist stored in NVM through a callback.
|
||||
* Function takes ownership of the memory. The whitelist and the ownership
|
||||
* will be returned in the callback.
|
||||
*
|
||||
* @param[in] cb callback that will receive the whitelist
|
||||
* @param[in] whitelist preallocated whitelist that will be filled in
|
||||
*/
|
||||
virtual void get_whitelist(
|
||||
WhitelistDbCb_t cb,
|
||||
::Gap::Whitelist_t *whitelist
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Asynchronously return a whitelist through a callback, generated from the
|
||||
* bond table.
|
||||
*
|
||||
* @param[in] cb callback that will receive the whitelist
|
||||
* @param[in] whitelist preallocated whitelist that will be filled in
|
||||
*/
|
||||
virtual void generate_whitelist_from_bond_table(
|
||||
WhitelistDbCb_t cb,
|
||||
::Gap::Whitelist_t *whitelist
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Update the whitelist stored in NVM by replacing it with new one.
|
||||
*
|
||||
* @param[in] whitelist
|
||||
*/
|
||||
virtual void set_whitelist(const ::Gap::Whitelist_t &whitelist) = 0;
|
||||
|
||||
/**
|
||||
* Add a new entry to the whitelist in the NVM.
|
||||
*
|
||||
* @param[in] address new whitelist entry
|
||||
*/
|
||||
virtual void add_whitelist_entry(const address_t &address) = 0;
|
||||
|
||||
/**
|
||||
* Remove whitelist entry from NVM.
|
||||
*
|
||||
* @param[in] address entry to be removed
|
||||
*/
|
||||
virtual void remove_whitelist_entry(const address_t &address) = 0;
|
||||
|
||||
/**
|
||||
*Remove all whitelist entries stored in the NVM.
|
||||
*/
|
||||
virtual void clear_whitelist() = 0;
|
||||
|
||||
/* saving and loading from nvm */
|
||||
|
||||
/**
|
||||
* Read values from storage.
|
||||
*/
|
||||
virtual void restore() = 0;
|
||||
|
||||
/**
|
||||
* Flush all values which might be stored in memory into NVM.
|
||||
*/
|
||||
virtual void sync() = 0;
|
||||
|
||||
/**
|
||||
* Toggle whether values should be preserved across resets.
|
||||
*
|
||||
* @param[in] reload if true values will be preserved across resets.
|
||||
*/
|
||||
virtual void set_restore(bool reload) = 0;
|
||||
};
|
||||
|
||||
} /* namespace pal */
|
||||
} /* namespace ble */
|
||||
|
||||
#endif /*PAL_SECURITY_MANAGER_DB_H__*/
|
|
@ -0,0 +1,74 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2017-2017 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.
|
||||
*/
|
||||
|
||||
#ifndef MBED_BLE_SIGNING_EVENT_MONITOR
|
||||
#define MBED_BLE_SIGNING_EVENT_MONITOR
|
||||
|
||||
#include "ble/BLETypes.h"
|
||||
|
||||
namespace ble {
|
||||
namespace pal {
|
||||
|
||||
/**
|
||||
* Implemented by classes that need to be notified of signing events.
|
||||
* Notification is done by calling functions in the passed in event handler
|
||||
*/
|
||||
class SigningEventMonitor {
|
||||
public:
|
||||
/**
|
||||
* Implemented by classes that are reacting to signing events.
|
||||
*/
|
||||
class EventHandler {
|
||||
public:
|
||||
/**
|
||||
* Set new signed write peer counter.
|
||||
*
|
||||
* @param[in] connection connection handle
|
||||
* @param[in] sign_coutner counter received from peer
|
||||
*/
|
||||
virtual void on_signed_write_received(
|
||||
connection_handle_t connection,
|
||||
uint32_t sign_coutner
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Indicate that signed data was rejected due to verification failure. This could
|
||||
* be due to an invalid CSRK key.
|
||||
*
|
||||
* @param[in] connection connection handle
|
||||
*/
|
||||
virtual void on_signed_write_verification_failure(
|
||||
connection_handle_t connection
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Notify a new signed write cmd was executed.
|
||||
*/
|
||||
virtual void on_signed_write() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Register a handler for singing events to be used internally and serviced first.
|
||||
*
|
||||
* @param[in] signing_event_handler Event handler being registered.
|
||||
*/
|
||||
virtual void set_signing_event_handler(EventHandler *signing_event_handler) = 0;
|
||||
};
|
||||
|
||||
} // namespace pal
|
||||
} // namespace ble
|
||||
|
||||
#endif /* MBED_BLE_SIGNING_EVENT_MONITOR */
|
|
@ -31,6 +31,28 @@
|
|||
#include <toolchain.h>
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && !defined(__CC_ARM)
|
||||
#define BLE_DEPRECATED_API_USE_BEGIN \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
|
||||
#elif defined(__CC_ARM)
|
||||
#define BLE_DEPRECATED_API_USE_BEGIN \
|
||||
_Pragma("push") \
|
||||
_Pragma("diag_suppress 1361")
|
||||
#else
|
||||
#define BLE_DEPRECATED_API_USE_BEGIN
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && !defined(__CC_ARM)
|
||||
#define BLE_DEPRECATED_API_USE_END \
|
||||
_Pragma("GCC diagnostic pop")
|
||||
#elif defined(__CC_ARM)
|
||||
#define BLE_DEPRECATED_API_USE_END \
|
||||
_Pragma("pop")
|
||||
#else
|
||||
#define BLE_DEPRECATED_API_USE_END
|
||||
#endif
|
||||
|
||||
static const char* error_strings[] = {
|
||||
"BLE_ERROR_NONE: No error",
|
||||
"BLE_ERROR_BUFFER_OVERFLOW: The requested action would cause a buffer overflow and has been aborted",
|
||||
|
@ -143,14 +165,18 @@ BLE::Instance(InstanceID_t id)
|
|||
static BLE *singletons[NUM_INSTANCES];
|
||||
if (id < NUM_INSTANCES) {
|
||||
if (singletons[id] == NULL) {
|
||||
BLE_DEPRECATED_API_USE_BEGIN
|
||||
singletons[id] = new BLE(id); /* This object will never be freed. */
|
||||
BLE_DEPRECATED_API_USE_END
|
||||
}
|
||||
|
||||
return *singletons[id];
|
||||
}
|
||||
|
||||
/* we come here only in the case of a bad interfaceID. */
|
||||
BLE_DEPRECATED_API_USE_BEGIN
|
||||
static BLE badSingleton(NUM_INSTANCES /* this is a bad index; and will result in a NULL transport. */);
|
||||
BLE_DEPRECATED_API_USE_END
|
||||
return badSingleton;
|
||||
}
|
||||
|
||||
|
@ -162,23 +188,6 @@ void defaultSchedulingCallback(BLE::OnEventsToProcessCallbackContext* params) {
|
|||
#define defaultSchedulingCallback NULL
|
||||
#endif
|
||||
|
||||
|
||||
BLE::BLE(InstanceID_t instanceIDIn) : instanceID(instanceIDIn), transport(),
|
||||
whenEventsToProcess(defaultSchedulingCallback),
|
||||
event_signaled(false)
|
||||
{
|
||||
static BLEInstanceBase *transportInstances[NUM_INSTANCES];
|
||||
|
||||
if (instanceID < NUM_INSTANCES) {
|
||||
if (!transportInstances[instanceID]) {
|
||||
transportInstances[instanceID] = instanceConstructors[instanceID](); /* Call the stack's initializer for the transport object. */
|
||||
}
|
||||
transport = transportInstances[instanceID];
|
||||
} else {
|
||||
transport = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool BLE::hasInitialized(void) const
|
||||
{
|
||||
if (!transport) {
|
||||
|
@ -332,3 +341,47 @@ void BLE::signalEventsToProcess()
|
|||
whenEventsToProcess(¶ms);
|
||||
}
|
||||
}
|
||||
|
||||
// start of deprecated functions
|
||||
|
||||
BLE_DEPRECATED_API_USE_BEGIN
|
||||
|
||||
// NOTE: move and remove deprecation once private
|
||||
BLE::BLE(InstanceID_t instanceIDIn) : instanceID(instanceIDIn), transport(),
|
||||
whenEventsToProcess(defaultSchedulingCallback),
|
||||
event_signaled(false)
|
||||
{
|
||||
static BLEInstanceBase *transportInstances[NUM_INSTANCES];
|
||||
|
||||
if (instanceID < NUM_INSTANCES) {
|
||||
if (!transportInstances[instanceID]) {
|
||||
transportInstances[instanceID] = instanceConstructors[instanceID](); /* Call the stack's initializer for the transport object. */
|
||||
}
|
||||
transport = transportInstances[instanceID];
|
||||
} else {
|
||||
transport = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ble_error_t BLE::setAddress(
|
||||
BLEProtocol::AddressType_t type,
|
||||
const BLEProtocol::AddressBytes_t address
|
||||
) {
|
||||
return gap().setAddress(type, address);
|
||||
}
|
||||
|
||||
ble_error_t BLE::connect(
|
||||
const BLEProtocol::AddressBytes_t peerAddr,
|
||||
BLEProtocol::AddressType_t peerAddrType,
|
||||
const Gap::ConnectionParams_t *connectionParams,
|
||||
const GapScanningParams *scanParams
|
||||
) {
|
||||
return gap().connect(peerAddr, peerAddrType, connectionParams, scanParams);
|
||||
}
|
||||
|
||||
ble_error_t BLE::disconnect(Gap::DisconnectionReason_t reason) {
|
||||
return gap().disconnect(reason);
|
||||
}
|
||||
|
||||
BLE_DEPRECATED_API_USE_END
|
||||
|
||||
|
|
|
@ -0,0 +1,344 @@
|
|||
/* 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"
|
||||
|
||||
namespace {
|
||||
|
||||
ble_error_t convert_address_type(
|
||||
Gap::PeerAddressType_t input_type,
|
||||
const BLEProtocol::AddressBytes_t address,
|
||||
BLEProtocol::AddressType_t& output_type
|
||||
) {
|
||||
typedef Gap::RandomAddressType_t RandomAddressType_t;
|
||||
typedef Gap::PeerAddressType_t PeerAddressType_t;
|
||||
typedef BLEProtocol::AddressType LegacyAddressType_t;
|
||||
|
||||
// best effort; peerAddrTypeIn should not be used when privacy is on.
|
||||
switch(input_type.value()) {
|
||||
case PeerAddressType_t::PUBLIC:
|
||||
case PeerAddressType_t::PUBLIC_IDENTITY:
|
||||
output_type = LegacyAddressType_t::PUBLIC;
|
||||
break;
|
||||
case PeerAddressType_t::RANDOM: {
|
||||
RandomAddressType_t random_address_type(RandomAddressType_t::STATIC);
|
||||
ble_error_t err = Gap::getRandomAddressType(address, &random_address_type);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
switch (random_address_type.value()) {
|
||||
case RandomAddressType_t::STATIC:
|
||||
output_type = LegacyAddressType_t::RANDOM_STATIC;
|
||||
break;
|
||||
case RandomAddressType_t::NON_RESOLVABLE_PRIVATE:
|
||||
output_type = LegacyAddressType_t::RANDOM_PRIVATE_NON_RESOLVABLE;
|
||||
break;
|
||||
case RandomAddressType_t::RESOLVABLE_PRIVATE:
|
||||
output_type = LegacyAddressType_t::RANDOM_PRIVATE_RESOLVABLE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PeerAddressType_t::RANDOM_STATIC_IDENTITY:
|
||||
output_type = LegacyAddressType_t::RANDOM_STATIC;
|
||||
break;
|
||||
}
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
Gap::PeerAddressType_t convert_legacy_address_type(
|
||||
BLEProtocol::AddressType_t legacy_address
|
||||
) {
|
||||
if (legacy_address == BLEProtocol::AddressType::PUBLIC) {
|
||||
return Gap::PeerAddressType_t::PUBLIC;
|
||||
} else {
|
||||
return Gap::PeerAddressType_t::RANDOM;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const Gap::PeripheralPrivacyConfiguration_t Gap::default_peripheral_privacy_configuration = {
|
||||
/* use_non_resolvable_random_address */ false,
|
||||
/* resolution_strategy */ PeripheralPrivacyConfiguration_t::PERFORM_PAIRING_PROCEDURE
|
||||
};
|
||||
|
||||
const Gap::CentralPrivacyConfiguration_t Gap::default_central_privacy_configuration = {
|
||||
/* use_non_resolvable_random_address */ false,
|
||||
/* resolution_strategy */ CentralPrivacyConfiguration_t::DO_NOT_RESOLVE
|
||||
};
|
||||
|
||||
void Gap::processConnectionEvent(
|
||||
Handle_t handle,
|
||||
Role_t role,
|
||||
PeerAddressType_t peerAddrType,
|
||||
const BLEProtocol::AddressBytes_t peerAddr,
|
||||
BLEProtocol::AddressType_t ownAddrType,
|
||||
const BLEProtocol::AddressBytes_t ownAddr,
|
||||
const ConnectionParams_t *connectionParams,
|
||||
const uint8_t *peerResolvableAddr,
|
||||
const uint8_t *localResolvableAddr
|
||||
) {
|
||||
/* Update Gap state */
|
||||
state.advertising = 0;
|
||||
state.connected = 1;
|
||||
++connectionCount;
|
||||
|
||||
ConnectionCallbackParams_t callbackParams(
|
||||
handle,
|
||||
role,
|
||||
peerAddrType,
|
||||
peerAddr,
|
||||
ownAddrType,
|
||||
ownAddr,
|
||||
connectionParams,
|
||||
peerResolvableAddr,
|
||||
localResolvableAddr
|
||||
);
|
||||
|
||||
connectionCallChain.call(&callbackParams);
|
||||
}
|
||||
|
||||
void Gap::processAdvertisementReport(
|
||||
const BLEProtocol::AddressBytes_t peerAddr,
|
||||
int8_t rssi,
|
||||
bool isScanResponse,
|
||||
GapAdvertisingParams::AdvertisingType_t type,
|
||||
uint8_t advertisingDataLen,
|
||||
const uint8_t *advertisingData,
|
||||
PeerAddressType_t addressType
|
||||
) {
|
||||
AdvertisementCallbackParams_t params;
|
||||
|
||||
memcpy(params.peerAddr, peerAddr, ADDR_LEN);
|
||||
params.rssi = rssi;
|
||||
params.isScanResponse = isScanResponse;
|
||||
params.type = type;
|
||||
params.advertisingDataLen = advertisingDataLen;
|
||||
params.advertisingData = advertisingData;
|
||||
params.peerAddrType = addressType;
|
||||
|
||||
convert_address_type(
|
||||
addressType,
|
||||
peerAddr,
|
||||
params.addressType
|
||||
);
|
||||
|
||||
onAdvertisementReport.call(¶ms);
|
||||
}
|
||||
|
||||
|
||||
#if defined(__GNUC__) && !defined(__CC_ARM)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#elif defined(__CC_ARM)
|
||||
#pragma push
|
||||
#pragma diag_suppress 1361
|
||||
#endif
|
||||
|
||||
Gap::AdvertisementCallbackParams_t::AdvertisementCallbackParams_t() :
|
||||
peerAddr(),
|
||||
rssi(),
|
||||
isScanResponse(),
|
||||
type(),
|
||||
advertisingDataLen(0),
|
||||
advertisingData(NULL),
|
||||
addressType(),
|
||||
peerAddrType(PeerAddressType_t::PUBLIC)
|
||||
{
|
||||
}
|
||||
|
||||
ble_error_t Gap::getRandomAddressType(
|
||||
const 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 0x01:
|
||||
*type = RandomAddressType_t::RESOLVABLE_PRIVATE;
|
||||
return BLE_ERROR_NONE;
|
||||
default:
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
Gap::ConnectionCallbackParams_t::ConnectionCallbackParams_t(
|
||||
Handle_t handleIn,
|
||||
Role_t roleIn,
|
||||
BLEProtocol::AddressType_t peerAddrTypeIn,
|
||||
const uint8_t *peerAddrIn,
|
||||
BLEProtocol::AddressType_t ownAddrTypeIn,
|
||||
const uint8_t *ownAddrIn,
|
||||
const ConnectionParams_t *connectionParamsIn,
|
||||
const uint8_t *peerResolvableAddrIn,
|
||||
const uint8_t *localResolvableAddrIn
|
||||
) : handle(handleIn),
|
||||
role(roleIn),
|
||||
peerAddrType(peerAddrTypeIn),
|
||||
peerAddr(),
|
||||
ownAddrType(ownAddrTypeIn),
|
||||
ownAddr(),
|
||||
connectionParams(connectionParamsIn),
|
||||
peerResolvableAddr(),
|
||||
localResolvableAddr(),
|
||||
peerAddressType(convert_legacy_address_type(peerAddrTypeIn))
|
||||
{
|
||||
constructor_helper(
|
||||
peerAddrIn,
|
||||
ownAddrIn,
|
||||
peerResolvableAddrIn,
|
||||
localResolvableAddrIn
|
||||
);
|
||||
}
|
||||
|
||||
Gap::ConnectionCallbackParams_t::ConnectionCallbackParams_t(
|
||||
Handle_t handleIn,
|
||||
Role_t roleIn,
|
||||
PeerAddressType_t peerAddrTypeIn,
|
||||
const uint8_t *peerAddrIn,
|
||||
BLEProtocol::AddressType_t ownAddrTypeIn,
|
||||
const uint8_t *ownAddrIn,
|
||||
const ConnectionParams_t *connectionParamsIn,
|
||||
const uint8_t *peerResolvableAddrIn,
|
||||
const uint8_t *localResolvableAddrIn
|
||||
) : handle(handleIn),
|
||||
role(roleIn),
|
||||
peerAddrType(),
|
||||
peerAddr(),
|
||||
ownAddrType(ownAddrTypeIn),
|
||||
ownAddr(),
|
||||
connectionParams(connectionParamsIn),
|
||||
peerResolvableAddr(),
|
||||
localResolvableAddr(),
|
||||
peerAddressType(peerAddrTypeIn)
|
||||
{
|
||||
constructor_helper(
|
||||
peerAddrIn,
|
||||
ownAddrIn,
|
||||
peerResolvableAddrIn,
|
||||
localResolvableAddrIn
|
||||
);
|
||||
|
||||
convert_address_type(peerAddrTypeIn, peerAddrIn, peerAddrType);
|
||||
}
|
||||
|
||||
void Gap::ConnectionCallbackParams_t::constructor_helper(
|
||||
const uint8_t *peerAddrIn,
|
||||
const uint8_t *ownAddrIn,
|
||||
const uint8_t *peerResolvableAddrIn,
|
||||
const uint8_t *localResolvableAddrIn
|
||||
) {
|
||||
memcpy(peerAddr, peerAddrIn, ADDR_LEN);
|
||||
|
||||
if (ownAddrIn) {
|
||||
memcpy(ownAddr, ownAddrIn, ADDR_LEN);
|
||||
} else {
|
||||
memset(ownAddr, 0, ADDR_LEN);
|
||||
}
|
||||
|
||||
if (peerResolvableAddrIn) {
|
||||
memcpy(peerResolvableAddr, peerResolvableAddrIn, ADDR_LEN);
|
||||
} else {
|
||||
memset(ownAddr, 0, ADDR_LEN);
|
||||
}
|
||||
|
||||
if (localResolvableAddrIn) {
|
||||
memcpy(localResolvableAddr, localResolvableAddrIn, ADDR_LEN);
|
||||
} else {
|
||||
memset(ownAddr, 0, ADDR_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
ble_error_t Gap::connect(
|
||||
const BLEProtocol::AddressBytes_t peerAddr,
|
||||
DeprecatedAddressType_t peerAddrType,
|
||||
const ConnectionParams_t *connectionParams,
|
||||
const GapScanningParams *scanParams
|
||||
) {
|
||||
return connect(
|
||||
peerAddr,
|
||||
(BLEProtocol::AddressType_t) peerAddrType,
|
||||
connectionParams,
|
||||
scanParams
|
||||
);
|
||||
}
|
||||
|
||||
void Gap::processConnectionEvent(
|
||||
Handle_t handle,
|
||||
Role_t role,
|
||||
BLEProtocol::AddressType_t peerAddrType,
|
||||
const BLEProtocol::AddressBytes_t peerAddr,
|
||||
BLEProtocol::AddressType_t ownAddrType,
|
||||
const BLEProtocol::AddressBytes_t ownAddr,
|
||||
const ConnectionParams_t *connectionParams,
|
||||
const uint8_t *peerResolvableAddr,
|
||||
const uint8_t *localResolvableAddr
|
||||
) {
|
||||
/* Update Gap state */
|
||||
state.advertising = 0;
|
||||
state.connected = 1;
|
||||
++connectionCount;
|
||||
|
||||
ConnectionCallbackParams_t callbackParams(
|
||||
handle,
|
||||
role,
|
||||
peerAddrType,
|
||||
peerAddr,
|
||||
ownAddrType,
|
||||
ownAddr,
|
||||
connectionParams,
|
||||
peerResolvableAddr,
|
||||
localResolvableAddr
|
||||
);
|
||||
|
||||
connectionCallChain.call(&callbackParams);
|
||||
}
|
||||
|
||||
void Gap::processAdvertisementReport(
|
||||
const BLEProtocol::AddressBytes_t peerAddr,
|
||||
int8_t rssi,
|
||||
bool isScanResponse,
|
||||
GapAdvertisingParams::AdvertisingType_t type,
|
||||
uint8_t advertisingDataLen,
|
||||
const uint8_t *advertisingData,
|
||||
BLEProtocol::AddressType_t addressType
|
||||
) {
|
||||
AdvertisementCallbackParams_t params;
|
||||
memcpy(params.peerAddr, peerAddr, ADDR_LEN);
|
||||
params.rssi = rssi;
|
||||
params.isScanResponse = isScanResponse;
|
||||
params.type = type;
|
||||
params.advertisingDataLen = advertisingDataLen;
|
||||
params.advertisingData = advertisingData;
|
||||
params.addressType = addressType;
|
||||
|
||||
params.peerAddrType = convert_legacy_address_type(addressType);
|
||||
onAdvertisementReport.call(¶ms);
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && !defined(__CC_ARM)
|
||||
#pragma GCC diagnostic pop
|
||||
#elif defined(__CC_ARM)
|
||||
#pragma pop
|
||||
#endif
|
|
@ -0,0 +1,394 @@
|
|||
/* 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 "FileSecurityDb.h"
|
||||
|
||||
namespace ble {
|
||||
namespace generic {
|
||||
|
||||
const uint16_t DB_VERSION = 1;
|
||||
|
||||
#define DB_STORE_OFFSET_FLAGS (0)
|
||||
#define DB_STORE_OFFSET_LOCAL_KEYS (DB_STORE_OFFSET_FLAGS + sizeof(SecurityDistributionFlags_t))
|
||||
#define DB_STORE_OFFSET_PEER_KEYS (DB_STORE_OFFSET_LOCAL_KEYS + sizeof(SecurityEntryKeys_t))
|
||||
#define DB_STORE_OFFSET_PEER_IDENTITY (DB_STORE_OFFSET_PEER_KEYS + sizeof(SecurityEntryKeys_t))
|
||||
#define DB_STORE_OFFSET_PEER_SIGNING (DB_STORE_OFFSET_PEER_IDENTITY + sizeof(SecurityEntryIdentity_t))
|
||||
|
||||
#define DB_STORE_OFFSET_LOCAL_KEYS_LTK (DB_STORE_OFFSET_LOCAL_KEYS)
|
||||
#define DB_STORE_OFFSET_LOCAL_KEYS_EDIV (DB_STORE_OFFSET_LOCAL_KEYS_LTK + sizeof(ltk_t))
|
||||
#define DB_STORE_OFFSET_LOCAL_KEYS_RAND (DB_STORE_OFFSET_LOCAL_KEYS_EDIV + sizeof(ediv_t))
|
||||
|
||||
#define DB_STORE_OFFSET_PEER_KEYS_LTK (DB_STORE_OFFSET_PEER_KEYS)
|
||||
#define DB_STORE_OFFSET_PEER_KEYS_EDIV (DB_STORE_OFFSET_PEER_KEYS_LTK + sizeof(ltk_t))
|
||||
#define DB_STORE_OFFSET_PEER_KEYS_RAND (DB_STORE_OFFSET_PEER_KEYS_EDIV + sizeof(ediv_t))
|
||||
|
||||
#define DB_STORE_OFFSET_PEER_IDENTITY_ADDRESS (DB_STORE_OFFSET_PEER_IDENTITY)
|
||||
#define DB_STORE_OFFSET_PEER_IDENTITY_IRK (DB_STORE_OFFSET_PEER_IDENTITY + sizeof(address_t))
|
||||
#define DB_STORE_OFFSET_PEER_IDENTITY_ADDRESS_IS_PUBLIC (DB_STORE_OFFSET_PEER_IDENTITY_IRK + sizeof(irk_t))
|
||||
|
||||
#define DB_STORE_OFFSET_PEER_SIGNING_COUNT (DB_STORE_OFFSET_PEER_SIGNING + sizeof(csrk_t))
|
||||
|
||||
/* make size multiple of 4 */
|
||||
#define PAD4(value) ((((value - 1) / 4) * 4) + 4)
|
||||
|
||||
#define DB_SIZE_STORE \
|
||||
PAD4( \
|
||||
sizeof(SecurityDistributionFlags_t) + \
|
||||
sizeof(SecurityEntryKeys_t) + \
|
||||
sizeof(SecurityEntryKeys_t) + \
|
||||
sizeof(SecurityEntryIdentity_t) + \
|
||||
sizeof(SecurityEntrySigning_t) \
|
||||
)
|
||||
|
||||
#define DB_SIZE_STORES \
|
||||
(FileSecurityDb::MAX_ENTRIES * DB_SIZE_STORE)
|
||||
|
||||
#define DB_OFFSET_VERSION (0)
|
||||
#define DB_OFFSET_RESTORE (DB_OFFSET_VERSION + sizeof(DB_VERSION))
|
||||
#define DB_OFFSET_LOCAL_IDENTITY (DB_OFFSET_RESTORE + sizeof(bool))
|
||||
#define DB_OFFSET_LOCAL_CSRK (DB_OFFSET_LOCAL_IDENTITY + sizeof(SecurityEntryIdentity_t))
|
||||
#define DB_OFFSET_LOCAL_SIGN_COUNT (DB_OFFSET_LOCAL_CSRK + sizeof(csrk_t))
|
||||
#define DB_OFFSET_STORES (DB_OFFSET_LOCAL_SIGN_COUNT + sizeof(sign_count_t))
|
||||
#define DB_OFFSET_MAX (DB_OFFSET_STORES + DB_SIZE_STORES)
|
||||
#define DB_SIZE PAD4(DB_OFFSET_MAX)
|
||||
|
||||
typedef SecurityDb::entry_handle_t entry_handle_t;
|
||||
|
||||
FileSecurityDb::FileSecurityDb(FILE *db_file)
|
||||
: SecurityDb(),
|
||||
_db_file(db_file) {
|
||||
/* init the offset in entries so they point to file positions */
|
||||
for (size_t i = 0; i < get_entry_count(); i++) {
|
||||
_entries[i].file_offset = DB_OFFSET_STORES + i * DB_SIZE_STORE;
|
||||
}
|
||||
}
|
||||
|
||||
FileSecurityDb::~FileSecurityDb() {
|
||||
fclose(_db_file);
|
||||
}
|
||||
|
||||
FILE* FileSecurityDb::open_db_file(const char *db_path) {
|
||||
if (!db_path) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* try to open an existing file */
|
||||
FILE *db_file = fopen(db_path, "rb+");
|
||||
|
||||
if (!db_file) {
|
||||
/* file doesn't exist, create it */
|
||||
db_file = fopen(db_path, "wb+");
|
||||
}
|
||||
|
||||
if (!db_file) {
|
||||
/* failed to create a file, abort */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* we will check the db file and if the version or size doesn't match
|
||||
* what we expect we will blank it */
|
||||
bool init = false;
|
||||
uint16_t version;
|
||||
|
||||
fseek(db_file, DB_OFFSET_VERSION, SEEK_SET);
|
||||
|
||||
if ((fread(&version, sizeof(version), 1, db_file) == 1) &&
|
||||
(version == DB_VERSION)) {
|
||||
/* if file size differs from database size init the file */
|
||||
fseek(db_file, 0, SEEK_END);
|
||||
if (ftell(db_file) != DB_SIZE) {
|
||||
init = true;
|
||||
}
|
||||
} else {
|
||||
init = true;
|
||||
}
|
||||
|
||||
if (init) {
|
||||
return erase_db_file(db_file);
|
||||
}
|
||||
|
||||
return db_file;
|
||||
}
|
||||
|
||||
FILE* FileSecurityDb::erase_db_file(FILE* db_file) {
|
||||
fseek(db_file, 0, SEEK_SET);
|
||||
|
||||
/* zero the file */
|
||||
const uint32_t zero = 0;
|
||||
size_t count = DB_SIZE / 4;
|
||||
while (count--) {
|
||||
if (fwrite(&zero, sizeof(zero), 1, db_file) != 1) {
|
||||
fclose(db_file);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (fflush(db_file)) {
|
||||
fclose(db_file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return db_file;
|
||||
}
|
||||
|
||||
SecurityDistributionFlags_t* FileSecurityDb::get_distribution_flags(
|
||||
entry_handle_t db_handle
|
||||
) {
|
||||
return reinterpret_cast<SecurityDistributionFlags_t*>(db_handle);
|
||||
}
|
||||
|
||||
/* local keys */
|
||||
|
||||
/* set */
|
||||
void FileSecurityDb::set_entry_local_ltk(
|
||||
entry_handle_t db_handle,
|
||||
const ltk_t <k
|
||||
) {
|
||||
entry_t *entry = as_entry(db_handle);
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
entry->flags.ltk_sent = true;
|
||||
|
||||
db_write(<k, entry->file_offset + DB_STORE_OFFSET_LOCAL_KEYS_LTK);
|
||||
}
|
||||
|
||||
void FileSecurityDb::set_entry_local_ediv_rand(
|
||||
entry_handle_t db_handle,
|
||||
const ediv_t &ediv,
|
||||
const rand_t &rand
|
||||
) {
|
||||
entry_t *entry = as_entry(db_handle);
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
db_write(&ediv, entry->file_offset + DB_STORE_OFFSET_LOCAL_KEYS_EDIV);
|
||||
db_write(&rand, entry->file_offset + DB_STORE_OFFSET_LOCAL_KEYS_RAND);
|
||||
}
|
||||
|
||||
/* peer's keys */
|
||||
|
||||
/* set */
|
||||
|
||||
void FileSecurityDb::set_entry_peer_ltk(
|
||||
entry_handle_t db_handle,
|
||||
const ltk_t <k
|
||||
) {
|
||||
entry_t *entry = as_entry(db_handle);
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
entry->flags.ltk_stored = true;
|
||||
|
||||
db_write(<k, entry->file_offset + DB_STORE_OFFSET_PEER_KEYS_LTK);
|
||||
}
|
||||
|
||||
void FileSecurityDb::set_entry_peer_ediv_rand(
|
||||
entry_handle_t db_handle,
|
||||
const ediv_t &ediv,
|
||||
const rand_t &rand
|
||||
) {
|
||||
entry_t *entry = as_entry(db_handle);
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
db_write(&ediv, entry->file_offset + DB_STORE_OFFSET_PEER_KEYS_EDIV);
|
||||
db_write(&rand, entry->file_offset + DB_STORE_OFFSET_PEER_KEYS_RAND);
|
||||
}
|
||||
|
||||
void FileSecurityDb::set_entry_peer_irk(
|
||||
entry_handle_t db_handle,
|
||||
const irk_t &irk
|
||||
) {
|
||||
entry_t *entry = as_entry(db_handle);
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
entry->flags.irk_stored = true;
|
||||
|
||||
db_write(&irk, entry->file_offset + DB_STORE_OFFSET_PEER_IDENTITY_IRK);
|
||||
}
|
||||
|
||||
void FileSecurityDb::set_entry_peer_bdaddr(
|
||||
entry_handle_t db_handle,
|
||||
bool address_is_public,
|
||||
const address_t &peer_address
|
||||
) {
|
||||
entry_t *entry = as_entry(db_handle);
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
db_write(&peer_address, entry->file_offset + DB_STORE_OFFSET_PEER_IDENTITY_ADDRESS);
|
||||
db_write(&address_is_public, entry->file_offset + DB_STORE_OFFSET_PEER_IDENTITY_ADDRESS_IS_PUBLIC);
|
||||
}
|
||||
|
||||
void FileSecurityDb::set_entry_peer_csrk(
|
||||
entry_handle_t db_handle,
|
||||
const csrk_t &csrk
|
||||
) {
|
||||
entry_t *entry = as_entry(db_handle);
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
entry->flags.csrk_stored = true;
|
||||
|
||||
db_write(&csrk, entry->file_offset + DB_STORE_OFFSET_PEER_SIGNING);
|
||||
}
|
||||
|
||||
void FileSecurityDb::set_entry_peer_sign_counter(
|
||||
entry_handle_t db_handle,
|
||||
sign_count_t sign_counter
|
||||
) {
|
||||
entry_t *entry = as_entry(db_handle);
|
||||
if (entry) {
|
||||
entry->peer_sign_counter = sign_counter;
|
||||
}
|
||||
}
|
||||
|
||||
/* saving and loading from nvm */
|
||||
|
||||
void FileSecurityDb::restore() {
|
||||
/* restore if requested */
|
||||
bool restore_toggle = false;
|
||||
db_read(&restore_toggle, DB_OFFSET_RESTORE);
|
||||
|
||||
if (!restore_toggle) {
|
||||
erase_db_file(_db_file);
|
||||
|
||||
db_write(&DB_VERSION, DB_OFFSET_VERSION);
|
||||
return;
|
||||
}
|
||||
|
||||
db_read(&_local_identity, DB_OFFSET_LOCAL_IDENTITY);
|
||||
db_read(&_local_csrk, DB_OFFSET_LOCAL_CSRK);
|
||||
db_read(&_local_sign_counter, DB_OFFSET_LOCAL_SIGN_COUNT);
|
||||
|
||||
/* read flags and sign counters */
|
||||
for (size_t i = 0; i < get_entry_count(); i++) {
|
||||
db_read(&_entries[i].flags, _entries[i].file_offset + DB_STORE_OFFSET_FLAGS);
|
||||
db_read(&_entries[i].peer_sign_counter, _entries[i].file_offset + DB_STORE_OFFSET_PEER_SIGNING_COUNT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FileSecurityDb::sync(entry_handle_t db_handle) {
|
||||
entry_t *entry = as_entry(db_handle);
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
db_write(&entry->peer_sign_counter, entry->file_offset + DB_STORE_OFFSET_PEER_SIGNING_COUNT);
|
||||
db_write(&entry->flags, entry->file_offset + DB_STORE_OFFSET_FLAGS);
|
||||
}
|
||||
|
||||
void FileSecurityDb::set_restore(bool reload) {
|
||||
db_write(&reload, DB_OFFSET_RESTORE);
|
||||
}
|
||||
|
||||
/* helper functions */
|
||||
|
||||
uint8_t FileSecurityDb::get_entry_count() {
|
||||
return MAX_ENTRIES;
|
||||
}
|
||||
|
||||
SecurityDistributionFlags_t* FileSecurityDb::get_entry_handle_by_index(uint8_t index) {
|
||||
if (index < MAX_ENTRIES) {
|
||||
return &_entries[index].flags;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void FileSecurityDb::reset_entry(entry_handle_t db_entry) {
|
||||
entry_t *entry = as_entry(db_entry);
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(_db_file, entry->file_offset, SEEK_SET);
|
||||
const uint32_t zero = 0;
|
||||
size_t count = DB_SIZE_STORE / 4;
|
||||
while (count--) {
|
||||
fwrite(&zero, sizeof(zero), 1, _db_file);
|
||||
}
|
||||
|
||||
entry->flags = SecurityDistributionFlags_t();
|
||||
entry->peer_sign_counter = 0;
|
||||
}
|
||||
|
||||
SecurityEntryIdentity_t* FileSecurityDb::read_in_entry_peer_identity(entry_handle_t db_entry) {
|
||||
entry_t *entry = as_entry(db_entry);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SecurityEntryIdentity_t* identity = reinterpret_cast<SecurityEntryIdentity_t*>(_buffer);
|
||||
db_read(identity, entry->file_offset + DB_STORE_OFFSET_PEER_IDENTITY);
|
||||
|
||||
return identity;
|
||||
};
|
||||
|
||||
SecurityEntryKeys_t* FileSecurityDb::read_in_entry_peer_keys(entry_handle_t db_entry) {
|
||||
entry_t *entry = as_entry(db_entry);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SecurityEntryKeys_t* keys = reinterpret_cast<SecurityEntryKeys_t*>(_buffer);
|
||||
db_read(keys, entry->file_offset + DB_STORE_OFFSET_PEER_KEYS);
|
||||
|
||||
return keys;
|
||||
};
|
||||
|
||||
SecurityEntryKeys_t* FileSecurityDb::read_in_entry_local_keys(entry_handle_t db_entry) {
|
||||
entry_t *entry = as_entry(db_entry);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SecurityEntryKeys_t* keys = reinterpret_cast<SecurityEntryKeys_t*>(_buffer);
|
||||
db_read(keys, entry->file_offset + DB_STORE_OFFSET_LOCAL_KEYS);
|
||||
|
||||
return keys;
|
||||
};
|
||||
|
||||
SecurityEntrySigning_t* FileSecurityDb::read_in_entry_peer_signing(entry_handle_t db_entry) {
|
||||
entry_t *entry = as_entry(db_entry);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* only read in the csrk */
|
||||
csrk_t* csrk = reinterpret_cast<csrk_t*>(_buffer);
|
||||
db_read(csrk, entry->file_offset + DB_STORE_OFFSET_PEER_SIGNING);
|
||||
|
||||
|
||||
/* use the counter held in memory */
|
||||
SecurityEntrySigning_t* signing = reinterpret_cast<SecurityEntrySigning_t*>(_buffer);
|
||||
signing->counter = entry->peer_sign_counter;
|
||||
|
||||
return signing;
|
||||
};
|
||||
|
||||
} /* namespace pal */
|
||||
} /* namespace ble */
|
|
@ -17,6 +17,7 @@
|
|||
#include <algorithm>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ble/BLEInstanceBase.h"
|
||||
#include "ble/BLEProtocol.h"
|
||||
#include "ble/Gap.h"
|
||||
#include "ble/pal/PalGap.h"
|
||||
|
@ -30,6 +31,10 @@
|
|||
namespace ble {
|
||||
namespace generic {
|
||||
|
||||
using pal::connection_peer_address_type_t;
|
||||
typedef BLEProtocol::AddressType_t LegacyAddressType_t;
|
||||
typedef BLEProtocol::AddressType LegacyAddressType;
|
||||
|
||||
namespace {
|
||||
|
||||
// Constants
|
||||
|
@ -228,8 +233,8 @@ static bool is_prand_24_bits_valid(const BLEProtocol::AddressBytes_t address)
|
|||
*/
|
||||
static bool is_random_static_address(const BLEProtocol::AddressBytes_t address)
|
||||
{
|
||||
// top two msb bits shall be equal to 1.
|
||||
if ((address[5] >> 6) != 0x03) {
|
||||
// top two msb bits shall be equal to 0b11.
|
||||
if ((address[5] & 0xC0) != 0xC0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -242,8 +247,8 @@ static bool is_random_static_address(const BLEProtocol::AddressBytes_t address)
|
|||
static bool is_random_private_non_resolvable_address(
|
||||
const BLEProtocol::AddressBytes_t address
|
||||
) {
|
||||
// top two msb bits shall be equal to 0.
|
||||
if ((address[5] >> 6) != 0x00) {
|
||||
// top two msb bits shall be equal to 0b00.
|
||||
if ((address[5] & 0xC0) != 0x00) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -256,8 +261,8 @@ static bool is_random_private_non_resolvable_address(
|
|||
static bool is_random_private_resolvable_address(
|
||||
const BLEProtocol::AddressBytes_t address
|
||||
) {
|
||||
// top two msb bits shall be equal to 01.
|
||||
if ((address[5] >> 6) != 0x01) {
|
||||
// top two msb bits shall be equal to 0b01.
|
||||
if ((address[5] & 0xC0) != 0x40) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -314,7 +319,9 @@ static bool is_whitelist_valid(const Gap::Whitelist_t& whitelist)
|
|||
|
||||
for (size_t i = 0; i < whitelist.size; ++i) {
|
||||
const BLEProtocol::Address_t& address = whitelist.addresses[i];
|
||||
if (address.type > BLEProtocol::AddressType::RANDOM_PRIVATE_NON_RESOLVABLE) {
|
||||
if (address.type != BLEProtocol::AddressType::PUBLIC &&
|
||||
address.type != BLEProtocol::AddressType::RANDOM_STATIC
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -350,14 +357,26 @@ static bool is_in_whitelist(
|
|||
/*
|
||||
* Convert a BLEProtocol::AddressType_t into a pal::whitelist_address_type_t.
|
||||
*/
|
||||
static pal::whitelist_address_type_t to_device_address_type(
|
||||
static pal::whitelist_address_type_t to_whitelist_address_type(
|
||||
BLEProtocol::AddressType_t address_type
|
||||
) {
|
||||
return (address_type == BLEProtocol::AddressType::PUBLIC) ?
|
||||
pal::whitelist_address_type_t::PUBLIC_DEVICE_ADDRESS :
|
||||
pal::whitelist_address_type_t::RANDOM_DEVICE_ADDRESS;
|
||||
pal::whitelist_address_type_t::PUBLIC_DEVICE_ADDRESS :
|
||||
pal::whitelist_address_type_t::RANDOM_DEVICE_ADDRESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a BLEProtocol::AddressType_t into a pal::peer_address_type
|
||||
*/
|
||||
static peer_address_type_t to_peer_address_type(
|
||||
LegacyAddressType_t address_type
|
||||
) {
|
||||
return (address_type == LegacyAddressType::PUBLIC) ?
|
||||
peer_address_type_t::PUBLIC :
|
||||
peer_address_type_t::RANDOM;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return true if the advertising parameters are valid.
|
||||
*/
|
||||
|
@ -379,15 +398,21 @@ static bool is_advertising_params_valid(const GapAdvertisingParams& params)
|
|||
GenericGap::GenericGap(
|
||||
pal::EventQueue& event_queue,
|
||||
pal::Gap& pal_gap,
|
||||
pal::GenericAccessService& generic_access_service
|
||||
pal::GenericAccessService& generic_access_service,
|
||||
pal::SecurityManager& pal_sm
|
||||
) : _event_queue(event_queue),
|
||||
_pal_gap(pal_gap),
|
||||
_gap_service(generic_access_service),
|
||||
_address_type(BLEProtocol::AddressType::PUBLIC),
|
||||
_pal_sm(pal_sm),
|
||||
_address_type(LegacyAddressType::PUBLIC),
|
||||
_initiator_policy_mode(pal::initiator_policy_t::NO_FILTER),
|
||||
_scanning_filter_policy(pal::scanning_filter_policy_t::NO_FILTER),
|
||||
_advertising_filter_policy(pal::advertising_filter_policy_t::NO_FILTER),
|
||||
_whitelist(),
|
||||
_privacy_enabled(false),
|
||||
_peripheral_privacy_configuration(default_peripheral_privacy_configuration),
|
||||
_central_privacy_configuration(default_central_privacy_configuration),
|
||||
_random_address_rotating(false),
|
||||
_advertising_timeout(),
|
||||
_scan_timeout(),
|
||||
_connection_event_handler(NULL)
|
||||
|
@ -395,6 +420,9 @@ GenericGap::GenericGap(
|
|||
_pal_gap.when_gap_event_received(
|
||||
mbed::callback(this, &GenericGap::on_gap_event_received)
|
||||
);
|
||||
|
||||
// Recover static random identity
|
||||
_random_static_identity_address = _pal_gap.get_random_address();
|
||||
}
|
||||
|
||||
GenericGap::~GenericGap()
|
||||
|
@ -402,16 +430,16 @@ GenericGap::~GenericGap()
|
|||
}
|
||||
|
||||
ble_error_t GenericGap::setAddress(
|
||||
BLEProtocol::AddressType_t type,
|
||||
const BLEProtocol::AddressBytes_t address
|
||||
LegacyAddressType_t type,
|
||||
const Address_t address
|
||||
) {
|
||||
switch (type) {
|
||||
case BLEProtocol::AddressType::PUBLIC:
|
||||
case LegacyAddressType::PUBLIC:
|
||||
// The public address cannot be set, just set the type to public
|
||||
_address_type = type;
|
||||
return BLE_ERROR_NONE;
|
||||
|
||||
case BLEProtocol::AddressType::RANDOM_STATIC: {
|
||||
case LegacyAddressType::RANDOM_STATIC: {
|
||||
if (is_random_static_address(address) == false) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
@ -425,30 +453,29 @@ ble_error_t GenericGap::setAddress(
|
|||
|
||||
_address_type = type;
|
||||
_address = ble::address_t(address);
|
||||
_random_static_identity_address = ble::address_t(address);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
case BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE:
|
||||
// TODO: Fix with the privacy/security rework
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
case BLEProtocol::AddressType::RANDOM_PRIVATE_NON_RESOLVABLE:
|
||||
// TODO: add process to set the random private non resolvable
|
||||
// address (privacy/security work)
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
case LegacyAddressType::RANDOM_PRIVATE_RESOLVABLE:
|
||||
case LegacyAddressType::RANDOM_PRIVATE_NON_RESOLVABLE:
|
||||
// Note: it is not allowed to set directly these addresses
|
||||
// privacy management handled it for users.
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
|
||||
default:
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
ble_error_t GenericGap::getAddress(
|
||||
BLEProtocol::AddressType_t *type,
|
||||
BLEProtocol::AddressBytes_t address
|
||||
LegacyAddressType_t *type,
|
||||
Address_t address
|
||||
) {
|
||||
*type = _address_type;
|
||||
ble::address_t address_value;
|
||||
if (_address_type == BLEProtocol::AddressType::PUBLIC) {
|
||||
|
||||
if (_address_type == LegacyAddressType::PUBLIC) {
|
||||
address_value = _pal_gap.get_device_address();
|
||||
} else {
|
||||
address_value = _pal_gap.get_random_address();
|
||||
|
@ -481,6 +508,10 @@ ble_error_t GenericGap::stopAdvertising()
|
|||
}
|
||||
_advertising_timeout.detach();
|
||||
state.advertising = false;
|
||||
|
||||
// Stop address rotation if required
|
||||
set_random_address_rotation(false);
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
@ -491,15 +522,18 @@ ble_error_t GenericGap::stopScan()
|
|||
return err;
|
||||
}
|
||||
|
||||
// Stop address rotation if required
|
||||
set_random_address_rotation(false);
|
||||
|
||||
_scan_timeout.detach();
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t GenericGap::connect(
|
||||
const BLEProtocol::AddressBytes_t peerAddr,
|
||||
BLEProtocol::AddressType_t peerAddrType,
|
||||
const ConnectionParams_t* connectionParams,
|
||||
const GapScanningParams* scanParams
|
||||
const Address_t peerAddr,
|
||||
PeerAddressType_t peerAddrType,
|
||||
const ConnectionParams_t *connectionParams,
|
||||
const GapScanningParams *scanParams
|
||||
) {
|
||||
if (connectionParams == NULL) {
|
||||
connectionParams = &default_connection_params;
|
||||
|
@ -517,8 +551,6 @@ ble_error_t GenericGap::connect(
|
|||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
// TODO fix upper layer API, address type factorization is incorrect.
|
||||
|
||||
// Force scan stop before initiating the scan used for connection
|
||||
stopScan();
|
||||
|
||||
|
@ -526,9 +558,9 @@ ble_error_t GenericGap::connect(
|
|||
scanParams->getInterval(),
|
||||
scanParams->getWindow(),
|
||||
_initiator_policy_mode,
|
||||
(pal::connection_peer_address_type_t::type) peerAddrType,
|
||||
(pal::connection_peer_address_type_t::type) peerAddrType.value(),
|
||||
ble::address_t(peerAddr),
|
||||
(pal::own_address_type_t::type) _address_type,
|
||||
get_own_address_type(CENTRAL_CONNECTION /* requires resolvable address */),
|
||||
connectionParams->minConnectionInterval,
|
||||
connectionParams->maxConnectionInterval,
|
||||
connectionParams->slaveLatency,
|
||||
|
@ -538,6 +570,21 @@ ble_error_t GenericGap::connect(
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
ble_error_t GenericGap::connect(
|
||||
const Address_t peerAddr,
|
||||
LegacyAddressType_t peerAddrType,
|
||||
const ConnectionParams_t* connectionParams,
|
||||
const GapScanningParams* scanParams
|
||||
) {
|
||||
return connect(
|
||||
peerAddr,
|
||||
to_peer_address_type(peerAddrType),
|
||||
connectionParams,
|
||||
scanParams
|
||||
);
|
||||
}
|
||||
|
||||
ble_error_t GenericGap::disconnect(Handle_t connectionHandle, DisconnectionReason_t reason)
|
||||
{
|
||||
if (is_disconnection_reason_valid(reason) == false) {
|
||||
|
@ -688,7 +735,7 @@ ble_error_t GenericGap::setWhitelist(const Whitelist_t &whitelist)
|
|||
|
||||
if (is_in_whitelist(device, whitelist) == false) {
|
||||
ble_error_t err = _pal_gap.remove_device_from_whitelist(
|
||||
to_device_address_type(device.type),
|
||||
to_whitelist_address_type(device.type),
|
||||
device.address
|
||||
);
|
||||
|
||||
|
@ -699,7 +746,7 @@ ble_error_t GenericGap::setWhitelist(const Whitelist_t &whitelist)
|
|||
|
||||
if (is_in_whitelist(device, whitelist) == false) {
|
||||
_pal_gap.add_device_to_whitelist(
|
||||
to_device_address_type(device.type),
|
||||
to_whitelist_address_type(device.type),
|
||||
device.address
|
||||
);
|
||||
}
|
||||
|
@ -715,7 +762,7 @@ ble_error_t GenericGap::setWhitelist(const Whitelist_t &whitelist)
|
|||
|
||||
if (is_in_whitelist(device, _whitelist) == false) {
|
||||
ble_error_t err = _pal_gap.add_device_to_whitelist(
|
||||
to_device_address_type(device.type),
|
||||
to_whitelist_address_type(device.type),
|
||||
device.address
|
||||
);
|
||||
|
||||
|
@ -727,7 +774,7 @@ ble_error_t GenericGap::setWhitelist(const Whitelist_t &whitelist)
|
|||
|
||||
if (is_in_whitelist(device, _whitelist) == false) {
|
||||
_pal_gap.remove_device_from_whitelist(
|
||||
to_device_address_type(device.type),
|
||||
to_whitelist_address_type(device.type),
|
||||
device.address
|
||||
);
|
||||
}
|
||||
|
@ -739,7 +786,7 @@ ble_error_t GenericGap::setWhitelist(const Whitelist_t &whitelist)
|
|||
|
||||
if (is_in_whitelist(device, whitelist) == false) {
|
||||
_pal_gap.add_device_to_whitelist(
|
||||
to_device_address_type(device.type),
|
||||
to_whitelist_address_type(device.type),
|
||||
device.address
|
||||
);
|
||||
}
|
||||
|
@ -816,11 +863,19 @@ ble_error_t GenericGap::startRadioScan(const GapScanningParams &scanningParams)
|
|||
return BLE_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
pal::own_address_type_t own_address_type = get_own_address_type(CENTRAL_SCAN /* central, can use non resolvable address for scan requests */);
|
||||
|
||||
if(_privacy_enabled && (own_address_type == pal::own_address_type_t::RANDOM_ADDRESS))
|
||||
{
|
||||
// Use non-resolvable static random address
|
||||
set_random_address_rotation(true);
|
||||
}
|
||||
|
||||
ble_error_t err = _pal_gap.set_scan_parameters(
|
||||
scanningParams.getActiveScanning(),
|
||||
scanningParams.getInterval(),
|
||||
scanningParams.getWindow(),
|
||||
get_own_address_type(),
|
||||
own_address_type,
|
||||
_scanning_filter_policy
|
||||
);
|
||||
|
||||
|
@ -851,6 +906,66 @@ ble_error_t GenericGap::initRadioNotification(void)
|
|||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
ble_error_t GenericGap::enablePrivacy(bool enable)
|
||||
{
|
||||
if(enable == _privacy_enabled) {
|
||||
// No change
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
if(enable && !_pal_gap.is_privacy_supported())
|
||||
{
|
||||
// Privacy is not supported by the implementation
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
_privacy_enabled = enable;
|
||||
|
||||
update_address_resolution_setting();
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t GenericGap::setPeripheralPrivacyConfiguration(
|
||||
const PeripheralPrivacyConfiguration_t *configuration
|
||||
)
|
||||
{
|
||||
_peripheral_privacy_configuration = *configuration;
|
||||
|
||||
update_address_resolution_setting();
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t GenericGap::getPeripheralPrivacyConfiguration(
|
||||
PeripheralPrivacyConfiguration_t *configuration
|
||||
)
|
||||
{
|
||||
*configuration = _peripheral_privacy_configuration;
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t GenericGap::setCentralPrivacyConfiguration(
|
||||
const CentralPrivacyConfiguration_t *configuration
|
||||
)
|
||||
{
|
||||
_central_privacy_configuration = *configuration;
|
||||
|
||||
update_address_resolution_setting();
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t GenericGap::getCentralPrivacyConfiguration(
|
||||
CentralPrivacyConfiguration_t *configuration
|
||||
)
|
||||
{
|
||||
*configuration = _central_privacy_configuration;
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t GenericGap::setAdvertisingData(const GapAdvertisingData &advData, const GapAdvertisingData &scanResponse)
|
||||
{
|
||||
ble_error_t err = _pal_gap.set_advertising_data(
|
||||
|
@ -873,6 +988,21 @@ ble_error_t GenericGap::startAdvertising(const GapAdvertisingParams& params)
|
|||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
// We can only use non resolvable addresses if the device is non connectable
|
||||
AddressUseType_t address_use_type =
|
||||
((params.getAdvertisingType() == GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED) ||
|
||||
(params.getAdvertisingType() == GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED)) ?
|
||||
PERIPHERAL_NON_CONNECTABLE :
|
||||
PERIPHERAL_CONNECTABLE;
|
||||
|
||||
pal::own_address_type_t own_address_type = get_own_address_type(address_use_type);
|
||||
|
||||
if(_privacy_enabled && (own_address_type == pal::own_address_type_t::RANDOM_ADDRESS))
|
||||
{
|
||||
// Use non-resolvable static random address
|
||||
set_random_address_rotation(true);
|
||||
}
|
||||
|
||||
// TODO: fix the high level API to have a min/max range
|
||||
// Going against recommendations (The Advertising_Interval_Min and
|
||||
// Advertising_Interval_Max should not be the same value to enable the
|
||||
|
@ -883,7 +1013,7 @@ ble_error_t GenericGap::startAdvertising(const GapAdvertisingParams& params)
|
|||
/* advertising_interval_min */ params.getIntervalInADVUnits(),
|
||||
/* advertising_interval_max */ params.getIntervalInADVUnits(),
|
||||
(pal::advertising_type_t::type) params.getAdvertisingType(),
|
||||
get_own_address_type(),
|
||||
own_address_type,
|
||||
pal::advertising_peer_address_type_t::PUBLIC_ADDRESS,
|
||||
ble::address_t(),
|
||||
pal::advertising_channel_map_t::ALL_ADVERTISING_CHANNELS,
|
||||
|
@ -925,11 +1055,13 @@ ble_error_t GenericGap::reset(void)
|
|||
void GenericGap::processConnectionEvent(
|
||||
Handle_t handle,
|
||||
Role_t role,
|
||||
BLEProtocol::AddressType_t peerAddrType,
|
||||
PeerAddressType_t peerAddrType,
|
||||
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,
|
||||
const uint8_t *localResolvableAddr
|
||||
) {
|
||||
if (_connection_event_handler) {
|
||||
_connection_event_handler->on_connected(
|
||||
|
@ -950,7 +1082,9 @@ void GenericGap::processConnectionEvent(
|
|||
peerAddr,
|
||||
ownAddrType,
|
||||
ownAddr,
|
||||
connectionParams
|
||||
connectionParams,
|
||||
peerResolvableAddr,
|
||||
localResolvableAddr
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -996,6 +1130,10 @@ void GenericGap::process_advertising_timeout()
|
|||
if (err) {
|
||||
// TODO: define the mechanism signaling the error
|
||||
}
|
||||
|
||||
// Stop address rotation if required
|
||||
set_random_address_rotation(false);
|
||||
|
||||
processTimeoutEvent(Gap::TIMEOUT_SRC_ADVERTISING);
|
||||
}
|
||||
|
||||
|
@ -1036,6 +1174,21 @@ void GenericGap::on_advertising_report(const pal::GapAdvertisingReportEvent& e)
|
|||
for (size_t i = 0; i < e.size(); ++i) {
|
||||
pal::GapAdvertisingReportEvent::advertising_t advertising = e[i];
|
||||
|
||||
// Check if the address hasn't been resolved
|
||||
if(_privacy_enabled &&
|
||||
_central_privacy_configuration.resolution_strategy == CentralPrivacyConfiguration_t::RESOLVE_AND_FILTER &&
|
||||
advertising.address_type == pal::connection_peer_address_type_t::RANDOM_ADDRESS &&
|
||||
is_random_private_resolvable_address(advertising.address.data())
|
||||
) {
|
||||
// Filter it out
|
||||
continue;
|
||||
}
|
||||
|
||||
// note 1-to-1 conversion between connection_peer_address_type_t and
|
||||
// peer_address_type_t
|
||||
peer_address_type_t peer_address_type =
|
||||
static_cast<peer_address_type_t::type>(advertising.address_type.value());
|
||||
|
||||
processAdvertisementReport(
|
||||
advertising.address.data(),
|
||||
advertising.rssi,
|
||||
|
@ -1043,51 +1196,105 @@ void GenericGap::on_advertising_report(const pal::GapAdvertisingReportEvent& e)
|
|||
(GapAdvertisingParams::AdvertisingType_t) advertising.type.value(),
|
||||
advertising.data.size(),
|
||||
advertising.data.data(),
|
||||
(BLEProtocol::AddressType_t) advertising.address_type.value()
|
||||
peer_address_type
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void GenericGap::on_connection_complete(const pal::GapConnectionCompleteEvent& e)
|
||||
{
|
||||
// TODO: deprecate ownAddrType and ownAddr, those are not specified
|
||||
// from the Bluetooth perspective
|
||||
if (e.status == pal::hci_error_code_t::SUCCESS) {
|
||||
if (e.role.value() == e.role.SLAVE) {
|
||||
_advertising_timeout.detach();
|
||||
_pal_gap.advertising_enable(false);
|
||||
}
|
||||
|
||||
// using these parameters if stupid, there is no range for the
|
||||
// connection interval when the connection is established
|
||||
ConnectionParams_t connection_params = {
|
||||
/* minConnectionInterval */ e.connection_interval,
|
||||
/* maxConnectionInterval */ e.connection_interval,
|
||||
e.connection_latency,
|
||||
e.supervision_timeout
|
||||
};
|
||||
ble::address_t address;
|
||||
if (_address_type == BLEProtocol::AddressType::PUBLIC) {
|
||||
address = _pal_gap.get_device_address();
|
||||
} else {
|
||||
address = _pal_gap.get_random_address();
|
||||
}
|
||||
|
||||
processConnectionEvent(
|
||||
e.connection_handle,
|
||||
e.role.value() == e.role.MASTER ? ::Gap::CENTRAL : ::Gap::PERIPHERAL,
|
||||
(BLEProtocol::AddressType_t) e.peer_address_type.value(),
|
||||
e.peer_address.data(),
|
||||
_address_type,
|
||||
address.data(),
|
||||
&connection_params
|
||||
);
|
||||
} else {
|
||||
if (e.status != pal::hci_error_code_t::SUCCESS) {
|
||||
// for now notify user that the connection failled by issuing a timeout
|
||||
// event
|
||||
|
||||
// TODO: Define events in case of connection faillure
|
||||
processTimeoutEvent(Gap::TIMEOUT_SRC_CONN);
|
||||
return;
|
||||
}
|
||||
|
||||
bool needs_pairing = false;
|
||||
bool needs_authentication = false;
|
||||
|
||||
if (_privacy_enabled &&
|
||||
e.role.value() == e.role.SLAVE &&
|
||||
e.peer_address_type == peer_address_type_t::RANDOM
|
||||
) {
|
||||
// Apply privacy policy if in peripheral mode for non-resolved addresses
|
||||
RandomAddressType_t random_address_type(RandomAddressType_t::RESOLVABLE_PRIVATE);
|
||||
ble_error_t err = getRandomAddressType(e.peer_address.data(), &random_address_type);
|
||||
if (err) {
|
||||
// FIXME: return for now; needs to report the error ?
|
||||
return;
|
||||
}
|
||||
|
||||
if (random_address_type == RandomAddressType_t::RESOLVABLE_PRIVATE) {
|
||||
switch(_peripheral_privacy_configuration.resolution_strategy) {
|
||||
case PeripheralPrivacyConfiguration_t::REJECT_NON_RESOLVED_ADDRESS:
|
||||
// Reject connection request - the user will get notified through a callback
|
||||
_pal_gap.disconnect(
|
||||
e.connection_handle,
|
||||
pal::disconnection_reason_t::AUTHENTICATION_FAILLURE
|
||||
);
|
||||
return;
|
||||
|
||||
case PeripheralPrivacyConfiguration_t::PERFORM_PAIRING_PROCEDURE:
|
||||
needs_pairing = true;
|
||||
break;
|
||||
|
||||
case PeripheralPrivacyConfiguration_t::PERFORM_AUTHENTICATION_PROCEDURE:
|
||||
needs_authentication = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (e.role.value() == e.role.SLAVE) {
|
||||
_advertising_timeout.detach();
|
||||
_pal_gap.advertising_enable(false);
|
||||
|
||||
// Stop address rotation if required
|
||||
set_random_address_rotation(false);
|
||||
}
|
||||
|
||||
// using these parameters if stupid, there is no range for the
|
||||
// connection interval when the connection is established
|
||||
ConnectionParams_t connection_params = {
|
||||
/* minConnectionInterval */ e.connection_interval,
|
||||
/* maxConnectionInterval */ e.connection_interval,
|
||||
e.connection_latency,
|
||||
e.supervision_timeout
|
||||
};
|
||||
|
||||
ble::address_t address;
|
||||
if (_address_type == LegacyAddressType::PUBLIC) {
|
||||
address = _pal_gap.get_device_address();
|
||||
} else {
|
||||
address = _pal_gap.get_random_address();
|
||||
}
|
||||
|
||||
processConnectionEvent(
|
||||
e.connection_handle,
|
||||
e.role.value() == e.role.MASTER ? ::Gap::CENTRAL : ::Gap::PERIPHERAL,
|
||||
e.peer_address_type,
|
||||
e.peer_address.data(),
|
||||
_address_type,
|
||||
address.data(),
|
||||
&connection_params,
|
||||
e.local_resolvable_private_address.data(),
|
||||
e.peer_resolvable_private_address.data()
|
||||
);
|
||||
|
||||
// Now starts pairing or authentication procedures if required
|
||||
if(needs_pairing) {
|
||||
SecurityManager &sm = createBLEInstance()->getSecurityManager();
|
||||
// Request authentication to start pairing procedure
|
||||
sm.requestAuthentication(e.connection_handle);
|
||||
} else if(needs_authentication) {
|
||||
// TODO: GAP Authentication != Security Manager authentication
|
||||
// Needs to be implemented
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1130,19 +1337,34 @@ void GenericGap::on_unexpected_error(const pal::GapUnexpectedErrorEvent& e)
|
|||
// has been updated.
|
||||
}
|
||||
|
||||
pal::own_address_type_t GenericGap::get_own_address_type()
|
||||
pal::own_address_type_t GenericGap::get_own_address_type(AddressUseType_t address_use_type)
|
||||
{
|
||||
if(_privacy_enabled) {
|
||||
bool use_non_resolvable_address = false;
|
||||
if(address_use_type == CENTRAL_SCAN) {
|
||||
use_non_resolvable_address = _central_privacy_configuration.use_non_resolvable_random_address;
|
||||
} else if (address_use_type == PERIPHERAL_NON_CONNECTABLE) {
|
||||
use_non_resolvable_address = _peripheral_privacy_configuration.use_non_resolvable_random_address;
|
||||
}
|
||||
|
||||
// An non resolvable private address should be generated
|
||||
if(use_non_resolvable_address) {
|
||||
return pal::own_address_type_t::RANDOM_ADDRESS;
|
||||
}
|
||||
|
||||
switch (_address_type) {
|
||||
case BLEProtocol::AddressType::PUBLIC:
|
||||
return pal::own_address_type_t::RESOLVABLE_PRIVATE_ADDRESS_PUBLIC_FALLBACK;
|
||||
default:
|
||||
return pal::own_address_type_t::RESOLVABLE_PRIVATE_ADDRESS_RANDOM_FALLBACK;
|
||||
}
|
||||
}
|
||||
|
||||
switch (_address_type) {
|
||||
case BLEProtocol::AddressType::PUBLIC:
|
||||
return pal::own_address_type_t::PUBLIC_ADDRESS;
|
||||
case BLEProtocol::AddressType::RANDOM_STATIC:
|
||||
case BLEProtocol::AddressType::RANDOM_PRIVATE_NON_RESOLVABLE:
|
||||
return pal::own_address_type_t::RANDOM_ADDRESS;
|
||||
case BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE:
|
||||
return pal::own_address_type_t::RESOLVABLE_PRIVATE_ADDRESS_PUBLIC_FALLBACK;
|
||||
default:
|
||||
// not reachable
|
||||
return pal::own_address_type_t::PUBLIC_ADDRESS;
|
||||
return pal::own_address_type_t::RANDOM_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1169,6 +1391,104 @@ bool GenericGap::initialize_whitelist() const
|
|||
return true;
|
||||
}
|
||||
|
||||
ble_error_t GenericGap::update_address_resolution_setting()
|
||||
{
|
||||
// Only disable if privacy is disabled or resolution is not requested in either central or peripheral mode
|
||||
bool enable = true;
|
||||
|
||||
if(!_privacy_enabled) {
|
||||
enable = false;
|
||||
}
|
||||
else if( (_peripheral_privacy_configuration.resolution_strategy == PeripheralPrivacyConfiguration_t::DO_NOT_RESOLVE)
|
||||
&& (_central_privacy_configuration.resolution_strategy == CentralPrivacyConfiguration_t::DO_NOT_RESOLVE) ) {
|
||||
enable = false;
|
||||
}
|
||||
|
||||
return _pal_gap.set_address_resolution(enable);
|
||||
}
|
||||
|
||||
void GenericGap::set_random_address_rotation(bool enable)
|
||||
{
|
||||
if(enable == _random_address_rotating) {
|
||||
return;
|
||||
}
|
||||
|
||||
_random_address_rotating = enable;
|
||||
|
||||
if(enable) {
|
||||
// Set first address
|
||||
update_random_address();
|
||||
|
||||
// Schedule rotations every 15 minutes as recomended by the spec
|
||||
_address_rotation_ticker.attach_us(
|
||||
mbed::callback(this, &GenericGap::on_address_rotation_timeout),
|
||||
15 * 60 * 1000000U
|
||||
);
|
||||
}
|
||||
else {
|
||||
// Stop ticker
|
||||
_address_rotation_ticker.detach();
|
||||
|
||||
// Set static random identity address
|
||||
_pal_gap.set_random_address(
|
||||
_random_static_identity_address
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void GenericGap::update_random_address()
|
||||
{
|
||||
if(!_random_address_rotating)
|
||||
{
|
||||
// This event might have been queued before we disabled address rotation
|
||||
return;
|
||||
}
|
||||
|
||||
ble::address_t address;
|
||||
|
||||
do {
|
||||
byte_array_t<8> random_data;
|
||||
|
||||
ble_error_t ret = _pal_sm.get_random_data(random_data);
|
||||
if (ret != BLE_ERROR_NONE) {
|
||||
// Abort
|
||||
return;
|
||||
}
|
||||
|
||||
// Build a non-resolvable private address as specified in the Core 4.2 spec, Vol 6, Part B, 1.3.2.2
|
||||
// Mask out two MSbs
|
||||
random_data[5] &= 0x3F;
|
||||
|
||||
// Copy to address - will copy first 6 bytes
|
||||
address = ble::address_t(random_data.data());
|
||||
|
||||
if(!is_random_private_non_resolvable_address(address.data()))
|
||||
{
|
||||
// If address is invalid, which is unlikely (all 0s or all 1s), try again
|
||||
// If implementation is faulty, we'll get stuck here
|
||||
continue;
|
||||
}
|
||||
|
||||
// Address is valid
|
||||
break;
|
||||
} while(true);
|
||||
|
||||
ble_error_t err = _pal_gap.set_random_address(
|
||||
address
|
||||
);
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
_address_type = LegacyAddressType::RANDOM_PRIVATE_NON_RESOLVABLE;
|
||||
_address = address;
|
||||
}
|
||||
|
||||
void GenericGap::on_address_rotation_timeout()
|
||||
{
|
||||
_event_queue.post(mbed::callback(this, &GenericGap::update_random_address));
|
||||
}
|
||||
|
||||
void GenericGap::set_connection_event_handler(pal::ConnectionEventMonitor::EventHandler *connection_event_handler)
|
||||
{
|
||||
_connection_event_handler = connection_event_handler;
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include <ble/DiscoveredCharacteristic.h>
|
||||
#include "ble/generic/GenericGattClient.h"
|
||||
#include "ble/blecommon.h"
|
||||
#include "ble/BLEInstanceBase.h"
|
||||
#include "ble/generic/GenericSecurityManager.h"
|
||||
#include <algorithm>
|
||||
|
||||
using ble::pal::AttServerMessage;
|
||||
|
@ -38,6 +40,11 @@ using ble::pal::AttHandleValueIndication;
|
|||
using ble::pal::AttHandleValueNotification;
|
||||
using ble::pal::AttFindInformationResponse;
|
||||
|
||||
#define PREPARE_WRITE_HEADER_LENGTH 5
|
||||
#define WRITE_HEADER_LENGTH 3
|
||||
#define CMAC_LENGTH 8
|
||||
#define MAC_COUNTER_LENGTH 4
|
||||
|
||||
namespace ble {
|
||||
namespace generic {
|
||||
|
||||
|
@ -930,6 +937,7 @@ struct GenericGattClient::DescriptorDiscoveryControlBlock : public ProcedureCont
|
|||
GenericGattClient::GenericGattClient(pal::GattClient* pal_client) :
|
||||
_pal_client(pal_client),
|
||||
_termination_callback(),
|
||||
_signing_event_handler(NULL),
|
||||
control_blocks(NULL),
|
||||
_is_reseting(false) {
|
||||
_pal_client->when_server_message_received(
|
||||
|
@ -1075,67 +1083,94 @@ ble_error_t GenericGattClient::write(
|
|||
return BLE_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
uint16_t mtu = get_mtu(connection_handle);
|
||||
uint16_t mtu = get_mtu(connection_handle);
|
||||
|
||||
if (cmd == GattClient::GATT_OP_WRITE_CMD) {
|
||||
if (length > (uint16_t)(mtu - 3)) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
return _pal_client->write_without_response(
|
||||
connection_handle,
|
||||
attribute_handle,
|
||||
make_const_ArrayView(value, length)
|
||||
);
|
||||
} else {
|
||||
uint8_t* data = NULL;
|
||||
/* if link is encrypted signed writes should be normal writes */
|
||||
if (cmd == GattClient::GATT_OP_SIGNED_WRITE_CMD) {
|
||||
ble::link_encryption_t encryption(ble::link_encryption_t::NOT_ENCRYPTED);
|
||||
SecurityManager &sm = createBLEInstance()->getSecurityManager();
|
||||
ble_error_t status = sm.getLinkEncryption(connection_handle, &encryption);
|
||||
if (status == BLE_ERROR_NONE &&
|
||||
(encryption == link_encryption_t::ENCRYPTED ||
|
||||
encryption == link_encryption_t::ENCRYPTED_WITH_MITM ||
|
||||
encryption == link_encryption_t::ENCRYPTED_WITH_SC_AND_MITM)
|
||||
) {
|
||||
cmd = GattClient::GATT_OP_WRITE_CMD;
|
||||
}
|
||||
}
|
||||
|
||||
if (length > (uint16_t)(mtu - 3)) {
|
||||
data = (uint8_t*) malloc(length);
|
||||
if (data == NULL) {
|
||||
return BLE_ERROR_NO_MEM;
|
||||
}
|
||||
memcpy(data, value, length);
|
||||
}
|
||||
if (cmd == GattClient::GATT_OP_WRITE_CMD) {
|
||||
if (length > (uint16_t) (mtu - WRITE_HEADER_LENGTH)) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
return _pal_client->write_without_response(
|
||||
connection_handle,
|
||||
attribute_handle,
|
||||
make_const_ArrayView(value, length)
|
||||
);
|
||||
} else if (cmd == GattClient::GATT_OP_SIGNED_WRITE_CMD) {
|
||||
if (length > (uint16_t) (mtu - WRITE_HEADER_LENGTH - CMAC_LENGTH - MAC_COUNTER_LENGTH)) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
ble_error_t status = _pal_client->signed_write_without_response(
|
||||
connection_handle,
|
||||
attribute_handle,
|
||||
make_const_ArrayView(value, length)
|
||||
);
|
||||
if (_signing_event_handler && (status == BLE_ERROR_NONE)) {
|
||||
_signing_event_handler->on_signed_write();
|
||||
}
|
||||
return status;
|
||||
} else {
|
||||
uint8_t* data = NULL;
|
||||
|
||||
WriteControlBlock* write_pcb = new(std::nothrow) WriteControlBlock(
|
||||
connection_handle,
|
||||
attribute_handle,
|
||||
data,
|
||||
length
|
||||
);
|
||||
if (length > (uint16_t) (mtu - WRITE_HEADER_LENGTH)) {
|
||||
data = (uint8_t*) malloc(length);
|
||||
if (data == NULL) {
|
||||
return BLE_ERROR_NO_MEM;
|
||||
}
|
||||
memcpy(data, value, length);
|
||||
}
|
||||
|
||||
if (write_pcb == NULL) {
|
||||
free(data);
|
||||
return BLE_ERROR_NO_MEM;
|
||||
}
|
||||
WriteControlBlock* write_pcb = new (std::nothrow) WriteControlBlock(
|
||||
connection_handle,
|
||||
attribute_handle,
|
||||
data,
|
||||
length
|
||||
);
|
||||
|
||||
insert_control_block(write_pcb);
|
||||
if (write_pcb == NULL) {
|
||||
free(data);
|
||||
return BLE_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
ble_error_t err = BLE_ERROR_UNSPECIFIED;
|
||||
if (data) {
|
||||
err = _pal_client->queue_prepare_write(
|
||||
connection_handle,
|
||||
attribute_handle,
|
||||
make_const_ArrayView(value, mtu - 5),
|
||||
/* offset */ 0
|
||||
);
|
||||
} else {
|
||||
err = _pal_client->write_attribute(
|
||||
connection_handle,
|
||||
attribute_handle,
|
||||
make_const_ArrayView(value, length)
|
||||
);
|
||||
}
|
||||
insert_control_block(write_pcb);
|
||||
|
||||
if (err) {
|
||||
remove_control_block(write_pcb);
|
||||
delete write_pcb;
|
||||
}
|
||||
ble_error_t err = BLE_ERROR_UNSPECIFIED;
|
||||
if (data) {
|
||||
err = _pal_client->queue_prepare_write(
|
||||
connection_handle,
|
||||
attribute_handle,
|
||||
make_const_ArrayView(value, mtu - PREPARE_WRITE_HEADER_LENGTH),
|
||||
/* offset */0
|
||||
);
|
||||
} else {
|
||||
err = _pal_client->write_attribute(
|
||||
connection_handle,
|
||||
attribute_handle,
|
||||
make_const_ArrayView(value, length)
|
||||
);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
if (err) {
|
||||
remove_control_block(write_pcb);
|
||||
delete write_pcb;
|
||||
}
|
||||
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
return err;
|
||||
}
|
||||
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void GenericGattClient::onServiceDiscoveryTermination(
|
||||
|
@ -1238,6 +1273,12 @@ ble_error_t GenericGattClient::reset(void) {
|
|||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
void GenericGattClient::set_signing_event_handler(
|
||||
EventHandler *signing_event_handler
|
||||
) {
|
||||
_signing_event_handler = signing_event_handler;
|
||||
}
|
||||
|
||||
void GenericGattClient::on_termination(Gap::Handle_t connection_handle) {
|
||||
if (_termination_callback) {
|
||||
_termination_callback(connection_handle);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -30,7 +30,6 @@
|
|||
#include "CordioPalGenericAccessService.h"
|
||||
#include "ble/generic/GenericGap.h"
|
||||
#include "ble/generic/GenericSecurityManager.h"
|
||||
#include "ble/pal/MemorySecurityDb.h"
|
||||
#include "ble/pal/SimpleEventQueue.h"
|
||||
|
||||
namespace ble {
|
||||
|
@ -85,12 +84,12 @@ public:
|
|||
/**
|
||||
* @see BLEInstanceBase::getGap
|
||||
*/
|
||||
virtual ::Gap& getGap();
|
||||
virtual generic::GenericGap& getGap();
|
||||
|
||||
/**
|
||||
* @see BLEInstanceBase::getGap
|
||||
*/
|
||||
virtual const ::Gap& getGap() const;
|
||||
virtual const generic::GenericGap& getGap() const;
|
||||
|
||||
/**
|
||||
* @see BLEInstanceBase::getGattServer
|
||||
|
@ -105,7 +104,7 @@ public:
|
|||
/**
|
||||
* @see BLEInstanceBase::getGattClient
|
||||
*/
|
||||
virtual ::GattClient &getGattClient();
|
||||
virtual generic::GenericGattClient &getGattClient();
|
||||
|
||||
/**
|
||||
* @see BLEInstanceBase::getSecurityManager
|
||||
|
@ -154,6 +153,17 @@ private:
|
|||
|
||||
::BLE::InstanceID_t instanceID;
|
||||
mutable pal::SimpleEventQueue _event_queue;
|
||||
|
||||
class SigningEventMonitorProxy : public pal::SigningEventMonitor {
|
||||
public:
|
||||
SigningEventMonitorProxy(BLE &ble) : _ble(ble) { }
|
||||
virtual void set_signing_event_handler(pal::SigningEventMonitor::EventHandler *handler) {
|
||||
_ble.getGattClient().set_signing_event_handler(handler);
|
||||
_ble.getGattServer().set_signing_event_handler(handler);
|
||||
}
|
||||
private:
|
||||
BLE &_ble;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace cordio
|
||||
|
|
|
@ -20,22 +20,42 @@
|
|||
#include <stddef.h>
|
||||
#include "ble/blecommon.h"
|
||||
#include "ble/GattServer.h"
|
||||
#include "ble/pal/SigningEventMonitor.h"
|
||||
#include "ble/Gap.h"
|
||||
#include "wsf_types.h"
|
||||
#include "att_api.h"
|
||||
|
||||
/*! Maximum count of characteristics that can be stored for authorisation purposes */
|
||||
#define MAX_CHARACTERISTIC_AUTHORIZATION_CNT 20
|
||||
|
||||
/*! client characteristic configuration descriptors settings */
|
||||
#define MAX_CCC_CNT 20
|
||||
#define MAX_CCCD_CNT 20
|
||||
|
||||
namespace ble {
|
||||
|
||||
// fwd declaration of CordioAttClient and BLE
|
||||
namespace pal {
|
||||
namespace vendor {
|
||||
namespace cordio {
|
||||
class CordioAttClient;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace vendor {
|
||||
namespace cordio {
|
||||
|
||||
class BLE;
|
||||
|
||||
/**
|
||||
* Cordio implementation of ::GattServer
|
||||
*/
|
||||
class GattServer : public ::GattServer
|
||||
class GattServer : public ::GattServer,
|
||||
public pal::SigningEventMonitor
|
||||
{
|
||||
friend ble::vendor::cordio::BLE;
|
||||
friend ble::pal::vendor::cordio::CordioAttClient;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Return the singleton of the Cordio implementation of ::GattServer.
|
||||
|
@ -147,35 +167,84 @@ public:
|
|||
*/
|
||||
virtual ble_error_t reset(void);
|
||||
|
||||
/**
|
||||
* @see pal::SigningEventMonitor::set_signing_event_handler
|
||||
*/
|
||||
virtual void set_signing_event_handler(
|
||||
pal::SigningEventMonitor::EventHandler *signing_event_handler
|
||||
) {
|
||||
_signing_event_handler = signing_event_handler;
|
||||
}
|
||||
|
||||
private:
|
||||
static void cccCback(attsCccEvt_t *pEvt);
|
||||
static void attCback(attEvt_t *pEvt);
|
||||
static uint8_t attsReadCback(dmConnId_t connId, uint16_t handle, uint8_t operation, uint16_t offset, attsAttr_t *pAttr);
|
||||
static uint8_t attsWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation, uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr);
|
||||
static uint16_t compute_attributes_count(GattService& service);
|
||||
|
||||
void insert_service_attribute(
|
||||
GattService& service,
|
||||
attsAttr_t *&attribute_it
|
||||
);
|
||||
|
||||
ble_error_t insert_characteristic(
|
||||
GattCharacteristic *characteristic,
|
||||
attsAttr_t *&attribute_it
|
||||
);
|
||||
|
||||
bool is_characteristic_valid(GattCharacteristic *characteristic);
|
||||
|
||||
void insert_characteristic_declaration_attribute(
|
||||
GattCharacteristic *characteristic,
|
||||
attsAttr_t *&attribute_it
|
||||
);
|
||||
|
||||
ble_error_t insert_characteristic_value_attribute(
|
||||
GattCharacteristic *characteristic,
|
||||
attsAttr_t *&attribute_it
|
||||
);
|
||||
|
||||
ble_error_t insert_descriptor(
|
||||
GattCharacteristic *characteristic,
|
||||
GattAttribute* descriptor,
|
||||
attsAttr_t *&attribute_it,
|
||||
bool& cccd_created
|
||||
);
|
||||
|
||||
ble_error_t insert_cccd(
|
||||
GattCharacteristic *characteristic,
|
||||
attsAttr_t *&attribute_it
|
||||
);
|
||||
|
||||
static void cccd_cb(attsCccEvt_t *pEvt);
|
||||
static void att_cb(const attEvt_t *pEvt);
|
||||
static uint8_t atts_read_cb(dmConnId_t connId, uint16_t handle, uint8_t operation, uint16_t offset, attsAttr_t *pAttr);
|
||||
static uint8_t atts_write_cb(dmConnId_t connId, uint16_t handle, uint8_t operation, uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr);
|
||||
static uint8_t atts_auth_cb(dmConnId_t connId, uint8_t permit, uint16_t handle);
|
||||
void add_generic_access_service();
|
||||
void add_generic_attribute_service();
|
||||
void* alloc_block(size_t block_size);
|
||||
GattCharacteristic* get_auth_char(uint16_t value_handle);
|
||||
bool get_cccd_id(GattAttribute::Handle_t cccd_handle, uint8_t& idx) const;
|
||||
bool has_cccd(GattAttribute::Handle_t char_handle) const;
|
||||
bool is_update_authorized(Gap::Handle_t connection, GattAttribute::Handle_t value_handle);
|
||||
|
||||
struct alloc_block_t {
|
||||
alloc_block_t* next;
|
||||
uint8_t data[1];
|
||||
};
|
||||
|
||||
struct internal_char_t {
|
||||
uint16_t descLen;
|
||||
};
|
||||
|
||||
struct internal_service_t {
|
||||
uint16_t uuidLen;
|
||||
internal_char_t *chars;
|
||||
attsGroup_t *attGroup;
|
||||
attsGroup_t attGroup;
|
||||
internal_service_t *next;
|
||||
};
|
||||
|
||||
attsCccSet_t cccSet[MAX_CCC_CNT];
|
||||
uint16_t cccValues[MAX_CCC_CNT];
|
||||
uint16_t cccHandles[MAX_CCC_CNT];
|
||||
uint8_t cccCnt;
|
||||
pal::SigningEventMonitor::EventHandler *_signing_event_handler;
|
||||
|
||||
attsCccSet_t cccds[MAX_CCCD_CNT];
|
||||
uint16_t cccd_values[MAX_CCCD_CNT];
|
||||
uint16_t cccd_handles[MAX_CCCD_CNT];
|
||||
uint8_t cccd_cnt;
|
||||
|
||||
GattCharacteristic *_auth_char[MAX_CHARACTERISTIC_AUTHORIZATION_CNT];
|
||||
uint8_t _auth_char_count;
|
||||
|
||||
struct {
|
||||
attsGroup_t service;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#ifndef CORDIO_PAL_ATT_CLIENT_
|
||||
#define CORDIO_PAL_ATT_CLIENT_
|
||||
|
||||
#include "CordioGattServer.h"
|
||||
#include "ble/pal/AttClient.h"
|
||||
#include "ble/pal/SimpleAttServerMessage.h"
|
||||
#include "att_api.h"
|
||||
|
@ -30,7 +31,8 @@ namespace cordio {
|
|||
class CordioAttClient : public ::ble::pal::AttClient {
|
||||
|
||||
public:
|
||||
CordioAttClient() : ::ble::pal::AttClient() { }
|
||||
CordioAttClient() : ::ble::pal::AttClient(), _local_sign_counter(0) { }
|
||||
|
||||
virtual ~CordioAttClient() { }
|
||||
|
||||
/**
|
||||
|
@ -216,13 +218,26 @@ public:
|
|||
AttcSignedWriteCmd(
|
||||
connection_handle,
|
||||
attribute_handle,
|
||||
/* sign counter from flash or AttsGetSignCounter() ? */ 0,
|
||||
_local_sign_counter,
|
||||
value.size(),
|
||||
const_cast<uint8_t*>(value.data())
|
||||
);
|
||||
_local_sign_counter++;
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises the counter used to sign messages. Counter will be incremented every
|
||||
* time a message is signed.
|
||||
*
|
||||
* @param sign_counter initialise the signing counter to this value
|
||||
*/
|
||||
virtual void set_sign_counter(
|
||||
sign_count_t sign_counter
|
||||
) {
|
||||
_local_sign_counter = sign_counter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ble::pal::AttClient::prepare_write_request
|
||||
*/
|
||||
|
@ -335,6 +350,9 @@ public:
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// pass events not handled to the server side
|
||||
ble::vendor::cordio::GattServer::getInstance().att_cb(event);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -612,6 +630,8 @@ private:
|
|||
);
|
||||
}
|
||||
};
|
||||
private:
|
||||
sign_count_t _local_sign_counter;
|
||||
};
|
||||
|
||||
} // cordio
|
||||
|
|
|
@ -308,6 +308,18 @@ public:
|
|||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual bool is_privacy_supported() {
|
||||
// We only support controller-based privacy, so return whether the controller supports it
|
||||
return HciLlPrivacySupported();
|
||||
}
|
||||
|
||||
virtual ble_error_t set_address_resolution(
|
||||
bool enable
|
||||
) {
|
||||
DmPrivSetAddrResEnable(enable);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
// singleton of the ARM Cordio client
|
||||
static Gap& get_gap() {
|
||||
static Gap _gap;
|
||||
|
@ -381,11 +393,13 @@ private:
|
|||
// note the usage of the stack handle, not the HCI handle
|
||||
conn_evt->hdr.param,
|
||||
(connection_role_t::type) conn_evt->role,
|
||||
(advertising_peer_address_type_t::type) conn_evt->addrType,
|
||||
(peer_address_type_t::type) conn_evt->addrType,
|
||||
conn_evt->peerAddr,
|
||||
conn_evt->connInterval,
|
||||
conn_evt->connLatency,
|
||||
conn_evt->supTimeout
|
||||
conn_evt->supTimeout,
|
||||
conn_evt->localRpa,
|
||||
conn_evt->peerRpa
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
#include "ble/pal/PalSecurityManager.h"
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_os.h"
|
||||
#include "sec_api.h"
|
||||
#include "smp_defs.h"
|
||||
#include "cfg_stack.h"
|
||||
|
||||
namespace ble {
|
||||
namespace pal {
|
||||
|
@ -83,16 +86,42 @@ public:
|
|||
virtual ble_error_t clear_resolving_list();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Feature support
|
||||
// Pairing
|
||||
//
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::set_secure_connections_support
|
||||
* @see ::ble::pal::SecurityManager::send_pairing_request
|
||||
*/
|
||||
virtual ble_error_t set_secure_connections_support(
|
||||
bool enabled, bool secure_connections_only = false
|
||||
virtual ble_error_t send_pairing_request(
|
||||
connection_handle_t connection,
|
||||
bool oob_data_flag,
|
||||
AuthenticationMask authentication_requirements,
|
||||
KeyDistribution initiator_dist,
|
||||
KeyDistribution responder_dist
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::send_pairing_response
|
||||
*/
|
||||
virtual ble_error_t send_pairing_response(
|
||||
connection_handle_t connection,
|
||||
bool oob_data_flag,
|
||||
AuthenticationMask authentication_requirements,
|
||||
KeyDistribution initiator_dist,
|
||||
KeyDistribution responder_dist
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::cancel_pairing
|
||||
*/
|
||||
virtual ble_error_t cancel_pairing(
|
||||
connection_handle_t connection, pairing_failure_t reason
|
||||
);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Feature support
|
||||
//
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::get_secure_connections_support
|
||||
*/
|
||||
|
@ -100,6 +129,11 @@ public:
|
|||
bool &enabled
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::set_io_capability
|
||||
*/
|
||||
virtual ble_error_t set_io_capability(io_capability_t io_capability);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Security settings
|
||||
//
|
||||
|
@ -118,6 +152,17 @@ public:
|
|||
connection_handle_t, uint16_t &timeout_in_10ms
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::set_encryption_key_requirements
|
||||
*/
|
||||
virtual ble_error_t set_encryption_key_requirements(
|
||||
uint8_t min_encryption_key_size,
|
||||
uint8_t max_encryption_key_size
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::slave_security_request
|
||||
*/
|
||||
virtual ble_error_t slave_security_request(
|
||||
connection_handle_t connection,
|
||||
AuthenticationMask authentication
|
||||
|
@ -193,68 +238,27 @@ public:
|
|||
/**
|
||||
* @see ::ble::pal::SecurityManager::set_csrk
|
||||
*/
|
||||
virtual ble_error_t set_csrk(const csrk_t &csrk);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::generate_public_key
|
||||
*/
|
||||
virtual ble_error_t generate_public_key();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Global parameters
|
||||
//
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::set_display_passkey
|
||||
*/
|
||||
virtual ble_error_t set_display_passkey(passkey_num_t passkey);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::set_io_capability
|
||||
*/
|
||||
virtual ble_error_t set_io_capability(io_capability_t io_capability);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::set_encryption_key_requirements
|
||||
*/
|
||||
virtual ble_error_t set_encryption_key_requirements(
|
||||
uint8_t min_encryption_key_size,
|
||||
uint8_t max_encryption_key_size
|
||||
virtual ble_error_t set_csrk(
|
||||
const csrk_t &csrk,
|
||||
sign_count_t sign_counter
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::set_peer_csrk
|
||||
*/
|
||||
virtual ble_error_t set_peer_csrk(
|
||||
connection_handle_t connection,
|
||||
const csrk_t &csrk,
|
||||
bool authenticated,
|
||||
sign_count_t sign_counter
|
||||
);
|
||||
|
||||
virtual ble_error_t remove_peer_csrk(connection_handle_t connection);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Authentication
|
||||
//
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::send_pairing_request
|
||||
*/
|
||||
virtual ble_error_t send_pairing_request(
|
||||
connection_handle_t connection,
|
||||
bool oob_data_flag,
|
||||
AuthenticationMask authentication_requirements,
|
||||
KeyDistribution initiator_dist,
|
||||
KeyDistribution responder_dist
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::send_pairing_response
|
||||
*/
|
||||
virtual ble_error_t send_pairing_response(
|
||||
connection_handle_t connection,
|
||||
bool oob_data_flag,
|
||||
AuthenticationMask authentication_requirements,
|
||||
KeyDistribution initiator_dist,
|
||||
KeyDistribution responder_dist
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::cancel_pairing
|
||||
*/
|
||||
virtual ble_error_t cancel_pairing(
|
||||
connection_handle_t connection, pairing_failure_t reason
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::get_random_data
|
||||
*/
|
||||
|
@ -264,6 +268,11 @@ public:
|
|||
// MITM
|
||||
//
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::set_display_passkey
|
||||
*/
|
||||
virtual ble_error_t set_display_passkey(passkey_num_t passkey);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::passkey_request_reply
|
||||
*/
|
||||
|
@ -273,9 +282,19 @@ public:
|
|||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::legacy_pairing_oob_data_request_reply
|
||||
* @see ::ble::pal::SecurityManager::secure_connections_oob_request_reply
|
||||
*/
|
||||
virtual ble_error_t legacy_pairing_oob_data_request_reply(
|
||||
virtual ble_error_t secure_connections_oob_request_reply(
|
||||
connection_handle_t connection,
|
||||
const oob_lesc_value_t &local_random,
|
||||
const oob_lesc_value_t &peer_random,
|
||||
const oob_confirm_t &peer_confirm
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::legacy_pairing_oob_request_reply
|
||||
*/
|
||||
virtual ble_error_t legacy_pairing_oob_request_reply(
|
||||
connection_handle_t connection,
|
||||
const oob_tk_t &oob_data
|
||||
);
|
||||
|
@ -295,13 +314,9 @@ public:
|
|||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::oob_data_verified
|
||||
* @see ::ble::pal::SecurityManager::generate_secure_connections_oob
|
||||
*/
|
||||
virtual ble_error_t oob_data_verified(
|
||||
connection_handle_t connection,
|
||||
const oob_lesc_value_t &local_random,
|
||||
const oob_lesc_value_t &peer_random
|
||||
);
|
||||
virtual ble_error_t generate_secure_connections_oob();
|
||||
|
||||
// singleton of the ARM Cordio Security Manager
|
||||
static CordioSecurityManager &get_security_manager();
|
||||
|
@ -310,8 +325,49 @@ public:
|
|||
static bool sm_handler(const wsfMsgHdr_t* msg);
|
||||
|
||||
private:
|
||||
struct PrivacyControlBlock;
|
||||
struct PrivacyClearResListControlBlock;
|
||||
struct PrivacyAddDevToResListControlBlock;
|
||||
struct PrivacyRemoveDevFromResListControlBlock;
|
||||
|
||||
// Queue control block to add device to resolving list
|
||||
void queue_add_device_to_resolving_list(
|
||||
advertising_peer_address_type_t peer_identity_address_type,
|
||||
const address_t &peer_identity_address,
|
||||
const irk_t &peer_irk
|
||||
);
|
||||
|
||||
// Queue control block to remove device from resolving list
|
||||
void queue_remove_device_from_resolving_list(
|
||||
advertising_peer_address_type_t peer_identity_address_type,
|
||||
const address_t &peer_identity_address
|
||||
);
|
||||
|
||||
// Queue control block to clear resolving list
|
||||
void queue_clear_resolving_list();
|
||||
|
||||
// Clear all control blocks
|
||||
void clear_privacy_control_blocks();
|
||||
|
||||
// Queue a control block
|
||||
void queue_privacy_control_block(PrivacyControlBlock* block);
|
||||
|
||||
// Try to dequeue and process the next control block
|
||||
// cb_completed is set when the previous block has completed
|
||||
void process_privacy_control_blocks(bool cb_completed);
|
||||
|
||||
void cleanup_peer_csrks();
|
||||
|
||||
bool _use_default_passkey;
|
||||
passkey_num_t _default_passkey;
|
||||
bool _lesc_keys_generated;
|
||||
uint8_t _public_key_x[SEC_ECC_KEY_LEN];
|
||||
|
||||
PrivacyControlBlock* _pending_privacy_control_blocks;
|
||||
bool _processing_privacy_control_block;
|
||||
irk_t _irk;
|
||||
csrk_t _csrk;
|
||||
csrk_t* _peer_csrks[DM_CONN_MAX];
|
||||
};
|
||||
|
||||
} // cordio
|
||||
|
|
|
@ -164,31 +164,25 @@ const char* BLE::getVersion()
|
|||
return version;
|
||||
}
|
||||
|
||||
::Gap& BLE::getGap()
|
||||
generic::GenericGap& BLE::getGap()
|
||||
{
|
||||
typedef ::Gap& return_type;
|
||||
const BLE* self = this;
|
||||
return const_cast<return_type>(self->getGap());
|
||||
}
|
||||
|
||||
const ::Gap& BLE::getGap() const
|
||||
{
|
||||
return getGenericGap();
|
||||
};
|
||||
|
||||
const generic::GenericGap& BLE::getGenericGap() const
|
||||
{
|
||||
static pal::vendor::cordio::Gap& cordio_pal_gap =
|
||||
pal::vendor::cordio::Gap::get_gap();
|
||||
static pal::vendor::cordio::GenericAccessService cordio_gap_service;
|
||||
static ble::generic::GenericGap gap(
|
||||
_event_queue,
|
||||
cordio_pal_gap,
|
||||
cordio_gap_service
|
||||
pal::vendor::cordio::Gap::get_gap(),
|
||||
cordio_gap_service,
|
||||
pal::vendor::cordio::CordioSecurityManager::get_security_manager()
|
||||
);
|
||||
|
||||
return gap;
|
||||
}
|
||||
|
||||
const generic::GenericGap& BLE::getGap() const
|
||||
{
|
||||
BLE &self = const_cast<BLE&>(*this);
|
||||
return const_cast<const generic::GenericGap&>(self.getGap());
|
||||
};
|
||||
|
||||
GattServer& BLE::getGattServer()
|
||||
{
|
||||
return cordio::GattServer::getInstance();
|
||||
|
@ -199,7 +193,7 @@ const GattServer& BLE::getGattServer() const
|
|||
return cordio::GattServer::getInstance();
|
||||
}
|
||||
|
||||
::GattClient& BLE::getGattClient()
|
||||
generic::GenericGattClient& BLE::getGattClient()
|
||||
{
|
||||
static pal::AttClientToGattClientAdapter pal_client(
|
||||
pal::vendor::cordio::CordioAttClient::get_client()
|
||||
|
@ -211,21 +205,20 @@ const GattServer& BLE::getGattServer() const
|
|||
|
||||
SecurityManager& BLE::getSecurityManager()
|
||||
{
|
||||
const BLE* self = this;
|
||||
return const_cast<SecurityManager&>(self->getSecurityManager());
|
||||
static SigningEventMonitorProxy signing_event_monitor(*this);
|
||||
static generic::GenericSecurityManager m_instance(
|
||||
pal::vendor::cordio::CordioSecurityManager::get_security_manager(),
|
||||
getGap(),
|
||||
signing_event_monitor
|
||||
);
|
||||
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
const SecurityManager& BLE::getSecurityManager() const
|
||||
{
|
||||
static pal::MemorySecurityDb m_db;
|
||||
pal::vendor::cordio::CordioSecurityManager &m_pal = pal::vendor::cordio::CordioSecurityManager::get_security_manager();
|
||||
static generic::GenericSecurityManager m_instance(
|
||||
m_pal,
|
||||
m_db,
|
||||
const_cast<generic::GenericGap&>(getGenericGap())
|
||||
);
|
||||
|
||||
return m_instance;
|
||||
const BLE &self = const_cast<BLE&>(*this);
|
||||
return const_cast<const SecurityManager&>(self.getSecurityManager());
|
||||
}
|
||||
|
||||
void BLE::waitForEvent()
|
||||
|
@ -361,7 +354,10 @@ void BLE::stack_setup()
|
|||
AttHandlerInit(handlerId);
|
||||
AttsInit();
|
||||
AttsIndInit();
|
||||
AttsSignInit();
|
||||
AttsAuthorRegister(GattServer::atts_auth_cb);
|
||||
AttcInit();
|
||||
AttcSignInit();
|
||||
|
||||
handlerId = WsfOsSetNextHandler(SmpHandler);
|
||||
SmpHandlerInit(handlerId);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -14,10 +14,15 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "CordioPalSecurityManager.h"
|
||||
#include "CordioBLE.h"
|
||||
#include "dm_api.h"
|
||||
#include "att_api.h"
|
||||
#include "smp_api.h"
|
||||
#include "wsf_os.h"
|
||||
#include "hci_core.h"
|
||||
|
||||
namespace ble {
|
||||
namespace pal {
|
||||
|
@ -27,14 +32,19 @@ namespace cordio {
|
|||
CordioSecurityManager::CordioSecurityManager() :
|
||||
::ble::pal::SecurityManager(),
|
||||
_use_default_passkey(false),
|
||||
_default_passkey(0)
|
||||
_default_passkey(0),
|
||||
_lesc_keys_generated(false),
|
||||
_public_key_x(),
|
||||
_pending_privacy_control_blocks(NULL),
|
||||
_processing_privacy_control_block(false),
|
||||
_peer_csrks()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CordioSecurityManager::~CordioSecurityManager()
|
||||
{
|
||||
|
||||
clear_privacy_control_blocks();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -43,16 +53,31 @@ CordioSecurityManager::~CordioSecurityManager()
|
|||
|
||||
ble_error_t CordioSecurityManager::initialize()
|
||||
{
|
||||
// reset local state
|
||||
_use_default_passkey = false;
|
||||
_default_passkey = 0;
|
||||
_lesc_keys_generated = false;
|
||||
memset(_peer_csrks, 0, sizeof(_peer_csrks));
|
||||
|
||||
#if 0
|
||||
// FIXME: need help from the stack or local calculation
|
||||
// generate a new set of keys
|
||||
DmSecGenerateEccKeyReq();
|
||||
#endif
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t CordioSecurityManager::terminate()
|
||||
{
|
||||
cleanup_peer_csrks();
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t CordioSecurityManager::reset()
|
||||
{
|
||||
cleanup_peer_csrks();
|
||||
initialize();
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
@ -62,37 +87,65 @@ ble_error_t CordioSecurityManager::reset()
|
|||
|
||||
uint8_t CordioSecurityManager::read_resolving_list_capacity()
|
||||
{
|
||||
// FIXME: Implement with privacy support.
|
||||
return 0;
|
||||
// The Cordio stack requests this from the controller during initialization
|
||||
return hciCoreCb.resListSize;
|
||||
}
|
||||
|
||||
// As the Cordio stack can only handle one of these methods at a time, we need to create a list of control blocks
|
||||
// that are dequeued one after the other on completion of the previous one
|
||||
ble_error_t CordioSecurityManager::add_device_to_resolving_list(
|
||||
advertising_peer_address_type_t peer_identity_address_type,
|
||||
const address_t &peer_identity_address,
|
||||
const irk_t &peer_irk
|
||||
) {
|
||||
// FIXME: Implement with privacy support.
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
if( read_resolving_list_capacity() == 0 )
|
||||
{
|
||||
// If 0 is returned as capacity, it means the controller does not support resolving addresses
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// Queue control block
|
||||
queue_add_device_to_resolving_list(peer_identity_address_type, peer_identity_address, peer_irk);
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t CordioSecurityManager::remove_device_from_resolving_list(
|
||||
advertising_peer_address_type_t peer_identity_address_type,
|
||||
const address_t& peer_identity_address
|
||||
) {
|
||||
// FIXME: Implement with privacy support.
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
if( read_resolving_list_capacity() == 0 )
|
||||
{
|
||||
// If 0 is returned as capacity, it means the controller does not support resolving addresses
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// Queue control block
|
||||
queue_remove_device_from_resolving_list(peer_identity_address_type, peer_identity_address);
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t CordioSecurityManager::clear_resolving_list()
|
||||
{
|
||||
// FIXME: Implement with privacy support.
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
if( read_resolving_list_capacity() == 0 )
|
||||
{
|
||||
// If 0 is returned as capacity, it means the controller does not support resolving addresses
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// Queue control block
|
||||
queue_clear_resolving_list();
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Feature support
|
||||
//
|
||||
|
||||
// FIXME: Enable when new function available in the pal.
|
||||
#if 0
|
||||
ble_error_t CordioSecurityManager::set_secure_connections_support(
|
||||
bool enabled, bool secure_connections_only
|
||||
) {
|
||||
|
@ -104,6 +157,7 @@ ble_error_t CordioSecurityManager::set_secure_connections_support(
|
|||
}
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
ble_error_t CordioSecurityManager::get_secure_connections_support(
|
||||
bool &enabled
|
||||
|
@ -243,20 +297,64 @@ ble_error_t CordioSecurityManager::set_ltk_not_found(
|
|||
|
||||
ble_error_t CordioSecurityManager::set_irk(const irk_t& irk)
|
||||
{
|
||||
DmSecSetLocalIrk(const_cast<uint8_t*>(irk.data()));
|
||||
_irk = irk;
|
||||
DmSecSetLocalIrk(_irk.data());
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t CordioSecurityManager::set_csrk(const csrk_t& csrk)
|
||||
{
|
||||
DmSecSetLocalCsrk(const_cast<uint8_t*>(csrk.data()));
|
||||
ble_error_t CordioSecurityManager::set_csrk(
|
||||
const csrk_t& csrk,
|
||||
sign_count_t sign_counter
|
||||
) {
|
||||
_csrk = csrk;
|
||||
DmSecSetLocalCsrk(_csrk.data());
|
||||
// extra set the sign counter used by the client
|
||||
CordioAttClient::get_client().set_sign_counter(sign_counter);
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t CordioSecurityManager::generate_public_key()
|
||||
ble_error_t CordioSecurityManager::set_peer_csrk(
|
||||
connection_handle_t connection,
|
||||
const csrk_t &csrk,
|
||||
bool authenticated,
|
||||
sign_count_t sign_counter
|
||||
) {
|
||||
if (connection == 0 || connection > DM_CONN_MAX) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
size_t connection_index = connection - 1;
|
||||
|
||||
if (_peer_csrks[connection_index]) {
|
||||
*_peer_csrks[connection_index] = csrk;
|
||||
} else {
|
||||
_peer_csrks[connection_index] = new (std::nothrow) csrk_t(csrk);
|
||||
if (_peer_csrks[connection_index] == NULL) {
|
||||
return BLE_ERROR_NO_MEM;
|
||||
}
|
||||
}
|
||||
|
||||
AttsSetCsrk(connection, _peer_csrks[connection_index]->data(), authenticated);
|
||||
AttsSetSignCounter(connection, sign_counter);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t CordioSecurityManager::remove_peer_csrk(connection_handle_t connection)
|
||||
{
|
||||
// FIXME
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
if (connection == 0 || connection > DM_CONN_MAX) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
size_t connection_index = connection - 1;
|
||||
|
||||
if (_peer_csrks[connection_index]) {
|
||||
delete _peer_csrks[connection_index];
|
||||
_peer_csrks[connection_index] = NULL;
|
||||
}
|
||||
|
||||
AttsSetCsrk(connection, NULL, false);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -344,7 +442,7 @@ ble_error_t CordioSecurityManager::cancel_pairing(
|
|||
|
||||
ble_error_t CordioSecurityManager::get_random_data(byte_array_t<8> &random_data)
|
||||
{
|
||||
SecRand(random_data.buffer(), random_data.size());
|
||||
SecRand(random_data.data(), random_data.size());
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
@ -364,7 +462,7 @@ ble_error_t CordioSecurityManager::passkey_request_reply(
|
|||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t CordioSecurityManager::legacy_pairing_oob_data_request_reply(
|
||||
ble_error_t CordioSecurityManager::legacy_pairing_oob_request_reply(
|
||||
connection_handle_t connection,
|
||||
const oob_tk_t &oob_data
|
||||
) {
|
||||
|
@ -380,8 +478,8 @@ ble_error_t CordioSecurityManager::legacy_pairing_oob_data_request_reply(
|
|||
ble_error_t CordioSecurityManager::confirmation_entered(
|
||||
connection_handle_t connection, bool confirmation
|
||||
) {
|
||||
// FIXME:
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
DmSecCompareRsp(connection, confirmation);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
// FIXME: remove when declaration from the stack is available
|
||||
|
@ -394,13 +492,32 @@ ble_error_t CordioSecurityManager::send_keypress_notification(
|
|||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t CordioSecurityManager::oob_data_verified(
|
||||
|
||||
ble_error_t CordioSecurityManager::generate_secure_connections_oob() {
|
||||
uint8_t oobLocalRandom[SMP_RAND_LEN];
|
||||
SecRand(oobLocalRandom, SMP_RAND_LEN);
|
||||
DmSecCalcOobReq(oobLocalRandom, _public_key_x);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t CordioSecurityManager::secure_connections_oob_request_reply(
|
||||
connection_handle_t connection,
|
||||
const oob_lesc_value_t &local_random,
|
||||
const oob_lesc_value_t &peer_random
|
||||
const oob_lesc_value_t &peer_random,
|
||||
const oob_confirm_t &peer_confirm
|
||||
) {
|
||||
dmSecLescOobCfg_t oob_config = { 0 };
|
||||
|
||||
memcpy(oob_config.localRandom, local_random.data(), local_random.size());
|
||||
// FIXME:
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
// memcpy(oob_config.localConfirm, ?, ?);
|
||||
memcpy(oob_config.peerRandom, peer_random.data(), peer_random.size());
|
||||
memcpy(oob_config.peerConfirm, peer_confirm.data(), peer_confirm.size());
|
||||
|
||||
DmSecSetOob(connection, &oob_config);
|
||||
DmSecAuthRsp(connection, 0, NULL);
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
CordioSecurityManager& CordioSecurityManager::get_security_manager()
|
||||
|
@ -410,8 +527,8 @@ CordioSecurityManager& CordioSecurityManager::get_security_manager()
|
|||
}
|
||||
|
||||
bool CordioSecurityManager::sm_handler(const wsfMsgHdr_t* msg) {
|
||||
SecurityManager::EventHandler* handler =
|
||||
get_security_manager().get_event_handler();
|
||||
CordioSecurityManager& self = get_security_manager();
|
||||
SecurityManager::EventHandler* handler = self.get_event_handler();
|
||||
|
||||
if ((msg == NULL) || (handler == NULL)) {
|
||||
return false;
|
||||
|
@ -473,6 +590,11 @@ bool CordioSecurityManager::sm_handler(const wsfMsgHdr_t* msg) {
|
|||
connection_handle_t connection = evt->hdr.param;
|
||||
|
||||
if (evt->oob) {
|
||||
// FIXME: Nothing in the API indicates if smp or sc OOB are
|
||||
// requested.
|
||||
// To set secure connection OOB:
|
||||
// - DmSecSetOob(connection, oob_data)
|
||||
// - DmSecAuthRsp(connection, 0, NULL)
|
||||
handler->on_legacy_pairing_oob_request(connection);
|
||||
} else if (evt->display) {
|
||||
if (get_security_manager()._use_default_passkey) {
|
||||
|
@ -596,18 +718,35 @@ bool CordioSecurityManager::sm_handler(const wsfMsgHdr_t* msg) {
|
|||
return true;
|
||||
}
|
||||
|
||||
case DM_SEC_CALC_OOB_IND:
|
||||
case DM_SEC_CALC_OOB_IND: {
|
||||
dmSecOobCalcIndEvt_t* evt = (dmSecOobCalcIndEvt_t*) msg;
|
||||
handler->on_secure_connections_oob_generated(
|
||||
evt->random,
|
||||
evt->confirm
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
case DM_SEC_ECC_KEY_IND:
|
||||
case DM_SEC_ECC_KEY_IND: {
|
||||
secEccMsg_t* evt = (secEccMsg_t*) msg;
|
||||
DmSecSetEccKey(&evt->data.key);
|
||||
memcpy(self._public_key_x, evt->data.key.pubKey_x, sizeof(_public_key_x));
|
||||
self._lesc_keys_generated = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
case DM_SEC_COMPARE_IND:
|
||||
case DM_SEC_COMPARE_IND: {
|
||||
dmSecCnfIndEvt_t* evt = (dmSecCnfIndEvt_t*) msg;
|
||||
handler->on_passkey_display(
|
||||
/* connection */ evt->hdr.param,
|
||||
DmSecGetCompareValue(evt->confirm)
|
||||
);
|
||||
handler->on_confirmation_request(/* connection */ evt->hdr.param);
|
||||
return true;
|
||||
}
|
||||
|
||||
case DM_SEC_KEYPRESS_IND: {
|
||||
dmSecKeypressIndEvt_t* evt = (dmSecKeypressIndEvt_t*) msg;
|
||||
|
||||
handler->on_keypress_notification(
|
||||
/* connection */ evt->hdr.param,
|
||||
(Keypress_t) evt->notificationType
|
||||
|
@ -615,11 +754,209 @@ bool CordioSecurityManager::sm_handler(const wsfMsgHdr_t* msg) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Privacy
|
||||
case DM_PRIV_ADD_DEV_TO_RES_LIST_IND: // Device added to resolving list
|
||||
case DM_PRIV_REM_DEV_FROM_RES_LIST_IND: // Device removed from resolving list
|
||||
case DM_PRIV_CLEAR_RES_LIST_IND: // Resolving list cleared
|
||||
{
|
||||
// Previous command completed, we can move to the next control block
|
||||
self.process_privacy_control_blocks(true);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
struct CordioSecurityManager::PrivacyControlBlock
|
||||
{
|
||||
PrivacyControlBlock() : _next(NULL) {}
|
||||
|
||||
virtual ~PrivacyControlBlock() {}
|
||||
|
||||
virtual void execute() = 0;
|
||||
|
||||
void set_next(PrivacyControlBlock* next) {
|
||||
_next = next;
|
||||
}
|
||||
|
||||
PrivacyControlBlock* next() const {
|
||||
return _next;
|
||||
}
|
||||
|
||||
private:
|
||||
PrivacyControlBlock* _next;
|
||||
};
|
||||
|
||||
struct CordioSecurityManager::PrivacyClearResListControlBlock : CordioSecurityManager::PrivacyControlBlock
|
||||
{
|
||||
PrivacyClearResListControlBlock() : PrivacyControlBlock()
|
||||
{}
|
||||
|
||||
virtual ~PrivacyClearResListControlBlock() {}
|
||||
|
||||
virtual void execute() {
|
||||
// Execute command
|
||||
DmPrivClearResList();
|
||||
}
|
||||
};
|
||||
|
||||
struct CordioSecurityManager::PrivacyAddDevToResListControlBlock : CordioSecurityManager::PrivacyControlBlock
|
||||
{
|
||||
PrivacyAddDevToResListControlBlock(
|
||||
advertising_peer_address_type_t peer_identity_address_type,
|
||||
const address_t &peer_identity_address,
|
||||
const irk_t &peer_irk
|
||||
) : PrivacyControlBlock(),
|
||||
_peer_identity_address_type(peer_identity_address_type),
|
||||
_peer_identity_address(peer_identity_address),
|
||||
_peer_irk(peer_irk)
|
||||
{}
|
||||
|
||||
virtual ~PrivacyAddDevToResListControlBlock() {}
|
||||
|
||||
virtual void execute() {
|
||||
// Execute command
|
||||
DmPrivAddDevToResList(_peer_identity_address_type.value(), _peer_identity_address.data(), _peer_irk.data(), DmSecGetLocalIrk(), false, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
advertising_peer_address_type_t _peer_identity_address_type;
|
||||
address_t _peer_identity_address;
|
||||
irk_t _peer_irk;
|
||||
};
|
||||
|
||||
struct CordioSecurityManager::PrivacyRemoveDevFromResListControlBlock : CordioSecurityManager::PrivacyControlBlock
|
||||
{
|
||||
PrivacyRemoveDevFromResListControlBlock(
|
||||
advertising_peer_address_type_t peer_identity_address_type,
|
||||
const address_t &peer_identity_address
|
||||
) : PrivacyControlBlock(),
|
||||
_peer_identity_address_type(peer_identity_address_type),
|
||||
_peer_identity_address(peer_identity_address)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~PrivacyRemoveDevFromResListControlBlock() {}
|
||||
|
||||
virtual void execute() {
|
||||
// Execute command
|
||||
DmPrivRemDevFromResList(_peer_identity_address_type.value(), _peer_identity_address.data(), 0);
|
||||
}
|
||||
|
||||
private:
|
||||
advertising_peer_address_type_t _peer_identity_address_type;
|
||||
address_t _peer_identity_address;
|
||||
};
|
||||
|
||||
// Helper functions for privacy
|
||||
void CordioSecurityManager::queue_add_device_to_resolving_list(
|
||||
advertising_peer_address_type_t peer_identity_address_type,
|
||||
const address_t &peer_identity_address,
|
||||
const irk_t &peer_irk
|
||||
)
|
||||
{
|
||||
PrivacyAddDevToResListControlBlock* cb =
|
||||
new (std::nothrow) PrivacyAddDevToResListControlBlock(peer_identity_address_type, peer_identity_address, peer_irk);
|
||||
if( cb == NULL )
|
||||
{
|
||||
// Cannot go further
|
||||
return;
|
||||
}
|
||||
|
||||
queue_privacy_control_block(cb);
|
||||
}
|
||||
|
||||
void CordioSecurityManager::queue_remove_device_from_resolving_list(
|
||||
advertising_peer_address_type_t peer_identity_address_type,
|
||||
const address_t &peer_identity_address
|
||||
)
|
||||
{
|
||||
PrivacyRemoveDevFromResListControlBlock* cb =
|
||||
new (std::nothrow) PrivacyRemoveDevFromResListControlBlock(peer_identity_address_type, peer_identity_address);
|
||||
if( cb == NULL )
|
||||
{
|
||||
// Cannot go further
|
||||
return;
|
||||
}
|
||||
|
||||
queue_privacy_control_block(cb);
|
||||
}
|
||||
|
||||
void CordioSecurityManager::queue_clear_resolving_list() {
|
||||
// Remove any pending control blocks, there's no point executing them as we're about to queue the list
|
||||
clear_privacy_control_blocks();
|
||||
|
||||
PrivacyClearResListControlBlock* cb =
|
||||
new (std::nothrow) PrivacyClearResListControlBlock();
|
||||
if( cb == NULL )
|
||||
{
|
||||
// Cannot go further
|
||||
return;
|
||||
}
|
||||
|
||||
queue_privacy_control_block(cb);
|
||||
}
|
||||
|
||||
void CordioSecurityManager::clear_privacy_control_blocks() {
|
||||
while(_pending_privacy_control_blocks != NULL)
|
||||
{
|
||||
PrivacyControlBlock* next = _pending_privacy_control_blocks->next();
|
||||
delete _pending_privacy_control_blocks;
|
||||
_pending_privacy_control_blocks = next;
|
||||
}
|
||||
}
|
||||
|
||||
void CordioSecurityManager::queue_privacy_control_block(PrivacyControlBlock* block)
|
||||
{
|
||||
if( _pending_privacy_control_blocks == NULL ) {
|
||||
_pending_privacy_control_blocks = block;
|
||||
}
|
||||
else {
|
||||
PrivacyControlBlock* node = _pending_privacy_control_blocks;
|
||||
while(node->next() != NULL) {
|
||||
node = node->next();
|
||||
}
|
||||
node->set_next(block);
|
||||
}
|
||||
|
||||
process_privacy_control_blocks(false);
|
||||
}
|
||||
|
||||
// If cb_completed is set to true, it means the previous control block has completed
|
||||
void CordioSecurityManager::process_privacy_control_blocks(bool cb_completed)
|
||||
{
|
||||
if( (_processing_privacy_control_block == true) && !cb_completed )
|
||||
{
|
||||
// Busy, cannot process next control block for now
|
||||
return;
|
||||
}
|
||||
|
||||
PrivacyControlBlock* cb = _pending_privacy_control_blocks;
|
||||
if(cb == NULL) {
|
||||
// All control blocks processed
|
||||
_processing_privacy_control_block = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Process next block and free it
|
||||
_processing_privacy_control_block = true;
|
||||
|
||||
PrivacyControlBlock* next = cb->next();
|
||||
cb->execute();
|
||||
delete cb;
|
||||
_pending_privacy_control_blocks = next;
|
||||
}
|
||||
|
||||
void CordioSecurityManager::cleanup_peer_csrks() {
|
||||
for (size_t i = 0; i < DM_CONN_MAX; ++i) {
|
||||
if (_peer_csrks[i]) {
|
||||
delete _peer_csrks[i];
|
||||
_peer_csrks[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // cordio
|
||||
} // vendor
|
||||
|
|
|
@ -565,7 +565,7 @@ uint16_t AttsCccEnabled(dmConnId_t connId, uint8_t idx);
|
|||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsSetCsrk(dmConnId_t connId, uint8_t *pCsrk);
|
||||
void AttsSetCsrk(dmConnId_t connId, uint8_t *pCsrk, bool_t authenticated);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -38,11 +38,9 @@
|
|||
extern "C" {
|
||||
#if (IS_LEGACY_DEVICE_MANAGER_ENABLED)
|
||||
#include "pstorage.h"
|
||||
#include "device_manager.h"
|
||||
#else
|
||||
#include "fstorage.h"
|
||||
#include "fds.h"
|
||||
#include "peer_manager.h"
|
||||
#include "ble_conn_state.h"
|
||||
#endif
|
||||
|
||||
|
@ -52,8 +50,8 @@ extern "C" {
|
|||
|
||||
#include "nrf_ble_hci.h"
|
||||
|
||||
#include "nRF5XPalGattClient.h"
|
||||
|
||||
#include "nRF5xPalGattClient.h"
|
||||
#include "nRF5xPalSecurityManager.h"
|
||||
|
||||
|
||||
bool isEventsSignaled = false;
|
||||
|
@ -63,7 +61,7 @@ void app_error_handler(uint32_t error_code, uint32_t line_num, const
|
|||
extern "C" void SD_EVT_IRQHandler(void); // export the softdevice event handler for registration by nvic-set-vector.
|
||||
|
||||
|
||||
static void btle_handler(ble_evt_t *p_ble_evt);
|
||||
void btle_handler(ble_evt_t *p_ble_evt);
|
||||
|
||||
static void sys_evt_dispatch(uint32_t sys_evt)
|
||||
{
|
||||
|
@ -145,9 +143,6 @@ error_t btle_init(void)
|
|||
return ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
// Peer Manger must been initialised prior any other call to its API (this file and btle_security_pm.cpp)
|
||||
pm_init();
|
||||
|
||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
||||
ble_gap_addr_t addr;
|
||||
if (sd_ble_gap_address_get(&addr) != NRF_SUCCESS) {
|
||||
|
@ -157,9 +152,7 @@ error_t btle_init(void)
|
|||
return ERROR_INVALID_PARAM;
|
||||
}
|
||||
#else
|
||||
ble_gap_privacy_params_t privacy_params = {0};
|
||||
privacy_params.privacy_mode = BLE_GAP_PRIVACY_MODE_OFF;
|
||||
pm_privacy_set(&privacy_params);
|
||||
|
||||
#endif
|
||||
|
||||
ASSERT_STATUS( softdevice_ble_evt_handler_set(btle_handler));
|
||||
|
@ -168,9 +161,10 @@ error_t btle_init(void)
|
|||
return btle_gap_init();
|
||||
}
|
||||
|
||||
static void btle_handler(ble_evt_t *p_ble_evt)
|
||||
void btle_handler(ble_evt_t *p_ble_evt)
|
||||
{
|
||||
using ble::pal::vendor::nordic::nRF5XGattClient;
|
||||
using ble::pal::vendor::nordic::nRF5xGattClient;
|
||||
using ble::pal::vendor::nordic::nRF5xSecurityManager;
|
||||
|
||||
/* Library service handlers */
|
||||
#if SDK_CONN_PARAMS_MODULE_ENABLE
|
||||
|
@ -178,59 +172,29 @@ static void btle_handler(ble_evt_t *p_ble_evt)
|
|||
#endif
|
||||
|
||||
#if (IS_LEGACY_DEVICE_MANAGER_ENABLED)
|
||||
dm_ble_evt_handler(p_ble_evt);
|
||||
#else
|
||||
// Forward BLE events to the Connection State module.
|
||||
// This must be called before any event handler that uses this module.
|
||||
ble_conn_state_on_ble_evt(p_ble_evt);
|
||||
|
||||
// Forward BLE events to the Peer Manager
|
||||
pm_on_ble_evt(p_ble_evt);
|
||||
#endif
|
||||
|
||||
#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
|
||||
nRF5XGattClient::handle_events(p_ble_evt);
|
||||
nRF5xGattClient::handle_events(p_ble_evt);
|
||||
#endif
|
||||
|
||||
nRF5xn &ble = nRF5xn::Instance(BLE::DEFAULT_INSTANCE);
|
||||
nRF5xGap &gap = (nRF5xGap &) ble.getGap();
|
||||
nRF5xGattServer &gattServer = (nRF5xGattServer &) ble.getGattServer();
|
||||
nRF5xSecurityManager &securityManager = (nRF5xSecurityManager &) ble.getSecurityManager();
|
||||
nRF5xSecurityManager &securityManager = nRF5xSecurityManager::get_security_manager();
|
||||
|
||||
/* Custom event handler */
|
||||
switch (p_ble_evt->header.evt_id) {
|
||||
case BLE_GAP_EVT_CONNECTED: {
|
||||
Gap::Handle_t handle = p_ble_evt->evt.gap_evt.conn_handle;
|
||||
#if defined(TARGET_MCU_NRF51_16K_S110) || defined(TARGET_MCU_NRF51_32K_S110)
|
||||
/* Only peripheral role is supported by S110 */
|
||||
Gap::Role_t role = Gap::PERIPHERAL;
|
||||
#else
|
||||
Gap::Role_t role = static_cast<Gap::Role_t>(p_ble_evt->evt.gap_evt.params.connected.role);
|
||||
#endif
|
||||
gap.setConnectionHandle(handle);
|
||||
const Gap::ConnectionParams_t *params = reinterpret_cast<Gap::ConnectionParams_t *>(&(p_ble_evt->evt.gap_evt.params.connected.conn_params));
|
||||
const ble_gap_addr_t *peer = &p_ble_evt->evt.gap_evt.params.connected.peer_addr;
|
||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
||||
const ble_gap_addr_t *own = &p_ble_evt->evt.gap_evt.params.connected.own_addr;
|
||||
|
||||
gap.processConnectionEvent(handle,
|
||||
role,
|
||||
static_cast<BLEProtocol::AddressType_t>(peer->addr_type), peer->addr,
|
||||
static_cast<BLEProtocol::AddressType_t>(own->addr_type), own->addr,
|
||||
params);
|
||||
#else
|
||||
Gap::AddressType_t addr_type;
|
||||
Gap::Address_t own_address;
|
||||
gap.getAddress(&addr_type, own_address);
|
||||
|
||||
gap.processConnectionEvent(handle,
|
||||
role,
|
||||
static_cast<BLEProtocol::AddressType_t>(peer->addr_type), peer->addr,
|
||||
addr_type, own_address,
|
||||
params);
|
||||
#endif
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
gap.on_connection(
|
||||
p_ble_evt->evt.gap_evt.conn_handle,
|
||||
p_ble_evt->evt.gap_evt.params.connected
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED: {
|
||||
Gap::Handle_t handle = p_ble_evt->evt.gap_evt.conn_handle;
|
||||
|
@ -258,17 +222,13 @@ static void btle_handler(ble_evt_t *p_ble_evt)
|
|||
|
||||
#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
|
||||
// Close all pending discoveries for this connection
|
||||
nRF5XGattClient::handle_connection_termination(handle);
|
||||
nRF5xGattClient::handle_connection_termination(handle);
|
||||
#endif
|
||||
|
||||
gap.processDisconnectionEvent(handle, reason);
|
||||
break;
|
||||
}
|
||||
|
||||
case BLE_GAP_EVT_PASSKEY_DISPLAY:
|
||||
securityManager.processPasskeyDisplayEvent(p_ble_evt->evt.gap_evt.conn_handle, p_ble_evt->evt.gap_evt.params.passkey_display.passkey);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_TIMEOUT:
|
||||
gap.processTimeoutEvent(static_cast<Gap::TimeoutSource_t>(p_ble_evt->evt.gap_evt.params.timeout.src));
|
||||
break;
|
||||
|
@ -280,22 +240,17 @@ static void btle_handler(ble_evt_t *p_ble_evt)
|
|||
// BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION));
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_ADV_REPORT: {
|
||||
const ble_gap_evt_adv_report_t *advReport = &p_ble_evt->evt.gap_evt.params.adv_report;
|
||||
gap.processAdvertisementReport(advReport->peer_addr.addr,
|
||||
advReport->rssi,
|
||||
advReport->scan_rsp,
|
||||
static_cast<GapAdvertisingParams::AdvertisingType_t>(advReport->type),
|
||||
advReport->dlen,
|
||||
advReport->data,
|
||||
static_cast<BLEProtocol::AddressType_t>(advReport->peer_addr.addr_type));
|
||||
case BLE_GAP_EVT_ADV_REPORT:
|
||||
gap.on_advertising_packet(p_ble_evt->evt.gap_evt.params.adv_report);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Process security manager events
|
||||
securityManager.sm_handler(p_ble_evt);
|
||||
|
||||
gattServer.hwCallback(p_ble_evt);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,326 +0,0 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2006-2013 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.
|
||||
*/
|
||||
#if defined(S110)
|
||||
#include "btle.h"
|
||||
|
||||
#include "nRF5xn.h"
|
||||
|
||||
extern "C" {
|
||||
#include "pstorage.h"
|
||||
#include "device_manager.h"
|
||||
#include "id_manager.h"
|
||||
}
|
||||
|
||||
#include "btle_security.h"
|
||||
|
||||
static dm_application_instance_t applicationInstance;
|
||||
static bool initialized = false;
|
||||
static ret_code_t dm_handler(dm_handle_t const *p_handle, dm_event_t const *p_event, ret_code_t event_result);
|
||||
|
||||
// default security parameters. Avoid "holes" between member assigments in order to compile by gcc++11.
|
||||
static ble_gap_sec_params_t securityParameters = {
|
||||
.bond = true, /**< Perform bonding. */
|
||||
.mitm = true, /**< Man In The Middle protection required. */
|
||||
.lesc = false, /**< Enable LE Secure Connection pairing. */
|
||||
.keypress = false, /**< Enable generation of keypress notifications. */
|
||||
.io_caps = SecurityManager::IO_CAPS_NONE, /**< IO capabilities, see @ref BLE_GAP_IO_CAPS. */
|
||||
.oob = 0, /**< Out Of Band data available. */
|
||||
.min_key_size = 16, /**< Minimum encryption key size in octets between 7 and 16. If 0 then not applicable in this instance. */
|
||||
.max_key_size = 16, /**< Maximum encryption key size in octets between min_key_size and 16. */
|
||||
.kdist_own = {
|
||||
.enc = 0, /**< Long Term Key and Master Identification. */
|
||||
.id = 0, /**< Identity Resolving Key and Identity Address Information. */
|
||||
.sign = 0, /**< Connection Signature Resolving Key. */
|
||||
.link = 0 /**< Derive the Link Key from the LTK. */
|
||||
}, /**< Key distribution bitmap: keys that the local device will distribute. */
|
||||
.kdist_peer = {
|
||||
.enc = 1, /**< Long Term Key and Master Identification. */
|
||||
.id = 1, /**< Identity Resolving Key and Identity Address Information. */
|
||||
.sign = 1, /**< Connection Signature Resolving Key. */
|
||||
.link = 0 /**< Derive the Link Key from the LTK. */
|
||||
} /**< Key distribution bitmap: keys that the peripheral device will distribute. */
|
||||
};
|
||||
|
||||
bool
|
||||
btle_hasInitializedSecurity(void)
|
||||
{
|
||||
return initialized;
|
||||
}
|
||||
|
||||
ble_error_t
|
||||
btle_initializeSecurity(bool enableBonding,
|
||||
bool requireMITM,
|
||||
SecurityManager::SecurityIOCapabilities_t iocaps,
|
||||
const SecurityManager::Passkey_t passkey)
|
||||
{
|
||||
/* guard against multiple initializations */
|
||||
if (initialized) {
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
if (pstorage_init() != NRF_SUCCESS) {
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
|
||||
ret_code_t rc;
|
||||
if (passkey) {
|
||||
ble_opt_t opts;
|
||||
opts.gap_opt.passkey.p_passkey = const_cast<uint8_t *>(passkey);
|
||||
if ((rc = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opts)) != NRF_SUCCESS) {
|
||||
switch (rc) {
|
||||
case BLE_ERROR_INVALID_CONN_HANDLE:
|
||||
case NRF_ERROR_INVALID_ADDR:
|
||||
case NRF_ERROR_INVALID_PARAM:
|
||||
default:
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
case NRF_ERROR_INVALID_STATE:
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
case NRF_ERROR_BUSY:
|
||||
return BLE_STACK_BUSY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dm_init_param_t dm_init_param = {
|
||||
.clear_persistent_data = false /* Set to true in case the module should clear all persistent data. */
|
||||
};
|
||||
if (dm_init(&dm_init_param) != NRF_SUCCESS) {
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
|
||||
// update default security parameters with function call parameters
|
||||
securityParameters.bond = enableBonding;
|
||||
securityParameters.mitm = requireMITM;
|
||||
securityParameters.io_caps = iocaps;
|
||||
|
||||
const dm_application_param_t dm_param = {
|
||||
.evt_handler = dm_handler,
|
||||
.service_type = DM_PROTOCOL_CNTXT_GATT_CLI_ID,
|
||||
.sec_param = securityParameters
|
||||
};
|
||||
|
||||
if ((rc = dm_register(&applicationInstance, &dm_param)) != NRF_SUCCESS) {
|
||||
switch (rc) {
|
||||
case NRF_ERROR_INVALID_STATE:
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
case NRF_ERROR_NO_MEM:
|
||||
return BLE_ERROR_NO_MEM;
|
||||
default:
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t
|
||||
btle_purgeAllBondingState(void)
|
||||
{
|
||||
ret_code_t rc;
|
||||
if ((rc = dm_device_delete_all(&applicationInstance)) == NRF_SUCCESS) {
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
switch (rc) {
|
||||
case NRF_ERROR_INVALID_STATE:
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
case NRF_ERROR_NO_MEM:
|
||||
return BLE_ERROR_NO_MEM;
|
||||
default:
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
ble_error_t
|
||||
btle_getLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::LinkSecurityStatus_t *securityStatusP)
|
||||
{
|
||||
ret_code_t rc;
|
||||
dm_handle_t dmHandle = {
|
||||
.appl_id = applicationInstance,
|
||||
};
|
||||
if ((rc = dm_handle_get(connectionHandle, &dmHandle)) != NRF_SUCCESS) {
|
||||
if (rc == NRF_ERROR_NOT_FOUND) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
} else {
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
if ((rc = dm_security_status_req(&dmHandle, reinterpret_cast<dm_security_status_t *>(securityStatusP))) != NRF_SUCCESS) {
|
||||
switch (rc) {
|
||||
case NRF_ERROR_INVALID_STATE:
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
case NRF_ERROR_NO_MEM:
|
||||
return BLE_ERROR_NO_MEM;
|
||||
default:
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t
|
||||
btle_setLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::SecurityMode_t securityMode)
|
||||
{
|
||||
// use default and updated parameters as starting point
|
||||
// and modify structure based on security mode.
|
||||
ble_gap_sec_params_t params = securityParameters;
|
||||
|
||||
switch (securityMode) {
|
||||
case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK:
|
||||
/**< Require no protection, open link. */
|
||||
securityParameters.bond = false;
|
||||
securityParameters.mitm = false;
|
||||
break;
|
||||
|
||||
case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM:
|
||||
/**< Require encryption, but no MITM protection. */
|
||||
securityParameters.bond = true;
|
||||
securityParameters.mitm = false;
|
||||
break;
|
||||
|
||||
// not yet implemented security modes
|
||||
case SecurityManager::SECURITY_MODE_NO_ACCESS:
|
||||
case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM:
|
||||
/**< Require encryption and MITM protection. */
|
||||
case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM:
|
||||
/**< Require signing or encryption, but no MITM protection. */
|
||||
case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM:
|
||||
/**< Require signing or encryption, and MITM protection. */
|
||||
default:
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// update security settings for given connection
|
||||
uint32_t result = sd_ble_gap_authenticate(connectionHandle, ¶ms);
|
||||
|
||||
if (result == NRF_SUCCESS) {
|
||||
return BLE_ERROR_NONE;
|
||||
} else {
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
ret_code_t
|
||||
dm_handler(dm_handle_t const *p_handle, dm_event_t const *p_event, ret_code_t event_result)
|
||||
{
|
||||
nRF5xn &ble = nRF5xn::Instance(BLE::DEFAULT_INSTANCE);
|
||||
nRF5xSecurityManager &securityManager = (nRF5xSecurityManager &) ble.getSecurityManager();
|
||||
|
||||
switch (p_event->event_id) {
|
||||
case DM_EVT_SECURITY_SETUP: /* started */ {
|
||||
const ble_gap_sec_params_t *peerParams = &p_event->event_param.p_gap_param->params.sec_params_request.peer_params;
|
||||
securityManager.processSecuritySetupInitiatedEvent(p_event->event_param.p_gap_param->conn_handle,
|
||||
peerParams->bond,
|
||||
peerParams->mitm,
|
||||
(SecurityManager::SecurityIOCapabilities_t)peerParams->io_caps);
|
||||
break;
|
||||
}
|
||||
case DM_EVT_SECURITY_SETUP_COMPLETE:
|
||||
securityManager.
|
||||
processSecuritySetupCompletedEvent(p_event->event_param.p_gap_param->conn_handle,
|
||||
(SecurityManager::SecurityCompletionStatus_t)(p_event->event_param.p_gap_param->params.auth_status.auth_status));
|
||||
break;
|
||||
case DM_EVT_LINK_SECURED: {
|
||||
unsigned securityMode = p_event->event_param.p_gap_param->params.conn_sec_update.conn_sec.sec_mode.sm;
|
||||
unsigned level = p_event->event_param.p_gap_param->params.conn_sec_update.conn_sec.sec_mode.lv;
|
||||
SecurityManager::SecurityMode_t resolvedSecurityMode = SecurityManager::SECURITY_MODE_NO_ACCESS;
|
||||
switch (securityMode) {
|
||||
case 1:
|
||||
switch (level) {
|
||||
case 1:
|
||||
resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK;
|
||||
break;
|
||||
case 2:
|
||||
resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM;
|
||||
break;
|
||||
case 3:
|
||||
resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch (level) {
|
||||
case 1:
|
||||
resolvedSecurityMode = SecurityManager::SECURITY_MODE_SIGNED_NO_MITM;
|
||||
break;
|
||||
case 2:
|
||||
resolvedSecurityMode = SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
securityManager.processLinkSecuredEvent(p_event->event_param.p_gap_param->conn_handle, resolvedSecurityMode);
|
||||
break;
|
||||
}
|
||||
case DM_EVT_DEVICE_CONTEXT_STORED:
|
||||
securityManager.processSecurityContextStoredEvent(p_event->event_param.p_gap_param->conn_handle);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
ble_error_t
|
||||
btle_createWhitelistFromBondTable(ble_gap_whitelist_t *p_whitelist)
|
||||
{
|
||||
if (!btle_hasInitializedSecurity()) {
|
||||
return BLE_ERROR_INITIALIZATION_INCOMPLETE;
|
||||
}
|
||||
ret_code_t err = dm_whitelist_create(&applicationInstance, p_whitelist);
|
||||
if (err == NRF_SUCCESS) {
|
||||
return BLE_ERROR_NONE;
|
||||
} else if (err == NRF_ERROR_NULL) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
} else {
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
btle_matchAddressAndIrk(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk)
|
||||
{
|
||||
/*
|
||||
* Use a helper function from the Nordic SDK to test whether the BLE
|
||||
* address can be generated using the IRK.
|
||||
*/
|
||||
return im_address_resolve(p_addr, p_irk);
|
||||
}
|
||||
|
||||
void
|
||||
btle_generateResolvableAddress(const ble_gap_irk_t &irk, ble_gap_addr_t &address)
|
||||
{
|
||||
/* Set type to resolvable */
|
||||
address.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE;
|
||||
|
||||
/*
|
||||
* Assign a random number to the most significant 3 bytes
|
||||
* of the address.
|
||||
*/
|
||||
address.addr[BLE_GAP_ADDR_LEN - 3] = 0x8E;
|
||||
address.addr[BLE_GAP_ADDR_LEN - 2] = 0x4F;
|
||||
address.addr[BLE_GAP_ADDR_LEN - 1] = 0x7C;
|
||||
|
||||
/* Calculate the hash and store it in the top half of the address */
|
||||
ah(irk.irk, &address.addr[BLE_GAP_ADDR_LEN - 3], address.addr);
|
||||
}
|
||||
#endif
|
|
@ -1,146 +0,0 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2006-2013 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.
|
||||
*/
|
||||
|
||||
#ifndef _BTLE_SECURITY_H_
|
||||
#define _BTLE_SECURITY_H_
|
||||
|
||||
#include "ble/Gap.h"
|
||||
#include "ble/SecurityManager.h"
|
||||
|
||||
/**
|
||||
* Function to test whether the SecurityManager has been initialized.
|
||||
* Possible by a call to @ref btle_initializeSecurity().
|
||||
*
|
||||
* @return True if the SecurityManager was previously initialized, false
|
||||
* otherwise.
|
||||
*/
|
||||
bool btle_hasInitializedSecurity(void);
|
||||
|
||||
/**
|
||||
* Enable Nordic's Device Manager, which brings in functionality from the
|
||||
* stack's Security Manager. The Security Manager implements the actual
|
||||
* cryptographic algorithms and protocol exchanges that allow two devices to
|
||||
* securely exchange data and privately detect each other.
|
||||
*
|
||||
* @param[in] enableBonding Allow for bonding.
|
||||
* @param[in] requireMITM Require protection for man-in-the-middle attacks.
|
||||
* @param[in] iocaps To specify IO capabilities of this peripheral,
|
||||
* such as availability of a display or keyboard to
|
||||
* support out-of-band exchanges of security data.
|
||||
* @param[in] passkey To specify a static passkey.
|
||||
*
|
||||
* @return BLE_ERROR_NONE on success.
|
||||
*/
|
||||
ble_error_t btle_initializeSecurity(bool enableBonding = true,
|
||||
bool requireMITM = true,
|
||||
SecurityManager::SecurityIOCapabilities_t iocaps = SecurityManager::IO_CAPS_NONE,
|
||||
const SecurityManager::Passkey_t passkey = NULL);
|
||||
|
||||
/**
|
||||
* Get the security status of a link.
|
||||
*
|
||||
* @param[in] connectionHandle
|
||||
* Handle to identify the connection.
|
||||
* @param[out] securityStatusP
|
||||
* security status.
|
||||
*
|
||||
* @return BLE_ERROR_NONE Or appropriate error code indicating reason for failure.
|
||||
*/
|
||||
ble_error_t btle_getLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::LinkSecurityStatus_t *securityStatusP);
|
||||
|
||||
/**
|
||||
* Set the security mode on a connection. Useful for elevating the security mode
|
||||
* once certain conditions are met, e.g., a particular service is found.
|
||||
*
|
||||
* @param[in] connectionHandle
|
||||
* Handle to identify the connection.
|
||||
* @param[in] securityMode
|
||||
* security mode.
|
||||
*
|
||||
* @return BLE_ERROR_NONE Or appropriate error code indicating reason for failure.
|
||||
*/
|
||||
ble_error_t btle_setLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::SecurityMode_t securityMode);
|
||||
|
||||
/**
|
||||
* Function for deleting all peer device context and all related bonding
|
||||
* information from the database.
|
||||
*
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure.
|
||||
* @retval BLE_ERROR_INVALID_STATE If the API is called without module initialization and/or
|
||||
* application registration.
|
||||
*/
|
||||
ble_error_t btle_purgeAllBondingState(void);
|
||||
|
||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
||||
/**
|
||||
* Query the SoftDevice bond table to extract a whitelist containing the BLE
|
||||
* addresses and IRKs of bonded devices.
|
||||
*
|
||||
* @param[in/out] p_whitelist
|
||||
* (on input) p_whitelist->addr_count and
|
||||
* p_whitelist->irk_count specify the maximum number of
|
||||
* addresses and IRKs added to the whitelist structure.
|
||||
* (on output) *p_whitelist is a whitelist containing the
|
||||
* addresses and IRKs of the bonded devices.
|
||||
*
|
||||
* @return BLE_ERROR_NONE Or appropriate error code indicating reason for failure.
|
||||
*/
|
||||
ble_error_t btle_createWhitelistFromBondTable(ble_gap_whitelist_t *p_whitelist);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Function to test whether a BLE address is generated using an IRK.
|
||||
*
|
||||
* @param[in] p_addr
|
||||
* Pointer to a BLE address.
|
||||
* @param[in] p_irk
|
||||
* Pointer to an IRK.
|
||||
*
|
||||
* @return True if p_addr can be generated using p_irk, false otherwise.
|
||||
*/
|
||||
bool btle_matchAddressAndIrk(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk);
|
||||
|
||||
/**
|
||||
* Function to generate a private resolvable BLE address.
|
||||
*
|
||||
* @param[out] p_addr
|
||||
* The output address.
|
||||
* @param[in] p_irk
|
||||
* A reference to a IRK.
|
||||
*
|
||||
* @note This function does not generate a secure address since the prand number in the
|
||||
* resolvable address is not truly random. Therefore, the output of this function
|
||||
* is only meant to be used by the application internally but never exported.
|
||||
*/
|
||||
void btle_generateResolvableAddress(const ble_gap_irk_t &irk, ble_gap_addr_t &address);
|
||||
|
||||
#if (NRF_SD_BLE_API_VERSION >= 3)
|
||||
/**
|
||||
* @brief Returns a list of addresses from peers in the stacks bond table.
|
||||
*
|
||||
* @param[in/out] addresses
|
||||
* (on input) @ref Gap::Whitelist_t structure where at
|
||||
* most addresses.capacity addresses from bonded peers will
|
||||
* be stored.
|
||||
* (on output) A copy of the addresses from bonded peers.
|
||||
*
|
||||
* @retval BLE_ERROR_NONE if successful.
|
||||
* @retval BLE_ERROR_UNSPECIFIED Bond data could not be found in flash or is inconsistent.
|
||||
*/
|
||||
ble_error_t btle_getAddressesFromBondTable(Gap::Whitelist_t &addrList);
|
||||
#endif
|
||||
|
||||
#endif /* _BTLE_SECURITY_H_ */
|
|
@ -1,486 +0,0 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2006-2013 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.
|
||||
*/
|
||||
|
||||
#if defined(S130) || defined(S132) || defined(S140)
|
||||
#include "btle.h"
|
||||
|
||||
#include "nRF5xn.h"
|
||||
|
||||
extern "C" {
|
||||
#include "peer_manager.h"
|
||||
#include "id_manager.h"
|
||||
#include "fds.h"
|
||||
}
|
||||
|
||||
#include "btle_security.h"
|
||||
|
||||
static bool initialized = false;
|
||||
|
||||
static void pm_handler(pm_evt_t const *p_event);
|
||||
static bool _enc_in_progress = false; // helper flag for distinguish between state of link connected and link connected in progres of encryption establishing.
|
||||
volatile static uint32_t async_ret_code; // busy loop support variable for asyncronous API.
|
||||
|
||||
// default security parameters. Avoid "holes" between member assigments in order to compile by gcc++11.
|
||||
static ble_gap_sec_params_t securityParameters = {
|
||||
.bond = true, /**< Perform bonding. */
|
||||
.mitm = true, /**< Man In The Middle protection required. */
|
||||
.lesc = false, /**< Enable LE Secure Connection pairing. */
|
||||
.keypress = false, /**< Enable generation of keypress notifications. */
|
||||
.io_caps = SecurityManager::IO_CAPS_NONE, /**< IO capabilities, see @ref BLE_GAP_IO_CAPS. */
|
||||
.oob = 0, /**< Out Of Band data available. */
|
||||
.min_key_size = 16, /**< Minimum encryption key size in octets between 7 and 16. If 0 then not applicable in this instance. */
|
||||
.max_key_size = 16, /**< Maximum encryption key size in octets between min_key_size and 16. */
|
||||
.kdist_own = {
|
||||
.enc = 0, /**< Long Term Key and Master Identification. */
|
||||
.id = 0, /**< Identity Resolving Key and Identity Address Information. */
|
||||
.sign = 0, /**< Connection Signature Resolving Key. */
|
||||
.link = 0 /**< Derive the Link Key from the LTK. */
|
||||
}, /**< Key distribution bitmap: keys that the local device will distribute. */
|
||||
.kdist_peer = {
|
||||
.enc = 1, /**< Long Term Key and Master Identification. */
|
||||
.id = 1, /**< Identity Resolving Key and Identity Address Information. */
|
||||
.sign = 0, /**< Connection Signature Resolving Key. */
|
||||
.link = 0 /**< Derive the Link Key from the LTK. */
|
||||
} /**< Key distribution bitmap: keys that the peripheral device will distribute. */
|
||||
};
|
||||
|
||||
bool
|
||||
btle_hasInitializedSecurity(void)
|
||||
{
|
||||
return initialized;
|
||||
}
|
||||
|
||||
|
||||
ble_error_t
|
||||
btle_initializeSecurity(bool enableBonding,
|
||||
bool requireMITM,
|
||||
SecurityManager::SecurityIOCapabilities_t iocaps,
|
||||
const SecurityManager::Passkey_t passkey)
|
||||
{
|
||||
/* guard against multiple initializations */
|
||||
if (initialized) {
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ret_code_t rc;
|
||||
if (passkey) {
|
||||
ble_opt_t opts;
|
||||
opts.gap_opt.passkey.p_passkey = const_cast<uint8_t *>(passkey);
|
||||
if ((rc = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opts)) != NRF_SUCCESS) {
|
||||
switch (rc) {
|
||||
case BLE_ERROR_INVALID_CONN_HANDLE:
|
||||
case NRF_ERROR_INVALID_ADDR:
|
||||
case NRF_ERROR_INVALID_PARAM:
|
||||
default:
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
case NRF_ERROR_INVALID_STATE:
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
case NRF_ERROR_BUSY:
|
||||
return BLE_STACK_BUSY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update default security parameters with function call parameters
|
||||
securityParameters.bond = enableBonding;
|
||||
securityParameters.mitm = requireMITM;
|
||||
securityParameters.io_caps = iocaps;
|
||||
|
||||
if (enableBonding) {
|
||||
securityParameters.kdist_own.enc = 1;
|
||||
securityParameters.kdist_own.id = 1;
|
||||
} else {
|
||||
securityParameters.kdist_own.enc = 0;
|
||||
securityParameters.kdist_own.id = 0;
|
||||
}
|
||||
rc = pm_sec_params_set(&securityParameters);
|
||||
|
||||
if (rc == NRF_SUCCESS) {
|
||||
rc = pm_register(pm_handler);
|
||||
}
|
||||
|
||||
switch (rc) {
|
||||
case NRF_SUCCESS:
|
||||
initialized = true;
|
||||
return BLE_ERROR_NONE;
|
||||
|
||||
case NRF_ERROR_INVALID_STATE:
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
|
||||
case NRF_ERROR_INVALID_PARAM:
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
|
||||
default:
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
|
||||
|
||||
initialized = true;
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t
|
||||
btle_purgeAllBondingState(void)
|
||||
{
|
||||
ret_code_t rc;
|
||||
|
||||
async_ret_code = NRF_ERROR_BUSY;
|
||||
|
||||
rc = pm_peers_delete(); // it is asynhronous API
|
||||
|
||||
if (rc == NRF_SUCCESS)
|
||||
{
|
||||
// waiting for respond from pm_handler
|
||||
while (async_ret_code == NRF_ERROR_BUSY) {
|
||||
// busy-loop
|
||||
}
|
||||
|
||||
rc = async_ret_code;
|
||||
}
|
||||
|
||||
switch (rc) {
|
||||
case NRF_SUCCESS:
|
||||
return BLE_ERROR_NONE;
|
||||
|
||||
case NRF_ERROR_INVALID_STATE:
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
|
||||
default:
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
ble_error_t
|
||||
btle_getLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::LinkSecurityStatus_t *securityStatusP)
|
||||
{
|
||||
ret_code_t rc;
|
||||
pm_conn_sec_status_t conn_sec_status;
|
||||
|
||||
rc = pm_conn_sec_status_get(connectionHandle, &conn_sec_status);
|
||||
|
||||
if (rc == NRF_SUCCESS)
|
||||
{
|
||||
if (conn_sec_status.encrypted) {
|
||||
*securityStatusP = SecurityManager::ENCRYPTED;
|
||||
}
|
||||
else if (conn_sec_status.connected) {
|
||||
if (_enc_in_progress) {
|
||||
*securityStatusP = SecurityManager::ENCRYPTION_IN_PROGRESS;
|
||||
}
|
||||
else {
|
||||
*securityStatusP = SecurityManager::NOT_ENCRYPTED;
|
||||
}
|
||||
}
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
switch (rc) {
|
||||
case BLE_ERROR_INVALID_CONN_HANDLE:
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
|
||||
case NRF_ERROR_INVALID_STATE:
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
|
||||
default:
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
ble_error_t
|
||||
btle_setLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::SecurityMode_t securityMode)
|
||||
{
|
||||
// use default and updated parameters as starting point
|
||||
// and modify structure based on security mode.
|
||||
ret_code_t rc;
|
||||
|
||||
switch (securityMode) {
|
||||
case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK:
|
||||
/**< Require no protection, open link. */
|
||||
securityParameters.bond = false;
|
||||
securityParameters.mitm = false;
|
||||
securityParameters.kdist_own.enc = 0;
|
||||
break;
|
||||
|
||||
case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM:
|
||||
/**< Require encryption, but no MITM protection. */
|
||||
securityParameters.bond = true;
|
||||
securityParameters.mitm = false;
|
||||
securityParameters.kdist_own.enc = 1;
|
||||
break;
|
||||
|
||||
// not yet implemented security modes
|
||||
case SecurityManager::SECURITY_MODE_NO_ACCESS:
|
||||
case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM:
|
||||
/**< Require encryption and MITM protection. */
|
||||
case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM:
|
||||
/**< Require signing or encryption, but no MITM protection. */
|
||||
case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM:
|
||||
/**< Require signing or encryption, and MITM protection. */
|
||||
default:
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// update security settings for given connection
|
||||
|
||||
rc = pm_sec_params_set(&securityParameters);
|
||||
|
||||
if (rc == NRF_SUCCESS) {
|
||||
rc = pm_conn_secure(connectionHandle, false);
|
||||
}
|
||||
|
||||
switch (rc) {
|
||||
case NRF_SUCCESS:
|
||||
initialized = true;
|
||||
return BLE_ERROR_NONE;
|
||||
|
||||
case NRF_ERROR_INVALID_STATE:
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
|
||||
case NRF_ERROR_INVALID_PARAM:
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
|
||||
default:
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void pm_handler(pm_evt_t const *p_event)
|
||||
{
|
||||
nRF5xn &ble = nRF5xn::Instance(BLE::DEFAULT_INSTANCE);
|
||||
nRF5xSecurityManager &securityManager = (nRF5xSecurityManager &) ble.getSecurityManager();
|
||||
ret_code_t err_code;
|
||||
SecurityManager::SecurityMode_t resolvedSecurityMode;
|
||||
|
||||
switch (p_event->evt_id) {
|
||||
case PM_EVT_CONN_SEC_START: /* started */ {
|
||||
const ble_gap_sec_params_t *peerParams = &securityParameters;
|
||||
securityManager.processSecuritySetupInitiatedEvent(p_event->conn_handle,
|
||||
peerParams->bond,
|
||||
peerParams->mitm,
|
||||
(SecurityManager::SecurityIOCapabilities_t)peerParams->io_caps);
|
||||
_enc_in_progress = true;
|
||||
break;
|
||||
}
|
||||
case PM_EVT_CONN_SEC_SUCCEEDED:
|
||||
// Update the rank of the peer.
|
||||
if (p_event->params.conn_sec_succeeded.procedure == PM_LINK_SECURED_PROCEDURE_BONDING)
|
||||
{
|
||||
err_code = pm_peer_rank_highest(p_event->peer_id);
|
||||
}
|
||||
|
||||
securityManager.
|
||||
processSecuritySetupCompletedEvent(p_event->conn_handle,
|
||||
SecurityManager::SEC_STATUS_SUCCESS);// SEC_STATUS_SUCCESS of SecurityCompletionStatus_t
|
||||
|
||||
ble_gap_conn_sec_t conn_sec;
|
||||
sd_ble_gap_conn_sec_get(p_event->conn_handle, &conn_sec);
|
||||
|
||||
resolvedSecurityMode = SecurityManager::SECURITY_MODE_NO_ACCESS;
|
||||
|
||||
switch (conn_sec.sec_mode.sm) {
|
||||
case 1:
|
||||
switch (conn_sec.sec_mode.lv) {
|
||||
case 1:
|
||||
resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK;
|
||||
break;
|
||||
case 2:
|
||||
resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM;
|
||||
break;
|
||||
case 3:
|
||||
resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch (conn_sec.sec_mode.lv) {
|
||||
case 1:
|
||||
resolvedSecurityMode = SecurityManager::SECURITY_MODE_SIGNED_NO_MITM;
|
||||
break;
|
||||
case 2:
|
||||
resolvedSecurityMode = SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
securityManager.processLinkSecuredEvent(p_event->conn_handle, resolvedSecurityMode);
|
||||
|
||||
_enc_in_progress = false;
|
||||
break;
|
||||
|
||||
case PM_EVT_CONN_SEC_FAILED:
|
||||
SecurityManager::SecurityCompletionStatus_t securityCompletionStatus;
|
||||
|
||||
if ((uint32_t)p_event->params.conn_sec_failed.error >= PM_CONN_SEC_ERROR_BASE ) {
|
||||
securityCompletionStatus = SecurityManager::SEC_STATUS_UNSPECIFIED;
|
||||
} else {
|
||||
securityCompletionStatus =
|
||||
(SecurityManager::SecurityCompletionStatus_t)p_event->params.conn_sec_failed.error;
|
||||
}
|
||||
|
||||
securityManager.
|
||||
processSecuritySetupCompletedEvent(p_event->conn_handle, securityCompletionStatus);
|
||||
|
||||
_enc_in_progress = false;
|
||||
break;
|
||||
|
||||
case PM_EVT_BONDED_PEER_CONNECTED:
|
||||
pm_peer_rank_highest(p_event->peer_id);
|
||||
break;
|
||||
|
||||
case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
|
||||
if (p_event->params.peer_data_update_succeeded.action == PM_PEER_DATA_OP_UPDATE)
|
||||
{
|
||||
securityManager.processSecurityContextStoredEvent(p_event->conn_handle);
|
||||
}
|
||||
break;
|
||||
|
||||
case PM_EVT_PEER_DATA_UPDATE_FAILED:
|
||||
break;
|
||||
|
||||
case PM_EVT_PEERS_DELETE_SUCCEEDED:
|
||||
async_ret_code = NRF_SUCCESS; // respond SUCCESS to the busy-loop in f. btle_purgeAllBondingState
|
||||
break;
|
||||
|
||||
case PM_EVT_PEERS_DELETE_FAILED:
|
||||
async_ret_code = NRF_ERROR_INTERNAL; // respond FAILURE to the busy-loop in f. btle_purgeAllBondingState
|
||||
break;
|
||||
|
||||
case PM_EVT_STORAGE_FULL:
|
||||
// Run garbage collection on the flash.
|
||||
err_code = fds_gc();
|
||||
if (err_code == FDS_ERR_BUSY || err_code == FDS_ERR_NO_SPACE_IN_QUEUES)
|
||||
{
|
||||
// Retry.
|
||||
}
|
||||
else
|
||||
{
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
break;//PM_EVT_STORAGE_FULL
|
||||
|
||||
case PM_EVT_CONN_SEC_CONFIG_REQ:{
|
||||
// A connected peer (central) is trying to pair, but the Peer Manager already has a bond
|
||||
// for that peer. Setting allow_repairing to false rejects the pairing request.
|
||||
// If this event is ignored (pm_conn_sec_config_reply is not called in the event
|
||||
// handler), the Peer Manager assumes allow_repairing to be false.
|
||||
pm_conn_sec_config_t conn_sec_config = {.allow_repairing = true};
|
||||
pm_conn_sec_config_reply(p_event->conn_handle, &conn_sec_config);
|
||||
}
|
||||
break;//PM_EVT_CONN_SEC_CONFIG_REQ
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
||||
ble_error_t
|
||||
btle_createWhitelistFromBondTable(ble_gap_whitelist_t *p_whitelist)
|
||||
{
|
||||
if (!btle_hasInitializedSecurity()) {
|
||||
return BLE_ERROR_INITIALIZATION_INCOMPLETE;
|
||||
}
|
||||
ret_code_t err = pm_whitelist_create( NULL, BLE_GAP_WHITELIST_ADDR_MAX_COUNT, p_whitelist);
|
||||
if (err == NRF_SUCCESS) {
|
||||
return BLE_ERROR_NONE;
|
||||
} else if (err == NRF_ERROR_NULL) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
} else {
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
btle_matchAddressAndIrk(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk)
|
||||
{
|
||||
/*
|
||||
* Use a helper function from the Nordic SDK to test whether the BLE
|
||||
* address can be generated using the IRK.
|
||||
*/
|
||||
return im_address_resolve(p_addr, p_irk);
|
||||
}
|
||||
|
||||
void
|
||||
btle_generateResolvableAddress(const ble_gap_irk_t &irk, ble_gap_addr_t &address)
|
||||
{
|
||||
/* Set type to resolvable */
|
||||
address.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE;
|
||||
|
||||
/*
|
||||
* Assign a random number to the most significant 3 bytes
|
||||
* of the address.
|
||||
*/
|
||||
address.addr[BLE_GAP_ADDR_LEN - 3] = 0x8E;
|
||||
address.addr[BLE_GAP_ADDR_LEN - 2] = 0x4F;
|
||||
address.addr[BLE_GAP_ADDR_LEN - 1] = 0x7C;
|
||||
|
||||
/* Calculate the hash and store it in the top half of the address */
|
||||
ah(irk.irk, &address.addr[BLE_GAP_ADDR_LEN - 3], address.addr);
|
||||
}
|
||||
|
||||
|
||||
#if (NRF_SD_BLE_API_VERSION >= 3)
|
||||
ble_error_t btle_getAddressesFromBondTable(Gap::Whitelist_t &addrList)
|
||||
{
|
||||
pm_peer_id_t peer_id;
|
||||
ret_code_t ret;
|
||||
pm_peer_data_bonding_t bond_data;
|
||||
|
||||
addrList.size = 0;
|
||||
peer_id = pm_next_peer_id_get(PM_PEER_ID_INVALID);
|
||||
|
||||
/**
|
||||
* Fill addresses list:
|
||||
* Copy addresses from bond table, or
|
||||
* for every private resolvable address in the bond table generate the resolvable address.
|
||||
*/
|
||||
while ((peer_id != PM_PEER_ID_INVALID) && (addrList.capacity > addrList.size)) {
|
||||
memset(&bond_data, 0x00, sizeof(bond_data));
|
||||
|
||||
// Read peer data from flash.
|
||||
ret = pm_peer_data_bonding_load(peer_id, &bond_data);
|
||||
|
||||
if ((ret == NRF_ERROR_NOT_FOUND) || (ret == NRF_ERROR_INVALID_PARAM)) {
|
||||
// Peer data could not be found in flash or peer ID is not valid.
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
|
||||
if (bond_data.peer_ble_id.id_addr_info.addr_type == BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE) {
|
||||
btle_generateResolvableAddress(bond_data.peer_ble_id.id_info,
|
||||
(ble_gap_addr_t &) addrList.addresses[addrList.size].address);
|
||||
} else {
|
||||
memcpy(&addrList.addresses[addrList.size].address,
|
||||
&bond_data.peer_ble_id.id_addr_info.addr,
|
||||
sizeof(addrList.addresses[0].address));
|
||||
}
|
||||
|
||||
addrList.addresses[addrList.size].type = static_cast<BLEProtocol::AddressType_t> (bond_data.peer_ble_id.id_addr_info.addr_type);
|
||||
|
||||
addrList.size++;
|
||||
|
||||
// get next peer id
|
||||
peer_id = pm_next_peer_id_get(peer_id);
|
||||
}
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // defined(S130) || defined(S132) || defined(S140)
|
|
@ -30,6 +30,34 @@ typedef struct {
|
|||
static unsigned uuidTableEntries = 0; /* current usage of the table */
|
||||
converted_uuid_table_entry_t convertedUUIDTable[UUID_TABLE_MAX_ENTRIES];
|
||||
|
||||
namespace {
|
||||
|
||||
static void set_perm(ble_gap_conn_sec_mode_t& dest, GattAttribute::Security_t src) {
|
||||
switch (src.value()) {
|
||||
case GattAttribute::Security_t::NONE:
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&dest);
|
||||
break;
|
||||
|
||||
case GattAttribute::Security_t::UNAUTHENTICATED:
|
||||
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&dest);
|
||||
break;
|
||||
|
||||
case GattAttribute::Security_t::AUTHENTICATED:
|
||||
BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(&dest);
|
||||
break;
|
||||
|
||||
case GattAttribute::Security_t::SC_AUTHENTICATED:
|
||||
BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(&dest);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void custom_reset_128bits_uuid_table() {
|
||||
uuidTableEntries = 0;
|
||||
}
|
||||
|
@ -203,7 +231,9 @@ error_t custom_decode_uuid_base(uint8_t const *const p_uuid_base,
|
|||
error_t custom_add_in_characteristic(uint16_t service_handle,
|
||||
ble_uuid_t *p_uuid,
|
||||
uint8_t properties,
|
||||
SecurityManager::SecurityMode_t requiredSecurity,
|
||||
GattAttribute::Security_t read_security,
|
||||
GattAttribute::Security_t write_security,
|
||||
GattAttribute::Security_t update_security,
|
||||
uint8_t *p_data,
|
||||
uint16_t length,
|
||||
uint16_t max_length,
|
||||
|
@ -226,8 +256,8 @@ error_t custom_add_in_characteristic(uint16_t service_handle,
|
|||
/* Notification requires cccd */
|
||||
memclr_( &cccd_md, sizeof(ble_gatts_attr_md_t));
|
||||
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
|
||||
set_perm(cccd_md.read_perm, GattAttribute::Security_t::NONE);
|
||||
set_perm(cccd_md.write_perm, update_security);
|
||||
}
|
||||
|
||||
ble_gatts_char_md_t char_md = {0};
|
||||
|
@ -256,49 +286,8 @@ error_t custom_add_in_characteristic(uint16_t service_handle,
|
|||
/* Always set variable size */
|
||||
attr_md.vlen = has_variable_len;
|
||||
|
||||
if (char_props.read || char_props.notify || char_props.indicate) {
|
||||
switch (requiredSecurity) {
|
||||
case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK :
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
|
||||
break;
|
||||
case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM :
|
||||
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.read_perm);
|
||||
break;
|
||||
case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM :
|
||||
BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(&attr_md.read_perm);
|
||||
break;
|
||||
case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM :
|
||||
BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(&attr_md.read_perm);
|
||||
break;
|
||||
case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM :
|
||||
BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(&attr_md.read_perm);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
if (char_props.write || char_props.write_wo_resp) {
|
||||
switch (requiredSecurity) {
|
||||
case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK :
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
|
||||
break;
|
||||
case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM :
|
||||
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.write_perm);
|
||||
break;
|
||||
case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM :
|
||||
BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(&attr_md.write_perm);
|
||||
break;
|
||||
case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM :
|
||||
BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(&attr_md.write_perm);
|
||||
break;
|
||||
case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM :
|
||||
BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(&attr_md.write_perm);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
set_perm(attr_md.read_perm, read_security);
|
||||
set_perm(attr_md.write_perm, write_security);
|
||||
|
||||
ble_gatts_attr_t attr_char_value = {0};
|
||||
|
||||
|
@ -342,7 +331,9 @@ error_t custom_add_in_descriptor(uint16_t char_handle,
|
|||
uint16_t length,
|
||||
uint16_t max_length,
|
||||
bool has_variable_len,
|
||||
uint16_t *p_desc_handle)
|
||||
uint16_t *p_desc_handle,
|
||||
GattAttribute::Security_t read_security,
|
||||
GattAttribute::Security_t write_security)
|
||||
{
|
||||
/* Descriptor metadata */
|
||||
ble_gatts_attr_md_t desc_md = {0};
|
||||
|
@ -352,8 +343,8 @@ error_t custom_add_in_descriptor(uint16_t char_handle,
|
|||
desc_md.vlen = has_variable_len;
|
||||
|
||||
/* Make it readable and writable */
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_md.read_perm);
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_md.write_perm);
|
||||
set_perm(desc_md.read_perm, read_security);
|
||||
set_perm(desc_md.write_perm, write_security);
|
||||
|
||||
ble_gatts_attr_t attr_desc = {0};
|
||||
|
||||
|
|
|
@ -45,7 +45,9 @@ ble_uuid_t custom_convert_to_nordic_uuid(const UUID &uuid);
|
|||
error_t custom_add_in_characteristic(uint16_t service_handle,
|
||||
ble_uuid_t *p_uuid,
|
||||
uint8_t properties,
|
||||
SecurityManager::SecurityMode_t requiredSecurity,
|
||||
GattAttribute::Security_t read_security,
|
||||
GattAttribute::Security_t write_security,
|
||||
GattAttribute::Security_t update_security,
|
||||
uint8_t *p_data,
|
||||
uint16_t length,
|
||||
uint16_t max_length,
|
||||
|
@ -64,7 +66,9 @@ error_t custom_add_in_descriptor(uint16_t char_handle,
|
|||
uint16_t length,
|
||||
uint16_t max_length,
|
||||
bool has_variable_len,
|
||||
uint16_t *p_desc_handle);
|
||||
uint16_t *p_desc_handle,
|
||||
GattAttribute::Security_t read_security,
|
||||
GattAttribute::Security_t write_security);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018-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 <algorithm>
|
||||
|
||||
#if !defined(MBEDTLS_CONFIG_FILE)
|
||||
#include "mbedtls/config.h"
|
||||
#else
|
||||
#include MBEDTLS_CONFIG_FILE
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(MBEDTLS_ECDH_C)
|
||||
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/ecdh.h"
|
||||
#include "mbedtls/memory_buffer_alloc.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ecp.h"
|
||||
|
||||
#endif
|
||||
|
||||
#include "platform/NonCopyable.h"
|
||||
#include "platform/CriticalSectionLock.h"
|
||||
#include "ble/BLETypes.h"
|
||||
#include "cmsis.h"
|
||||
#include "nRF5xCrypto.h"
|
||||
#include "platform/mbed_assert.h"
|
||||
#include "nrf_soc.h"
|
||||
|
||||
|
||||
namespace ble {
|
||||
namespace pal {
|
||||
namespace vendor {
|
||||
namespace nordic {
|
||||
|
||||
#if defined(MBEDTLS_ECDH_C)
|
||||
|
||||
CryptoToolbox::CryptoToolbox() : _initialized(false) {
|
||||
mbedtls_entropy_init(&_entropy_context);
|
||||
mbedtls_ecp_group_init(&_group);
|
||||
int err = mbedtls_ecp_group_load(
|
||||
&_group,
|
||||
MBEDTLS_ECP_DP_SECP256R1
|
||||
);
|
||||
_initialized = err ? false : true;
|
||||
}
|
||||
|
||||
CryptoToolbox::~CryptoToolbox() {
|
||||
mbedtls_ecp_group_free(&_group);
|
||||
mbedtls_entropy_free(&_entropy_context);
|
||||
}
|
||||
|
||||
bool CryptoToolbox::generate_keys(
|
||||
ArrayView<uint8_t, lesc_key_size_> X,
|
||||
ArrayView<uint8_t, lesc_key_size_> Y,
|
||||
ArrayView<uint8_t, lesc_key_size_> secret
|
||||
) {
|
||||
mbedtls_mpi secret_key;
|
||||
mbedtls_ecp_point public_keys;
|
||||
|
||||
mbedtls_mpi_init(&secret_key);
|
||||
mbedtls_ecp_point_init(&public_keys);
|
||||
|
||||
int err = mbedtls_ecp_gen_keypair(
|
||||
&_group,
|
||||
&secret_key,
|
||||
&public_keys,
|
||||
mbedtls_entropy_func,
|
||||
&_entropy_context
|
||||
);
|
||||
|
||||
if (!err) {
|
||||
store_mpi(secret, secret_key);
|
||||
store_mpi(X, public_keys.X);
|
||||
store_mpi(Y, public_keys.Y);
|
||||
}
|
||||
|
||||
mbedtls_ecp_point_free(&public_keys);
|
||||
mbedtls_mpi_free(&secret_key);
|
||||
|
||||
return err ? false : true;
|
||||
}
|
||||
|
||||
bool CryptoToolbox::generate_shared_secret(
|
||||
const ArrayView<const uint8_t, lesc_key_size_>& peer_X,
|
||||
const ArrayView<const uint8_t, lesc_key_size_>& peer_Y,
|
||||
const ArrayView<const uint8_t, lesc_key_size_>& own_secret,
|
||||
ArrayView<uint8_t, lesc_key_size_> shared_secret
|
||||
) {
|
||||
mbedtls_mpi result;
|
||||
mbedtls_mpi secret_key;
|
||||
mbedtls_ecp_point public_keys;
|
||||
|
||||
mbedtls_mpi_init(&result);
|
||||
mbedtls_mpi_init(&secret_key);
|
||||
mbedtls_ecp_point_init(&public_keys);
|
||||
|
||||
load_mpi(secret_key, own_secret);
|
||||
load_mpi(public_keys.X, peer_X);
|
||||
load_mpi(public_keys.Y, peer_Y);
|
||||
mbedtls_mpi_lset( &public_keys.Z, 1 );
|
||||
|
||||
int err = mbedtls_ecdh_compute_shared(
|
||||
&_group,
|
||||
&result,
|
||||
&public_keys,
|
||||
&secret_key,
|
||||
/* rng function; optional */ NULL,
|
||||
/* rng param */ NULL
|
||||
);
|
||||
|
||||
if (!err) {
|
||||
store_mpi(shared_secret, result);
|
||||
}
|
||||
|
||||
mbedtls_ecp_point_free(&public_keys);
|
||||
mbedtls_mpi_free(&secret_key);
|
||||
mbedtls_mpi_free(&result);
|
||||
|
||||
return err ? false : true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool CryptoToolbox::ah(
|
||||
const ArrayView<const uint8_t, irk_size_>& irk,
|
||||
const ArrayView<const uint8_t, prand_size_>& prand,
|
||||
ArrayView<uint8_t, hash_size_> hash
|
||||
) {
|
||||
// Note copy then swap operation can be optimized.
|
||||
|
||||
// Note: the encryption block works in big endian; go figure.
|
||||
nrf_ecb_hal_data_t ecb_hal_data;
|
||||
|
||||
memcpy(ecb_hal_data.key, irk.data(), irk.size());
|
||||
swap_endian(ecb_hal_data.key, sizeof(ecb_hal_data.key));
|
||||
|
||||
memcpy(ecb_hal_data.cleartext, prand.data(), prand.size());
|
||||
memset(ecb_hal_data.cleartext + prand.size(), 0, sizeof(ecb_hal_data.cleartext) - prand.size());
|
||||
swap_endian(ecb_hal_data.cleartext, sizeof(ecb_hal_data.cleartext));
|
||||
|
||||
uint32_t err = sd_ecb_block_encrypt(&ecb_hal_data);
|
||||
|
||||
if (err) {
|
||||
return false;
|
||||
}
|
||||
|
||||
swap_endian(ecb_hal_data.ciphertext, sizeof(ecb_hal_data.ciphertext));
|
||||
|
||||
memcpy(hash.data(), ecb_hal_data.ciphertext, hash.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_ECDH_C)
|
||||
|
||||
void CryptoToolbox::load_mpi(mbedtls_mpi& dest, const ArrayView<const uint8_t, lesc_key_size_>& src) {
|
||||
ble::public_key_coord_t src_be = src.data();
|
||||
swap_endian(src_be.data(), src_be.size());
|
||||
mbedtls_mpi_read_binary(&dest, src_be.data(), src_be.size());
|
||||
}
|
||||
|
||||
void CryptoToolbox::store_mpi(ArrayView<uint8_t, lesc_key_size_>& dest, const mbedtls_mpi& src) {
|
||||
mbedtls_mpi_write_binary(&src, dest.data(), dest.size());
|
||||
swap_endian(dest.data(), dest.size());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void CryptoToolbox::swap_endian(uint8_t* buf, size_t len) {
|
||||
for(size_t low = 0, high = (len - 1); high > low; --high, ++low) {
|
||||
std::swap(buf[low], buf[high]);
|
||||
}
|
||||
}
|
||||
|
||||
} // nordic
|
||||
} // vendor
|
||||
} // pal
|
||||
} // ble
|
|
@ -0,0 +1,156 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018-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.
|
||||
*/
|
||||
|
||||
#ifndef NRF5X_CRYPTO_
|
||||
#define NRF5X_CRYPTO_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if !defined(MBEDTLS_CONFIG_FILE)
|
||||
#include "mbedtls/config.h"
|
||||
#else
|
||||
#include MBEDTLS_CONFIG_FILE
|
||||
#endif
|
||||
|
||||
#if defined(MBEDTLS_ECDH_C)
|
||||
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ecp.h"
|
||||
|
||||
#endif
|
||||
|
||||
#include "platform/NonCopyable.h"
|
||||
#include "ble/BLETypes.h"
|
||||
|
||||
namespace ble {
|
||||
namespace pal {
|
||||
namespace vendor {
|
||||
namespace nordic {
|
||||
|
||||
/**
|
||||
* Toolbox of cryptographic functions used in BLE.
|
||||
*/
|
||||
class CryptoToolbox : mbed::NonCopyable<CryptoToolbox> {
|
||||
|
||||
public:
|
||||
/**
|
||||
* Size of the Key used in lesc crypto operations.
|
||||
*/
|
||||
static const ptrdiff_t lesc_key_size_ = public_key_coord_t::size_;
|
||||
|
||||
/**
|
||||
* Size of an IRK.
|
||||
*/
|
||||
static const ptrdiff_t irk_size_ = irk_t::size_;
|
||||
|
||||
/**
|
||||
* Size of the hash generated by ah.
|
||||
*/
|
||||
static const ptrdiff_t hash_size_ = 3;
|
||||
|
||||
/**
|
||||
* Size of prand.
|
||||
*/
|
||||
static const ptrdiff_t prand_size_ = 3;
|
||||
|
||||
#if defined(MBEDTLS_ECDH_C)
|
||||
|
||||
/**
|
||||
* Create a new CryptoToolbox.
|
||||
*/
|
||||
CryptoToolbox();
|
||||
|
||||
/**
|
||||
* Destroy a CryptoTioolbox object.
|
||||
*/
|
||||
~CryptoToolbox();
|
||||
|
||||
/**
|
||||
* Generate lesc public and private keys.
|
||||
* @param[out] X The component X of the public key.
|
||||
* @param[out] Y The component Y of the public key.
|
||||
* @param[out] secret The secret key.
|
||||
* @return true if the shared secret has been successfully generated and
|
||||
* false otherwise.
|
||||
*/
|
||||
bool generate_keys(
|
||||
ArrayView<uint8_t, lesc_key_size_> X,
|
||||
ArrayView<uint8_t, lesc_key_size_> Y,
|
||||
ArrayView<uint8_t, lesc_key_size_> secret
|
||||
);
|
||||
|
||||
/**
|
||||
* Generate a shared secret from a peer public key and a local secret key.
|
||||
* @param[in] peer_X The component X of the peer public key.
|
||||
* @param[in] peer_Y The component Y of the peer public key.
|
||||
* @param[in] own_secret The local secret key.
|
||||
* @param[out] shared_secret The shared secret generated.
|
||||
* @return true if the shared secret has been successfully generated and
|
||||
* false otherwise.
|
||||
*/
|
||||
bool generate_shared_secret(
|
||||
const ArrayView<const uint8_t, lesc_key_size_>& peer_X,
|
||||
const ArrayView<const uint8_t, lesc_key_size_>& peer_Y,
|
||||
const ArrayView<const uint8_t, lesc_key_size_>& own_secret,
|
||||
ArrayView<uint8_t, lesc_key_size_> shared_secret
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Execute the function ah. This function can be used to generate private
|
||||
* resolvable addresses and resolve them.
|
||||
*
|
||||
* @note all parameters passed and return by this fucntion are in little
|
||||
* endian.
|
||||
*
|
||||
* @param[in] irk The key used to create hash.
|
||||
* @param[in] prand The random part from which the hash will be generated.
|
||||
* @param[out] hash The hash generated.
|
||||
*
|
||||
* @return true in case of success and false otherwise.
|
||||
*/
|
||||
static bool ah(
|
||||
const ArrayView<const uint8_t, irk_size_>& irk,
|
||||
const ArrayView<const uint8_t, prand_size_>& prand,
|
||||
ArrayView<uint8_t, hash_size_> hash
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
#if defined(MBEDTLS_ECDH_C)
|
||||
void load_mpi(mbedtls_mpi& dest, const ArrayView<const uint8_t, lesc_key_size_>& src);
|
||||
|
||||
void store_mpi(ArrayView<uint8_t, lesc_key_size_>& dest, const mbedtls_mpi& src);
|
||||
#endif
|
||||
|
||||
static void swap_endian(uint8_t* buf, size_t len);
|
||||
|
||||
#if defined(MBEDTLS_ECDH_C)
|
||||
bool _initialized;
|
||||
mbedtls_entropy_context _entropy_context;
|
||||
mbedtls_ecp_group _group;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
} // nordic
|
||||
} // vendor
|
||||
} // pal
|
||||
} // ble
|
||||
|
||||
#endif // NRF5X_CRYPTO_
|
File diff suppressed because it is too large
Load Diff
|
@ -44,6 +44,7 @@
|
|||
#include "ble/GapAdvertisingData.h"
|
||||
#include "ble/Gap.h"
|
||||
#include "ble/GapScanningParams.h"
|
||||
#include "ble/pal/ConnectionEventMonitor.h"
|
||||
|
||||
#include "nrf_soc.h"
|
||||
|
||||
|
@ -52,8 +53,6 @@ extern "C" {
|
|||
#include "app_util_platform.h"
|
||||
}
|
||||
|
||||
#include "btle_security.h"
|
||||
|
||||
void radioNotificationStaticCallback(bool param);
|
||||
|
||||
/**************************************************************************/
|
||||
|
@ -62,9 +61,12 @@ void radioNotificationStaticCallback(bool param);
|
|||
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class nRF5xGap : public Gap
|
||||
{
|
||||
class nRF5xGap : public ::Gap, public ble::pal::ConnectionEventMonitor {
|
||||
public:
|
||||
nRF5xGap();
|
||||
|
||||
virtual ~nRF5xGap() { }
|
||||
|
||||
/* Functions that must be implemented from Gap */
|
||||
virtual ble_error_t setAddress(AddressType_t type, const Address_t address);
|
||||
virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address);
|
||||
|
@ -76,7 +78,9 @@ public:
|
|||
|
||||
virtual ble_error_t startAdvertising(const GapAdvertisingParams &);
|
||||
virtual ble_error_t stopAdvertising(void);
|
||||
virtual ble_error_t connect(const Address_t, ble::peer_address_type_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams);
|
||||
virtual ble_error_t connect(const Address_t, BLEProtocol::AddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams);
|
||||
ble_error_t connect(const Address_t, BLEProtocol::AddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams, bool identity);
|
||||
virtual ble_error_t disconnect(Handle_t connectionHandle, DisconnectionReason_t reason);
|
||||
virtual ble_error_t disconnect(DisconnectionReason_t reason);
|
||||
|
||||
|
@ -120,6 +124,24 @@ public:
|
|||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
|
||||
virtual ble_error_t enablePrivacy(bool enable);
|
||||
|
||||
virtual ble_error_t setPeripheralPrivacyConfiguration(
|
||||
const PeripheralPrivacyConfiguration_t *configuration
|
||||
);
|
||||
|
||||
virtual ble_error_t getPeripheralPrivacyConfiguration(
|
||||
PeripheralPrivacyConfiguration_t *configuration
|
||||
);
|
||||
|
||||
virtual ble_error_t setCentralPrivacyConfiguration(
|
||||
const CentralPrivacyConfiguration_t *configuration
|
||||
);
|
||||
|
||||
virtual ble_error_t getCentralPrivacyConfiguration(
|
||||
CentralPrivacyConfiguration_t *configuration
|
||||
);
|
||||
|
||||
/* Observer role is not supported by S110, return BLE_ERROR_NOT_IMPLEMENTED */
|
||||
#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
|
||||
virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams);
|
||||
|
@ -139,39 +161,6 @@ private:
|
|||
uint8_t whitelistAddressesSize;
|
||||
ble_gap_addr_t whitelistAddresses[YOTTA_CFG_WHITELIST_MAX_SIZE];
|
||||
|
||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
||||
/*
|
||||
* An internal function used to populate the ble_gap_whitelist_t that will be used by
|
||||
* the SoftDevice for filtering requests. This function is needed because for the BLE
|
||||
* API the whitelist is just a collection of keys, but for the stack it also includes
|
||||
* the IRK table.
|
||||
*/
|
||||
ble_error_t generateStackWhitelist(ble_gap_whitelist_t &whitelist);
|
||||
#endif
|
||||
|
||||
#if (NRF_SD_BLE_API_VERSION >= 3)
|
||||
/* internal type for passing a whitelist and a identities list. */
|
||||
typedef struct
|
||||
{
|
||||
ble_gap_addr_t addrs[YOTTA_CFG_WHITELIST_MAX_SIZE];
|
||||
uint32_t addrs_cnt;
|
||||
|
||||
ble_gap_id_key_t identities[YOTTA_CFG_IRK_TABLE_MAX_SIZE];
|
||||
uint32_t identities_cnt;
|
||||
} GapWhiteAndIdentityList_t;
|
||||
|
||||
/* Function for preparing setting of the whitelist feature and the identity-resolving feature (privacy).*/
|
||||
ble_error_t getStackWhiteIdentityList(GapWhiteAndIdentityList_t &whiteAndIdentityList);
|
||||
|
||||
/* Function for applying setting of the whitelist feature and identity-resolving feature (privacy).*/
|
||||
ble_error_t applyWhiteIdentityList(GapWhiteAndIdentityList_t &whiteAndIdentityList);
|
||||
|
||||
/* Function for introducing whitelist feature and the identity-resolving feature setting into SoftDevice.
|
||||
*
|
||||
* This function incorporates getStackWhiteIdentityList and applyWhiteIdentityList together. */
|
||||
ble_error_t updateWhiteAndIdentityListInStack(void);
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool radioNotificationCallbackParam; /* parameter to be passed into the Timeout-generated radio notification callback. */
|
||||
Timeout radioNotificationTimeout;
|
||||
|
@ -254,21 +243,43 @@ private:
|
|||
}
|
||||
friend void radioNotificationStaticCallback(bool param); /* allow invocations of processRadioNotificationEvent() */
|
||||
|
||||
public:
|
||||
/** @note Implements ConnectionEventMonitor.
|
||||
* @copydoc ConnectionEventMonitor::set_connection_event_handler
|
||||
*/
|
||||
virtual void set_connection_event_handler(
|
||||
ConnectionEventMonitor::EventHandler* connection_event_handler
|
||||
);
|
||||
|
||||
/**
|
||||
* @copydoc ::Gap::processDisconnectionEvent
|
||||
*/
|
||||
void processDisconnectionEvent(
|
||||
Handle_t handle,
|
||||
DisconnectionReason_t reason
|
||||
);
|
||||
|
||||
private:
|
||||
friend void btle_handler(ble_evt_t *p_ble_evt);
|
||||
|
||||
void on_connection(Handle_t handle, const ble_gap_evt_connected_t& evt);
|
||||
void on_advertising_packet(const ble_gap_evt_adv_report_t &evt);
|
||||
|
||||
uint16_t m_connectionHandle;
|
||||
|
||||
ConnectionEventMonitor::EventHandler* _connection_event_handler;
|
||||
|
||||
bool _privacy_enabled;
|
||||
PeripheralPrivacyConfiguration_t _peripheral_privacy_configuration;
|
||||
CentralPrivacyConfiguration_t _central_privacy_configuration;
|
||||
AddressType_t _non_private_address_type;
|
||||
Address_t _non_private_address;
|
||||
|
||||
/*
|
||||
* Allow instantiation from nRF5xn when required.
|
||||
*/
|
||||
friend class nRF5xn;
|
||||
|
||||
nRF5xGap() :
|
||||
advertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST),
|
||||
scanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST),
|
||||
whitelistAddressesSize(0) {
|
||||
m_connectionHandle = BLE_CONN_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
nRF5xGap(nRF5xGap const &);
|
||||
void operator=(nRF5xGap const &);
|
||||
};
|
||||
|
|
|
@ -25,42 +25,43 @@
|
|||
#include "btle/custom/custom_helper.h"
|
||||
|
||||
#include "nRF5xn.h"
|
||||
#include "nrf_ble_gap.h"
|
||||
|
||||
namespace {
|
||||
|
||||
static const ble_gatts_rw_authorize_reply_params_t write_auth_queue_full_reply = {
|
||||
.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE,
|
||||
.params = {
|
||||
.write = {
|
||||
.gatt_status = BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL
|
||||
/* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
|
||||
/* .params = */ {
|
||||
/* .write = */ {
|
||||
/* .gatt_status = */ BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static const ble_gatts_rw_authorize_reply_params_t write_auth_invalid_offset_reply = {
|
||||
.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE,
|
||||
.params = {
|
||||
.write = {
|
||||
.gatt_status = BLE_GATT_STATUS_ATTERR_INVALID_OFFSET
|
||||
/* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
|
||||
/* .params = */ {
|
||||
/* .write = */ {
|
||||
/* .gatt_status = */ BLE_GATT_STATUS_ATTERR_INVALID_OFFSET
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static const ble_gatts_rw_authorize_reply_params_t write_auth_succes_reply = {
|
||||
.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE,
|
||||
.params = {
|
||||
.write = {
|
||||
.gatt_status = BLE_GATT_STATUS_SUCCESS,
|
||||
.update = 0
|
||||
/* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
|
||||
/* .params = */ {
|
||||
/* .write = */ {
|
||||
/* .gatt_status = */ BLE_GATT_STATUS_SUCCESS,
|
||||
/* .update = */ 0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static const ble_gatts_rw_authorize_reply_params_t write_auth_invalid_reply = {
|
||||
.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE,
|
||||
.params = {
|
||||
.write = {
|
||||
.gatt_status = BLE_GATT_STATUS_ATTERR_INVALID
|
||||
/* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
|
||||
/* .params = */ {
|
||||
/* .write = */ {
|
||||
/* .gatt_status = */ BLE_GATT_STATUS_ATTERR_INVALID
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -164,21 +165,25 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
|
|||
}
|
||||
|
||||
ASSERT_TRUE ( ERROR_NONE ==
|
||||
custom_add_in_characteristic(BLE_GATT_HANDLE_INVALID,
|
||||
&nordicUUID,
|
||||
p_char->getProperties(),
|
||||
p_char->getRequiredSecurity(),
|
||||
p_char->getValueAttribute().getValuePtr(),
|
||||
p_char->getValueAttribute().getLength(),
|
||||
p_char->getValueAttribute().getMaxLength(),
|
||||
p_char->getValueAttribute().hasVariableLength(),
|
||||
userDescriptionDescriptorValuePtr,
|
||||
userDescriptionDescriptorValueLen,
|
||||
presentationFormatDescriptorValuePtr,
|
||||
presentationFormatDescriptorValueLen,
|
||||
p_char->isReadAuthorizationEnabled(),
|
||||
p_char->isWriteAuthorizationEnabled(),
|
||||
&nrfCharacteristicHandles[characteristicCount]),
|
||||
custom_add_in_characteristic(
|
||||
BLE_GATT_HANDLE_INVALID,
|
||||
&nordicUUID,
|
||||
p_char->getProperties(),
|
||||
p_char->getReadSecurityRequirement(),
|
||||
p_char->getWriteSecurityRequirement(),
|
||||
p_char->getUpdateSecurityRequirement(),
|
||||
p_char->getValueAttribute().getValuePtr(),
|
||||
p_char->getValueAttribute().getLength(),
|
||||
p_char->getValueAttribute().getMaxLength(),
|
||||
p_char->getValueAttribute().hasVariableLength(),
|
||||
userDescriptionDescriptorValuePtr,
|
||||
userDescriptionDescriptorValueLen,
|
||||
presentationFormatDescriptorValuePtr,
|
||||
presentationFormatDescriptorValueLen,
|
||||
p_char->isReadAuthorizationEnabled(),
|
||||
p_char->isWriteAuthorizationEnabled(),
|
||||
&nrfCharacteristicHandles[characteristicCount]
|
||||
),
|
||||
BLE_ERROR_PARAM_OUT_OF_RANGE );
|
||||
|
||||
/* Update the characteristic handle */
|
||||
|
@ -218,7 +223,9 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
|
|||
p_desc->getLength(),
|
||||
p_desc->getMaxLength(),
|
||||
p_desc->hasVariableLength(),
|
||||
&nrfDescriptorHandles[descriptorCount]),
|
||||
&nrfDescriptorHandles[descriptorCount],
|
||||
p_desc->getReadSecurityRequirement(),
|
||||
p_desc->getWriteSecurityRequirement()),
|
||||
BLE_ERROR_PARAM_OUT_OF_RANGE);
|
||||
|
||||
p_descriptors[descriptorCount] = p_desc;
|
||||
|
@ -260,9 +267,9 @@ ble_error_t nRF5xGattServer::read(GattAttribute::Handle_t attributeHandle, uint8
|
|||
ble_error_t nRF5xGattServer::read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP)
|
||||
{
|
||||
ble_gatts_value_t value = {
|
||||
.len = *lengthP,
|
||||
.offset = 0,
|
||||
.p_value = buffer,
|
||||
/* .len = */ *lengthP,
|
||||
/* .offset = */ 0,
|
||||
/* .p_value = */ buffer,
|
||||
};
|
||||
|
||||
ASSERT_TRUE( ERROR_NONE ==
|
||||
|
@ -302,9 +309,9 @@ ble_error_t nRF5xGattServer::write(Gap::Handle_t connectionHandle, GattAttribute
|
|||
ble_error_t returnValue = BLE_ERROR_NONE;
|
||||
|
||||
ble_gatts_value_t value = {
|
||||
.len = len,
|
||||
.offset = 0,
|
||||
.p_value = const_cast<uint8_t *>(buffer),
|
||||
/* .len = */ len,
|
||||
/* .offset = */ 0,
|
||||
/* .p_value = */ const_cast<uint8_t *>(buffer),
|
||||
};
|
||||
|
||||
if (localOnly) {
|
||||
|
@ -345,7 +352,16 @@ ble_error_t nRF5xGattServer::write(Gap::Handle_t connectionHandle, GattAttribute
|
|||
}
|
||||
}
|
||||
|
||||
if (updatesEnabled) {
|
||||
bool updates_permitted = false;
|
||||
ble_gap_conn_sec_t connection_security;
|
||||
uint32_t err = sd_ble_gap_conn_sec_get(connectionHandle, &connection_security);
|
||||
if (!err &&
|
||||
(connection_security.sec_mode.sm == 1) &&
|
||||
(connection_security.sec_mode.lv >= p_characteristics[characteristicIndex]->getUpdateSecurityRequirement().value())) {
|
||||
updates_permitted = true;
|
||||
}
|
||||
|
||||
if (updatesEnabled && updates_permitted) {
|
||||
error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params);
|
||||
if (error != ERROR_NONE) {
|
||||
switch (error) {
|
||||
|
@ -453,7 +469,7 @@ ble_error_t nRF5xGattServer::reset(void)
|
|||
@brief Callback handler for events getting pushed up from the SD
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void nRF5xGattServer::hwCallback(ble_evt_t *p_ble_evt)
|
||||
void nRF5xGattServer::hwCallback(const ble_evt_t *p_ble_evt)
|
||||
{
|
||||
GattAttribute::Handle_t handle_value;
|
||||
GattServerEvents::gattEvent_t eventType;
|
||||
|
@ -611,14 +627,14 @@ void nRF5xGattServer::hwCallback(ble_evt_t *p_ble_evt)
|
|||
|
||||
// success, signal it to the softdevice
|
||||
ble_gatts_rw_authorize_reply_params_t reply = {
|
||||
.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE,
|
||||
.params = {
|
||||
.write = {
|
||||
.gatt_status = BLE_GATT_STATUS_SUCCESS,
|
||||
.update = 1,
|
||||
.offset = input_req.offset,
|
||||
.len = input_req.len,
|
||||
.p_data = input_req.data
|
||||
/* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
|
||||
/* .params = */ {
|
||||
/* .write = */ {
|
||||
/* .gatt_status = */ BLE_GATT_STATUS_SUCCESS,
|
||||
/* .update = */ 1,
|
||||
/* .offset = */ input_req.offset,
|
||||
/* .len = */ input_req.len,
|
||||
/* .p_data = */ input_req.data
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -639,12 +655,12 @@ void nRF5xGattServer::hwCallback(ble_evt_t *p_ble_evt)
|
|||
}
|
||||
|
||||
GattWriteAuthCallbackParams cbParams = {
|
||||
.connHandle = conn_handle,
|
||||
.handle = req->attr_handle,
|
||||
.offset = req->offset,
|
||||
.len = req->length,
|
||||
.data = req->data,
|
||||
.authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
|
||||
/* .connHandle = */ conn_handle,
|
||||
/* .handle = */ req->attr_handle,
|
||||
/* .offset = */ req->offset,
|
||||
/* .len = */ req->length,
|
||||
/* .data = */ req->data,
|
||||
/* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
|
||||
* set to AUTH_CALLBACK_REPLY_SUCCESS if the client
|
||||
* request is to proceed. */
|
||||
};
|
||||
|
@ -661,9 +677,9 @@ void nRF5xGattServer::hwCallback(ble_evt_t *p_ble_evt)
|
|||
|
||||
// FIXME can't use ::write here, this function doesn't take the offset into account ...
|
||||
ble_gatts_value_t value = {
|
||||
.len = req->length,
|
||||
.offset = req->offset,
|
||||
.p_value = req->data
|
||||
/* .len = */ req->length,
|
||||
/* .offset = */ req->offset,
|
||||
/* .p_value = */ req->data
|
||||
};
|
||||
uint32_t update_err = sd_ble_gatts_value_set(conn_handle, req->attr_handle, &value);
|
||||
if (update_err) {
|
||||
|
@ -688,25 +704,25 @@ void nRF5xGattServer::hwCallback(ble_evt_t *p_ble_evt)
|
|||
}
|
||||
|
||||
GattWriteAuthCallbackParams cbParams = {
|
||||
.connHandle = gattsEventP->conn_handle,
|
||||
.handle = handle_value,
|
||||
.offset = gattsEventP->params.authorize_request.request.write.offset,
|
||||
.len = gattsEventP->params.authorize_request.request.write.len,
|
||||
.data = gattsEventP->params.authorize_request.request.write.data,
|
||||
.authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
|
||||
/* .connHandle = */ gattsEventP->conn_handle,
|
||||
/* .handle = */ handle_value,
|
||||
/* .offset = */ gattsEventP->params.authorize_request.request.write.offset,
|
||||
/* .len = */ gattsEventP->params.authorize_request.request.write.len,
|
||||
/* .data = */ gattsEventP->params.authorize_request.request.write.data,
|
||||
/* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
|
||||
* set to AUTH_CALLBACK_REPLY_SUCCESS if the client
|
||||
* request is to proceed. */
|
||||
};
|
||||
|
||||
ble_gatts_rw_authorize_reply_params_t reply = {
|
||||
.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE,
|
||||
.params = {
|
||||
.write = {
|
||||
.gatt_status = p_characteristics[characteristicIndex]->authorizeWrite(&cbParams),
|
||||
.update = 1,
|
||||
.offset = cbParams.offset,
|
||||
.len = cbParams.len,
|
||||
.p_data = cbParams.data
|
||||
/* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
|
||||
/* .params = */ {
|
||||
/* .write = */ {
|
||||
/* .gatt_status = */ p_characteristics[characteristicIndex]->authorizeWrite(&cbParams),
|
||||
/* .update = */ 1,
|
||||
/* .offset = */ cbParams.offset,
|
||||
/* .len = */ cbParams.len,
|
||||
/* .p_data = */ cbParams.data
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -740,21 +756,21 @@ void nRF5xGattServer::hwCallback(ble_evt_t *p_ble_evt)
|
|||
}
|
||||
case GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ: {
|
||||
GattReadAuthCallbackParams cbParams = {
|
||||
.connHandle = gattsEventP->conn_handle,
|
||||
.handle = handle_value,
|
||||
.offset = gattsEventP->params.authorize_request.request.read.offset,
|
||||
.len = 0,
|
||||
.data = NULL,
|
||||
.authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
|
||||
/* .connHandle = */ gattsEventP->conn_handle,
|
||||
/* .handle = */ handle_value,
|
||||
/* .offset = */ gattsEventP->params.authorize_request.request.read.offset,
|
||||
/* .len = */ 0,
|
||||
/* .data = */ NULL,
|
||||
/* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
|
||||
* set to AUTH_CALLBACK_REPLY_SUCCESS if the client
|
||||
* request is to proceed. */
|
||||
};
|
||||
|
||||
ble_gatts_rw_authorize_reply_params_t reply = {
|
||||
.type = BLE_GATTS_AUTHORIZE_TYPE_READ,
|
||||
.params = {
|
||||
.read = {
|
||||
.gatt_status = p_characteristics[characteristicIndex]->authorizeRead(&cbParams)
|
||||
/* .type = */ BLE_GATTS_AUTHORIZE_TYPE_READ,
|
||||
/* .params = */ {
|
||||
/* .read = */ {
|
||||
/* .gatt_status = */ p_characteristics[characteristicIndex]->authorizeRead(&cbParams)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
|
||||
/* nRF51 Functions */
|
||||
void eventCallback(void);
|
||||
void hwCallback(ble_evt_t *p_ble_evt);
|
||||
void hwCallback(const ble_evt_t *p_ble_evt);
|
||||
|
||||
|
||||
private:
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
#include <new>
|
||||
|
||||
#include "nRF5XPalGattClient.h"
|
||||
#include "nRF5xPalGattClient.h"
|
||||
|
||||
#include "ble/pal/PalGattClient.h"
|
||||
#include "ble/pal/SimpleAttServerMessage.h"
|
||||
|
@ -159,30 +159,30 @@ static const size_t characteristic_declaration_length = 1 + 2 + 16;
|
|||
|
||||
} // end of anonymous namespace
|
||||
|
||||
nRF5XGattClient::nRF5XGattClient() :
|
||||
nRF5xGattClient::nRF5xGattClient() :
|
||||
ble::pal::GattClient(),
|
||||
_procedures()
|
||||
{
|
||||
}
|
||||
|
||||
nRF5XGattClient::~nRF5XGattClient()
|
||||
nRF5xGattClient::~nRF5xGattClient()
|
||||
{
|
||||
terminate();
|
||||
}
|
||||
|
||||
ble_error_t nRF5XGattClient::initialize()
|
||||
ble_error_t nRF5xGattClient::initialize()
|
||||
{
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t nRF5XGattClient::exchange_mtu(connection_handle_t connection)
|
||||
ble_error_t nRF5xGattClient::exchange_mtu(connection_handle_t connection)
|
||||
{
|
||||
// FIXME: implement when SD 140 5.x.x is present
|
||||
// (see sd_ble_gatts_exchange_mtu_reply)
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
ble_error_t nRF5XGattClient::get_mtu_size(
|
||||
ble_error_t nRF5xGattClient::get_mtu_size(
|
||||
connection_handle_t connection_handle, uint16_t& mtu_size
|
||||
) {
|
||||
#if (NRF_SD_BLE_API_VERSION >= 3)
|
||||
|
@ -195,7 +195,7 @@ ble_error_t nRF5XGattClient::get_mtu_size(
|
|||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t nRF5XGattClient::discover_primary_service(
|
||||
ble_error_t nRF5xGattClient::discover_primary_service(
|
||||
connection_handle_t connection,
|
||||
attribute_handle_t discovery_range_begining
|
||||
) {
|
||||
|
@ -204,7 +204,7 @@ ble_error_t nRF5XGattClient::discover_primary_service(
|
|||
);
|
||||
}
|
||||
|
||||
ble_error_t nRF5XGattClient::discover_primary_service_by_service_uuid(
|
||||
ble_error_t nRF5xGattClient::discover_primary_service_by_service_uuid(
|
||||
connection_handle_t connection_handle,
|
||||
attribute_handle_t discovery_range_beginning,
|
||||
const UUID& uuid
|
||||
|
@ -214,7 +214,7 @@ ble_error_t nRF5XGattClient::discover_primary_service_by_service_uuid(
|
|||
);
|
||||
}
|
||||
|
||||
ble_error_t nRF5XGattClient::find_included_service(
|
||||
ble_error_t nRF5xGattClient::find_included_service(
|
||||
connection_handle_t connection_handle,
|
||||
attribute_handle_range_t service_range
|
||||
) {
|
||||
|
@ -223,7 +223,7 @@ ble_error_t nRF5XGattClient::find_included_service(
|
|||
);
|
||||
}
|
||||
|
||||
ble_error_t nRF5XGattClient::discover_characteristics_of_a_service(
|
||||
ble_error_t nRF5xGattClient::discover_characteristics_of_a_service(
|
||||
connection_handle_t connection_handle,
|
||||
attribute_handle_range_t discovery_range
|
||||
) {
|
||||
|
@ -232,7 +232,7 @@ ble_error_t nRF5XGattClient::discover_characteristics_of_a_service(
|
|||
);
|
||||
}
|
||||
|
||||
ble_error_t nRF5XGattClient::discover_characteristics_descriptors(
|
||||
ble_error_t nRF5xGattClient::discover_characteristics_descriptors(
|
||||
connection_handle_t connection_handle,
|
||||
attribute_handle_range_t descriptors_discovery_range
|
||||
) {
|
||||
|
@ -241,7 +241,7 @@ ble_error_t nRF5XGattClient::discover_characteristics_descriptors(
|
|||
);
|
||||
}
|
||||
|
||||
ble_error_t nRF5XGattClient::read_attribute_value(
|
||||
ble_error_t nRF5xGattClient::read_attribute_value(
|
||||
connection_handle_t connection_handle,
|
||||
attribute_handle_t attribute_handle
|
||||
) {
|
||||
|
@ -250,7 +250,7 @@ ble_error_t nRF5XGattClient::read_attribute_value(
|
|||
);
|
||||
}
|
||||
|
||||
ble_error_t nRF5XGattClient::read_using_characteristic_uuid(
|
||||
ble_error_t nRF5xGattClient::read_using_characteristic_uuid(
|
||||
connection_handle_t connection_handle,
|
||||
attribute_handle_range_t read_range,
|
||||
const UUID& uuid
|
||||
|
@ -260,7 +260,7 @@ ble_error_t nRF5XGattClient::read_using_characteristic_uuid(
|
|||
);
|
||||
}
|
||||
|
||||
ble_error_t nRF5XGattClient::read_attribute_blob(
|
||||
ble_error_t nRF5xGattClient::read_attribute_blob(
|
||||
connection_handle_t connection,
|
||||
attribute_handle_t attribute_handle,
|
||||
uint16_t offset
|
||||
|
@ -270,7 +270,7 @@ ble_error_t nRF5XGattClient::read_attribute_blob(
|
|||
);
|
||||
}
|
||||
|
||||
ble_error_t nRF5XGattClient::read_multiple_characteristic_values(
|
||||
ble_error_t nRF5xGattClient::read_multiple_characteristic_values(
|
||||
connection_handle_t connection,
|
||||
const ArrayView<const attribute_handle_t>& characteristic_handles
|
||||
) {
|
||||
|
@ -279,7 +279,7 @@ ble_error_t nRF5XGattClient::read_multiple_characteristic_values(
|
|||
);
|
||||
}
|
||||
|
||||
ble_error_t nRF5XGattClient::write_without_response(
|
||||
ble_error_t nRF5xGattClient::write_without_response(
|
||||
connection_handle_t connection_handle,
|
||||
attribute_handle_t characteristic_value_handle,
|
||||
const ArrayView<const uint8_t>& value
|
||||
|
@ -297,7 +297,7 @@ ble_error_t nRF5XGattClient::write_without_response(
|
|||
return convert_sd_error(err);
|
||||
}
|
||||
|
||||
ble_error_t nRF5XGattClient::signed_write_without_response(
|
||||
ble_error_t nRF5xGattClient::signed_write_without_response(
|
||||
connection_handle_t connection_handle,
|
||||
attribute_handle_t characteristic_value_handle,
|
||||
const ArrayView<const uint8_t>& value
|
||||
|
@ -315,7 +315,7 @@ ble_error_t nRF5XGattClient::signed_write_without_response(
|
|||
return convert_sd_error(err);
|
||||
}
|
||||
|
||||
ble_error_t nRF5XGattClient::write_attribute(
|
||||
ble_error_t nRF5xGattClient::write_attribute(
|
||||
connection_handle_t connection_handle,
|
||||
attribute_handle_t attribute_handle,
|
||||
const ArrayView<const uint8_t>& value
|
||||
|
@ -325,7 +325,7 @@ ble_error_t nRF5XGattClient::write_attribute(
|
|||
);
|
||||
}
|
||||
|
||||
ble_error_t nRF5XGattClient::queue_prepare_write(
|
||||
ble_error_t nRF5xGattClient::queue_prepare_write(
|
||||
connection_handle_t connection_handle,
|
||||
attribute_handle_t characteristic_value_handle,
|
||||
const ArrayView<const uint8_t>& value,
|
||||
|
@ -336,7 +336,7 @@ ble_error_t nRF5XGattClient::queue_prepare_write(
|
|||
);
|
||||
}
|
||||
|
||||
ble_error_t nRF5XGattClient::execute_write_queue(
|
||||
ble_error_t nRF5xGattClient::execute_write_queue(
|
||||
connection_handle_t connection_handle,
|
||||
bool execute
|
||||
) {
|
||||
|
@ -367,7 +367,7 @@ ble_error_t nRF5XGattClient::execute_write_queue(
|
|||
* @note Commands such as write without response or signed write without response
|
||||
* are not procedures.
|
||||
*/
|
||||
struct nRF5XGattClient::GattProcedure {
|
||||
struct nRF5xGattClient::GattProcedure {
|
||||
/**
|
||||
* Initialize the procedure.
|
||||
*
|
||||
|
@ -424,7 +424,7 @@ struct nRF5XGattClient::GattProcedure {
|
|||
* Given that such procedure expects a single event type from the soft device,
|
||||
* error handling can be generalized.
|
||||
*/
|
||||
struct nRF5XGattClient::RegularGattProcedure : GattProcedure {
|
||||
struct nRF5xGattClient::RegularGattProcedure : GattProcedure {
|
||||
|
||||
/**
|
||||
* Construct a RegularGattProcedure.
|
||||
|
@ -483,7 +483,7 @@ protected:
|
|||
* In such case a read request is issued for each service attribute handle
|
||||
* to extract that information.
|
||||
*/
|
||||
struct nRF5XGattClient::DiscoverPrimaryServiceProcedure : GattProcedure {
|
||||
struct nRF5xGattClient::DiscoverPrimaryServiceProcedure : GattProcedure {
|
||||
|
||||
typedef ArrayView<const ble_gattc_service_t> services_array_t;
|
||||
|
||||
|
@ -692,7 +692,7 @@ struct nRF5XGattClient::DiscoverPrimaryServiceProcedure : GattProcedure {
|
|||
* response it is possible to reconstruct it by keeping a copy of the UUID to
|
||||
* find.
|
||||
*/
|
||||
struct nRF5XGattClient::DiscoverPrimaryServiceByUUIDProcedure : RegularGattProcedure {
|
||||
struct nRF5xGattClient::DiscoverPrimaryServiceByUUIDProcedure : RegularGattProcedure {
|
||||
|
||||
typedef ArrayView<const ble_gattc_service_t> services_array_t;
|
||||
|
||||
|
@ -766,7 +766,7 @@ struct nRF5XGattClient::DiscoverPrimaryServiceByUUIDProcedure : RegularGattProce
|
|||
/**
|
||||
* Procedure that manage Find Included Services transactions.
|
||||
*/
|
||||
struct nRF5XGattClient::FindIncludedServicesProcedure : RegularGattProcedure {
|
||||
struct nRF5xGattClient::FindIncludedServicesProcedure : RegularGattProcedure {
|
||||
|
||||
typedef ArrayView<const ble_gattc_service_t> services_array_t;
|
||||
|
||||
|
@ -841,7 +841,7 @@ struct nRF5XGattClient::FindIncludedServicesProcedure : RegularGattProcedure {
|
|||
* In such case a read request is issued for each attribute handle of
|
||||
* characteristics that exposes a long UUID.
|
||||
*/
|
||||
struct nRF5XGattClient::DiscoverCharacteristicsProcedure : GattProcedure {
|
||||
struct nRF5xGattClient::DiscoverCharacteristicsProcedure : GattProcedure {
|
||||
/**
|
||||
* Data structure returned by the function flatten_response.
|
||||
*/
|
||||
|
@ -1060,7 +1060,7 @@ struct nRF5XGattClient::DiscoverCharacteristicsProcedure : GattProcedure {
|
|||
/**
|
||||
* Procedure that handle discovery of characteristic descriptors.
|
||||
*/
|
||||
struct nRF5XGattClient::DiscoverDescriptorsProcedure : RegularGattProcedure {
|
||||
struct nRF5xGattClient::DiscoverDescriptorsProcedure : RegularGattProcedure {
|
||||
DiscoverDescriptorsProcedure(connection_handle_t connection) :
|
||||
RegularGattProcedure(
|
||||
connection,
|
||||
|
@ -1151,7 +1151,7 @@ struct nRF5XGattClient::DiscoverDescriptorsProcedure : RegularGattProcedure {
|
|||
/**
|
||||
* Procedure that handle read of attribute handles.
|
||||
*/
|
||||
struct nRF5XGattClient::ReadAttributeProcedure : RegularGattProcedure {
|
||||
struct nRF5xGattClient::ReadAttributeProcedure : RegularGattProcedure {
|
||||
ReadAttributeProcedure(connection_handle_t connection) :
|
||||
RegularGattProcedure(
|
||||
connection, AttributeOpcode::READ_REQUEST, BLE_GATTC_EVT_READ_RSP
|
||||
|
@ -1178,7 +1178,7 @@ struct nRF5XGattClient::ReadAttributeProcedure : RegularGattProcedure {
|
|||
/**
|
||||
* Procedure that handle read of characteristic using characteristic UUID.
|
||||
*/
|
||||
struct nRF5XGattClient::ReadUsingCharacteristicUUIDProcedure : RegularGattProcedure {
|
||||
struct nRF5xGattClient::ReadUsingCharacteristicUUIDProcedure : RegularGattProcedure {
|
||||
ReadUsingCharacteristicUUIDProcedure(connection_handle_t connection) :
|
||||
RegularGattProcedure(
|
||||
connection,
|
||||
|
@ -1265,7 +1265,7 @@ struct nRF5XGattClient::ReadUsingCharacteristicUUIDProcedure : RegularGattProced
|
|||
/**
|
||||
* Procedure that handles read blob transactions.
|
||||
*/
|
||||
struct nRF5XGattClient::ReadAttributeBlobProcedure : RegularGattProcedure {
|
||||
struct nRF5xGattClient::ReadAttributeBlobProcedure : RegularGattProcedure {
|
||||
ReadAttributeBlobProcedure(connection_handle_t connection) :
|
||||
RegularGattProcedure(
|
||||
connection, AttributeOpcode::READ_BLOB_REQUEST, BLE_GATTC_EVT_READ_RSP
|
||||
|
@ -1291,7 +1291,7 @@ struct nRF5XGattClient::ReadAttributeBlobProcedure : RegularGattProcedure {
|
|||
/**
|
||||
* Procedure that handles Read Multiple Characteristic Values transactions.
|
||||
*/
|
||||
struct nRF5XGattClient::ReadMultipleCharacteristicsProcedure : RegularGattProcedure {
|
||||
struct nRF5xGattClient::ReadMultipleCharacteristicsProcedure : RegularGattProcedure {
|
||||
ReadMultipleCharacteristicsProcedure(connection_handle_t connection) :
|
||||
RegularGattProcedure(
|
||||
connection,
|
||||
|
@ -1321,7 +1321,7 @@ struct nRF5XGattClient::ReadMultipleCharacteristicsProcedure : RegularGattProced
|
|||
/**
|
||||
* Procedure that handles Write transactions.
|
||||
*/
|
||||
struct nRF5XGattClient::WriteAttributeProcedure : RegularGattProcedure {
|
||||
struct nRF5xGattClient::WriteAttributeProcedure : RegularGattProcedure {
|
||||
WriteAttributeProcedure(connection_handle_t connection) :
|
||||
RegularGattProcedure(
|
||||
connection, AttributeOpcode::WRITE_REQUEST, BLE_GATTC_EVT_WRITE_RSP
|
||||
|
@ -1352,7 +1352,7 @@ struct nRF5XGattClient::WriteAttributeProcedure : RegularGattProcedure {
|
|||
/**
|
||||
* Procedure that handles Prepare Write transactions.
|
||||
*/
|
||||
struct nRF5XGattClient::QueuePrepareWriteProcedure : RegularGattProcedure {
|
||||
struct nRF5xGattClient::QueuePrepareWriteProcedure : RegularGattProcedure {
|
||||
QueuePrepareWriteProcedure(connection_handle_t connection) :
|
||||
RegularGattProcedure(
|
||||
connection,
|
||||
|
@ -1398,7 +1398,7 @@ struct nRF5XGattClient::QueuePrepareWriteProcedure : RegularGattProcedure {
|
|||
/**
|
||||
* Procedure that handles Execute Write transactions.
|
||||
*/
|
||||
struct nRF5XGattClient::ExecuteWriteQueueProcedure : RegularGattProcedure {
|
||||
struct nRF5xGattClient::ExecuteWriteQueueProcedure : RegularGattProcedure {
|
||||
ExecuteWriteQueueProcedure(connection_handle_t connection) :
|
||||
RegularGattProcedure(
|
||||
connection,
|
||||
|
@ -1437,7 +1437,7 @@ struct nRF5XGattClient::ExecuteWriteQueueProcedure : RegularGattProcedure {
|
|||
};
|
||||
|
||||
// NOTE: position after declaration of GattProcedure on purpose.
|
||||
ble_error_t nRF5XGattClient::terminate()
|
||||
ble_error_t nRF5xGattClient::terminate()
|
||||
{
|
||||
for (size_t i = 0; i < max_procedures_count; ++i) {
|
||||
if (_procedures[i]) {
|
||||
|
@ -1450,7 +1450,7 @@ ble_error_t nRF5XGattClient::terminate()
|
|||
}
|
||||
|
||||
template<typename ProcType, typename A0>
|
||||
ble_error_t nRF5XGattClient::launch_procedure(
|
||||
ble_error_t nRF5xGattClient::launch_procedure(
|
||||
connection_handle_t connection, const A0& a0
|
||||
) {
|
||||
ProcType* p = new(std::nothrow) ProcType(connection);
|
||||
|
@ -1473,7 +1473,7 @@ ble_error_t nRF5XGattClient::launch_procedure(
|
|||
}
|
||||
|
||||
template<typename ProcType, typename A0, typename A1>
|
||||
ble_error_t nRF5XGattClient::launch_procedure(
|
||||
ble_error_t nRF5xGattClient::launch_procedure(
|
||||
connection_handle_t connection, const A0& a0, const A1& a1
|
||||
) {
|
||||
ProcType* p = new(std::nothrow) ProcType(connection);
|
||||
|
@ -1496,7 +1496,7 @@ ble_error_t nRF5XGattClient::launch_procedure(
|
|||
}
|
||||
|
||||
template<typename ProcType, typename A0, typename A1, typename A2>
|
||||
ble_error_t nRF5XGattClient::launch_procedure(
|
||||
ble_error_t nRF5xGattClient::launch_procedure(
|
||||
connection_handle_t connection,
|
||||
const A0& a0, const A1& a1, const A2& a2
|
||||
) {
|
||||
|
@ -1520,7 +1520,7 @@ ble_error_t nRF5XGattClient::launch_procedure(
|
|||
}
|
||||
|
||||
template<typename ProcType, typename A0, typename A1, typename A2, typename A3>
|
||||
ble_error_t nRF5XGattClient::launch_procedure(
|
||||
ble_error_t nRF5xGattClient::launch_procedure(
|
||||
connection_handle_t connection,
|
||||
const A0& a0, const A1& a1, const A2& a2, const A3& a3
|
||||
) {
|
||||
|
@ -1543,7 +1543,7 @@ ble_error_t nRF5XGattClient::launch_procedure(
|
|||
return err;
|
||||
}
|
||||
|
||||
nRF5XGattClient::GattProcedure* nRF5XGattClient::get_procedure(
|
||||
nRF5xGattClient::GattProcedure* nRF5xGattClient::get_procedure(
|
||||
connection_handle_t connection
|
||||
) const {
|
||||
for (size_t i = 0; i < max_procedures_count; ++i) {
|
||||
|
@ -1554,7 +1554,7 @@ nRF5XGattClient::GattProcedure* nRF5XGattClient::get_procedure(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
bool nRF5XGattClient::register_procedure(GattProcedure *p)
|
||||
bool nRF5xGattClient::register_procedure(GattProcedure *p)
|
||||
{
|
||||
if (get_procedure(p->connection_handle)) {
|
||||
return false;
|
||||
|
@ -1570,7 +1570,7 @@ bool nRF5XGattClient::register_procedure(GattProcedure *p)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool nRF5XGattClient::remove_procedure(nRF5XGattClient::GattProcedure* p)
|
||||
bool nRF5xGattClient::remove_procedure(nRF5xGattClient::GattProcedure* p)
|
||||
{
|
||||
for (size_t i = 0; i < max_procedures_count; ++i) {
|
||||
if (_procedures[i] == p) {
|
||||
|
@ -1583,13 +1583,13 @@ bool nRF5XGattClient::remove_procedure(nRF5XGattClient::GattProcedure* p)
|
|||
}
|
||||
|
||||
// singleton of the ARM Cordio client
|
||||
nRF5XGattClient& nRF5XGattClient::get_client()
|
||||
nRF5xGattClient& nRF5xGattClient::get_client()
|
||||
{
|
||||
static nRF5XGattClient _client;
|
||||
static nRF5xGattClient _client;
|
||||
return _client;
|
||||
}
|
||||
|
||||
void nRF5XGattClient::handle_events(const ble_evt_t *evt) {
|
||||
void nRF5xGattClient::handle_events(const ble_evt_t *evt) {
|
||||
switch (evt->header.evt_id) {
|
||||
case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:
|
||||
case BLE_GATTC_EVT_REL_DISC_RSP:
|
||||
|
@ -1611,7 +1611,7 @@ void nRF5XGattClient::handle_events(const ble_evt_t *evt) {
|
|||
}
|
||||
}
|
||||
|
||||
void nRF5XGattClient::handle_procedure_event(const ble_evt_t &evt)
|
||||
void nRF5xGattClient::handle_procedure_event(const ble_evt_t &evt)
|
||||
{
|
||||
GattProcedure* p = get_procedure(evt.evt.gattc_evt.conn_handle);
|
||||
if (p) {
|
||||
|
@ -1619,7 +1619,7 @@ void nRF5XGattClient::handle_procedure_event(const ble_evt_t &evt)
|
|||
}
|
||||
}
|
||||
|
||||
void nRF5XGattClient::handle_hvx_event(const ble_evt_t &evt)
|
||||
void nRF5xGattClient::handle_hvx_event(const ble_evt_t &evt)
|
||||
{
|
||||
connection_handle_t connection = evt.evt.gattc_evt.conn_handle;
|
||||
const ble_gattc_evt_hvx_t &hvx_evt = evt.evt.gattc_evt.params.hvx;
|
||||
|
@ -1650,7 +1650,7 @@ void nRF5XGattClient::handle_hvx_event(const ble_evt_t &evt)
|
|||
}
|
||||
}
|
||||
|
||||
void nRF5XGattClient::handle_timeout_event(const ble_evt_t &evt)
|
||||
void nRF5xGattClient::handle_timeout_event(const ble_evt_t &evt)
|
||||
{
|
||||
connection_handle_t connection = evt.evt.gattc_evt.conn_handle;
|
||||
GattProcedure* p = get_procedure(connection);
|
||||
|
@ -1661,7 +1661,7 @@ void nRF5XGattClient::handle_timeout_event(const ble_evt_t &evt)
|
|||
on_transaction_timeout(connection);
|
||||
}
|
||||
|
||||
void nRF5XGattClient::handle_connection_termination(connection_handle_t connection)
|
||||
void nRF5xGattClient::handle_connection_termination(connection_handle_t connection)
|
||||
{
|
||||
GattProcedure* p = get_client().get_procedure(connection);
|
||||
if (p) {
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue