mirror of https://github.com/ARMmbed/mbed-os.git
Merge
commit
3f7a7a4213
|
@ -129,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. */
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -460,6 +461,74 @@ struct random_address_type_t : SafeEnum<random_address_type_t, uint8_t> {
|
|||
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) { }
|
||||
};
|
||||
|
||||
} // namespace ble
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 &);
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -417,6 +417,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] dbPath Path to the folder used to store keys in the filesystem,
|
||||
* if NULL keys will be only stored in memory
|
||||
*
|
||||
*
|
||||
* @return BLE_ERROR_NONE on success.
|
||||
*/
|
||||
|
@ -424,12 +427,14 @@ public:
|
|||
bool requireMITM = true,
|
||||
SecurityIOCapabilities_t iocaps = IO_CAPS_NONE,
|
||||
const Passkey_t passkey = NULL,
|
||||
bool signing = true) {
|
||||
bool signing = true,
|
||||
const char *dbPath = NULL) {
|
||||
/* Avoid compiler warnings about unused variables. */
|
||||
(void)enableBonding;
|
||||
(void)requireMITM;
|
||||
(void)iocaps;
|
||||
(void)passkey;
|
||||
(void)dbPath;
|
||||
|
||||
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
|
||||
}
|
||||
|
@ -967,15 +972,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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1079,7 +1100,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_*/
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#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"
|
||||
|
@ -37,8 +37,6 @@ class GenericSecurityManager : public SecurityManager,
|
|||
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 */
|
||||
|
||||
|
@ -51,7 +49,8 @@ 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 reset();
|
||||
|
@ -236,13 +235,12 @@ public:
|
|||
public:
|
||||
GenericSecurityManager(
|
||||
pal::SecurityManager &palImpl,
|
||||
pal::SecurityDb &dbImpl,
|
||||
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),
|
||||
|
@ -256,6 +254,10 @@ public:
|
|||
_oob_local_random[0] = 1;
|
||||
}
|
||||
|
||||
~GenericSecurityManager() {
|
||||
delete _db;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Helper functions
|
||||
//
|
||||
|
@ -308,7 +310,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
|
||||
);
|
||||
|
||||
|
@ -319,7 +321,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
|
||||
);
|
||||
|
||||
|
@ -327,24 +329,22 @@ private:
|
|||
* Returns the CSRK for the connection. Called by the security db.
|
||||
*
|
||||
* @param[in] connectionHandle Handle to identify the connection.
|
||||
* @param[in] csrk connection signature resolving key.
|
||||
* @param[in] signing connection signature resolving key and counter.
|
||||
*/
|
||||
void return_csrk_cb(
|
||||
pal::SecurityDb::entry_handle_t connection,
|
||||
const csrk_t *csrk,
|
||||
sign_count_t sign_counter
|
||||
SecurityDb::entry_handle_t connection,
|
||||
const SecurityEntrySigning_t *signing
|
||||
);
|
||||
|
||||
/**
|
||||
* Set the peer CSRK for the connection. Called by the security db.
|
||||
*
|
||||
* @param[in] connectionHandle Handle to identify the connection.
|
||||
* @param[in] csrk connection signature resolving key.
|
||||
* @param[in] signing connection signature resolving key and counter.
|
||||
*/
|
||||
void set_peer_csrk_cb(
|
||||
pal::SecurityDb::entry_handle_t connection,
|
||||
const csrk_t *csrk,
|
||||
sign_count_t sign_counter
|
||||
SecurityDb::entry_handle_t connection,
|
||||
const SecurityEntrySigning_t *signing
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -407,8 +407,8 @@ private:
|
|||
* @param identity The identity associated with the entry; may be NULL.
|
||||
*/
|
||||
void on_security_entry_retrieved(
|
||||
pal::SecurityDb::entry_handle_t entry,
|
||||
const pal::SecurityEntryIdentity_t* identity
|
||||
SecurityDb::entry_handle_t entry,
|
||||
const SecurityEntryIdentity_t* identity
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -421,12 +421,12 @@ private:
|
|||
* @param count Number of identities entries retrieved.
|
||||
*/
|
||||
void on_identity_list_retrieved(
|
||||
ble::ArrayView<pal::SecurityEntryIdentity_t*>& identity_list,
|
||||
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() {
|
||||
|
@ -443,7 +443,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 */
|
||||
|
||||
|
@ -473,10 +473,11 @@ private:
|
|||
};
|
||||
|
||||
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;
|
||||
|
@ -718,7 +719,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(
|
||||
BLEProtocol::AddressType_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 == BLEProtocol::AddressType::PUBLIC) ||
|
||||
(peer_address_type == BLEProtocol::AddressType::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(
|
||||
BLEProtocol::AddressType_t peer_address_type,
|
||||
const address_t &peer_address
|
||||
) {
|
||||
const bool peer_address_public =
|
||||
(peer_address_type == BLEProtocol::AddressType::PUBLIC) ||
|
||||
(peer_address_type == BLEProtocol::AddressType::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 == BLEProtocol::AddressType::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(
|
||||
BLEProtocol::AddressType_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__*/
|
|
@ -1,446 +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() : sign_counter(0), state(ENTRY_FREE) { };
|
||||
SecurityDistributionFlags_t flags;
|
||||
SecurityEntryKeys_t peer_keys;
|
||||
SecurityEntryKeys_t local_keys;
|
||||
SecurityEntryIdentity_t peer_identity;
|
||||
csrk_t csrk;
|
||||
sign_count_t sign_counter;
|
||||
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() : _local_sign_counter(0) { }
|
||||
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;
|
||||
sign_count_t sign_counter = 0;
|
||||
entry_t *entry = as_entry(entry_handle);
|
||||
if (entry) {
|
||||
csrk = entry->csrk;
|
||||
sign_counter = entry->sign_counter;
|
||||
}
|
||||
cb(entry_handle, &csrk, sign_counter);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
virtual void get_entry_identity(
|
||||
SecurityEntryIdentityDbCb_t cb,
|
||||
entry_handle_t entry_handle
|
||||
) {
|
||||
entry_t *entry = as_entry(entry_handle);
|
||||
if (entry && entry->flags.irk_stored) {
|
||||
cb(entry_handle, &entry->peer_identity);
|
||||
} else {
|
||||
cb(entry_handle, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void get_identity_list(
|
||||
IdentitylistDbCb_t cb,
|
||||
ArrayView<SecurityEntryIdentity_t*>& entries
|
||||
) {
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < MAX_ENTRIES && count < entries.size(); ++i) {
|
||||
entry_t& e = _entries[i];
|
||||
|
||||
if (e.state == ENTRY_WRITTEN && e.flags.irk_stored) {
|
||||
entries[count] = &e.peer_identity;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
cb(entries, count);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
entry->flags.irk_stored = true;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
entry->peer_identity.identity_address_is_public = address_is_public;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_entry_peer_sign_counter(
|
||||
entry_handle_t entry_handle,
|
||||
sign_count_t sign_counter
|
||||
) {
|
||||
entry_t *entry = as_entry(entry_handle);
|
||||
if (entry) {
|
||||
entry->state = ENTRY_WRITTEN;
|
||||
entry->sign_counter = sign_counter;
|
||||
}
|
||||
}
|
||||
|
||||
/* local csrk */
|
||||
|
||||
virtual const csrk_t* get_local_csrk() {
|
||||
return &_local_csrk;
|
||||
}
|
||||
|
||||
virtual void set_local_csrk(const csrk_t &csrk) {
|
||||
_local_csrk = csrk;
|
||||
}
|
||||
|
||||
virtual sign_count_t get_local_sign_counter() {
|
||||
return _local_sign_counter;
|
||||
}
|
||||
|
||||
virtual void set_local_sign_counter(
|
||||
sign_count_t sign_counter
|
||||
) {
|
||||
_local_sign_counter = sign_counter;
|
||||
}
|
||||
|
||||
/* 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) ||
|
||||
(peer_address_type == BLEProtocol::AddressType::PUBLIC_IDENTITY);
|
||||
|
||||
for (size_t i = 0; i < MAX_ENTRIES; i++) {
|
||||
entry_t& e = _entries[i];
|
||||
|
||||
if (e.state == ENTRY_FREE) {
|
||||
continue;
|
||||
} else {
|
||||
if (peer_address_type == BLEProtocol::AddressType::PUBLIC_IDENTITY &&
|
||||
e.flags.irk_stored == false
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// lookup for the identity address then the connection address.
|
||||
if (e.flags.irk_stored &&
|
||||
e.peer_identity.identity_address == peer_address &&
|
||||
e.peer_identity.identity_address_is_public == peer_address_public
|
||||
) {
|
||||
return &e;
|
||||
// lookup for connection address used during bonding
|
||||
} else if (e.flags.peer_address == peer_address &&
|
||||
e.flags.peer_address_is_public == peer_address_public
|
||||
) {
|
||||
return &e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// determine if the address in input is private or not.
|
||||
bool is_private_address = false;
|
||||
if (peer_address_type == BLEProtocol::AddressType::RANDOM) {
|
||||
::Gap::RandomAddressType_t random_type(::Gap::RandomAddressType_t::STATIC);
|
||||
ble_error_t err = ::Gap::getRandomAddressType(peer_address.data(), &random_type);
|
||||
if (err) {
|
||||
return NULL;
|
||||
}
|
||||
if (random_type != ::Gap::RandomAddressType_t::STATIC) {
|
||||
is_private_address = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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();
|
||||
// do not store private addresses in the flags; just store public
|
||||
// or random static address so it can be reused latter.
|
||||
if (is_private_address == false) {
|
||||
_entries[i].flags.peer_address = peer_address;
|
||||
_entries[i].flags.peer_address_is_public = peer_address_public;
|
||||
} else {
|
||||
_entries[i].flags.peer_address = address_t();
|
||||
}
|
||||
_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;
|
||||
sign_count_t _local_sign_counter;
|
||||
};
|
||||
|
||||
} /* namespace pal */
|
||||
} /* namespace ble */
|
||||
|
||||
#endif /*PAL_MEMORY_SECURITY_DB_H_*/
|
|
@ -883,6 +883,8 @@ public:
|
|||
sign_count_t sign_counter
|
||||
) = 0;
|
||||
|
||||
virtual ble_error_t remove_peer_csrk(connection_handle_t connection) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Authentication
|
||||
//
|
||||
|
|
|
@ -1,462 +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),
|
||||
csrk_stored(false),
|
||||
csrk_mitm_protected(false),
|
||||
ltk_stored(false),
|
||||
ltk_mitm_protected(false),
|
||||
secure_connections_paired(false),
|
||||
irk_stored(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;
|
||||
/** 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;
|
||||
/** the security entry has been distributed and stored */
|
||||
uint8_t irk_stored: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;
|
||||
/** 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 csrk_t*, uint32_t sign_counter)>
|
||||
SecurityEntryCsrkDbCb_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() { };
|
||||
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;
|
||||
|
||||
/**
|
||||
* Retrieve stored identity address and IRK.
|
||||
*
|
||||
* @param[in] cb callback that will receive the SecurityEntryIdentity_t struct
|
||||
* @param[in] db_entry handle of the entry being queried.
|
||||
*/
|
||||
virtual void get_entry_identity(
|
||||
SecurityEntryIdentityDbCb_t cb,
|
||||
entry_handle_t db_entry
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* 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
|
||||
) = 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;
|
||||
|
||||
/**
|
||||
* Update peer signing counter.
|
||||
*
|
||||
* @param[in] db_entry 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_entry,
|
||||
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() = 0;
|
||||
|
||||
/**
|
||||
* Return local signing counter.
|
||||
*
|
||||
* @return signing counter
|
||||
*/
|
||||
virtual sign_count_t get_local_sign_counter() = 0;
|
||||
|
||||
/**
|
||||
* Update local signing key.
|
||||
*
|
||||
* @param[in] csrk new CSRK value
|
||||
*/
|
||||
virtual void set_local_csrk(
|
||||
const csrk_t &csrk
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Update local signing counter.
|
||||
*
|
||||
* @param[in] sign_counter new signing counter value
|
||||
*/
|
||||
virtual void set_local_sign_counter(
|
||||
sign_count_t sign_counter
|
||||
) = 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,393 @@
|
|||
/* 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_LOCAL_KEYS (0)
|
||||
#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(SecurityEntryKeys_t) + \
|
||||
sizeof(SecurityEntryKeys_t) + \
|
||||
sizeof(SecurityEntryIdentity_t) + \
|
||||
sizeof(SecurityEntrySigning_t) + \
|
||||
sizeof(sign_count_t))
|
||||
|
||||
/* without the size of the file offset as we don't store it */
|
||||
#define DB_SIZE_ENTRY \
|
||||
(sizeof(SecurityDistributionFlags_t) + sizeof(sign_count_t))
|
||||
|
||||
#define DB_SIZE_ENTRIES \
|
||||
(FileSecurityDb::MAX_ENTRIES * DB_SIZE_ENTRY)
|
||||
|
||||
#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_ENTRIES (DB_OFFSET_LOCAL_SIGN_COUNT + sizeof(sign_count_t))
|
||||
#define DB_OFFSET_STORES (DB_OFFSET_ENTRIES + DB_SIZE_ENTRIES)
|
||||
#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;
|
||||
}
|
||||
|
||||
FILE *db_file = fopen(db_path, "wb+");
|
||||
|
||||
if (!db_file) {
|
||||
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)) {
|
||||
/* version checks out, try the size */
|
||||
fseek(db_file, DB_SIZE - 1, SEEK_SET);
|
||||
/* read one byte and expect to hit EOF */
|
||||
if ((fread(&version, 1, 1, db_file) != 1) || !feof(db_file)) {
|
||||
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() {
|
||||
|
||||
fseek(_db_file, DB_OFFSET_RESTORE, SEEK_SET);
|
||||
|
||||
/* restore if requested */
|
||||
bool restore_toggle;
|
||||
if (fread(&restore_toggle, sizeof(bool), 1, _db_file) == 1) {
|
||||
if (!restore_toggle) {
|
||||
erase_db_file(_db_file);
|
||||
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);
|
||||
|
||||
fseek(_db_file, DB_OFFSET_ENTRIES, SEEK_SET);
|
||||
/* we read the entries partially and fill the offsets ourselves*/
|
||||
for (size_t i = 0; i < get_entry_count(); i++) {
|
||||
fread(&_entries[i], DB_SIZE_ENTRY, 1, _db_file);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 */
|
|
@ -1090,9 +1090,11 @@ ble_error_t GenericGattClient::write(
|
|||
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 == ble::link_encryption_t::ENCRYPTED
|
||||
|| encryption == ble::link_encryption_t::ENCRYPTED_WITH_MITM) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include "ble/SecurityManager.h"
|
||||
#include "ble/pal/PalSecurityManager.h"
|
||||
#include "ble/generic/GenericSecurityManager.h"
|
||||
#include "ble/generic/MemorySecurityDb.h"
|
||||
#include "ble/generic/FileSecurityDb.h"
|
||||
|
||||
using ble::pal::advertising_peer_address_type_t;
|
||||
using ble::pal::AuthenticationMask;
|
||||
|
@ -37,14 +39,33 @@ ble_error_t GenericSecurityManager::init(
|
|||
bool mitm,
|
||||
SecurityIOCapabilities_t iocaps,
|
||||
const Passkey_t passkey,
|
||||
bool signing
|
||||
bool signing,
|
||||
const char* db_path
|
||||
) {
|
||||
|
||||
ble_error_t err = _pal.initialize();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
_db.restore();
|
||||
if (_db) {
|
||||
delete _db;
|
||||
}
|
||||
|
||||
FILE* db_file = FileSecurityDb::open_db_file(db_path);
|
||||
|
||||
if (db_file) {
|
||||
_db = new (std::nothrow) FileSecurityDb(db_file);
|
||||
} else {
|
||||
_db = new (std::nothrow) MemorySecurityDb();
|
||||
}
|
||||
|
||||
if (!_db) {
|
||||
return BLE_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
_db->restore();
|
||||
|
||||
_pal.set_io_capability((io_capability_t::type) iocaps);
|
||||
|
||||
if (passkey) {
|
||||
|
@ -63,7 +84,8 @@ ble_error_t GenericSecurityManager::init(
|
|||
_default_authentication.set_secure_connections(secure_connections);
|
||||
_default_authentication.set_keypress_notification(true);
|
||||
|
||||
_default_key_distribution.set_link(secure_connections);
|
||||
// FIXME: depends on BR/EDR support
|
||||
_default_key_distribution.set_link(false);
|
||||
|
||||
_default_key_distribution.set_signing(signing);
|
||||
if (signing) {
|
||||
|
@ -75,16 +97,16 @@ ble_error_t GenericSecurityManager::init(
|
|||
_pal.set_event_handler(this);
|
||||
|
||||
uint8_t resolving_list_capacity = _pal.read_resolving_list_capacity();
|
||||
pal::SecurityEntryIdentity_t** identity_list_p =
|
||||
new (std::nothrow) pal::SecurityEntryIdentity_t*[resolving_list_capacity];
|
||||
SecurityEntryIdentity_t* identity_list_p =
|
||||
new (std::nothrow) SecurityEntryIdentity_t[resolving_list_capacity];
|
||||
|
||||
if (identity_list_p) {
|
||||
ArrayView<pal::SecurityEntryIdentity_t*> identity_list(
|
||||
ArrayView<SecurityEntryIdentity_t> identity_list(
|
||||
identity_list_p,
|
||||
resolving_list_capacity
|
||||
);
|
||||
|
||||
_db.get_identity_list(
|
||||
_db->get_identity_list(
|
||||
mbed::callback(this, &GenericSecurityManager::on_identity_list_retrieved),
|
||||
identity_list
|
||||
);
|
||||
|
@ -94,7 +116,6 @@ ble_error_t GenericSecurityManager::init(
|
|||
}
|
||||
|
||||
ble_error_t GenericSecurityManager::reset(void) {
|
||||
_db.sync();
|
||||
_pal.reset();
|
||||
SecurityManager::reset();
|
||||
|
||||
|
@ -102,7 +123,8 @@ ble_error_t GenericSecurityManager::reset(void) {
|
|||
}
|
||||
|
||||
ble_error_t GenericSecurityManager::preserveBondingStateOnReset(bool enabled) {
|
||||
_db.set_restore(enabled);
|
||||
MBED_ASSERT(_db);
|
||||
_db->set_restore(enabled);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
@ -111,13 +133,15 @@ ble_error_t GenericSecurityManager::preserveBondingStateOnReset(bool enabled) {
|
|||
//
|
||||
|
||||
ble_error_t GenericSecurityManager::purgeAllBondingState(void) {
|
||||
_db.clear_entries();
|
||||
MBED_ASSERT(_db);
|
||||
_db->clear_entries();
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t GenericSecurityManager::generateWhitelistFromBondTable(Gap::Whitelist_t *whitelist) const {
|
||||
MBED_ASSERT(_db);
|
||||
if (eventHandler) {
|
||||
_db.generate_whitelist_from_bond_table(
|
||||
_db->generate_whitelist_from_bond_table(
|
||||
mbed::callback(eventHandler, &::SecurityManager::EventHandler::whitelistFromBondTable),
|
||||
whitelist
|
||||
);
|
||||
|
@ -150,17 +174,20 @@ ble_error_t GenericSecurityManager::requestPairing(connection_handle_t connectio
|
|||
|
||||
/* by default the initiator doesn't send any keys other then identity */
|
||||
KeyDistribution initiator_distribution(
|
||||
KeyDistribution::KEY_DISTRIBUTION_IDENTITY | _default_key_distribution.get_link()
|
||||
KeyDistribution::KEY_DISTRIBUTION_IDENTITY |
|
||||
_default_key_distribution.get_link()
|
||||
);
|
||||
|
||||
initiator_distribution.set_signing(
|
||||
cb->signing_override_default ?
|
||||
cb->signing_requested :
|
||||
_default_key_distribution.get_signing()
|
||||
);
|
||||
|
||||
/* if requested the initiator may send all the default keys for later
|
||||
* use when roles are changed */
|
||||
if (_master_sends_keys) {
|
||||
initiator_distribution = _default_key_distribution;
|
||||
/* override default if requested */
|
||||
if (cb->signing_override_default) {
|
||||
initiator_distribution.set_signing(cb->signing_requested);
|
||||
}
|
||||
}
|
||||
|
||||
KeyDistribution responder_distribution(_default_key_distribution);
|
||||
|
@ -198,13 +225,18 @@ ble_error_t GenericSecurityManager::acceptPairingRequest(connection_handle_t con
|
|||
if (_master_sends_keys) {
|
||||
initiator_distribution &= _default_key_distribution;
|
||||
} else {
|
||||
initiator_distribution &= KeyDistribution(KeyDistribution::KEY_DISTRIBUTION_IDENTITY | KeyDistribution::KEY_DISTRIBUTION_LINK);
|
||||
initiator_distribution &= KeyDistribution(
|
||||
KeyDistribution::KEY_DISTRIBUTION_IDENTITY |
|
||||
KeyDistribution::KEY_DISTRIBUTION_LINK
|
||||
);
|
||||
}
|
||||
|
||||
/* signing has to be offered and enabled on the link */
|
||||
if (master_signing) {
|
||||
initiator_distribution.set_signing(
|
||||
cb->signing_override_default ? cb->signing_requested : _default_key_distribution.get_signing()
|
||||
cb->signing_override_default ?
|
||||
cb->signing_requested :
|
||||
_default_key_distribution.get_signing()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -215,7 +247,9 @@ ble_error_t GenericSecurityManager::acceptPairingRequest(connection_handle_t con
|
|||
/* signing has to be requested and enabled on the link */
|
||||
if (responder_distribution.get_signing()) {
|
||||
responder_distribution.set_signing(
|
||||
cb->signing_override_default ? cb->signing_requested : _default_key_distribution.get_signing()
|
||||
cb->signing_override_default ?
|
||||
cb->signing_requested :
|
||||
_default_key_distribution.get_signing()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -322,18 +356,24 @@ ble_error_t GenericSecurityManager::enableSigning(
|
|||
connection_handle_t connection,
|
||||
bool enabled
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
cb->signing_override_default = true;
|
||||
|
||||
if (enabled && !cb->signing_requested && !_default_key_distribution.get_signing()) {
|
||||
cb->signing_requested = true;
|
||||
if (cb->csrk_stored) {
|
||||
if (flags->csrk_stored) {
|
||||
/* used the stored ones when available */
|
||||
_db.get_entry_peer_csrk(
|
||||
_db->get_entry_peer_csrk(
|
||||
mbed::callback(this, &GenericSecurityManager::set_peer_csrk_cb),
|
||||
cb->db_entry
|
||||
);
|
||||
|
@ -366,15 +406,24 @@ ble_error_t GenericSecurityManager::getLinkEncryption(
|
|||
connection_handle_t connection,
|
||||
link_encryption_t *encryption
|
||||
) {
|
||||
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (cb->encrypted) {
|
||||
if (cb->ltk_mitm_protected || cb->mitm_performed) {
|
||||
*encryption = link_encryption_t::ENCRYPTED_WITH_MITM;
|
||||
if (flags->ltk_mitm_protected || cb->mitm_performed) {
|
||||
if (flags->secure_connections_paired) {
|
||||
*encryption = link_encryption_t::ENCRYPTED_WITH_SC_AND_MITM;
|
||||
} else {
|
||||
*encryption = link_encryption_t::ENCRYPTED_WITH_MITM;
|
||||
}
|
||||
} else {
|
||||
*encryption = link_encryption_t::ENCRYPTED;
|
||||
}
|
||||
|
@ -391,11 +440,17 @@ ble_error_t GenericSecurityManager::setLinkEncryption(
|
|||
connection_handle_t connection,
|
||||
link_encryption_t encryption
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
link_encryption_t current_encryption(link_encryption_t::NOT_ENCRYPTED);
|
||||
getLinkEncryption(connection, ¤t_encryption);
|
||||
|
||||
|
@ -408,20 +463,34 @@ ble_error_t GenericSecurityManager::setLinkEncryption(
|
|||
/* ignore if the link is already at required state*/
|
||||
|
||||
} else if (encryption == link_encryption_t::NOT_ENCRYPTED) {
|
||||
|
||||
/* ignore if we are requesting an open link on an already encrypted link */
|
||||
|
||||
// Fail as it is not permitted to turn down encryption
|
||||
return BLE_ERROR_OPERATION_NOT_PERMITTED;
|
||||
} else if (encryption == link_encryption_t::ENCRYPTED) {
|
||||
|
||||
/* only change if we're not already encrypted with mitm */
|
||||
if (current_encryption != link_encryption_t::ENCRYPTED_WITH_MITM) {
|
||||
if (current_encryption != link_encryption_t::ENCRYPTED_WITH_MITM ||
|
||||
current_encryption != link_encryption_t::ENCRYPTED_WITH_SC_AND_MITM
|
||||
) {
|
||||
cb->encryption_requested = true;
|
||||
return enable_encryption(connection);
|
||||
}
|
||||
|
||||
} else if (encryption == link_encryption_t::ENCRYPTED_WITH_MITM) {
|
||||
|
||||
if (cb->ltk_mitm_protected && !cb->encrypted) {
|
||||
if (flags->ltk_mitm_protected && !cb->encrypted) {
|
||||
cb->encryption_requested = true;
|
||||
return enable_encryption(connection);
|
||||
} else {
|
||||
cb->encryption_requested = true;
|
||||
return requestAuthentication(connection);
|
||||
}
|
||||
|
||||
} else if (encryption == link_encryption_t::ENCRYPTED_WITH_SC_AND_MITM) {
|
||||
|
||||
if (flags->ltk_mitm_protected &&
|
||||
flags->secure_connections_paired &&
|
||||
!cb->encrypted
|
||||
) {
|
||||
cb->encryption_requested = true;
|
||||
return enable_encryption(connection);
|
||||
} else {
|
||||
|
@ -442,13 +511,19 @@ ble_error_t GenericSecurityManager::getEncryptionKeySize(
|
|||
connection_handle_t connection,
|
||||
uint8_t *size
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (cb) {
|
||||
*size = cb->encryption_key_size;
|
||||
return BLE_ERROR_NONE;
|
||||
} else {
|
||||
if (!cb) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
*size = flags->encryption_key_size;
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t GenericSecurityManager::setEncryptionKeyRequirements(
|
||||
|
@ -463,15 +538,21 @@ ble_error_t GenericSecurityManager::setEncryptionKeyRequirements(
|
|||
//
|
||||
|
||||
ble_error_t GenericSecurityManager::getSigningKey(connection_handle_t connection, bool authenticated) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (cb->csrk_stored && (cb->csrk_mitm_protected || !authenticated)) {
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (flags->csrk_stored && (flags->csrk_mitm_protected || !authenticated)) {
|
||||
/* we have a key that is either authenticated or we don't care if it is
|
||||
* so retrieve it from the db now */
|
||||
_db.get_entry_peer_csrk(
|
||||
_db->get_entry_peer_csrk(
|
||||
mbed::callback(this, &GenericSecurityManager::return_csrk_cb),
|
||||
cb->db_entry
|
||||
);
|
||||
|
@ -503,12 +584,18 @@ ble_error_t GenericSecurityManager::setPrivateAddressTimeout(uint16_t timeout_in
|
|||
//
|
||||
|
||||
ble_error_t GenericSecurityManager::requestAuthentication(connection_handle_t connection) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (cb->ltk_mitm_protected) {
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (flags->ltk_mitm_protected) {
|
||||
if (cb->authenticated) {
|
||||
return BLE_ERROR_NONE;
|
||||
} else {
|
||||
|
@ -614,16 +701,22 @@ ble_error_t GenericSecurityManager::legacyPairingOobReceived(
|
|||
const address_t *address,
|
||||
const oob_tk_t *tk
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
if (address && tk) {
|
||||
ControlBlock_t *cb = get_control_block(*address);
|
||||
if (!cb) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
_oob_temporary_key = *tk;
|
||||
_oob_temporary_key_creator_address = *address;
|
||||
|
||||
if (cb->peer_address == _oob_temporary_key_creator_address) {
|
||||
if (flags->peer_address == _oob_temporary_key_creator_address) {
|
||||
cb->attempt_oob = true;
|
||||
}
|
||||
|
||||
|
@ -658,8 +751,9 @@ ble_error_t GenericSecurityManager::oobReceived(
|
|||
//
|
||||
|
||||
ble_error_t GenericSecurityManager::init_signing() {
|
||||
const csrk_t *pcsrk = _db.get_local_csrk();
|
||||
sign_count_t local_sign_counter = _db.get_local_sign_counter();
|
||||
MBED_ASSERT(_db);
|
||||
const csrk_t *pcsrk = _db->get_local_csrk();
|
||||
sign_count_t local_sign_counter = _db->get_local_sign_counter();
|
||||
|
||||
if (!pcsrk) {
|
||||
csrk_t csrk;
|
||||
|
@ -670,8 +764,8 @@ ble_error_t GenericSecurityManager::init_signing() {
|
|||
}
|
||||
|
||||
pcsrk = &csrk;
|
||||
_db.set_local_csrk(csrk);
|
||||
_db.set_local_sign_counter(local_sign_counter);
|
||||
_db->set_local_csrk(csrk);
|
||||
_db->set_local_sign_counter(local_sign_counter);
|
||||
}
|
||||
|
||||
return _pal.set_csrk(*pcsrk, local_sign_counter);
|
||||
|
@ -707,13 +801,20 @@ ble_error_t GenericSecurityManager::slave_security_request(connection_handle_t c
|
|||
}
|
||||
|
||||
ble_error_t GenericSecurityManager::enable_encryption(connection_handle_t connection) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (cb->is_master) {
|
||||
if (cb->ltk_stored) {
|
||||
_db.get_entry_peer_keys(
|
||||
if (flags->ltk_stored) {
|
||||
_db->get_entry_peer_keys(
|
||||
mbed::callback(this, &GenericSecurityManager::enable_encryption_cb),
|
||||
cb->db_entry
|
||||
);
|
||||
|
@ -727,85 +828,121 @@ ble_error_t GenericSecurityManager::enable_encryption(connection_handle_t connec
|
|||
}
|
||||
|
||||
void GenericSecurityManager::enable_encryption_cb(
|
||||
pal::SecurityDb::entry_handle_t db_entry,
|
||||
SecurityDb::entry_handle_t db_entry,
|
||||
const SecurityEntryKeys_t* entryKeys
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(db_entry);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cb && entryKeys) {
|
||||
if (cb->secure_connections_paired) {
|
||||
_pal.enable_encryption(cb->connection, entryKeys->ltk, cb->ltk_mitm_protected);
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (entryKeys) {
|
||||
if (flags->secure_connections_paired) {
|
||||
_pal.enable_encryption(cb->connection, entryKeys->ltk, flags->ltk_mitm_protected);
|
||||
} else {
|
||||
_pal.enable_encryption(cb->connection, entryKeys->ltk, entryKeys->rand, entryKeys->ediv, cb->ltk_mitm_protected);
|
||||
_pal.enable_encryption(cb->connection, entryKeys->ltk, entryKeys->rand, entryKeys->ediv, flags->ltk_mitm_protected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GenericSecurityManager::set_ltk_cb(
|
||||
pal::SecurityDb::entry_handle_t db_entry,
|
||||
SecurityDb::entry_handle_t db_entry,
|
||||
const SecurityEntryKeys_t* entryKeys
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(db_entry);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cb) {
|
||||
if (entryKeys) {
|
||||
_pal.set_ltk(cb->connection, entryKeys->ltk, cb->ltk_mitm_protected, cb->secure_connections_paired);
|
||||
} else {
|
||||
_pal.set_ltk_not_found(cb->connection);
|
||||
}
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (entryKeys) {
|
||||
_pal.set_ltk(
|
||||
cb->connection,
|
||||
entryKeys->ltk,
|
||||
flags->ltk_mitm_protected,
|
||||
flags->secure_connections_paired
|
||||
);
|
||||
} else {
|
||||
_pal.set_ltk_not_found(cb->connection);
|
||||
}
|
||||
}
|
||||
|
||||
void GenericSecurityManager::set_peer_csrk_cb(
|
||||
pal::SecurityDb::entry_handle_t db_entry,
|
||||
const csrk_t *csrk,
|
||||
sign_count_t sign_counter
|
||||
SecurityDb::entry_handle_t db_entry,
|
||||
const SecurityEntrySigning_t* signing
|
||||
) {
|
||||
ControlBlock_t *cb = get_control_block(db_entry);
|
||||
if (!cb) {
|
||||
if (!cb || !signing) {
|
||||
return;
|
||||
}
|
||||
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
_pal.set_peer_csrk(
|
||||
cb->connection,
|
||||
*csrk,
|
||||
cb->csrk_mitm_protected,
|
||||
sign_counter
|
||||
signing->csrk,
|
||||
flags->csrk_mitm_protected,
|
||||
signing->counter
|
||||
);
|
||||
}
|
||||
|
||||
void GenericSecurityManager::return_csrk_cb(
|
||||
pal::SecurityDb::entry_handle_t db_entry,
|
||||
const csrk_t *csrk,
|
||||
sign_count_t sign_counter
|
||||
SecurityDb::entry_handle_t db_entry,
|
||||
const SecurityEntrySigning_t *signing
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(db_entry);
|
||||
if (!cb) {
|
||||
if (!cb || !signing) {
|
||||
return;
|
||||
}
|
||||
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
eventHandler->signingKey(
|
||||
cb->connection,
|
||||
csrk,
|
||||
cb->csrk_mitm_protected
|
||||
&signing->csrk,
|
||||
flags->csrk_mitm_protected
|
||||
);
|
||||
}
|
||||
|
||||
void GenericSecurityManager::update_oob_presence(connection_handle_t connection) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* if we support secure connection we only care about secure connections oob data */
|
||||
if (_default_authentication.get_secure_connections()) {
|
||||
cb->oob_present = (cb->peer_address == _oob_peer_address);
|
||||
cb->oob_present = (flags->peer_address == _oob_peer_address);
|
||||
} else {
|
||||
/* otherwise for legacy pairing we first set the oob based on set preference */
|
||||
cb->oob_present = cb->attempt_oob;
|
||||
|
||||
/* and also turn it on if we have oob data for legacy pairing */
|
||||
if (cb->peer_address == _oob_temporary_key_creator_address
|
||||
if (flags->peer_address == _oob_temporary_key_creator_address
|
||||
|| cb->local_address == _oob_temporary_key_creator_address) {
|
||||
cb->oob_present = true;
|
||||
}
|
||||
|
@ -833,34 +970,30 @@ void GenericSecurityManager::on_connected(
|
|||
const BLEProtocol::AddressBytes_t local_address,
|
||||
const Gap::ConnectionParams_t *connection_params
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = acquire_control_block(connection);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
// setup the control block
|
||||
cb->peer_address = peer_address;
|
||||
cb->local_address = local_address;
|
||||
cb->peer_address_is_public =
|
||||
(peer_address_type == BLEProtocol::AddressType::PUBLIC);
|
||||
cb->is_master = (role == Gap::CENTRAL);
|
||||
|
||||
// get the associated db handle and the distribution flags if any
|
||||
cb->db_entry = _db.open_entry(peer_address_type, peer_address);
|
||||
cb->db_entry = _db->open_entry(peer_address_type, peer_address);
|
||||
|
||||
const pal::SecurityDistributionFlags_t* dist_flags =
|
||||
_db.get_distribution_flags(cb->db_entry);
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
|
||||
if (dist_flags) {
|
||||
*static_cast<pal::SecurityDistributionFlags_t*>(cb) = *dist_flags;
|
||||
}
|
||||
flags->peer_address = peer_address;
|
||||
flags->peer_address_is_public = (peer_address_type == BLEProtocol::AddressType::PUBLIC);
|
||||
|
||||
const bool signing = cb->signing_override_default ?
|
||||
cb->signing_requested :
|
||||
_default_key_distribution.get_signing();
|
||||
|
||||
if (signing && cb->csrk_stored) {
|
||||
_db.get_entry_peer_csrk(
|
||||
if (signing && flags->csrk_stored) {
|
||||
_db->get_entry_peer_csrk(
|
||||
mbed::callback(this, &GenericSecurityManager::set_peer_csrk_cb),
|
||||
cb->db_entry
|
||||
);
|
||||
|
@ -871,20 +1004,21 @@ void GenericSecurityManager::on_disconnected(
|
|||
connection_handle_t connection,
|
||||
Gap::DisconnectionReason_t reason
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
_db.close_entry(cb->db_entry);
|
||||
release_control_block(cb);
|
||||
_pal.remove_peer_csrk(connection);
|
||||
|
||||
_db.sync();
|
||||
_db->close_entry(cb->db_entry);
|
||||
release_control_block(cb);
|
||||
}
|
||||
|
||||
void GenericSecurityManager::on_security_entry_retrieved(
|
||||
pal::SecurityDb::entry_handle_t entry,
|
||||
const pal::SecurityEntryIdentity_t* identity
|
||||
SecurityDb::entry_handle_t entry,
|
||||
const SecurityEntryIdentity_t* identity
|
||||
) {
|
||||
if (!identity) {
|
||||
return;
|
||||
|
@ -902,7 +1036,7 @@ void GenericSecurityManager::on_security_entry_retrieved(
|
|||
}
|
||||
|
||||
void GenericSecurityManager::on_identity_list_retrieved(
|
||||
ble::ArrayView<pal::SecurityEntryIdentity_t*>& identity_list,
|
||||
ble::ArrayView<SecurityEntryIdentity_t>& identity_list,
|
||||
size_t count
|
||||
) {
|
||||
typedef advertising_peer_address_type_t address_type_t;
|
||||
|
@ -910,11 +1044,11 @@ void GenericSecurityManager::on_identity_list_retrieved(
|
|||
_pal.clear_resolving_list();
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
_pal.add_device_to_resolving_list(
|
||||
identity_list[i]->identity_address_is_public ?
|
||||
identity_list[i].identity_address_is_public ?
|
||||
address_type_t::PUBLIC_ADDRESS :
|
||||
address_type_t::RANDOM_ADDRESS,
|
||||
identity_list[i]->identity_address,
|
||||
identity_list[i]->irk
|
||||
identity_list[i].identity_address,
|
||||
identity_list[i].irk
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -989,11 +1123,10 @@ void GenericSecurityManager::on_pairing_timed_out(connection_handle_t connection
|
|||
}
|
||||
|
||||
void GenericSecurityManager::on_pairing_completed(connection_handle_t connection) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (cb) {
|
||||
// set the distribution flags in the db
|
||||
_db.set_distribution_flags(cb->db_entry, *cb);
|
||||
_db.get_entry_identity(
|
||||
_db->get_entry_identity(
|
||||
mbed::callback(this, &GenericSecurityManager::on_security_entry_retrieved),
|
||||
cb->db_entry
|
||||
);
|
||||
|
@ -1017,11 +1150,12 @@ void GenericSecurityManager::on_signed_write_received(
|
|||
connection_handle_t connection,
|
||||
sign_count_t sign_counter
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
_db.set_entry_peer_sign_counter(cb->db_entry, sign_counter);
|
||||
_db->set_entry_peer_sign_counter(cb->db_entry, sign_counter);
|
||||
}
|
||||
|
||||
void GenericSecurityManager::on_signed_write_verification_failure(
|
||||
|
@ -1050,26 +1184,33 @@ void GenericSecurityManager::on_signed_write_verification_failure(
|
|||
}
|
||||
|
||||
void GenericSecurityManager::on_signed_write() {
|
||||
_db.set_local_sign_counter(_db.get_local_sign_counter() + 1);
|
||||
MBED_ASSERT(_db);
|
||||
_db->set_local_sign_counter(_db->get_local_sign_counter() + 1);
|
||||
}
|
||||
|
||||
void GenericSecurityManager::on_slave_security_request(
|
||||
connection_handle_t connection,
|
||||
AuthenticationMask authentication
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool pairing_required = false;
|
||||
|
||||
if (authentication.get_secure_connections() && !cb->secure_connections_paired
|
||||
if (authentication.get_secure_connections() && !flags->secure_connections_paired
|
||||
&& _default_authentication.get_secure_connections()) {
|
||||
pairing_required = true;
|
||||
}
|
||||
|
||||
if (authentication.get_mitm() && !cb->ltk_mitm_protected) {
|
||||
if (authentication.get_mitm() && !flags->ltk_mitm_protected) {
|
||||
pairing_required = true;
|
||||
cb->mitm_requested = true;
|
||||
}
|
||||
|
@ -1102,7 +1243,10 @@ void GenericSecurityManager::on_link_encryption_result(
|
|||
cb->encryption_failed = false;
|
||||
cb->encrypted = true;
|
||||
|
||||
} else if (result == link_encryption_t::ENCRYPTED_WITH_MITM) {
|
||||
} else if (
|
||||
result == link_encryption_t::ENCRYPTED_WITH_MITM ||
|
||||
result == link_encryption_t::ENCRYPTED_WITH_SC_AND_MITM
|
||||
) {
|
||||
|
||||
cb->encryption_requested = false;
|
||||
cb->encryption_failed = false;
|
||||
|
@ -1171,7 +1315,12 @@ void GenericSecurityManager::on_secure_connections_oob_request(connection_handle
|
|||
return;
|
||||
}
|
||||
|
||||
if (cb->peer_address == _oob_peer_address) {
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags->peer_address == _oob_peer_address) {
|
||||
_pal.secure_connections_oob_request_reply(connection, _oob_local_random, _oob_peer_random, _oob_peer_confirm);
|
||||
/* do not re-use peer OOB */
|
||||
set_all_zeros(_oob_peer_address);
|
||||
|
@ -1181,19 +1330,25 @@ void GenericSecurityManager::on_secure_connections_oob_request(connection_handle
|
|||
}
|
||||
|
||||
void GenericSecurityManager::on_legacy_pairing_oob_request(connection_handle_t connection) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cb->peer_address == _oob_temporary_key_creator_address
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags->peer_address == _oob_temporary_key_creator_address
|
||||
|| cb->local_address == _oob_temporary_key_creator_address) {
|
||||
|
||||
set_mitm_performed(connection);
|
||||
_pal.legacy_pairing_oob_request_reply(connection, _oob_temporary_key);
|
||||
|
||||
/* do not re-use peer OOB */
|
||||
if (cb->peer_address == _oob_temporary_key_creator_address) {
|
||||
if (flags->peer_address == _oob_temporary_key_creator_address) {
|
||||
set_all_zeros(_oob_temporary_key_creator_address);
|
||||
}
|
||||
|
||||
|
@ -1221,27 +1376,41 @@ void GenericSecurityManager::on_secure_connections_ltk_generated(
|
|||
connection_handle_t connection,
|
||||
const ltk_t <k
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
cb->ltk_mitm_protected = cb->mitm_performed;
|
||||
cb->secure_connections_paired = true;
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
_db.set_entry_peer_ltk(cb->db_entry, ltk);
|
||||
flags->ltk_mitm_protected = cb->mitm_performed;
|
||||
flags->secure_connections_paired = true;
|
||||
|
||||
_db->set_entry_peer_ltk(cb->db_entry, ltk);
|
||||
}
|
||||
|
||||
void GenericSecurityManager::on_keys_distributed_ltk(
|
||||
connection_handle_t connection,
|
||||
const ltk_t <k
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
cb->ltk_mitm_protected = cb->mitm_performed;
|
||||
_db.set_entry_peer_ltk(cb->db_entry, ltk);
|
||||
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
flags->ltk_mitm_protected = cb->mitm_performed;
|
||||
|
||||
_db->set_entry_peer_ltk(cb->db_entry, ltk);
|
||||
}
|
||||
|
||||
void GenericSecurityManager::on_keys_distributed_ediv_rand(
|
||||
|
@ -1249,24 +1418,31 @@ void GenericSecurityManager::on_keys_distributed_ediv_rand(
|
|||
const ediv_t &ediv,
|
||||
const rand_t &rand
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
_db.set_entry_peer_ediv_rand(cb->db_entry, ediv, rand);
|
||||
_db->set_entry_peer_ediv_rand(cb->db_entry, ediv, rand);
|
||||
}
|
||||
|
||||
void GenericSecurityManager::on_keys_distributed_local_ltk(
|
||||
connection_handle_t connection,
|
||||
const ltk_t <k
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
_db.set_entry_local_ltk(cb->db_entry, ltk);
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
_db->set_entry_local_ltk(cb->db_entry, ltk);
|
||||
}
|
||||
|
||||
void GenericSecurityManager::on_keys_distributed_local_ediv_rand(
|
||||
|
@ -1274,24 +1450,31 @@ void GenericSecurityManager::on_keys_distributed_local_ediv_rand(
|
|||
const ediv_t &ediv,
|
||||
const rand_t &rand
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
_db.set_entry_local_ediv_rand(cb->db_entry, ediv, rand);
|
||||
_db->set_entry_local_ediv_rand(cb->db_entry, ediv, rand);
|
||||
}
|
||||
|
||||
void GenericSecurityManager::on_keys_distributed_irk(
|
||||
connection_handle_t connection,
|
||||
const irk_t &irk
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
_db.set_entry_peer_irk(cb->db_entry, irk);
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
_db->set_entry_peer_irk(cb->db_entry, irk);
|
||||
}
|
||||
|
||||
void GenericSecurityManager::on_keys_distributed_bdaddr(
|
||||
|
@ -1299,12 +1482,13 @@ void GenericSecurityManager::on_keys_distributed_bdaddr(
|
|||
advertising_peer_address_type_t peer_address_type,
|
||||
const address_t &peer_identity_address
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
_db.set_entry_peer_bdaddr(
|
||||
_db->set_entry_peer_bdaddr(
|
||||
cb->db_entry,
|
||||
(peer_address_type == advertising_peer_address_type_t::PUBLIC_ADDRESS),
|
||||
peer_identity_address
|
||||
|
@ -1315,19 +1499,24 @@ void GenericSecurityManager::on_keys_distributed_csrk(
|
|||
connection_handle_t connection,
|
||||
const csrk_t &csrk
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
cb->csrk_mitm_protected = cb->mitm_performed;
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
_db.set_entry_peer_csrk(cb->db_entry, csrk);
|
||||
flags->csrk_mitm_protected = cb->mitm_performed;
|
||||
_db->set_entry_peer_csrk(cb->db_entry, csrk);
|
||||
|
||||
eventHandler->signingKey(
|
||||
connection,
|
||||
&csrk,
|
||||
cb->csrk_mitm_protected
|
||||
flags->csrk_mitm_protected
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1336,23 +1525,30 @@ void GenericSecurityManager::on_ltk_request(
|
|||
const ediv_t &ediv,
|
||||
const rand_t &rand
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
_db.get_entry_local_keys(
|
||||
mbed::callback(this, &GenericSecurityManager::set_ltk_cb),
|
||||
cb->db_entry,
|
||||
ediv,
|
||||
rand
|
||||
);
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (!flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags->ltk_stored) {
|
||||
_db->get_entry_local_keys(
|
||||
mbed::callback(this, &GenericSecurityManager::set_ltk_cb),
|
||||
cb->db_entry,
|
||||
ediv,
|
||||
rand
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* control blocks list management */
|
||||
|
||||
GenericSecurityManager::ControlBlock_t::ControlBlock_t() :
|
||||
pal::SecurityDistributionFlags_t(),
|
||||
connection(0),
|
||||
db_entry(0),
|
||||
local_address(),
|
||||
|
@ -1374,12 +1570,13 @@ GenericSecurityManager::ControlBlock_t::ControlBlock_t() :
|
|||
|
||||
void GenericSecurityManager::on_ltk_request(connection_handle_t connection)
|
||||
{
|
||||
MBED_ASSERT(_db);
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
_db.get_entry_local_keys(
|
||||
_db->get_entry_local_keys(
|
||||
mbed::callback(this, &GenericSecurityManager::set_ltk_cb),
|
||||
cb->db_entry
|
||||
);
|
||||
|
@ -1417,18 +1614,21 @@ GenericSecurityManager::ControlBlock_t* GenericSecurityManager::get_control_bloc
|
|||
GenericSecurityManager::ControlBlock_t* GenericSecurityManager::get_control_block(
|
||||
const address_t &peer_address
|
||||
) {
|
||||
MBED_ASSERT(_db);
|
||||
for (size_t i = 0; i < MAX_CONTROL_BLOCKS; i++) {
|
||||
if (!_control_blocks[i].connected) {
|
||||
continue;
|
||||
} else if (peer_address == _control_blocks[i].peer_address) {
|
||||
return &_control_blocks[i];
|
||||
ControlBlock_t *cb = &_control_blocks[i];
|
||||
if (cb->connected) {
|
||||
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
|
||||
if (flags && (flags->peer_address == peer_address)) {
|
||||
return cb;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GenericSecurityManager::ControlBlock_t* GenericSecurityManager::get_control_block(
|
||||
pal::SecurityDb::entry_handle_t db_entry
|
||||
SecurityDb::entry_handle_t db_entry
|
||||
) {
|
||||
for (size_t i = 0; i < MAX_CONTROL_BLOCKS; i++) {
|
||||
if (!_control_blocks[i].connected) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -25,12 +25,27 @@
|
|||
#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
|
||||
|
@ -38,6 +53,9 @@ namespace cordio {
|
|||
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.
|
||||
|
@ -159,36 +177,74 @@ public:
|
|||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
pal::SigningEventMonitor::EventHandler *_signing_event_handler;
|
||||
|
||||
attsCccSet_t cccSet[MAX_CCC_CNT];
|
||||
uint16_t cccValues[MAX_CCC_CNT];
|
||||
uint16_t cccHandles[MAX_CCC_CNT];
|
||||
uint8_t cccCnt;
|
||||
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() { }
|
||||
|
||||
/**
|
||||
|
@ -348,6 +350,9 @@ public:
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// pass events not handled to the server side
|
||||
ble::vendor::cordio::GattServer::getInstance().att_cb(event);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "wsf_os.h"
|
||||
#include "sec_api.h"
|
||||
#include "smp_defs.h"
|
||||
#include "cfg_stack.h"
|
||||
|
||||
namespace ble {
|
||||
namespace pal {
|
||||
|
@ -252,6 +253,8 @@ public:
|
|||
sign_count_t sign_counter
|
||||
);
|
||||
|
||||
virtual ble_error_t remove_peer_csrk(connection_handle_t connection);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Authentication
|
||||
//
|
||||
|
@ -353,6 +356,8 @@ private:
|
|||
// 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;
|
||||
|
@ -360,6 +365,9 @@ private:
|
|||
|
||||
PrivacyControlBlock* _pending_privacy_control_blocks;
|
||||
bool _processing_privacy_control_block;
|
||||
irk_t _irk;
|
||||
csrk_t _csrk;
|
||||
csrk_t* _peer_csrks[DM_CONN_MAX];
|
||||
};
|
||||
|
||||
} // cordio
|
||||
|
|
|
@ -205,11 +205,9 @@ generic::GenericGattClient& BLE::getGattClient()
|
|||
|
||||
SecurityManager& BLE::getSecurityManager()
|
||||
{
|
||||
static pal::MemorySecurityDb m_db;
|
||||
static SigningEventMonitorProxy signing_event_monitor(*this);
|
||||
static generic::GenericSecurityManager m_instance(
|
||||
pal::vendor::cordio::CordioSecurityManager::get_security_manager(),
|
||||
m_db,
|
||||
getGap(),
|
||||
signing_event_monitor
|
||||
);
|
||||
|
@ -356,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
|
@ -36,7 +36,8 @@ CordioSecurityManager::CordioSecurityManager() :
|
|||
_lesc_keys_generated(false),
|
||||
_public_key_x(),
|
||||
_pending_privacy_control_blocks(NULL),
|
||||
_processing_privacy_control_block(false)
|
||||
_processing_privacy_control_block(false),
|
||||
_peer_csrks()
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -56,6 +57,7 @@ ble_error_t CordioSecurityManager::initialize()
|
|||
_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
|
||||
|
@ -68,11 +70,13 @@ ble_error_t CordioSecurityManager::initialize()
|
|||
|
||||
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;
|
||||
}
|
||||
|
@ -293,7 +297,8 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -301,8 +306,11 @@ 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);
|
||||
DmSecSetLocalCsrk(const_cast<uint8_t*>(csrk.data()));
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
@ -312,9 +320,40 @@ ble_error_t CordioSecurityManager::set_peer_csrk(
|
|||
bool authenticated,
|
||||
sign_count_t sign_counter
|
||||
) {
|
||||
AttsSetCsrk(connection, const_cast<uint8_t*>(csrk.data()));
|
||||
AttsSetSignCounter(connection, 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -910,6 +949,14 @@ void CordioSecurityManager::process_privacy_control_blocks(bool cb_completed)
|
|||
_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.
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -602,6 +602,11 @@ ble_error_t nRF5xSecurityManager::set_peer_csrk(
|
|||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
ble_error_t nRF5xSecurityManager::remove_peer_csrk(connection_handle_t connection)
|
||||
{
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Authentication
|
||||
//
|
||||
|
|
|
@ -284,6 +284,11 @@ public:
|
|||
sign_count_t sign_counter
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::remove_peer_csrk
|
||||
*/
|
||||
virtual ble_error_t remove_peer_csrk(connection_handle_t connection);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Authentication
|
||||
|
|
|
@ -208,7 +208,6 @@ SecurityManager& nRF5xn::getSecurityManager()
|
|||
|
||||
const SecurityManager& nRF5xn::getSecurityManager() const
|
||||
{
|
||||
static ble::pal::MemorySecurityDb m_db;
|
||||
ble::pal::vendor::nordic::nRF5xSecurityManager &m_pal =
|
||||
ble::pal::vendor::nordic::nRF5xSecurityManager::get_security_manager();
|
||||
static struct : ble::pal::SigningEventMonitor {
|
||||
|
@ -217,7 +216,6 @@ const SecurityManager& nRF5xn::getSecurityManager() const
|
|||
|
||||
static ble::generic::GenericSecurityManager m_instance(
|
||||
m_pal,
|
||||
m_db,
|
||||
const_cast<nRF5xGap&>(getGap()),
|
||||
dummy_signing_event_monitor
|
||||
);
|
||||
|
@ -233,8 +231,12 @@ nRF5xn::waitForEvent(void)
|
|||
}
|
||||
|
||||
void nRF5xn::processEvents() {
|
||||
core_util_critical_section_enter();
|
||||
if (isEventsSignaled) {
|
||||
isEventsSignaled = false;
|
||||
core_util_critical_section_exit();
|
||||
intern_softdevice_events_execute();
|
||||
} else {
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "ble/BLEInstanceBase.h"
|
||||
#include "ble/generic/GenericGattClient.h"
|
||||
#include "ble/generic/GenericSecurityManager.h"
|
||||
#include "ble/pal/MemorySecurityDb.h"
|
||||
#include "ble/pal/SimpleEventQueue.h"
|
||||
#include "nRF5xPalSecurityManager.h"
|
||||
|
||||
|
|
|
@ -21,24 +21,12 @@
|
|||
#include "btle_clock.h"
|
||||
|
||||
#include "ble_flash.h"
|
||||
#include "ble_conn_params.h"
|
||||
|
||||
#include "btle_gap.h"
|
||||
#include "custom/custom_helper.h"
|
||||
|
||||
#include "ble/GapEvents.h"
|
||||
#include "nRF5xn.h"
|
||||
|
||||
// This is a C++ file, so C11 _Static_assert (works with -std=gnu99 on GCC) won't work
|
||||
#undef STATIC_ASSERT_SIMPLE
|
||||
#undef STATIC_ASSERT_MSG
|
||||
|
||||
// FIXME : We can't use mbed_assert.h because we're using these macros within functions
|
||||
#define STATIC_ASSERT_MSG(EXPR, MSG)
|
||||
#define STATIC_ASSERT_SIMPLE(EXPR)
|
||||
|
||||
#warning FIXME : We can't use mbed_assert.h because we're using these within functions
|
||||
|
||||
#ifdef S110
|
||||
#define IS_LEGACY_DEVICE_MANAGER_ENABLED 1
|
||||
#elif defined(S130) || defined(S132)
|
||||
|
@ -52,8 +40,6 @@ extern "C" {
|
|||
#else
|
||||
#include "nrf_fstorage.h"
|
||||
#include "fds.h"
|
||||
#include "peer_manager.h"
|
||||
#include "ble_conn_state.h"
|
||||
#endif
|
||||
|
||||
#include "nrf_sdh.h"
|
||||
|
@ -64,6 +50,16 @@ extern "C" {
|
|||
|
||||
#include "nRF5xPalGattClient.h"
|
||||
|
||||
// This is a C++ file, so C11 _Static_assert (works with -std=gnu99 on GCC) won't work
|
||||
#undef STATIC_ASSERT_SIMPLE
|
||||
#undef STATIC_ASSERT_MSG
|
||||
|
||||
// FIXME : We can't use mbed_assert.h because we're using these macros within functions
|
||||
#define STATIC_ASSERT_MSG(EXPR, MSG)
|
||||
#define STATIC_ASSERT_SIMPLE(EXPR)
|
||||
|
||||
#warning FIXME : We can't use mbed_assert.h because we're using these within functions
|
||||
|
||||
|
||||
// Make this volatile at it will be set in interrupt context
|
||||
volatile bool isEventsSignaled = false;
|
||||
|
@ -76,9 +72,9 @@ 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.
|
||||
|
||||
#if NRF_SDK14PLUS_EVENT_HANDLERS
|
||||
static void btle_handler(const ble_evt_t *p_ble_evt, void *p_context);
|
||||
void btle_handler(const ble_evt_t *p_ble_evt, void *p_context);
|
||||
#else
|
||||
static void btle_handler(ble_evt_t *p_ble_evt);
|
||||
void btle_handler(ble_evt_t *p_ble_evt);
|
||||
#endif
|
||||
|
||||
#if !NRF_SDK14PLUS_EVENT_HANDLERS
|
||||
|
@ -232,9 +228,6 @@ error_t btle_init(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
// 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) {
|
||||
|
@ -243,10 +236,6 @@ error_t btle_init(void)
|
|||
if (sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &addr) != NRF_SUCCESS) {
|
||||
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
|
||||
|
||||
// From SDK 14 onwards event handlers are registered differently
|
||||
|
@ -259,19 +248,20 @@ error_t btle_init(void)
|
|||
ASSERT_STATUS( softdevice_sys_evt_handler_set(sys_evt_dispatch));
|
||||
#endif
|
||||
|
||||
return btle_gap_init();
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
#if NRF_SDK14PLUS_EVENT_HANDLERS
|
||||
static void btle_handler(const ble_evt_t *p_ble_evt, void *p_context)
|
||||
void btle_handler(const ble_evt_t *p_ble_evt, void *p_context)
|
||||
#else
|
||||
static void btle_handler(ble_evt_t *p_ble_evt)
|
||||
void btle_handler(const ble_evt_t *p_ble_evt)
|
||||
#endif
|
||||
{
|
||||
#if NRF_SDK14PLUS_EVENT_HANDLERS
|
||||
(void)p_context; // Keep compiler happy
|
||||
#endif
|
||||
using ble::pal::vendor::nordic::nRF5xGattClient;
|
||||
using ble::pal::vendor::nordic::nRF5xSecurityManager;
|
||||
|
||||
// In SDK14+, all other modules from the SDK will be registered independently as softdevice events observers
|
||||
#if !NRF_SDK14PLUS_EVENT_HANDLERS
|
||||
|
@ -286,9 +276,6 @@ static void btle_handler(ble_evt_t *p_ble_evt)
|
|||
// 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
|
||||
#endif
|
||||
|
||||
|
@ -299,42 +286,16 @@ static void btle_handler(ble_evt_t *p_ble_evt)
|
|||
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<const 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;
|
||||
|
@ -416,10 +377,6 @@ static void btle_handler(ble_evt_t *p_ble_evt)
|
|||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
@ -431,21 +388,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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ extern "C" {
|
|||
|
||||
#include "common/common.h"
|
||||
|
||||
#include "ble_srv_common.h"
|
||||
#include "headers/nrf_ble.h"
|
||||
|
||||
#if NRF_SD_BLE_API_VERSION >= 5
|
||||
|
|
|
@ -1,99 +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.
|
||||
*/
|
||||
#include "common/common.h"
|
||||
|
||||
#include "headers/ble_gap.h"
|
||||
#include "ble_conn_params.h"
|
||||
|
||||
static inline uint32_t msec_to_1_25msec(uint32_t interval_ms) ATTR_ALWAYS_INLINE ATTR_CONST;
|
||||
#if SDK_CONN_PARAMS_MODULE_ENABLE
|
||||
static void error_callback(uint32_t nrf_error);
|
||||
#endif // SDK_CONN_PARAMS_MODULE_ENABLE
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Initialise GAP in the underlying SoftDevice
|
||||
|
||||
@returns
|
||||
*/
|
||||
/**************************************************************************/
|
||||
error_t btle_gap_init(void)
|
||||
{
|
||||
ble_gap_conn_params_t gap_conn_params = {0};
|
||||
|
||||
gap_conn_params.min_conn_interval = msec_to_1_25msec(CFG_GAP_CONNECTION_MIN_INTERVAL_MS); // in 1.25ms units
|
||||
gap_conn_params.max_conn_interval = msec_to_1_25msec(CFG_GAP_CONNECTION_MAX_INTERVAL_MS); // in 1.25ms unit
|
||||
gap_conn_params.slave_latency = CFG_GAP_CONNECTION_SLAVE_LATENCY;
|
||||
gap_conn_params.conn_sup_timeout = CFG_GAP_CONNECTION_SUPERVISION_TIMEOUT_MS / 10; // in 10ms unit
|
||||
|
||||
ble_gap_conn_sec_mode_t sec_mode;
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); // no security is needed
|
||||
|
||||
ASSERT_STATUS( sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *) CFG_GAP_LOCAL_NAME, strlen(CFG_GAP_LOCAL_NAME)));
|
||||
ASSERT_STATUS( sd_ble_gap_appearance_set(CFG_GAP_APPEARANCE));
|
||||
ASSERT_STATUS( sd_ble_gap_ppcp_set(&gap_conn_params));
|
||||
ASSERT_STATUS( sd_ble_gap_tx_power_set(CFG_BLE_TX_POWER_LEVEL));
|
||||
|
||||
/**
|
||||
* Call to conn_params_init() is not necessary; and so is disabled by default.
|
||||
* This API should be exposed to the user to be invoked when necessary.
|
||||
*/
|
||||
#if SDK_CONN_PARAMS_MODULE_ENABLE
|
||||
/* Connection Parameters */
|
||||
enum {
|
||||
FIRST_UPDATE_DELAY = APP_TIMER_TICKS(5000, CFG_TIMER_PRESCALER),
|
||||
NEXT_UPDATE_DELAY = APP_TIMER_TICKS(5000, CFG_TIMER_PRESCALER),
|
||||
MAX_UPDATE_COUNT = 3
|
||||
};
|
||||
|
||||
ble_conn_params_init_t cp_init = {0};
|
||||
|
||||
cp_init.p_conn_params = NULL;
|
||||
cp_init.first_conn_params_update_delay = FIRST_UPDATE_DELAY;
|
||||
cp_init.next_conn_params_update_delay = NEXT_UPDATE_DELAY;
|
||||
cp_init.max_conn_params_update_count = MAX_UPDATE_COUNT;
|
||||
cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID;
|
||||
cp_init.disconnect_on_fail = true;
|
||||
cp_init.evt_handler = NULL;
|
||||
cp_init.error_handler = error_callback;
|
||||
|
||||
ASSERT_STATUS ( ble_conn_params_init(&cp_init));
|
||||
#endif // SDK_CONN_PARAMS_MODULE_ENABLE
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Converts msecs to an integer representing 1.25ms units
|
||||
|
||||
@param[in] ms
|
||||
The number of milliseconds to conver to 1.25ms units
|
||||
|
||||
@returns The number of 1.25ms units in the supplied number of ms
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static inline uint32_t msec_to_1_25msec(uint32_t interval_ms)
|
||||
{
|
||||
return (interval_ms * 4) / 5;
|
||||
}
|
||||
|
||||
#if SDK_CONN_PARAMS_MODULE_ENABLE
|
||||
static void error_callback(uint32_t nrf_error)
|
||||
{
|
||||
ASSERT_STATUS_RET_VOID( nrf_error );
|
||||
}
|
||||
#endif // SDK_CONN_PARAMS_MODULE_ENABLE
|
|
@ -1,24 +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_GAP_H_
|
||||
#define _BTLE_GAP_H_
|
||||
|
||||
#include "common/common.h"
|
||||
|
||||
error_t btle_gap_init(void);
|
||||
|
||||
#endif // ifndef _BTLE_GAP_H_
|
|
@ -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,488 +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"
|
||||
|
||||
extern "C" void ah(uint8_t const * p_k, uint8_t const * p_r, uint8_t * p_local_hash);
|
||||
|
||||
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)
|
|
@ -31,6 +31,32 @@ 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;
|
||||
}
|
||||
|
@ -204,7 +230,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,
|
||||
|
@ -227,8 +255,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};
|
||||
|
@ -257,49 +285,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};
|
||||
|
||||
|
@ -343,7 +330,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};
|
||||
|
@ -353,8 +342,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};
|
||||
|
||||
|
|
|
@ -42,7 +42,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,
|
||||
|
@ -61,7 +63,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,188 @@
|
|||
/* 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"
|
||||
|
||||
#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 {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
#endif //defined(MBEDTLS_ECDH_C)
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
/* 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"
|
||||
|
||||
#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;
|
||||
|
||||
/**
|
||||
* 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
|
||||
);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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:
|
||||
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);
|
||||
|
||||
void swap_endian(uint8_t* buf, size_t len);
|
||||
|
||||
bool _initialized;
|
||||
mbedtls_entropy_context _entropy_context;
|
||||
mbedtls_ecp_group _group;
|
||||
};
|
||||
|
||||
} // nordic
|
||||
} // vendor
|
||||
} // pal
|
||||
} // ble
|
||||
|
||||
#endif // defined(MBEDTLS_ECDH_C)
|
||||
|
||||
#endif // NRF5X_CRYPTO_
|
|
@ -23,20 +23,117 @@
|
|||
#include "ble/BLE.h"
|
||||
|
||||
#include "common/common.h"
|
||||
#include "ble_advdata.h"
|
||||
#include "headers/ble_hci.h"
|
||||
#include "ble/pal/ConnectionEventMonitor.h"
|
||||
#include "nRF5xPalSecurityManager.h"
|
||||
|
||||
#if (NRF_SD_BLE_API_VERSION >= 3)
|
||||
#include "peer_manager.h"
|
||||
#include "peer_data_storage.h"
|
||||
using ble::pal::vendor::nordic::nRF5xSecurityManager;
|
||||
typedef nRF5xSecurityManager::resolving_list_entry_t resolving_list_entry_t;
|
||||
using ble::ArrayView;
|
||||
using ble::pal::advertising_peer_address_type_t;
|
||||
|
||||
namespace {
|
||||
|
||||
nRF5xSecurityManager& get_sm() {
|
||||
return nRF5xSecurityManager::get_security_manager();
|
||||
}
|
||||
|
||||
ble_error_t set_private_resolvable_address() {
|
||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
||||
ble_gap_addr_t addr = {
|
||||
BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE
|
||||
};
|
||||
|
||||
sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_AUTO, &addr);
|
||||
return BLE_ERROR_NONE;
|
||||
#else
|
||||
ble_gap_privacy_params_t privacy_config = { 0 };
|
||||
uint32_t err = sd_ble_gap_privacy_get(&privacy_config);
|
||||
if (err) {
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
|
||||
privacy_config.private_addr_type = BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE;
|
||||
err = sd_ble_gap_privacy_set(&privacy_config);
|
||||
return err ? BLE_ERROR_UNSPECIFIED : BLE_ERROR_NONE;
|
||||
#endif
|
||||
}
|
||||
|
||||
ble_error_t set_private_non_resolvable_address() {
|
||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
||||
ble_gap_addr_t addr = { BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE };
|
||||
sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_AUTO, &addr);
|
||||
#else
|
||||
ble_gap_privacy_params_t privacy_config = { 0 };
|
||||
uint32_t err = sd_ble_gap_privacy_get(&privacy_config);
|
||||
if (err) {
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
|
||||
privacy_config.private_addr_type = BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE;
|
||||
err = sd_ble_gap_privacy_set(&privacy_config);
|
||||
return err ? BLE_ERROR_UNSPECIFIED : BLE_ERROR_NONE;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool is_advertising_non_connectable(const GapAdvertisingParams ¶ms) {
|
||||
switch (params.getAdvertisingType()) {
|
||||
case GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED:
|
||||
case GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_identity_address(BLEProtocol::AddressType_t address_type) {
|
||||
switch (address_type) {
|
||||
case BLEProtocol::AddressType::PUBLIC_IDENTITY:
|
||||
case BLEProtocol::AddressType::RANDOM_STATIC_IDENTITY:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
BLEProtocol::AddressType_t convert_nordic_address(uint8_t address) {
|
||||
if (address == BLE_GAP_ADDR_TYPE_PUBLIC) {
|
||||
return BLEProtocol::AddressType::PUBLIC;
|
||||
} else {
|
||||
return BLEProtocol::AddressType::RANDOM;
|
||||
}
|
||||
}
|
||||
|
||||
BLEProtocol::AddressType_t convert_identity_address(advertising_peer_address_type_t address) {
|
||||
if (address == advertising_peer_address_type_t::PUBLIC_ADDRESS) {
|
||||
return BLEProtocol::AddressType::PUBLIC_IDENTITY;
|
||||
} else {
|
||||
return BLEProtocol::AddressType::RANDOM_STATIC_IDENTITY;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void radioNotificationStaticCallback(bool param) {
|
||||
nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap();
|
||||
gap.processRadioNotificationEvent(param);
|
||||
}
|
||||
|
||||
nRF5xGap::nRF5xGap() : Gap(),
|
||||
advertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST),
|
||||
scanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST),
|
||||
whitelistAddressesSize(0),
|
||||
whitelistAddresses(),
|
||||
radioNotificationCallbackParam(false),
|
||||
radioNotificationTimeout(),
|
||||
_connection_event_handler(NULL),
|
||||
_privacy_enabled(false),
|
||||
_peripheral_privacy_configuration(default_peripheral_privacy_configuration),
|
||||
_central_privacy_configuration(default_central_privacy_configuration),
|
||||
_non_private_address_type(BLEProtocol::AddressType::RANDOM)
|
||||
{
|
||||
m_connectionHandle = BLE_CONN_HANDLE_INVALID;
|
||||
}
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Sets the advertising parameters and payload for the device
|
||||
|
@ -196,6 +293,28 @@ ble_error_t nRF5xGap::startAdvertising(const GapAdvertisingParams ¶ms)
|
|||
}
|
||||
}
|
||||
|
||||
if (_privacy_enabled) {
|
||||
if (_peripheral_privacy_configuration.resolution_strategy != PeripheralPrivacyConfiguration_t::DO_NOT_RESOLVE) {
|
||||
ArrayView<resolving_list_entry_t> entries = get_sm().get_resolving_list();
|
||||
|
||||
size_t limit = std::min(
|
||||
entries.size(), (size_t) YOTTA_CFG_IRK_TABLE_MAX_SIZE
|
||||
);
|
||||
|
||||
for (size_t i = 0; i < limit; ++i) {
|
||||
whitelistIrkPtrs[i] = (ble_gap_irk_t*) entries[i].peer_irk.data();
|
||||
}
|
||||
whitelist.irk_count = limit;
|
||||
}
|
||||
|
||||
if (_peripheral_privacy_configuration.use_non_resolvable_random_address &&
|
||||
is_advertising_non_connectable(params)
|
||||
) {
|
||||
set_private_non_resolvable_address();
|
||||
} else {
|
||||
set_private_resolvable_address();
|
||||
}
|
||||
}
|
||||
adv_para.p_whitelist = &whitelist;
|
||||
#endif
|
||||
/* For NRF_SD_BLE_API_VERSION >= 3 nRF5xGap::setWhitelist setups the whitelist. */
|
||||
|
@ -250,6 +369,7 @@ ble_error_t nRF5xGap::startRadioScan(const GapScanningParams &scanningParams)
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: fill the irk list once addresses are resolved by the softdevice.
|
||||
scanParams.selective = scanningPolicyMode; /**< If 1, ignore unknown devices (non whitelisted). */
|
||||
scanParams.p_whitelist = &whitelist; /**< Pointer to whitelist, NULL if none is given. */
|
||||
#else
|
||||
|
@ -264,6 +384,13 @@ ble_error_t nRF5xGap::startRadioScan(const GapScanningParams &scanningParams)
|
|||
scanParams.interval = scanningParams.getInterval(); /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */
|
||||
scanParams.window = scanningParams.getWindow(); /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */
|
||||
scanParams.timeout = scanningParams.getTimeout(); /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */
|
||||
if (_privacy_enabled) {
|
||||
if (_central_privacy_configuration.use_non_resolvable_random_address) {
|
||||
set_private_non_resolvable_address();
|
||||
} else {
|
||||
set_private_resolvable_address();
|
||||
}
|
||||
}
|
||||
|
||||
if (sd_ble_gap_scan_start(&scanParams) != NRF_SUCCESS) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
|
@ -313,6 +440,7 @@ ble_error_t nRF5xGap::connect(const Address_t peerAddr,
|
|||
const GapScanningParams *scanParamsIn)
|
||||
{
|
||||
ble_gap_addr_t addr;
|
||||
ble_gap_addr_t* addr_ptr = &addr;
|
||||
addr.addr_type = peerAddrType;
|
||||
memcpy(addr.addr, peerAddr, Gap::ADDR_LEN);
|
||||
|
||||
|
@ -352,6 +480,34 @@ ble_error_t nRF5xGap::connect(const Address_t peerAddr,
|
|||
|
||||
scanParams.selective = scanningPolicyMode; /**< If 1, ignore unknown devices (non whitelisted). */
|
||||
scanParams.p_whitelist = &whitelist; /**< Pointer to whitelist, NULL if none is given. */
|
||||
if (_privacy_enabled) {
|
||||
// configure the "whitelist" with the IRK associated with the identity
|
||||
// address in input.
|
||||
if (is_identity_address(peerAddrType)) {
|
||||
ArrayView<resolving_list_entry_t> entries = get_sm().get_resolving_list();
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < entries.size(); ++i) {
|
||||
const ble::address_t& entry_address = entries[i].peer_identity_address;
|
||||
|
||||
// entry found; fill the whitelist and invalidate addr_ptr
|
||||
if (memcmp(entry_address.data(), peerAddr, entry_address.size_) == 0) {
|
||||
whitelist.pp_irks[0] = (ble_gap_irk_t*) entries[i].peer_irk.data();
|
||||
whitelist.irk_count = 1;
|
||||
scanParams.selective = 1;
|
||||
addr_ptr = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Occur only if the address in input hasn't been resolved.
|
||||
if (i == entries.size()) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
set_private_resolvable_address();
|
||||
}
|
||||
#else
|
||||
/* For NRF_SD_BLE_API_VERSION >= 3 nRF5xGap::setWhitelist setups the whitelist. */
|
||||
|
||||
|
@ -384,9 +540,9 @@ ble_error_t nRF5xGap::connect(const Address_t peerAddr,
|
|||
}
|
||||
|
||||
#if NRF_SD_BLE_API_VERSION >= 5
|
||||
uint32_t rc = sd_ble_gap_connect(&addr, &scanParams, &connParams, NRF_CONNECTION_TAG);
|
||||
uint32_t rc = sd_ble_gap_connect(addr_ptr, &scanParams, &connParams, NRF_CONNECTION_TAG);
|
||||
#else
|
||||
uint32_t rc = sd_ble_gap_connect(&addr, &scanParams, &connParams);
|
||||
uint32_t rc = sd_ble_gap_connect(addr_ptr, &scanParams, &connParams);
|
||||
#endif
|
||||
if (rc == NRF_SUCCESS) {
|
||||
return BLE_ERROR_NONE;
|
||||
|
@ -500,7 +656,6 @@ ble_error_t nRF5xGap::reset(void)
|
|||
/* Clear the internal whitelist */
|
||||
whitelistAddressesSize = 0;
|
||||
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
@ -542,103 +697,75 @@ uint16_t nRF5xGap::getConnectionHandle(void)
|
|||
/**************************************************************************/
|
||||
ble_error_t nRF5xGap::setAddress(AddressType_t type, const Address_t address)
|
||||
{
|
||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
||||
uint8_t cycle_mode;
|
||||
#else
|
||||
ble_gap_privacy_params_t privacy_params = {0};
|
||||
#endif
|
||||
using BLEProtocol::AddressType;
|
||||
|
||||
if (type != AddressType::PUBLIC || type != AddressType::RANDOM_STATIC) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (_privacy_enabled) {
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
ble_gap_addr_t dev_addr;
|
||||
memcpy(dev_addr.addr, address, ADDR_LEN);
|
||||
if (type == AddressType::PUBLIC) {
|
||||
dev_addr.addr_type = BLE_GAP_ADDR_TYPE_PUBLIC;
|
||||
} else {
|
||||
dev_addr.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC;
|
||||
}
|
||||
|
||||
/* When using Public or Static addresses, the cycle mode must be None.
|
||||
When using Random Private addresses, the cycle mode must be Auto.
|
||||
In auto mode, the given address is ignored.
|
||||
*/
|
||||
if ((type == BLEProtocol::AddressType::PUBLIC) || (type == BLEProtocol::AddressType::RANDOM_STATIC))
|
||||
{
|
||||
memcpy(dev_addr.addr, address, ADDR_LEN);
|
||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
||||
cycle_mode = BLE_GAP_ADDR_CYCLE_MODE_NONE;
|
||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
||||
uint32_t err = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &dev_addr);
|
||||
#else
|
||||
privacy_params.privacy_mode = BLE_GAP_PRIVACY_MODE_OFF;
|
||||
dev_addr.addr_type = type;
|
||||
|
||||
ASSERT_INT(ERROR_NONE, pm_id_addr_set(&dev_addr), BLE_ERROR_PARAM_OUT_OF_RANGE);
|
||||
ASSERT_INT(ERROR_NONE, pm_privacy_set(&privacy_params), BLE_ERROR_PARAM_OUT_OF_RANGE);
|
||||
#endif
|
||||
}
|
||||
else if ((type == BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE) || (type == BLEProtocol::AddressType::RANDOM_PRIVATE_NON_RESOLVABLE))
|
||||
{
|
||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
||||
cycle_mode = BLE_GAP_ADDR_CYCLE_MODE_AUTO;
|
||||
#else
|
||||
privacy_params.privacy_mode = BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY;
|
||||
privacy_params.private_addr_type = type;
|
||||
|
||||
ASSERT_INT(ERROR_NONE, pm_privacy_set(&privacy_params), BLE_ERROR_PARAM_OUT_OF_RANGE);
|
||||
#endif
|
||||
// address is ignored when in auto mode
|
||||
}
|
||||
else
|
||||
{
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
||||
dev_addr.addr_type = type;
|
||||
ASSERT_INT(ERROR_NONE, sd_ble_gap_address_set(cycle_mode, &dev_addr), BLE_ERROR_PARAM_OUT_OF_RANGE);
|
||||
uint32_t err = sd_ble_gap_addr_set(&dev_addr);
|
||||
#endif
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
switch (err) {
|
||||
case NRF_SUCCESS:
|
||||
return BLE_ERROR_NONE;
|
||||
case NRF_ERROR_INVALID_ADDR:
|
||||
case BLE_ERROR_GAP_INVALID_BLE_ADDR:
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
case NRF_ERROR_BUSY:
|
||||
return BLE_STACK_BUSY;
|
||||
case NRF_ERROR_INVALID_STATE:
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
default:
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
ble_error_t nRF5xGap::getAddress(AddressType_t *typeP, Address_t address)
|
||||
{
|
||||
ble_gap_addr_t dev_addr;
|
||||
ble_gap_irk_t irk = {0};
|
||||
ble_gap_privacy_params_t privacy_params = {0};
|
||||
privacy_params.p_device_irk = &irk;
|
||||
// FIXME: check if privacy is enabled ?
|
||||
if (typeP == NULL || address == NULL) {
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
ble_gap_addr_t dev_addr;
|
||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
||||
if (sd_ble_gap_address_get(&dev_addr) != NRF_SUCCESS) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
#else
|
||||
// Check privacy mode
|
||||
if( pm_privacy_get(&privacy_params) != NRF_SUCCESS) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
// If in private mode, the address is generated by softdevice, so return a nulled address with correct type
|
||||
if( privacy_params.privacy_mode == BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY )
|
||||
{
|
||||
memset(address, 0, ADDR_LEN);
|
||||
switch( privacy_params.private_addr_type )
|
||||
{
|
||||
case BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE:
|
||||
*typeP = BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE;
|
||||
break;
|
||||
case BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE:
|
||||
default:
|
||||
*typeP = BLEProtocol::AddressType::RANDOM_PRIVATE_NON_RESOLVABLE;
|
||||
break;
|
||||
}
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
// Otherwise recover public/static address
|
||||
if (sd_ble_gap_addr_get(&dev_addr) != NRF_SUCCESS) {
|
||||
#endif
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (typeP != NULL) {
|
||||
*typeP = static_cast<AddressType_t>(dev_addr.addr_type);
|
||||
}
|
||||
if (address != NULL) {
|
||||
memcpy(address, dev_addr.addr, ADDR_LEN);
|
||||
switch (dev_addr.addr_type) {
|
||||
case BLE_GAP_ADDR_TYPE_PUBLIC:
|
||||
*typeP = BLEProtocol::AddressType::PUBLIC;
|
||||
break;
|
||||
|
||||
case BLE_GAP_ADDR_TYPE_RANDOM_STATIC:
|
||||
*typeP = BLEProtocol::AddressType::RANDOM_STATIC;
|
||||
break;
|
||||
|
||||
default:
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
memcpy(address, dev_addr.addr, ADDR_LEN);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
@ -824,17 +951,33 @@ ble_error_t nRF5xGap::setWhitelist(const Gap::Whitelist_t &whitelistIn)
|
|||
}
|
||||
|
||||
whitelistAddressesSize = whitelistIn.size;
|
||||
ble_gap_addr_t* pp_addrs[YOTTA_CFG_WHITELIST_MAX_SIZE];
|
||||
|
||||
for (uint32_t i = 0; i < whitelistIn.size; ++i) {
|
||||
memcpy(&whitelistAddresses[i].addr , &whitelistIn.addresses[i].address , sizeof(whitelistAddresses[0].addr));
|
||||
memcpy(&whitelistAddresses[i].addr, &whitelistIn.addresses[i].address , sizeof(whitelistAddresses[0].addr));
|
||||
whitelistAddresses[i].addr_type = static_cast<uint8_t> (whitelistIn.addresses[i].type);
|
||||
pp_addrs[i] = &whitelistAddresses[i];
|
||||
}
|
||||
|
||||
#if (NRF_SD_BLE_API_VERSION >= 3)
|
||||
updateWhiteAndIdentityListInStack();
|
||||
#endif
|
||||
ble_gap_addr_t** addresses_list_ptr = (whitelistIn.size == 0) ? NULL : pp_addrs;
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
uint32_t err = sd_ble_gap_whitelist_set(addresses_list_ptr, whitelistAddressesSize);
|
||||
|
||||
switch(err) {
|
||||
case NRF_SUCCESS:
|
||||
return BLE_ERROR_NONE;
|
||||
|
||||
case BLE_ERROR_GAP_WHITELIST_IN_USE:
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
|
||||
case NRF_ERROR_INVALID_ADDR:
|
||||
case BLE_ERROR_GAP_INVALID_BLE_ADDR:
|
||||
case NRF_ERROR_DATA_SIZE:
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
|
||||
default:
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
@ -860,7 +1003,6 @@ ble_error_t nRF5xGap::setWhitelist(const Gap::Whitelist_t &whitelistIn)
|
|||
ble_error_t nRF5xGap::setAdvertisingPolicyMode(Gap::AdvertisingPolicyMode_t mode)
|
||||
{
|
||||
advertisingPolicyMode = mode;
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
@ -973,267 +1115,247 @@ Gap::InitiatorPolicyMode_t nRF5xGap::getInitiatorPolicyMode(void) const
|
|||
return Gap::INIT_POLICY_IGNORE_WHITELIST;
|
||||
}
|
||||
|
||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Helper function used to populate the ble_gap_whitelist_t that
|
||||
will be used by the SoftDevice for filtering requests.
|
||||
|
||||
@returns \ref ble_error_t
|
||||
|
||||
@retval BLE_ERROR_NONE
|
||||
Everything executed properly
|
||||
|
||||
@retval BLE_ERROR_INVALID_STATE
|
||||
The internal stack was not initialized correctly.
|
||||
|
||||
@note Both the SecurityManager and Gap must initialize correctly for
|
||||
this function to succeed.
|
||||
|
||||
@note 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.
|
||||
|
||||
@section EXAMPLE
|
||||
|
||||
@code
|
||||
|
||||
@endcode
|
||||
*/
|
||||
/**************************************************************************/
|
||||
ble_error_t nRF5xGap::generateStackWhitelist(ble_gap_whitelist_t &whitelist)
|
||||
ble_error_t nRF5xGap::enablePrivacy(bool enable_privacy)
|
||||
{
|
||||
ble_gap_whitelist_t whitelistFromBondTable;
|
||||
ble_gap_addr_t *addressPtr[1];
|
||||
ble_gap_irk_t *irkPtr[YOTTA_CFG_IRK_TABLE_MAX_SIZE];
|
||||
|
||||
nRF5xSecurityManager& securityManager = (nRF5xSecurityManager&) nRF5xn::Instance(0).getSecurityManager();
|
||||
|
||||
if (securityManager.hasInitialized()) {
|
||||
/* We do not care about the addresses, set the count to 0 */
|
||||
whitelistFromBondTable.addr_count = 0;
|
||||
/* The Nordic SDK will return a failure if we set pp_addr to NULL */
|
||||
whitelistFromBondTable.pp_addrs = addressPtr;
|
||||
/* We want all the IRKs we can get because we do not know which ones match the addresses */
|
||||
whitelistFromBondTable.irk_count = YOTTA_CFG_IRK_TABLE_MAX_SIZE;
|
||||
whitelistFromBondTable.pp_irks = irkPtr;
|
||||
|
||||
/* Use the security manager to get the IRKs from the bond table */
|
||||
ble_error_t error = securityManager.createWhitelistFromBondTable(whitelistFromBondTable);
|
||||
if (error != BLE_ERROR_NONE) {
|
||||
return error;
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* If there is no security manager then we cannot access the bond table,
|
||||
* so disable IRK matching
|
||||
*/
|
||||
whitelistFromBondTable.addr_count = 0;
|
||||
whitelistFromBondTable.irk_count = 0;
|
||||
if (enable_privacy == _privacy_enabled) {
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* For every private resolvable address in the local whitelist check if
|
||||
* there is an IRK for said address in the bond table and add it to the
|
||||
* local IRK list.
|
||||
*/
|
||||
whitelist.irk_count = 0;
|
||||
whitelist.addr_count = 0;
|
||||
for (uint8_t i = 0; i < whitelistAddressesSize; ++i) {
|
||||
if (whitelistAddresses[i].addr_type == BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE) {
|
||||
/* Test if there is a matching IRK for this private resolvable address */
|
||||
for (uint8_t j = 0; j < whitelistFromBondTable.irk_count; ++j) {
|
||||
if (securityManager.matchAddressAndIrk(&whitelistAddresses[i], whitelistFromBondTable.pp_irks[j])) {
|
||||
/* Found the corresponding IRK, add it to our local whitelist */
|
||||
whitelist.pp_irks[whitelist.irk_count] = whitelistFromBondTable.pp_irks[j];
|
||||
whitelist.irk_count++;
|
||||
/* Make sure we do not look at this IRK again */
|
||||
if (j != whitelistFromBondTable.irk_count - 1) {
|
||||
/**
|
||||
* This is not the last IRK, so replace the pointer
|
||||
* with the last pointer in the array
|
||||
*/
|
||||
whitelistFromBondTable.pp_irks[j] =
|
||||
whitelistFromBondTable.pp_irks[whitelistFromBondTable.irk_count - 1];
|
||||
}
|
||||
/**
|
||||
* If the IRK is the last pointer in the array simply
|
||||
* decrement the total IRK count
|
||||
*/
|
||||
whitelistFromBondTable.irk_count--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Include the address into the whitelist */
|
||||
whitelist.pp_addrs[whitelist.addr_count] = &whitelistAddresses[i];
|
||||
whitelist.addr_count++;
|
||||
}
|
||||
}
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (NRF_SD_BLE_API_VERSION >= 3)
|
||||
|
||||
/**
|
||||
* Function for preparing settings of the whitelist feature and the identity-resolving feature (privacy) for the SoftDevice.
|
||||
*
|
||||
* Gap::setWhitelist provides the base for preparation of these settings.
|
||||
* This function matches resolvable addresses (passed by Gap::setWhitelist) to IRK data in bonds table.
|
||||
* Therefore resolvable addresses instead of being passed to the whitelist (intended to be passed to the Softdevice)
|
||||
* are passed to the identities list (intended to be passed to the Softdevice).
|
||||
*
|
||||
* @param[out] gapAdrHelper Reference to the struct for storing settings.
|
||||
*/
|
||||
|
||||
ble_error_t nRF5xGap::getStackWhiteIdentityList(GapWhiteAndIdentityList_t &gapAdrHelper)
|
||||
{
|
||||
pm_peer_id_t peer_id;
|
||||
|
||||
ret_code_t ret;
|
||||
|
||||
pm_peer_data_bonding_t bond_data;
|
||||
|
||||
uint8_t irk_found[YOTTA_CFG_WHITELIST_MAX_SIZE];
|
||||
|
||||
memset(irk_found, 0x00, sizeof(irk_found));
|
||||
|
||||
|
||||
gapAdrHelper.identities_cnt = 0;
|
||||
|
||||
|
||||
peer_id = pm_next_peer_id_get(PM_PEER_ID_INVALID);
|
||||
|
||||
nRF5xSecurityManager& securityManager = (nRF5xSecurityManager&) nRF5xn::Instance(0).getSecurityManager();
|
||||
|
||||
/**
|
||||
* Build identities list:
|
||||
* For every private resolvable address in the bond table check if
|
||||
* there is maching address in th provided whitelist.
|
||||
*/
|
||||
while (peer_id != PM_PEER_ID_INVALID)
|
||||
{
|
||||
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)
|
||||
{
|
||||
for (uint8_t i = 0; i < whitelistAddressesSize; ++i)
|
||||
{
|
||||
if (!irk_found[i])
|
||||
{
|
||||
if (whitelistAddresses[i].addr_type == BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE)
|
||||
{
|
||||
|
||||
//ble_gap_irk_t *p_dfg = &bond_data.peer_ble_id.id_info;
|
||||
if (securityManager.matchAddressAndIrk(&whitelistAddresses[i], &bond_data.peer_ble_id.id_info))
|
||||
{
|
||||
// Copy data to the buffer.
|
||||
memcpy(&gapAdrHelper.identities[i], &bond_data.peer_ble_id, sizeof(ble_gap_id_key_t));
|
||||
gapAdrHelper.identities_cnt++;
|
||||
|
||||
irk_found[i] = 1; // don't look at this address again
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get next peer id
|
||||
peer_id = pm_next_peer_id_get(peer_id);
|
||||
}
|
||||
|
||||
gapAdrHelper.addrs_cnt = 0;
|
||||
|
||||
/**
|
||||
* Build whitelist from the rest of addresses (explicit addresses)
|
||||
*/
|
||||
for (uint8_t i = 0; i < whitelistAddressesSize; ++i)
|
||||
{
|
||||
if (!irk_found[i])
|
||||
{
|
||||
memcpy(&gapAdrHelper.addrs[i], &whitelistAddresses[i], sizeof(ble_gap_addr_t));
|
||||
gapAdrHelper.addrs[i].addr_id_peer = 0;
|
||||
gapAdrHelper.addrs_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t nRF5xGap::applyWhiteIdentityList(GapWhiteAndIdentityList_t &gapAdrHelper)
|
||||
{
|
||||
uint32_t retc;
|
||||
|
||||
if (gapAdrHelper.identities_cnt == 0) {
|
||||
retc = sd_ble_gap_device_identities_set(NULL, NULL, 0);
|
||||
ble_error_t err = BLE_ERROR_UNSPECIFIED;
|
||||
if (enable_privacy == false) {
|
||||
err = setAddress(_non_private_address_type, _non_private_address);
|
||||
} else {
|
||||
ble_gap_id_key_t * pp_identities[YOTTA_CFG_IRK_TABLE_MAX_SIZE];
|
||||
|
||||
for (uint32_t i = 0; i < gapAdrHelper.identities_cnt; ++i)
|
||||
{
|
||||
pp_identities[i] = &gapAdrHelper.identities[i];
|
||||
}
|
||||
|
||||
retc = sd_ble_gap_device_identities_set(pp_identities, NULL /* Don't use local IRKs*/,gapAdrHelper.identities_cnt);
|
||||
err = getAddress(&_non_private_address_type, _non_private_address);
|
||||
}
|
||||
|
||||
if (retc == NRF_SUCCESS) {
|
||||
if (gapAdrHelper.addrs_cnt == 0) {
|
||||
retc = sd_ble_gap_whitelist_set(NULL, 0);
|
||||
} else {
|
||||
ble_gap_addr_t * pp_addrs[YOTTA_CFG_IRK_TABLE_MAX_SIZE];
|
||||
|
||||
for (uint32_t i = 0; i < gapAdrHelper.addrs_cnt; ++i)
|
||||
{
|
||||
pp_addrs[i] = &gapAdrHelper.addrs[i];
|
||||
}
|
||||
|
||||
retc = sd_ble_gap_whitelist_set(pp_addrs, gapAdrHelper.addrs_cnt);
|
||||
}
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
switch(retc) {
|
||||
case NRF_SUCCESS:
|
||||
return BLE_ERROR_NONE;
|
||||
|
||||
case BLE_ERROR_GAP_WHITELIST_IN_USE: //The whitelist is in use by a BLE role and cannot be set or cleared.
|
||||
case BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE: //The device identity list is in use and cannot be set or cleared.
|
||||
return BLE_ERROR_ALREADY_INITIALIZED;
|
||||
|
||||
case NRF_ERROR_INVALID_ADDR:
|
||||
case BLE_ERROR_GAP_INVALID_BLE_ADDR: //Invalid address type is supplied.
|
||||
case NRF_ERROR_DATA_SIZE:
|
||||
case BLE_ERROR_GAP_DEVICE_IDENTITIES_DUPLICATE: //The device identity list contains multiple entries with the same identity address.
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
|
||||
default:
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
ble_error_t nRF5xGap::updateWhiteAndIdentityListInStack()
|
||||
{
|
||||
GapWhiteAndIdentityList_t whiteAndIdentityList;
|
||||
uint32_t err;
|
||||
|
||||
err = getStackWhiteIdentityList(whiteAndIdentityList);
|
||||
|
||||
if (err != BLE_ERROR_NONE) {
|
||||
return (ble_error_t)err;
|
||||
#if (NRF_SD_BLE_API_VERSION > 2)
|
||||
ble_gap_privacy_params_t privacy_config = { 0 };
|
||||
if (sd_ble_gap_privacy_get(&privacy_config)) {
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
|
||||
return applyWhiteIdentityList(whiteAndIdentityList);
|
||||
}
|
||||
privacy_config.privacy_mode = enable_privacy ?
|
||||
BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY :
|
||||
BLE_GAP_PRIVACY_MODE_OFF;
|
||||
if (sd_ble_gap_privacy_set(&privacy_config)) {
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
#endif
|
||||
|
||||
_privacy_enabled = enable_privacy;
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t nRF5xGap::setPeripheralPrivacyConfiguration(
|
||||
const PeripheralPrivacyConfiguration_t *configuration
|
||||
) {
|
||||
_peripheral_privacy_configuration = *configuration;
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t nRF5xGap::getPeripheralPrivacyConfiguration(
|
||||
PeripheralPrivacyConfiguration_t *configuration
|
||||
) {
|
||||
*configuration = _peripheral_privacy_configuration;
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t nRF5xGap::setCentralPrivacyConfiguration(
|
||||
const CentralPrivacyConfiguration_t *configuration
|
||||
) {
|
||||
_central_privacy_configuration = *configuration;
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t nRF5xGap::getCentralPrivacyConfiguration(
|
||||
CentralPrivacyConfiguration_t *configuration
|
||||
) {
|
||||
*configuration = _central_privacy_configuration;
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
void nRF5xGap::set_connection_event_handler(
|
||||
ConnectionEventMonitor::EventHandler* connection_event_handler
|
||||
) {
|
||||
_connection_event_handler = connection_event_handler;
|
||||
}
|
||||
|
||||
void nRF5xGap::processDisconnectionEvent(
|
||||
Handle_t handle,
|
||||
DisconnectionReason_t reason
|
||||
) {
|
||||
if (_connection_event_handler) {
|
||||
_connection_event_handler->on_disconnected(
|
||||
handle,
|
||||
reason
|
||||
);
|
||||
}
|
||||
|
||||
::Gap::processDisconnectionEvent(
|
||||
handle,
|
||||
reason
|
||||
);
|
||||
}
|
||||
|
||||
void nRF5xGap::on_connection(Gap::Handle_t handle, const ble_gap_evt_connected_t& evt) {
|
||||
using BLEProtocol::AddressType;
|
||||
|
||||
// set the new connection handle as the _default_ handle in gap
|
||||
setConnectionHandle(handle);
|
||||
|
||||
// deal with own address
|
||||
AddressType_t own_addr_type;
|
||||
Address_t own_address;
|
||||
const uint8_t* own_resolvable_address = NULL;
|
||||
|
||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
||||
if (evt.own_addr.addr_type == BLE_GAP_ADDR_TYPE_PUBLIC) {
|
||||
own_addr_type = AddressType::PUBLIC;
|
||||
} else {
|
||||
own_addr_type = AddressType::RANDOM;
|
||||
}
|
||||
memcpy(own_address, evt.own_addr.addr, sizeof(own_address));
|
||||
#else
|
||||
// FIXME: handle privacy ???
|
||||
getAddress(&own_addr_type, own_address);
|
||||
#endif
|
||||
|
||||
if (_privacy_enabled) {
|
||||
own_resolvable_address = own_address;
|
||||
}
|
||||
|
||||
// deal with the peer address: If privacy is enabled then the softdevice
|
||||
// indicates if the address has been resolved or not. If the address has
|
||||
// been resolved then the identity address should be passed to the application.
|
||||
// Depending on the privacy chosen by the application, connection request
|
||||
// from privacy enabled peers may trigger a disconnection, the pairing procedure
|
||||
// or the authentication procedure.
|
||||
AddressType_t peer_addr_type;
|
||||
const uint8_t* peer_address;
|
||||
const uint8_t* peer_resolvable_address;
|
||||
|
||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
||||
bool private_peer_known = evt.irk_match;
|
||||
#else
|
||||
bool private_peer_known = evt.peer_addr.addr_id_peer;
|
||||
#endif
|
||||
|
||||
|
||||
if (private_peer_known) {
|
||||
// FIXME: Is this correct for SD > 2 ?
|
||||
const resolving_list_entry_t* entry = get_sm().resolve_address(
|
||||
evt.peer_addr.addr
|
||||
);
|
||||
MBED_ASSERT(entry == NULL);
|
||||
|
||||
peer_addr_type = convert_identity_address(entry->peer_identity_address_type);
|
||||
peer_address = entry->peer_identity_address.data();
|
||||
peer_resolvable_address = evt.peer_addr.addr;
|
||||
} else {
|
||||
if (_privacy_enabled &&
|
||||
evt.role == BLE_GAP_ROLE_PERIPH &&
|
||||
_peripheral_privacy_configuration.resolution_strategy == PeripheralPrivacyConfiguration_t::REJECT_NON_RESOLVED_ADDRESS &&
|
||||
evt.peer_addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE &&
|
||||
get_sm().get_resolving_list().size() > 0
|
||||
) {
|
||||
// FIXME: should use BLE_HCI_AUTHENTICATION_FAILURE; not possible
|
||||
// with the softdevice ...
|
||||
sd_ble_gap_disconnect(handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
|
||||
return;
|
||||
}
|
||||
|
||||
peer_addr_type = convert_nordic_address(evt.peer_addr.addr_type);
|
||||
peer_address = evt.peer_addr.addr;
|
||||
peer_resolvable_address = NULL;
|
||||
}
|
||||
|
||||
// notify internal event handler before applying the resolution strategy
|
||||
if (_connection_event_handler) {
|
||||
_connection_event_handler->on_connected(
|
||||
handle,
|
||||
static_cast<Role_t>(evt.role),
|
||||
peer_addr_type,
|
||||
peer_address,
|
||||
own_addr_type,
|
||||
own_address,
|
||||
reinterpret_cast<const ConnectionParams_t *>(&(evt.conn_params))
|
||||
);
|
||||
}
|
||||
|
||||
// Apply authentication strategy before application notification
|
||||
if (!private_peer_known &&
|
||||
_privacy_enabled &&
|
||||
evt.role == BLE_GAP_ROLE_PERIPH &&
|
||||
evt.peer_addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE
|
||||
) {
|
||||
switch (_peripheral_privacy_configuration.resolution_strategy) {
|
||||
case PeripheralPrivacyConfiguration_t::PERFORM_PAIRING_PROCEDURE:
|
||||
nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getSecurityManager().requestPairing(handle);
|
||||
break;
|
||||
|
||||
case PeripheralPrivacyConfiguration_t::PERFORM_AUTHENTICATION_PROCEDURE:
|
||||
// FIXME: lookup secure DB to know what to do.
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
processConnectionEvent(
|
||||
handle,
|
||||
static_cast<Role_t>(evt.role),
|
||||
peer_addr_type,
|
||||
peer_address,
|
||||
own_addr_type,
|
||||
own_address,
|
||||
reinterpret_cast<const ConnectionParams_t *>(&(evt.conn_params)),
|
||||
peer_resolvable_address,
|
||||
own_resolvable_address
|
||||
);
|
||||
}
|
||||
|
||||
void nRF5xGap::on_advertising_packet(const ble_gap_evt_adv_report_t &evt) {
|
||||
using BLEProtocol::AddressType;
|
||||
|
||||
AddressType_t peer_addr_type;
|
||||
const uint8_t* peer_address = evt.peer_addr.addr;
|
||||
|
||||
if (_privacy_enabled &&
|
||||
evt.peer_addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE &&
|
||||
_central_privacy_configuration.resolution_strategy != CentralPrivacyConfiguration_t::DO_NOT_RESOLVE
|
||||
) {
|
||||
using ble::pal::vendor::nordic::nRF5xSecurityManager;
|
||||
|
||||
const resolving_list_entry_t* entry = get_sm().resolve_address(
|
||||
peer_address
|
||||
);
|
||||
|
||||
if (entry) {
|
||||
peer_address = entry->peer_identity_address.data();
|
||||
peer_addr_type = convert_identity_address(entry->peer_identity_address_type);
|
||||
} else if (_central_privacy_configuration.resolution_strategy != CentralPrivacyConfiguration_t::RESOLVE_AND_FORWARD) {
|
||||
peer_addr_type = convert_nordic_address(evt.peer_addr.addr_type);
|
||||
} else {
|
||||
// filter out the packet.
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
peer_addr_type = convert_nordic_address(evt.peer_addr.addr_type);
|
||||
}
|
||||
|
||||
processAdvertisementReport(
|
||||
peer_address,
|
||||
evt.rssi,
|
||||
evt.scan_rsp,
|
||||
static_cast<GapAdvertisingParams::AdvertisingType_t>(evt.type),
|
||||
evt.dlen,
|
||||
evt.data,
|
||||
peer_addr_type
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,11 @@ 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);
|
||||
|
@ -129,6 +130,23 @@ 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);
|
||||
|
@ -148,39 +166,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;
|
||||
|
@ -262,22 +247,42 @@ private:
|
|||
radioNotificationTimeout.attach_us(mbed::callback(this, &nRF5xGap::postRadioNotificationCallback), 0);
|
||||
}
|
||||
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(const ble_evt_t *p_ble_evt);
|
||||
friend void btle_handler(const ble_evt_t *p_ble_evt, void *p_context);
|
||||
|
||||
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 &);
|
||||
};
|
||||
|
|
|
@ -29,38 +29,38 @@
|
|||
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,10 +164,13 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
|
|||
}
|
||||
|
||||
ASSERT_TRUE ( ERROR_NONE ==
|
||||
custom_add_in_characteristic(BLE_GATT_HANDLE_INVALID,
|
||||
custom_add_in_characteristic(
|
||||
BLE_GATT_HANDLE_INVALID,
|
||||
&nordicUUID,
|
||||
p_char->getProperties(),
|
||||
p_char->getRequiredSecurity(),
|
||||
p_char->getReadSecurityRequirement(),
|
||||
p_char->getWriteSecurityRequirement(),
|
||||
p_char->getUpdateSecurityRequirement(),
|
||||
p_char->getValueAttribute().getValuePtr(),
|
||||
p_char->getValueAttribute().getLength(),
|
||||
p_char->getValueAttribute().getMaxLength(),
|
||||
|
@ -178,7 +181,8 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
|
|||
presentationFormatDescriptorValueLen,
|
||||
p_char->isReadAuthorizationEnabled(),
|
||||
p_char->isWriteAuthorizationEnabled(),
|
||||
&nrfCharacteristicHandles[characteristicCount]),
|
||||
&nrfCharacteristicHandles[characteristicCount]
|
||||
),
|
||||
BLE_ERROR_PARAM_OUT_OF_RANGE );
|
||||
|
||||
/* Update the characteristic handle */
|
||||
|
@ -218,7 +222,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 +266,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 +308,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 +351,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) {
|
||||
|
@ -618,14 +633,14 @@ void nRF5xGattServer::hwCallback(const 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
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -646,12 +661,12 @@ void nRF5xGattServer::hwCallback(const 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. */
|
||||
};
|
||||
|
@ -668,9 +683,9 @@ void nRF5xGattServer::hwCallback(const 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) {
|
||||
|
@ -695,25 +710,25 @@ void nRF5xGattServer::hwCallback(const 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
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -747,21 +762,21 @@ void nRF5xGattServer::hwCallback(const 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)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,407 @@
|
|||
/* 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_PAL_SECURITY_MANAGER_
|
||||
#define NRF5X_PAL_SECURITY_MANAGER_
|
||||
|
||||
#include "ble/BLETypes.h"
|
||||
#include "ble/pal/PalSecurityManager.h"
|
||||
#include "nrf_ble.h"
|
||||
#include "nRF5xCrypto.h"
|
||||
|
||||
|
||||
namespace ble {
|
||||
namespace pal {
|
||||
namespace vendor {
|
||||
namespace nordic {
|
||||
|
||||
class nRF5xSecurityManager : public ::ble::pal::SecurityManager {
|
||||
public:
|
||||
nRF5xSecurityManager();
|
||||
|
||||
virtual ~nRF5xSecurityManager();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// SM lifecycle management
|
||||
//
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::initialize
|
||||
*/
|
||||
virtual ble_error_t initialize();
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::terminate
|
||||
*/
|
||||
virtual ble_error_t terminate();
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::reset
|
||||
*/
|
||||
virtual ble_error_t reset() ;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Resolving list management
|
||||
//
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::read_resolving_list_capacity
|
||||
*/
|
||||
virtual uint8_t read_resolving_list_capacity();
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::add_device_to_resolving_list
|
||||
*/
|
||||
virtual ble_error_t 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
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::remove_device_from_resolving_list
|
||||
*/
|
||||
virtual ble_error_t remove_device_from_resolving_list(
|
||||
advertising_peer_address_type_t peer_identity_address_type,
|
||||
const address_t &peer_identity_address
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::clear_resolving_list
|
||||
*/
|
||||
virtual ble_error_t clear_resolving_list();
|
||||
|
||||
/**
|
||||
* An entry of the resolving list stored in the SecurityManager.
|
||||
*/
|
||||
struct resolving_list_entry_t {
|
||||
resolving_list_entry_t() :
|
||||
peer_identity_address_type(
|
||||
advertising_peer_address_type_t::PUBLIC_ADDRESS
|
||||
)
|
||||
{ }
|
||||
|
||||
irk_t peer_irk;
|
||||
address_t peer_identity_address;
|
||||
advertising_peer_address_type_t peer_identity_address_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the IRKs present in the resolving list
|
||||
* @param count The number of entries present in the resolving list.
|
||||
* @param pointer to the first entry of the resolving list.
|
||||
*/
|
||||
ArrayView<resolving_list_entry_t> get_resolving_list();
|
||||
|
||||
/**
|
||||
* Try to resolve a private resolvable address.
|
||||
*
|
||||
* @param resolvable_address The address to resolve.
|
||||
*
|
||||
* @return Pointer to the entry found if any.
|
||||
*/
|
||||
const resolving_list_entry_t* resolve_address(
|
||||
const address_t& resolvable_address
|
||||
);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Pairing
|
||||
//
|
||||
|
||||
/**
|
||||
* @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
|
||||
);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Feature support
|
||||
//
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::get_secure_connections_support
|
||||
*/
|
||||
virtual ble_error_t get_secure_connections_support(
|
||||
bool &enabled
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::set_io_capability
|
||||
*/
|
||||
virtual ble_error_t set_io_capability(io_capability_t io_capability);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Security settings
|
||||
//
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::set_authentication_timeout
|
||||
*/
|
||||
virtual ble_error_t set_authentication_timeout(
|
||||
connection_handle_t, uint16_t timeout_in_10ms
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::get_authentication_timeout
|
||||
*/
|
||||
virtual ble_error_t get_authentication_timeout(
|
||||
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
|
||||
);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Encryption
|
||||
//
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::enable_encryption
|
||||
*/
|
||||
virtual ble_error_t enable_encryption(
|
||||
connection_handle_t connection,
|
||||
const ltk_t <k,
|
||||
const rand_t &rand,
|
||||
const ediv_t &ediv,
|
||||
bool mitm
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::enable_encryption
|
||||
*/
|
||||
virtual ble_error_t enable_encryption(
|
||||
connection_handle_t connection,
|
||||
const ltk_t <k,
|
||||
bool mitm
|
||||
) ;
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::encrypt_data
|
||||
*/
|
||||
virtual ble_error_t encrypt_data(
|
||||
const byte_array_t<16> &key,
|
||||
encryption_block_t &data
|
||||
);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Privacy
|
||||
//
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::set_private_address_timeout
|
||||
*/
|
||||
virtual ble_error_t set_private_address_timeout(uint16_t timeout_in_seconds);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Keys
|
||||
//
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::set_ltk
|
||||
*/
|
||||
virtual ble_error_t set_ltk(
|
||||
connection_handle_t connection,
|
||||
const ltk_t <k,
|
||||
bool mitm,
|
||||
bool secure_connections
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::set_ltk_not_found
|
||||
*/
|
||||
virtual ble_error_t set_ltk_not_found(
|
||||
connection_handle_t connection
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::set_irk
|
||||
*/
|
||||
virtual ble_error_t set_irk(const irk_t &irk);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::set_csrk
|
||||
*/
|
||||
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
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::remove_peer_csrk
|
||||
*/
|
||||
virtual ble_error_t remove_peer_csrk(connection_handle_t connection);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Authentication
|
||||
//
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::get_random_data
|
||||
*/
|
||||
virtual ble_error_t get_random_data(byte_array_t<8> &random_data);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
*/
|
||||
virtual ble_error_t passkey_request_reply(
|
||||
connection_handle_t connection,
|
||||
passkey_num_t passkey
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::secure_connections_oob_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
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::confirmation_entered
|
||||
*/
|
||||
virtual ble_error_t confirmation_entered(
|
||||
connection_handle_t connection, bool confirmation
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::send_keypress_notification
|
||||
*/
|
||||
virtual ble_error_t send_keypress_notification(
|
||||
connection_handle_t connection, Keypress_t keypress
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::generate_secure_connections_oob
|
||||
*/
|
||||
virtual ble_error_t generate_secure_connections_oob();
|
||||
|
||||
// singleton of nordic Security Manager
|
||||
static nRF5xSecurityManager& get_security_manager();
|
||||
|
||||
// Event handler
|
||||
bool sm_handler(const ble_evt_t *evt);
|
||||
|
||||
private:
|
||||
csrk_t _csrk;
|
||||
sign_count_t _sign_counter;
|
||||
io_capability_t _io_capability;
|
||||
uint8_t _min_encryption_key_size;
|
||||
uint8_t _max_encryption_key_size;
|
||||
|
||||
struct pairing_control_block_t;
|
||||
|
||||
ble_gap_sec_params_t make_security_params(
|
||||
bool oob_data_flag,
|
||||
AuthenticationMask authentication_requirements,
|
||||
KeyDistribution initiator_dist,
|
||||
KeyDistribution responder_dist
|
||||
);
|
||||
|
||||
ble_gap_sec_keyset_t make_keyset(
|
||||
pairing_control_block_t& pairing_cb,
|
||||
KeyDistribution initiator_dist,
|
||||
KeyDistribution responder_dist
|
||||
);
|
||||
|
||||
pairing_control_block_t* allocate_pairing_cb(connection_handle_t connection);
|
||||
void release_pairing_cb(pairing_control_block_t* pairing_cb);
|
||||
pairing_control_block_t* get_pairing_cb(connection_handle_t connection);
|
||||
void release_all_pairing_cb();
|
||||
|
||||
pairing_control_block_t* _control_blocks;
|
||||
#if defined(MBEDTLS_ECDH_C)
|
||||
CryptoToolbox _crypto;
|
||||
ble::public_key_coord_t X;
|
||||
ble::public_key_coord_t Y;
|
||||
ble::public_key_coord_t secret;
|
||||
#endif
|
||||
|
||||
static const size_t MAX_RESOLVING_LIST_ENTRIES = BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT;
|
||||
|
||||
size_t resolving_list_entry_count;
|
||||
resolving_list_entry_t resolving_list[MAX_RESOLVING_LIST_ENTRIES];
|
||||
};
|
||||
|
||||
} // nordic
|
||||
} // vendor
|
||||
} // pal
|
||||
} // ble
|
||||
|
||||
#endif /* NRF5X_PAL_SECURITY_MANAGER_ */
|
|
@ -1,194 +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 __NRF51822_SECURITY_MANAGER_H__
|
||||
#define __NRF51822_SECURITY_MANAGER_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "nRF5xGap.h"
|
||||
#include "ble/SecurityManager.h"
|
||||
#include "btle_security.h"
|
||||
|
||||
class nRF5xSecurityManager : public SecurityManager
|
||||
{
|
||||
public:
|
||||
/* Functions that must be implemented from SecurityManager */
|
||||
virtual ble_error_t init(bool enableBonding,
|
||||
bool requireMITM,
|
||||
SecurityIOCapabilities_t iocaps,
|
||||
const Passkey_t passkey) {
|
||||
return btle_initializeSecurity(enableBonding, requireMITM, iocaps, passkey);
|
||||
}
|
||||
|
||||
virtual ble_error_t getLinkSecurity(Gap::Handle_t connectionHandle, LinkSecurityStatus_t *securityStatusP) {
|
||||
return btle_getLinkSecurity(connectionHandle, securityStatusP);
|
||||
}
|
||||
|
||||
virtual ble_error_t setLinkSecurity(Gap::Handle_t connectionHandle, SecurityMode_t securityMode) {
|
||||
return btle_setLinkSecurity(connectionHandle, securityMode);
|
||||
}
|
||||
|
||||
virtual ble_error_t purgeAllBondingState(void) {
|
||||
return btle_purgeAllBondingState();
|
||||
}
|
||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
* @return
|
||||
* BLE_ERROR_NONE if successful.
|
||||
*/
|
||||
virtual ble_error_t getAddressesFromBondTable(Gap::Whitelist_t &addresses) const {
|
||||
uint8_t i;
|
||||
|
||||
ble_gap_whitelist_t whitelistFromBondTable;
|
||||
ble_gap_addr_t *addressPtr[YOTTA_CFG_WHITELIST_MAX_SIZE];
|
||||
ble_gap_irk_t *irkPtr[YOTTA_CFG_IRK_TABLE_MAX_SIZE];
|
||||
|
||||
/* Initialize the structure so that we get as many addreses as the whitelist can hold */
|
||||
whitelistFromBondTable.addr_count = YOTTA_CFG_IRK_TABLE_MAX_SIZE;
|
||||
whitelistFromBondTable.pp_addrs = addressPtr;
|
||||
whitelistFromBondTable.irk_count = YOTTA_CFG_IRK_TABLE_MAX_SIZE;
|
||||
whitelistFromBondTable.pp_irks = irkPtr;
|
||||
|
||||
ble_error_t error = createWhitelistFromBondTable(whitelistFromBondTable);
|
||||
if (error != BLE_ERROR_NONE) {
|
||||
addresses.size = 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Put all the addresses in the structure */
|
||||
for (i = 0; i < whitelistFromBondTable.addr_count; ++i) {
|
||||
if (i >= addresses.capacity) {
|
||||
/* Ran out of space in the output Gap::Whitelist_t */
|
||||
addresses.size = i;
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
memcpy(&addresses.addresses[i], whitelistFromBondTable.pp_addrs[i], sizeof(BLEProtocol::Address_t));
|
||||
}
|
||||
|
||||
/* Update the current address count */
|
||||
addresses.size = i;
|
||||
|
||||
/* The assumption here is that the underlying implementation of
|
||||
* createWhitelistFromBondTable() will not return the private resolvable
|
||||
* addresses (which is the case in the SoftDevice). Rather it returns the
|
||||
* IRKs, so we need to generate the private resolvable address by ourselves.
|
||||
*/
|
||||
for (i = 0; i < whitelistFromBondTable.irk_count; ++i) {
|
||||
if (i + addresses.size >= addresses.capacity) {
|
||||
/* Ran out of space in the output Gap::Whitelist_t */
|
||||
addresses.size += i;
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
btle_generateResolvableAddress(
|
||||
*whitelistFromBondTable.pp_irks[i],
|
||||
(ble_gap_addr_t &) addresses.addresses[i + addresses.size]
|
||||
);
|
||||
}
|
||||
|
||||
/* Update the current address count */
|
||||
addresses.size += i;
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
#else // -> 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.
|
||||
*/
|
||||
virtual ble_error_t getAddressesFromBondTable(Gap::Whitelist_t &addresses) const {
|
||||
return btle_getAddressesFromBondTable(addresses);
|
||||
}
|
||||
#endif // #if (NRF_SD_BLE_API_VERSION <= 2)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Clear nRF5xSecurityManager's state.
|
||||
*
|
||||
* @return
|
||||
* BLE_ERROR_NONE if successful.
|
||||
*/
|
||||
virtual ble_error_t reset(void)
|
||||
{
|
||||
if (SecurityManager::reset() != BLE_ERROR_NONE) {
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
bool hasInitialized(void) const {
|
||||
return btle_hasInitializedSecurity();
|
||||
}
|
||||
|
||||
public:
|
||||
/*
|
||||
* Allow instantiation from nRF5xn when required.
|
||||
*/
|
||||
friend class nRF5xn;
|
||||
|
||||
nRF5xSecurityManager() {
|
||||
/* empty */
|
||||
}
|
||||
|
||||
private:
|
||||
nRF5xSecurityManager(const nRF5xSecurityManager &);
|
||||
const nRF5xSecurityManager& operator=(const nRF5xSecurityManager &);
|
||||
|
||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
||||
/*
|
||||
* Expose an interface that allows us to query the SoftDevice bond table
|
||||
* and extract a whitelist.
|
||||
*/
|
||||
ble_error_t createWhitelistFromBondTable(ble_gap_whitelist_t &whitelistFromBondTable) const {
|
||||
return btle_createWhitelistFromBondTable(&whitelistFromBondTable);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Given a BLE address and a IRK this function check whether the address
|
||||
* can be generated from the IRK. To do so, this function uses the hash
|
||||
* function and algorithm described in the Bluetooth low Energy
|
||||
* Specification. Internally, Nordic SDK functions are used.
|
||||
*/
|
||||
bool matchAddressAndIrk(ble_gap_addr_t *address, ble_gap_irk_t *irk) const {
|
||||
return btle_matchAddressAndIrk(address, irk);
|
||||
}
|
||||
|
||||
/*
|
||||
* Give nRF5xGap access to createWhitelistFromBondTable() and
|
||||
* matchAddressAndIrk()
|
||||
*/
|
||||
friend class nRF5xGap;
|
||||
};
|
||||
|
||||
#endif // ifndef __NRF51822_SECURITY_MANAGER_H__
|
|
@ -62,8 +62,7 @@ nRF5xn::nRF5xn(void) :
|
|||
instanceID(BLE::DEFAULT_INSTANCE),
|
||||
gapInstance(),
|
||||
gattServerInstance(NULL),
|
||||
gattClient(&(ble::pal::vendor::nordic::nRF5xGattClient::get_client())),
|
||||
securityManagerInstance(NULL)
|
||||
gattClient(&(ble::pal::vendor::nordic::nRF5xGattClient::get_client()))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -126,7 +125,7 @@ ble_error_t nRF5xn::init(BLE::InstanceID_t instanceID, FunctionPointerWithContex
|
|||
return BLE_ERROR_ALREADY_INITIALIZED;
|
||||
}
|
||||
|
||||
instanceID = instanceID;
|
||||
this->instanceID = instanceID;
|
||||
|
||||
/* ToDo: Clear memory contents, reset the SD, etc. */
|
||||
if (btle_init() != ERROR_NONE) {
|
||||
|
@ -187,13 +186,6 @@ ble_error_t nRF5xn::shutdown(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (securityManagerInstance != NULL) {
|
||||
error = securityManagerInstance->reset();
|
||||
if (error != BLE_ERROR_NONE) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
/* S110 does not support BLE client features, nothing to reset. */
|
||||
#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
|
||||
error = getGattClient().reset();
|
||||
|
@ -214,6 +206,29 @@ ble_error_t nRF5xn::shutdown(void)
|
|||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
SecurityManager& nRF5xn::getSecurityManager()
|
||||
{
|
||||
const nRF5xn* self = this;
|
||||
return const_cast<SecurityManager&>(self->getSecurityManager());
|
||||
}
|
||||
|
||||
const SecurityManager& nRF5xn::getSecurityManager() const
|
||||
{
|
||||
ble::pal::vendor::nordic::nRF5xSecurityManager &m_pal =
|
||||
ble::pal::vendor::nordic::nRF5xSecurityManager::get_security_manager();
|
||||
static struct : ble::pal::SigningEventMonitor {
|
||||
virtual void set_signing_event_handler(EventHandler *signing_event_handler) { }
|
||||
} dummy_signing_event_monitor;
|
||||
|
||||
static ble::generic::GenericSecurityManager m_instance(
|
||||
m_pal,
|
||||
const_cast<nRF5xGap&>(getGap()),
|
||||
dummy_signing_event_monitor
|
||||
);
|
||||
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
void
|
||||
nRF5xn::waitForEvent(void)
|
||||
{
|
||||
|
@ -223,19 +238,18 @@ nRF5xn::waitForEvent(void)
|
|||
|
||||
void nRF5xn::processEvents() {
|
||||
core_util_critical_section_enter();
|
||||
while (isEventsSignaled) {
|
||||
if (isEventsSignaled) {
|
||||
isEventsSignaled = false;
|
||||
core_util_critical_section_exit();
|
||||
#if NRF_SD_BLE_API_VERSION >= 5
|
||||
#if NRF_SD_BLE_API_VERSION >= 5
|
||||
// We use the "polling" dispatch model
|
||||
// http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v14.2.0/group__nrf__sdh.html?cp=4_0_0_6_11_60_20#gab4d7be69304d4f5feefd1d440cc3e6c7
|
||||
// This will process any pending events from the Softdevice
|
||||
nrf_sdh_evts_poll();
|
||||
#else
|
||||
#else
|
||||
intern_softdevice_events_execute();
|
||||
#endif
|
||||
|
||||
core_util_critical_section_enter();
|
||||
#endif
|
||||
} else {
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
|
|
@ -21,10 +21,12 @@
|
|||
#include "ble/blecommon.h"
|
||||
#include "ble/BLEInstanceBase.h"
|
||||
#include "ble/generic/GenericGattClient.h"
|
||||
#include "ble/generic/GenericSecurityManager.h"
|
||||
#include "ble/pal/SimpleEventQueue.h"
|
||||
#include "nRF5xPalSecurityManager.h"
|
||||
|
||||
#include "nRF5xGap.h"
|
||||
#include "nRF5xGattServer.h"
|
||||
#include "nRF5xSecurityManager.h"
|
||||
|
||||
#include "btle.h"
|
||||
|
||||
|
@ -82,18 +84,14 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* Accessors to Security Manager. This function checks whether a SecurityManager
|
||||
* object was previously instantiated. If such object does not exist, then
|
||||
* it is created before returning.
|
||||
*
|
||||
* @return A reference to GattServer.
|
||||
* @see BLEInstanceBase::getSecurityManager
|
||||
*/
|
||||
virtual nRF5xSecurityManager &getSecurityManager() {
|
||||
if (securityManagerInstance == NULL) {
|
||||
securityManagerInstance = new nRF5xSecurityManager();
|
||||
}
|
||||
return *securityManagerInstance;
|
||||
}
|
||||
virtual SecurityManager &getSecurityManager();
|
||||
|
||||
/**
|
||||
* @see BLEInstanceBase::getSecurityManager
|
||||
*/
|
||||
virtual const SecurityManager &getSecurityManager() const;
|
||||
|
||||
/**
|
||||
* Accessors to GAP. This function checks whether gapInstance points to an
|
||||
|
@ -130,23 +128,6 @@ public:
|
|||
return *gattServerInstance;
|
||||
};
|
||||
|
||||
/**
|
||||
* Accessors to Security Manager. This function checks whether a SecurityManager
|
||||
* object was previously instantiated. If such object does not exist, then
|
||||
* it is created before returning.
|
||||
*
|
||||
* @return A const reference to GattServer.
|
||||
*
|
||||
* @note The accessor is able to modify the object's state because the
|
||||
* internal pointer has been declared mutable.
|
||||
*/
|
||||
virtual const nRF5xSecurityManager &getSecurityManager() const {
|
||||
if (securityManagerInstance == NULL) {
|
||||
securityManagerInstance = new nRF5xSecurityManager();
|
||||
}
|
||||
return *securityManagerInstance;
|
||||
}
|
||||
|
||||
virtual void waitForEvent(void);
|
||||
|
||||
virtual void processEvents();
|
||||
|
@ -170,10 +151,7 @@ private:
|
|||
* it can be assigned inside a 'const' function. */
|
||||
ble::generic::GenericGattClient gattClient;
|
||||
|
||||
mutable nRF5xSecurityManager *securityManagerInstance; /**< Pointer to the SecurityManager object instance.
|
||||
* If NULL, then SecurityManager has not been initialized.
|
||||
* The pointer has been declared as 'mutable' so that
|
||||
* it can be assigned inside a 'const' function. */
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
#define MBED_RAM_START 0x20000000
|
||||
#define MBED_RAM_SIZE 0x10000
|
||||
#else
|
||||
#define MBED_RAM_START 0x20003800
|
||||
#define MBED_RAM_SIZE 0xC800
|
||||
#define MBED_RAM_START 0x200031D0
|
||||
#define MBED_RAM_SIZE 0xCE30
|
||||
#endif
|
||||
|
||||
#define MBED_RAM0_START MBED_RAM_START
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
#define MBED_RAM_START 0x20000000
|
||||
#define MBED_RAM_SIZE 0x10000
|
||||
#else
|
||||
#define MBED_RAM_START 0x20003800
|
||||
#define MBED_RAM_SIZE 0xC800
|
||||
#define MBED_RAM_START 0x200031D0
|
||||
#define MBED_RAM_SIZE 0xCE30
|
||||
#endif
|
||||
|
||||
#define MBED_RAM0_START MBED_RAM_START
|
||||
|
|
|
@ -16,8 +16,8 @@ if (MBED_APP_START == 0) {
|
|||
define symbol MBED_RAM_START = 0x20000000;
|
||||
define symbol MBED_RAM_SIZE = 0x10000;
|
||||
} else {
|
||||
define symbol MBED_RAM_START = 0x20003800;
|
||||
define symbol MBED_RAM_SIZE = 0xC800;
|
||||
define symbol MBED_RAM_START = 0x20003188;
|
||||
define symbol MBED_RAM_SIZE = 0x3CE78;
|
||||
}
|
||||
|
||||
define symbol MBED_RAM0_START = MBED_RAM_START;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue