pull/6932/head
Donatien Garnier 2018-05-16 12:44:36 +01:00
commit 3f7a7a4213
155 changed files with 6178 additions and 22360 deletions

View File

@ -129,7 +129,8 @@ struct link_encryption_t : SafeEnum<link_encryption_t, uint8_t> {
NOT_ENCRYPTED, /**< The link is not secured. */ NOT_ENCRYPTED, /**< The link is not secured. */
ENCRYPTION_IN_PROGRESS, /**< Link security is being established. */ ENCRYPTION_IN_PROGRESS, /**< Link security is being established. */
ENCRYPTED, /**< The link is secure. */ 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) { } 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 } // namespace ble
/** /**

View File

@ -72,6 +72,9 @@ public:
static const Handle_t INVALID_HANDLE = 0x0000; static const Handle_t INVALID_HANDLE = 0x0000;
public: public:
typedef ble::att_security_requirement_t Security_t;
/** /**
* Construct an attribute. * Construct an attribute.
* *
@ -102,6 +105,9 @@ public:
* true // variable length * true // variable length
* ); * );
* @endcode * @endcode
*
* @note By default, read and write operations are allowed and does not
* require any security.
*/ */
GattAttribute( GattAttribute(
const UUID &uuid, const UUID &uuid,
@ -113,8 +119,12 @@ public:
_valuePtr(valuePtr), _valuePtr(valuePtr),
_lenMax(maxLen), _lenMax(maxLen),
_len(len), _len(len),
_handle(),
_hasVariableLen(hasVariableLen), _hasVariableLen(hasVariableLen),
_handle() { _read_allowed(true),
_read_security(Security_t::NONE),
_write_allowed(true),
_write_security(Security_t::NONE) {
} }
public: public:
@ -209,6 +219,78 @@ public:
return _hasVariableLen; 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: private:
/** /**
* Characteristic's UUID. * Characteristic's UUID.
@ -230,15 +312,35 @@ private:
*/ */
uint16_t _len; uint16_t _len;
/**
* The attribute's handle in the ATT table.
*/
Handle_t _handle;
/** /**
* Whether the length of the value can change throughout time. * Whether the length of the value can change throughout time.
*/ */
bool _hasVariableLen; 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: private:
/* Disallow copy and assignment. */ /* Disallow copy and assignment. */

View File

@ -73,24 +73,23 @@
* of the characteristic. Clients use this handle to interact with the * of the characteristic. Clients use this handle to interact with the
* characteristic. This handle is used locally in GattServer APIs. * 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.
* *
* * @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
* Representation of a GattServer characteristic. * the link is encrypted.
*
* 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.
*/ */
class GattCharacteristic { class GattCharacteristic {
public: public:
@ -1276,9 +1275,40 @@ public:
* defines additional characteristic properties. * defines additional characteristic properties.
*/ */
BLE_GATT_CHAR_PROPERTIES_EXTENDED_PROPERTIES = 0x80 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. * 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. * @brief Constructs a new GattCharacteristic.
* *
@ -1371,13 +1406,21 @@ public:
bool hasVariableLen = true bool hasVariableLen = true
) : _valueAttribute(uuid, valuePtr, len, maxLen, hasVariableLen), ) : _valueAttribute(uuid, valuePtr, len, maxLen, hasVariableLen),
_properties(props), _properties(props),
_requiredSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK),
_descriptors(descriptors), _descriptors(descriptors),
_descriptorCount(numDescriptors), _descriptorCount(numDescriptors),
enabledReadAuthorization(false),
enabledWriteAuthorization(false),
readAuthorizationCallback(), 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: public:
@ -1387,10 +1430,120 @@ public:
* *
* @param[in] securityMode Can be one of encryption or signing, with or * @param[in] securityMode Can be one of encryption or signing, with or
* without protection for man in the middle attacks (MITM). * 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) 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: public:
@ -1407,7 +1560,6 @@ public:
void (*callback)(GattWriteAuthCallbackParams *) void (*callback)(GattWriteAuthCallbackParams *)
) { ) {
writeAuthorizationCallback.attach(callback); writeAuthorizationCallback.attach(callback);
enabledWriteAuthorization = true;
} }
/** /**
@ -1428,7 +1580,6 @@ public:
void (T::*member)(GattWriteAuthCallbackParams *) void (T::*member)(GattWriteAuthCallbackParams *)
) { ) {
writeAuthorizationCallback.attach(object, member); writeAuthorizationCallback.attach(object, member);
enabledWriteAuthorization = true;
} }
/** /**
@ -1445,7 +1596,6 @@ public:
void (*callback)(GattReadAuthCallbackParams *) void (*callback)(GattReadAuthCallbackParams *)
) { ) {
readAuthorizationCallback.attach(callback); readAuthorizationCallback.attach(callback);
enabledReadAuthorization = true;
} }
/** /**
@ -1467,7 +1617,6 @@ public:
void (T::*member)(GattReadAuthCallbackParams *) void (T::*member)(GattReadAuthCallbackParams *)
) { ) {
readAuthorizationCallback.attach(object, member); readAuthorizationCallback.attach(object, member);
enabledReadAuthorization = true;
} }
/** /**
@ -1580,10 +1729,54 @@ public:
* Get the characteristic's required security. * Get the characteristic's required security.
* *
* @return 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 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 bool isReadAuthorizationEnabled() const
{ {
return enabledReadAuthorization; return readAuthorizationCallback;
} }
/** /**
@ -1619,7 +1812,7 @@ public:
*/ */
bool isWriteAuthorizationEnabled() const bool isWriteAuthorizationEnabled() const
{ {
return enabledWriteAuthorization; return writeAuthorizationCallback;
} }
/** /**
@ -1640,6 +1833,39 @@ public:
} }
private: 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. * Attribute that contains the actual value of this characteristic.
*/ */
@ -1651,11 +1877,6 @@ private:
*/ */
uint8_t _properties; uint8_t _properties;
/**
* The characteristic's required security.
*/
SecurityManager::SecurityMode_t _requiredSecurity;
/** /**
* The characteristic's descriptor attributes. * The characteristic's descriptor attributes.
*/ */
@ -1666,16 +1887,6 @@ private:
*/ */
uint8_t _descriptorCount; 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. * The registered callback handler for read authorization reply.
*/ */
@ -1688,6 +1899,14 @@ private:
FunctionPointerWithContext<GattWriteAuthCallbackParams *> FunctionPointerWithContext<GattWriteAuthCallbackParams *>
writeAuthorizationCallback; 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: private:
/* Disallow copy and assignment. */ /* Disallow copy and assignment. */
GattCharacteristic(const GattCharacteristic &); GattCharacteristic(const GattCharacteristic &);

View File

@ -139,6 +139,57 @@ struct SafeEnum {
return !(lhs == rhs); 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. * Explicit access to the inner value of the SafeEnum instance.
*/ */

View File

@ -417,6 +417,9 @@ public:
* support out-of-band exchanges of security data. * support out-of-band exchanges of security data.
* @param[in] passkey To specify a static passkey. * @param[in] passkey To specify a static passkey.
* @param[in] signing Generate and distribute signing key during pairing * @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. * @return BLE_ERROR_NONE on success.
*/ */
@ -424,12 +427,14 @@ public:
bool requireMITM = true, bool requireMITM = true,
SecurityIOCapabilities_t iocaps = IO_CAPS_NONE, SecurityIOCapabilities_t iocaps = IO_CAPS_NONE,
const Passkey_t passkey = NULL, const Passkey_t passkey = NULL,
bool signing = true) { bool signing = true,
const char *dbPath = NULL) {
/* Avoid compiler warnings about unused variables. */ /* Avoid compiler warnings about unused variables. */
(void)enableBonding; (void)enableBonding;
(void)requireMITM; (void)requireMITM;
(void)iocaps; (void)iocaps;
(void)passkey; (void)passkey;
(void)dbPath;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */ 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_error_t getLinkSecurity(ble::connection_handle_t connectionHandle, LinkSecurityStatus_t *securityStatus) {
ble::link_encryption_t encryption(ble::link_encryption_t::NOT_ENCRYPTED); ble::link_encryption_t encryption(ble::link_encryption_t::NOT_ENCRYPTED);
ble_error_t status = getLinkEncryption(connectionHandle, &encryption); ble_error_t err = getLinkEncryption(connectionHandle, &encryption);
/* legacy support limits the return values */ if (err) {
if (encryption.value() == ble::link_encryption_t::ENCRYPTED_WITH_MITM) { return err;
*securityStatus = ENCRYPTED;
} else {
*securityStatus = (LinkSecurityStatus_t)encryption.value();
} }
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; SecurityManager::SecurityMode_t securityMode;
if (result == ble::link_encryption_t::ENCRYPTED) { if (result == ble::link_encryption_t::ENCRYPTED) {
securityMode = SECURITY_MODE_ENCRYPTION_NO_MITM; 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; securityMode = SECURITY_MODE_ENCRYPTION_WITH_MITM;
} else { } else {
securityMode = SECURITY_MODE_ENCRYPTION_OPEN_LINK; securityMode = SECURITY_MODE_ENCRYPTION_OPEN_LINK;

View File

@ -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 &ltk
);
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 &ltk
);
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_*/

View File

@ -19,7 +19,7 @@
#include "ble/pal/GapTypes.h" #include "ble/pal/GapTypes.h"
#include "ble/BLETypes.h" #include "ble/BLETypes.h"
#include "ble/pal/SecurityDb.h" #include "ble/generic/SecurityDb.h"
#include "platform/Callback.h" #include "platform/Callback.h"
#include "ble/pal/ConnectionEventMonitor.h" #include "ble/pal/ConnectionEventMonitor.h"
#include "ble/pal/SigningEventMonitor.h" #include "ble/pal/SigningEventMonitor.h"
@ -37,8 +37,6 @@ class GenericSecurityManager : public SecurityManager,
public pal::ConnectionEventMonitor::EventHandler, public pal::ConnectionEventMonitor::EventHandler,
public pal::SigningEventMonitor::EventHandler { public pal::SigningEventMonitor::EventHandler {
public: public:
typedef ble::pal::SecurityDistributionFlags_t SecurityDistributionFlags_t;
typedef ble::pal::SecurityEntryKeys_t SecurityEntryKeys_t;
/* implements SecurityManager */ /* implements SecurityManager */
@ -51,7 +49,8 @@ public:
bool mitm = true, bool mitm = true,
SecurityIOCapabilities_t iocaps = IO_CAPS_NONE, SecurityIOCapabilities_t iocaps = IO_CAPS_NONE,
const Passkey_t passkey = NULL, const Passkey_t passkey = NULL,
bool signing = true bool signing = true,
const char* db_path = NULL
); );
virtual ble_error_t reset(); virtual ble_error_t reset();
@ -236,13 +235,12 @@ public:
public: public:
GenericSecurityManager( GenericSecurityManager(
pal::SecurityManager &palImpl, pal::SecurityManager &palImpl,
pal::SecurityDb &dbImpl,
pal::ConnectionEventMonitor &connMonitorImpl, pal::ConnectionEventMonitor &connMonitorImpl,
pal::SigningEventMonitor &signingMonitorImpl pal::SigningEventMonitor &signingMonitorImpl
) : _pal(palImpl), ) : _pal(palImpl),
_db(dbImpl),
_connection_monitor(connMonitorImpl), _connection_monitor(connMonitorImpl),
_signing_monitor(signingMonitorImpl), _signing_monitor(signingMonitorImpl),
_db(NULL),
_default_authentication(0), _default_authentication(0),
_default_key_distribution(pal::KeyDistribution::KEY_DISTRIBUTION_ALL), _default_key_distribution(pal::KeyDistribution::KEY_DISTRIBUTION_ALL),
_pairing_authorisation_required(false), _pairing_authorisation_required(false),
@ -256,6 +254,10 @@ public:
_oob_local_random[0] = 1; _oob_local_random[0] = 1;
} }
~GenericSecurityManager() {
delete _db;
}
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Helper functions // Helper functions
// //
@ -308,7 +310,7 @@ private:
* @param[in] entryKeys security entry containing keys. * @param[in] entryKeys security entry containing keys.
*/ */
void enable_encryption_cb( void enable_encryption_cb(
pal::SecurityDb::entry_handle_t entry, SecurityDb::entry_handle_t entry,
const SecurityEntryKeys_t* entryKeys const SecurityEntryKeys_t* entryKeys
); );
@ -319,7 +321,7 @@ private:
* @param[in] entryKeys security entry containing keys. * @param[in] entryKeys security entry containing keys.
*/ */
void set_ltk_cb( void set_ltk_cb(
pal::SecurityDb::entry_handle_t entry, SecurityDb::entry_handle_t entry,
const SecurityEntryKeys_t* entryKeys const SecurityEntryKeys_t* entryKeys
); );
@ -327,24 +329,22 @@ private:
* Returns the CSRK for the connection. Called by the security db. * Returns the CSRK for the connection. Called by the security db.
* *
* @param[in] connectionHandle Handle to identify the connection. * @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( void return_csrk_cb(
pal::SecurityDb::entry_handle_t connection, SecurityDb::entry_handle_t connection,
const csrk_t *csrk, const SecurityEntrySigning_t *signing
sign_count_t sign_counter
); );
/** /**
* Set the peer CSRK for the connection. Called by the security db. * Set the peer CSRK for the connection. Called by the security db.
* *
* @param[in] connectionHandle Handle to identify the connection. * @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( void set_peer_csrk_cb(
pal::SecurityDb::entry_handle_t connection, SecurityDb::entry_handle_t connection,
const csrk_t *csrk, const SecurityEntrySigning_t *signing
sign_count_t sign_counter
); );
/** /**
@ -407,8 +407,8 @@ private:
* @param identity The identity associated with the entry; may be NULL. * @param identity The identity associated with the entry; may be NULL.
*/ */
void on_security_entry_retrieved( void on_security_entry_retrieved(
pal::SecurityDb::entry_handle_t entry, SecurityDb::entry_handle_t entry,
const pal::SecurityEntryIdentity_t* identity const SecurityEntryIdentity_t* identity
); );
/** /**
@ -421,12 +421,12 @@ private:
* @param count Number of identities entries retrieved. * @param count Number of identities entries retrieved.
*/ */
void on_identity_list_retrieved( void on_identity_list_retrieved(
ble::ArrayView<pal::SecurityEntryIdentity_t*>& identity_list, ble::ArrayView<SecurityEntryIdentity_t>& identity_list,
size_t count size_t count
); );
private: private:
struct ControlBlock_t : public pal::SecurityDistributionFlags_t { struct ControlBlock_t {
ControlBlock_t(); ControlBlock_t();
pal::KeyDistribution get_initiator_key_distribution() { pal::KeyDistribution get_initiator_key_distribution() {
@ -443,7 +443,7 @@ private:
}; };
connection_handle_t connection; 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 */ address_t local_address; /**< address used for connection, possibly different from identity */
@ -473,10 +473,11 @@ private:
}; };
pal::SecurityManager &_pal; pal::SecurityManager &_pal;
pal::SecurityDb &_db;
pal::ConnectionEventMonitor &_connection_monitor; pal::ConnectionEventMonitor &_connection_monitor;
pal::SigningEventMonitor &_signing_monitor; pal::SigningEventMonitor &_signing_monitor;
SecurityDb *_db;
/* OOB data */ /* OOB data */
address_t _oob_local_address; address_t _oob_local_address;
address_t _oob_peer_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(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); void release_control_block(ControlBlock_t* entry);
}; };

View File

@ -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 &ltk
) {
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 &ltk
) {
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_*/

View File

@ -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 &ltk
) = 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 &ltk
) = 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__*/

View File

@ -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 &ltk
) {
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 &ltk
) {
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_*/

View File

@ -883,6 +883,8 @@ public:
sign_count_t sign_counter sign_count_t sign_counter
) = 0; ) = 0;
virtual ble_error_t remove_peer_csrk(connection_handle_t connection) = 0;
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Authentication // Authentication
// //

View File

@ -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 &ltk
) = 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 &ltk
) = 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__*/

View File

@ -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 &ltk
) {
entry_t *entry = as_entry(db_handle);
if (!entry) {
return;
}
entry->flags.ltk_sent = true;
db_write(&ltk, 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 &ltk
) {
entry_t *entry = as_entry(db_handle);
if (!entry) {
return;
}
entry->flags.ltk_stored = true;
db_write(&ltk, 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 */

View File

@ -1090,9 +1090,11 @@ ble_error_t GenericGattClient::write(
ble::link_encryption_t encryption(ble::link_encryption_t::NOT_ENCRYPTED); ble::link_encryption_t encryption(ble::link_encryption_t::NOT_ENCRYPTED);
SecurityManager &sm = createBLEInstance()->getSecurityManager(); SecurityManager &sm = createBLEInstance()->getSecurityManager();
ble_error_t status = sm.getLinkEncryption(connection_handle, &encryption); ble_error_t status = sm.getLinkEncryption(connection_handle, &encryption);
if (status == BLE_ERROR_NONE if (status == BLE_ERROR_NONE &&
|| encryption == ble::link_encryption_t::ENCRYPTED (encryption == link_encryption_t::ENCRYPTED ||
|| encryption == ble::link_encryption_t::ENCRYPTED_WITH_MITM) { encryption == link_encryption_t::ENCRYPTED_WITH_MITM ||
encryption == link_encryption_t::ENCRYPTED_WITH_SC_AND_MITM)
) {
cmd = GattClient::GATT_OP_WRITE_CMD; cmd = GattClient::GATT_OP_WRITE_CMD;
} }
} }

View File

@ -17,6 +17,8 @@
#include "ble/SecurityManager.h" #include "ble/SecurityManager.h"
#include "ble/pal/PalSecurityManager.h" #include "ble/pal/PalSecurityManager.h"
#include "ble/generic/GenericSecurityManager.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::advertising_peer_address_type_t;
using ble::pal::AuthenticationMask; using ble::pal::AuthenticationMask;
@ -37,14 +39,33 @@ ble_error_t GenericSecurityManager::init(
bool mitm, bool mitm,
SecurityIOCapabilities_t iocaps, SecurityIOCapabilities_t iocaps,
const Passkey_t passkey, const Passkey_t passkey,
bool signing bool signing,
const char* db_path
) { ) {
ble_error_t err = _pal.initialize(); ble_error_t err = _pal.initialize();
if (err) { if (err) {
return 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); _pal.set_io_capability((io_capability_t::type) iocaps);
if (passkey) { if (passkey) {
@ -63,7 +84,8 @@ ble_error_t GenericSecurityManager::init(
_default_authentication.set_secure_connections(secure_connections); _default_authentication.set_secure_connections(secure_connections);
_default_authentication.set_keypress_notification(true); _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); _default_key_distribution.set_signing(signing);
if (signing) { if (signing) {
@ -75,16 +97,16 @@ ble_error_t GenericSecurityManager::init(
_pal.set_event_handler(this); _pal.set_event_handler(this);
uint8_t resolving_list_capacity = _pal.read_resolving_list_capacity(); uint8_t resolving_list_capacity = _pal.read_resolving_list_capacity();
pal::SecurityEntryIdentity_t** identity_list_p = SecurityEntryIdentity_t* identity_list_p =
new (std::nothrow) pal::SecurityEntryIdentity_t*[resolving_list_capacity]; new (std::nothrow) SecurityEntryIdentity_t[resolving_list_capacity];
if (identity_list_p) { if (identity_list_p) {
ArrayView<pal::SecurityEntryIdentity_t*> identity_list( ArrayView<SecurityEntryIdentity_t> identity_list(
identity_list_p, identity_list_p,
resolving_list_capacity resolving_list_capacity
); );
_db.get_identity_list( _db->get_identity_list(
mbed::callback(this, &GenericSecurityManager::on_identity_list_retrieved), mbed::callback(this, &GenericSecurityManager::on_identity_list_retrieved),
identity_list identity_list
); );
@ -94,7 +116,6 @@ ble_error_t GenericSecurityManager::init(
} }
ble_error_t GenericSecurityManager::reset(void) { ble_error_t GenericSecurityManager::reset(void) {
_db.sync();
_pal.reset(); _pal.reset();
SecurityManager::reset(); SecurityManager::reset();
@ -102,7 +123,8 @@ ble_error_t GenericSecurityManager::reset(void) {
} }
ble_error_t GenericSecurityManager::preserveBondingStateOnReset(bool enabled) { ble_error_t GenericSecurityManager::preserveBondingStateOnReset(bool enabled) {
_db.set_restore(enabled); MBED_ASSERT(_db);
_db->set_restore(enabled);
return BLE_ERROR_NONE; return BLE_ERROR_NONE;
} }
@ -111,13 +133,15 @@ ble_error_t GenericSecurityManager::preserveBondingStateOnReset(bool enabled) {
// //
ble_error_t GenericSecurityManager::purgeAllBondingState(void) { ble_error_t GenericSecurityManager::purgeAllBondingState(void) {
_db.clear_entries(); MBED_ASSERT(_db);
_db->clear_entries();
return BLE_ERROR_NONE; return BLE_ERROR_NONE;
} }
ble_error_t GenericSecurityManager::generateWhitelistFromBondTable(Gap::Whitelist_t *whitelist) const { ble_error_t GenericSecurityManager::generateWhitelistFromBondTable(Gap::Whitelist_t *whitelist) const {
MBED_ASSERT(_db);
if (eventHandler) { if (eventHandler) {
_db.generate_whitelist_from_bond_table( _db->generate_whitelist_from_bond_table(
mbed::callback(eventHandler, &::SecurityManager::EventHandler::whitelistFromBondTable), mbed::callback(eventHandler, &::SecurityManager::EventHandler::whitelistFromBondTable),
whitelist 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 */ /* by default the initiator doesn't send any keys other then identity */
KeyDistribution initiator_distribution( 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 /* if requested the initiator may send all the default keys for later
* use when roles are changed */ * use when roles are changed */
if (_master_sends_keys) { if (_master_sends_keys) {
initiator_distribution = _default_key_distribution; 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); KeyDistribution responder_distribution(_default_key_distribution);
@ -198,13 +225,18 @@ ble_error_t GenericSecurityManager::acceptPairingRequest(connection_handle_t con
if (_master_sends_keys) { if (_master_sends_keys) {
initiator_distribution &= _default_key_distribution; initiator_distribution &= _default_key_distribution;
} else { } 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 */ /* signing has to be offered and enabled on the link */
if (master_signing) { if (master_signing) {
initiator_distribution.set_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 */ /* signing has to be requested and enabled on the link */
if (responder_distribution.get_signing()) { if (responder_distribution.get_signing()) {
responder_distribution.set_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, connection_handle_t connection,
bool enabled bool enabled
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; 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; cb->signing_override_default = true;
if (enabled && !cb->signing_requested && !_default_key_distribution.get_signing()) { if (enabled && !cb->signing_requested && !_default_key_distribution.get_signing()) {
cb->signing_requested = true; cb->signing_requested = true;
if (cb->csrk_stored) { if (flags->csrk_stored) {
/* used the stored ones when available */ /* used the stored ones when available */
_db.get_entry_peer_csrk( _db->get_entry_peer_csrk(
mbed::callback(this, &GenericSecurityManager::set_peer_csrk_cb), mbed::callback(this, &GenericSecurityManager::set_peer_csrk_cb),
cb->db_entry cb->db_entry
); );
@ -366,15 +406,24 @@ ble_error_t GenericSecurityManager::getLinkEncryption(
connection_handle_t connection, connection_handle_t connection,
link_encryption_t *encryption link_encryption_t *encryption
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; 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->encrypted) {
if (cb->ltk_mitm_protected || cb->mitm_performed) { if (flags->ltk_mitm_protected || cb->mitm_performed) {
*encryption = link_encryption_t::ENCRYPTED_WITH_MITM; if (flags->secure_connections_paired) {
*encryption = link_encryption_t::ENCRYPTED_WITH_SC_AND_MITM;
} else {
*encryption = link_encryption_t::ENCRYPTED_WITH_MITM;
}
} else { } else {
*encryption = link_encryption_t::ENCRYPTED; *encryption = link_encryption_t::ENCRYPTED;
} }
@ -391,11 +440,17 @@ ble_error_t GenericSecurityManager::setLinkEncryption(
connection_handle_t connection, connection_handle_t connection,
link_encryption_t encryption link_encryption_t encryption
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; 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); link_encryption_t current_encryption(link_encryption_t::NOT_ENCRYPTED);
getLinkEncryption(connection, &current_encryption); getLinkEncryption(connection, &current_encryption);
@ -408,20 +463,34 @@ ble_error_t GenericSecurityManager::setLinkEncryption(
/* ignore if the link is already at required state*/ /* ignore if the link is already at required state*/
} else if (encryption == link_encryption_t::NOT_ENCRYPTED) { } else if (encryption == link_encryption_t::NOT_ENCRYPTED) {
// Fail as it is not permitted to turn down encryption
/* ignore if we are requesting an open link on an already encrypted link */ return BLE_ERROR_OPERATION_NOT_PERMITTED;
} else if (encryption == link_encryption_t::ENCRYPTED) { } else if (encryption == link_encryption_t::ENCRYPTED) {
/* only change if we're not already encrypted with mitm */ /* 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; cb->encryption_requested = true;
return enable_encryption(connection); return enable_encryption(connection);
} }
} else if (encryption == link_encryption_t::ENCRYPTED_WITH_MITM) { } 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; cb->encryption_requested = true;
return enable_encryption(connection); return enable_encryption(connection);
} else { } else {
@ -442,13 +511,19 @@ ble_error_t GenericSecurityManager::getEncryptionKeySize(
connection_handle_t connection, connection_handle_t connection,
uint8_t *size uint8_t *size
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (cb) { if (!cb) {
*size = cb->encryption_key_size;
return BLE_ERROR_NONE;
} else {
return BLE_ERROR_INVALID_PARAM; 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( 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) { ble_error_t GenericSecurityManager::getSigningKey(connection_handle_t connection, bool authenticated) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; 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 /* we have a key that is either authenticated or we don't care if it is
* so retrieve it from the db now */ * so retrieve it from the db now */
_db.get_entry_peer_csrk( _db->get_entry_peer_csrk(
mbed::callback(this, &GenericSecurityManager::return_csrk_cb), mbed::callback(this, &GenericSecurityManager::return_csrk_cb),
cb->db_entry 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) { ble_error_t GenericSecurityManager::requestAuthentication(connection_handle_t connection) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; 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) { if (cb->authenticated) {
return BLE_ERROR_NONE; return BLE_ERROR_NONE;
} else { } else {
@ -614,16 +701,22 @@ ble_error_t GenericSecurityManager::legacyPairingOobReceived(
const address_t *address, const address_t *address,
const oob_tk_t *tk const oob_tk_t *tk
) { ) {
MBED_ASSERT(_db);
if (address && tk) { if (address && tk) {
ControlBlock_t *cb = get_control_block(*address); ControlBlock_t *cb = get_control_block(*address);
if (!cb) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; 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 = *tk;
_oob_temporary_key_creator_address = *address; _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; cb->attempt_oob = true;
} }
@ -658,8 +751,9 @@ ble_error_t GenericSecurityManager::oobReceived(
// //
ble_error_t GenericSecurityManager::init_signing() { ble_error_t GenericSecurityManager::init_signing() {
const csrk_t *pcsrk = _db.get_local_csrk(); MBED_ASSERT(_db);
sign_count_t local_sign_counter = _db.get_local_sign_counter(); const csrk_t *pcsrk = _db->get_local_csrk();
sign_count_t local_sign_counter = _db->get_local_sign_counter();
if (!pcsrk) { if (!pcsrk) {
csrk_t csrk; csrk_t csrk;
@ -670,8 +764,8 @@ ble_error_t GenericSecurityManager::init_signing() {
} }
pcsrk = &csrk; pcsrk = &csrk;
_db.set_local_csrk(csrk); _db->set_local_csrk(csrk);
_db.set_local_sign_counter(local_sign_counter); _db->set_local_sign_counter(local_sign_counter);
} }
return _pal.set_csrk(*pcsrk, 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) { ble_error_t GenericSecurityManager::enable_encryption(connection_handle_t connection) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; 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->is_master) {
if (cb->ltk_stored) { if (flags->ltk_stored) {
_db.get_entry_peer_keys( _db->get_entry_peer_keys(
mbed::callback(this, &GenericSecurityManager::enable_encryption_cb), mbed::callback(this, &GenericSecurityManager::enable_encryption_cb),
cb->db_entry cb->db_entry
); );
@ -727,85 +828,121 @@ ble_error_t GenericSecurityManager::enable_encryption(connection_handle_t connec
} }
void GenericSecurityManager::enable_encryption_cb( void GenericSecurityManager::enable_encryption_cb(
pal::SecurityDb::entry_handle_t db_entry, SecurityDb::entry_handle_t db_entry,
const SecurityEntryKeys_t* entryKeys const SecurityEntryKeys_t* entryKeys
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(db_entry); ControlBlock_t *cb = get_control_block(db_entry);
if (!cb) {
return;
}
if (cb && entryKeys) { SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
if (cb->secure_connections_paired) { if (!flags) {
_pal.enable_encryption(cb->connection, entryKeys->ltk, cb->ltk_mitm_protected); return;
}
if (entryKeys) {
if (flags->secure_connections_paired) {
_pal.enable_encryption(cb->connection, entryKeys->ltk, flags->ltk_mitm_protected);
} else { } 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( void GenericSecurityManager::set_ltk_cb(
pal::SecurityDb::entry_handle_t db_entry, SecurityDb::entry_handle_t db_entry,
const SecurityEntryKeys_t* entryKeys const SecurityEntryKeys_t* entryKeys
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(db_entry); ControlBlock_t *cb = get_control_block(db_entry);
if (!cb) {
return;
}
if (cb) { SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
if (entryKeys) { if (!flags) {
_pal.set_ltk(cb->connection, entryKeys->ltk, cb->ltk_mitm_protected, cb->secure_connections_paired); return;
} else { }
_pal.set_ltk_not_found(cb->connection);
} 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( void GenericSecurityManager::set_peer_csrk_cb(
pal::SecurityDb::entry_handle_t db_entry, SecurityDb::entry_handle_t db_entry,
const csrk_t *csrk, const SecurityEntrySigning_t* signing
sign_count_t sign_counter
) { ) {
ControlBlock_t *cb = get_control_block(db_entry); 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; return;
} }
_pal.set_peer_csrk( _pal.set_peer_csrk(
cb->connection, cb->connection,
*csrk, signing->csrk,
cb->csrk_mitm_protected, flags->csrk_mitm_protected,
sign_counter signing->counter
); );
} }
void GenericSecurityManager::return_csrk_cb( void GenericSecurityManager::return_csrk_cb(
pal::SecurityDb::entry_handle_t db_entry, SecurityDb::entry_handle_t db_entry,
const csrk_t *csrk, const SecurityEntrySigning_t *signing
sign_count_t sign_counter
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(db_entry); 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; return;
} }
eventHandler->signingKey( eventHandler->signingKey(
cb->connection, cb->connection,
csrk, &signing->csrk,
cb->csrk_mitm_protected flags->csrk_mitm_protected
); );
} }
void GenericSecurityManager::update_oob_presence(connection_handle_t connection) { void GenericSecurityManager::update_oob_presence(connection_handle_t connection) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return; 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 we support secure connection we only care about secure connections oob data */
if (_default_authentication.get_secure_connections()) { 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 { } else {
/* otherwise for legacy pairing we first set the oob based on set preference */ /* otherwise for legacy pairing we first set the oob based on set preference */
cb->oob_present = cb->attempt_oob; cb->oob_present = cb->attempt_oob;
/* and also turn it on if we have oob data for legacy pairing */ /* 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->local_address == _oob_temporary_key_creator_address) {
cb->oob_present = true; cb->oob_present = true;
} }
@ -833,34 +970,30 @@ void GenericSecurityManager::on_connected(
const BLEProtocol::AddressBytes_t local_address, const BLEProtocol::AddressBytes_t local_address,
const Gap::ConnectionParams_t *connection_params const Gap::ConnectionParams_t *connection_params
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = acquire_control_block(connection); ControlBlock_t *cb = acquire_control_block(connection);
if (!cb) { if (!cb) {
return; return;
} }
// setup the control block // setup the control block
cb->peer_address = peer_address;
cb->local_address = local_address; cb->local_address = local_address;
cb->peer_address_is_public =
(peer_address_type == BLEProtocol::AddressType::PUBLIC);
cb->is_master = (role == Gap::CENTRAL); cb->is_master = (role == Gap::CENTRAL);
// get the associated db handle and the distribution flags if any // 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 = SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
_db.get_distribution_flags(cb->db_entry);
if (dist_flags) { flags->peer_address = peer_address;
*static_cast<pal::SecurityDistributionFlags_t*>(cb) = *dist_flags; flags->peer_address_is_public = (peer_address_type == BLEProtocol::AddressType::PUBLIC);
}
const bool signing = cb->signing_override_default ? const bool signing = cb->signing_override_default ?
cb->signing_requested : cb->signing_requested :
_default_key_distribution.get_signing(); _default_key_distribution.get_signing();
if (signing && cb->csrk_stored) { if (signing && flags->csrk_stored) {
_db.get_entry_peer_csrk( _db->get_entry_peer_csrk(
mbed::callback(this, &GenericSecurityManager::set_peer_csrk_cb), mbed::callback(this, &GenericSecurityManager::set_peer_csrk_cb),
cb->db_entry cb->db_entry
); );
@ -871,20 +1004,21 @@ void GenericSecurityManager::on_disconnected(
connection_handle_t connection, connection_handle_t connection,
Gap::DisconnectionReason_t reason Gap::DisconnectionReason_t reason
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return; return;
} }
_db.close_entry(cb->db_entry); _pal.remove_peer_csrk(connection);
release_control_block(cb);
_db.sync(); _db->close_entry(cb->db_entry);
release_control_block(cb);
} }
void GenericSecurityManager::on_security_entry_retrieved( void GenericSecurityManager::on_security_entry_retrieved(
pal::SecurityDb::entry_handle_t entry, SecurityDb::entry_handle_t entry,
const pal::SecurityEntryIdentity_t* identity const SecurityEntryIdentity_t* identity
) { ) {
if (!identity) { if (!identity) {
return; return;
@ -902,7 +1036,7 @@ void GenericSecurityManager::on_security_entry_retrieved(
} }
void GenericSecurityManager::on_identity_list_retrieved( void GenericSecurityManager::on_identity_list_retrieved(
ble::ArrayView<pal::SecurityEntryIdentity_t*>& identity_list, ble::ArrayView<SecurityEntryIdentity_t>& identity_list,
size_t count size_t count
) { ) {
typedef advertising_peer_address_type_t address_type_t; typedef advertising_peer_address_type_t address_type_t;
@ -910,11 +1044,11 @@ void GenericSecurityManager::on_identity_list_retrieved(
_pal.clear_resolving_list(); _pal.clear_resolving_list();
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
_pal.add_device_to_resolving_list( _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::PUBLIC_ADDRESS :
address_type_t::RANDOM_ADDRESS, address_type_t::RANDOM_ADDRESS,
identity_list[i]->identity_address, identity_list[i].identity_address,
identity_list[i]->irk 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) { void GenericSecurityManager::on_pairing_completed(connection_handle_t connection) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (cb) { if (cb) {
// set the distribution flags in the db _db->get_entry_identity(
_db.set_distribution_flags(cb->db_entry, *cb);
_db.get_entry_identity(
mbed::callback(this, &GenericSecurityManager::on_security_entry_retrieved), mbed::callback(this, &GenericSecurityManager::on_security_entry_retrieved),
cb->db_entry cb->db_entry
); );
@ -1017,11 +1150,12 @@ void GenericSecurityManager::on_signed_write_received(
connection_handle_t connection, connection_handle_t connection,
sign_count_t sign_counter sign_count_t sign_counter
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return; 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( void GenericSecurityManager::on_signed_write_verification_failure(
@ -1050,26 +1184,33 @@ void GenericSecurityManager::on_signed_write_verification_failure(
} }
void GenericSecurityManager::on_signed_write() { 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( void GenericSecurityManager::on_slave_security_request(
connection_handle_t connection, connection_handle_t connection,
AuthenticationMask authentication AuthenticationMask authentication
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return; return;
} }
SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
if (!flags) {
return;
}
bool pairing_required = false; 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()) { && _default_authentication.get_secure_connections()) {
pairing_required = true; pairing_required = true;
} }
if (authentication.get_mitm() && !cb->ltk_mitm_protected) { if (authentication.get_mitm() && !flags->ltk_mitm_protected) {
pairing_required = true; pairing_required = true;
cb->mitm_requested = true; cb->mitm_requested = true;
} }
@ -1102,7 +1243,10 @@ void GenericSecurityManager::on_link_encryption_result(
cb->encryption_failed = false; cb->encryption_failed = false;
cb->encrypted = true; 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_requested = false;
cb->encryption_failed = false; cb->encryption_failed = false;
@ -1171,7 +1315,12 @@ void GenericSecurityManager::on_secure_connections_oob_request(connection_handle
return; 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); _pal.secure_connections_oob_request_reply(connection, _oob_local_random, _oob_peer_random, _oob_peer_confirm);
/* do not re-use peer OOB */ /* do not re-use peer OOB */
set_all_zeros(_oob_peer_address); 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) { void GenericSecurityManager::on_legacy_pairing_oob_request(connection_handle_t connection) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return; 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) { || cb->local_address == _oob_temporary_key_creator_address) {
set_mitm_performed(connection); set_mitm_performed(connection);
_pal.legacy_pairing_oob_request_reply(connection, _oob_temporary_key); _pal.legacy_pairing_oob_request_reply(connection, _oob_temporary_key);
/* do not re-use peer OOB */ /* 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); set_all_zeros(_oob_temporary_key_creator_address);
} }
@ -1221,27 +1376,41 @@ void GenericSecurityManager::on_secure_connections_ltk_generated(
connection_handle_t connection, connection_handle_t connection,
const ltk_t &ltk const ltk_t &ltk
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return; return;
} }
cb->ltk_mitm_protected = cb->mitm_performed; SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
cb->secure_connections_paired = true; 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( void GenericSecurityManager::on_keys_distributed_ltk(
connection_handle_t connection, connection_handle_t connection,
const ltk_t &ltk const ltk_t &ltk
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return; 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( void GenericSecurityManager::on_keys_distributed_ediv_rand(
@ -1249,24 +1418,31 @@ void GenericSecurityManager::on_keys_distributed_ediv_rand(
const ediv_t &ediv, const ediv_t &ediv,
const rand_t &rand const rand_t &rand
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return; 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( void GenericSecurityManager::on_keys_distributed_local_ltk(
connection_handle_t connection, connection_handle_t connection,
const ltk_t &ltk const ltk_t &ltk
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return; 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( 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 ediv_t &ediv,
const rand_t &rand const rand_t &rand
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return; 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( void GenericSecurityManager::on_keys_distributed_irk(
connection_handle_t connection, connection_handle_t connection,
const irk_t &irk const irk_t &irk
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return; 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( void GenericSecurityManager::on_keys_distributed_bdaddr(
@ -1299,12 +1482,13 @@ void GenericSecurityManager::on_keys_distributed_bdaddr(
advertising_peer_address_type_t peer_address_type, advertising_peer_address_type_t peer_address_type,
const address_t &peer_identity_address const address_t &peer_identity_address
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return; return;
} }
_db.set_entry_peer_bdaddr( _db->set_entry_peer_bdaddr(
cb->db_entry, cb->db_entry,
(peer_address_type == advertising_peer_address_type_t::PUBLIC_ADDRESS), (peer_address_type == advertising_peer_address_type_t::PUBLIC_ADDRESS),
peer_identity_address peer_identity_address
@ -1315,19 +1499,24 @@ void GenericSecurityManager::on_keys_distributed_csrk(
connection_handle_t connection, connection_handle_t connection,
const csrk_t &csrk const csrk_t &csrk
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return; 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( eventHandler->signingKey(
connection, connection,
&csrk, &csrk,
cb->csrk_mitm_protected flags->csrk_mitm_protected
); );
} }
@ -1336,23 +1525,30 @@ void GenericSecurityManager::on_ltk_request(
const ediv_t &ediv, const ediv_t &ediv,
const rand_t &rand const rand_t &rand
) { ) {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return; return;
} }
_db.get_entry_local_keys( SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
mbed::callback(this, &GenericSecurityManager::set_ltk_cb), if (!flags) {
cb->db_entry, return;
ediv, }
rand
); 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 */ /* control blocks list management */
GenericSecurityManager::ControlBlock_t::ControlBlock_t() : GenericSecurityManager::ControlBlock_t::ControlBlock_t() :
pal::SecurityDistributionFlags_t(),
connection(0), connection(0),
db_entry(0), db_entry(0),
local_address(), local_address(),
@ -1374,12 +1570,13 @@ GenericSecurityManager::ControlBlock_t::ControlBlock_t() :
void GenericSecurityManager::on_ltk_request(connection_handle_t connection) void GenericSecurityManager::on_ltk_request(connection_handle_t connection)
{ {
MBED_ASSERT(_db);
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return; return;
} }
_db.get_entry_local_keys( _db->get_entry_local_keys(
mbed::callback(this, &GenericSecurityManager::set_ltk_cb), mbed::callback(this, &GenericSecurityManager::set_ltk_cb),
cb->db_entry cb->db_entry
); );
@ -1417,18 +1614,21 @@ GenericSecurityManager::ControlBlock_t* GenericSecurityManager::get_control_bloc
GenericSecurityManager::ControlBlock_t* GenericSecurityManager::get_control_block( GenericSecurityManager::ControlBlock_t* GenericSecurityManager::get_control_block(
const address_t &peer_address const address_t &peer_address
) { ) {
MBED_ASSERT(_db);
for (size_t i = 0; i < MAX_CONTROL_BLOCKS; i++) { for (size_t i = 0; i < MAX_CONTROL_BLOCKS; i++) {
if (!_control_blocks[i].connected) { ControlBlock_t *cb = &_control_blocks[i];
continue; if (cb->connected) {
} else if (peer_address == _control_blocks[i].peer_address) { SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry);
return &_control_blocks[i]; if (flags && (flags->peer_address == peer_address)) {
return cb;
}
} }
} }
return NULL; return NULL;
} }
GenericSecurityManager::ControlBlock_t* GenericSecurityManager::get_control_block( 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++) { for (size_t i = 0; i < MAX_CONTROL_BLOCKS; i++) {
if (!_control_blocks[i].connected) { if (!_control_blocks[i].connected) {

View File

@ -30,7 +30,6 @@
#include "CordioPalGenericAccessService.h" #include "CordioPalGenericAccessService.h"
#include "ble/generic/GenericGap.h" #include "ble/generic/GenericGap.h"
#include "ble/generic/GenericSecurityManager.h" #include "ble/generic/GenericSecurityManager.h"
#include "ble/pal/MemorySecurityDb.h"
#include "ble/pal/SimpleEventQueue.h" #include "ble/pal/SimpleEventQueue.h"
namespace ble { namespace ble {

View File

@ -25,12 +25,27 @@
#include "wsf_types.h" #include "wsf_types.h"
#include "att_api.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 */ /*! client characteristic configuration descriptors settings */
#define MAX_CCC_CNT 20 #define MAX_CCCD_CNT 20
namespace ble { namespace ble {
// fwd declaration of CordioAttClient and BLE
namespace pal {
namespace vendor { namespace vendor {
namespace cordio { namespace cordio {
class CordioAttClient;
}
}
}
namespace vendor {
namespace cordio {
class BLE;
/** /**
* Cordio implementation of ::GattServer * Cordio implementation of ::GattServer
@ -38,6 +53,9 @@ namespace cordio {
class GattServer : public ::GattServer, class GattServer : public ::GattServer,
public pal::SigningEventMonitor public pal::SigningEventMonitor
{ {
friend ble::vendor::cordio::BLE;
friend ble::pal::vendor::cordio::CordioAttClient;
public: public:
/** /**
* Return the singleton of the Cordio implementation of ::GattServer. * Return the singleton of the Cordio implementation of ::GattServer.
@ -159,36 +177,74 @@ public:
} }
private: private:
static void cccCback(attsCccEvt_t *pEvt); static uint16_t compute_attributes_count(GattService& service);
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); void insert_service_attribute(
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); 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_access_service();
void add_generic_attribute_service(); void add_generic_attribute_service();
void* alloc_block(size_t block_size); 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 { struct alloc_block_t {
alloc_block_t* next; alloc_block_t* next;
uint8_t data[1]; uint8_t data[1];
}; };
struct internal_char_t {
uint16_t descLen;
};
struct internal_service_t { struct internal_service_t {
uint16_t uuidLen; attsGroup_t attGroup;
internal_char_t *chars;
attsGroup_t *attGroup;
internal_service_t *next; internal_service_t *next;
}; };
pal::SigningEventMonitor::EventHandler *_signing_event_handler; pal::SigningEventMonitor::EventHandler *_signing_event_handler;
attsCccSet_t cccSet[MAX_CCC_CNT]; attsCccSet_t cccds[MAX_CCCD_CNT];
uint16_t cccValues[MAX_CCC_CNT]; uint16_t cccd_values[MAX_CCCD_CNT];
uint16_t cccHandles[MAX_CCC_CNT]; uint16_t cccd_handles[MAX_CCCD_CNT];
uint8_t cccCnt; uint8_t cccd_cnt;
GattCharacteristic *_auth_char[MAX_CHARACTERISTIC_AUTHORIZATION_CNT];
uint8_t _auth_char_count;
struct { struct {
attsGroup_t service; attsGroup_t service;

View File

@ -17,6 +17,7 @@
#ifndef CORDIO_PAL_ATT_CLIENT_ #ifndef CORDIO_PAL_ATT_CLIENT_
#define CORDIO_PAL_ATT_CLIENT_ #define CORDIO_PAL_ATT_CLIENT_
#include "CordioGattServer.h"
#include "ble/pal/AttClient.h" #include "ble/pal/AttClient.h"
#include "ble/pal/SimpleAttServerMessage.h" #include "ble/pal/SimpleAttServerMessage.h"
#include "att_api.h" #include "att_api.h"
@ -30,7 +31,8 @@ namespace cordio {
class CordioAttClient : public ::ble::pal::AttClient { class CordioAttClient : public ::ble::pal::AttClient {
public: public:
CordioAttClient() : ::ble::pal::AttClient() { } CordioAttClient() : ::ble::pal::AttClient(), _local_sign_counter(0) { }
virtual ~CordioAttClient() { } virtual ~CordioAttClient() { }
/** /**
@ -348,6 +350,9 @@ public:
return; return;
} }
} }
// pass events not handled to the server side
ble::vendor::cordio::GattServer::getInstance().att_cb(event);
} }
private: private:

View File

@ -22,6 +22,7 @@
#include "wsf_os.h" #include "wsf_os.h"
#include "sec_api.h" #include "sec_api.h"
#include "smp_defs.h" #include "smp_defs.h"
#include "cfg_stack.h"
namespace ble { namespace ble {
namespace pal { namespace pal {
@ -252,6 +253,8 @@ public:
sign_count_t sign_counter sign_count_t sign_counter
); );
virtual ble_error_t remove_peer_csrk(connection_handle_t connection);
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Authentication // Authentication
// //
@ -353,6 +356,8 @@ private:
// cb_completed is set when the previous block has completed // cb_completed is set when the previous block has completed
void process_privacy_control_blocks(bool cb_completed); void process_privacy_control_blocks(bool cb_completed);
void cleanup_peer_csrks();
bool _use_default_passkey; bool _use_default_passkey;
passkey_num_t _default_passkey; passkey_num_t _default_passkey;
bool _lesc_keys_generated; bool _lesc_keys_generated;
@ -360,6 +365,9 @@ private:
PrivacyControlBlock* _pending_privacy_control_blocks; PrivacyControlBlock* _pending_privacy_control_blocks;
bool _processing_privacy_control_block; bool _processing_privacy_control_block;
irk_t _irk;
csrk_t _csrk;
csrk_t* _peer_csrks[DM_CONN_MAX];
}; };
} // cordio } // cordio

View File

@ -205,11 +205,9 @@ generic::GenericGattClient& BLE::getGattClient()
SecurityManager& BLE::getSecurityManager() SecurityManager& BLE::getSecurityManager()
{ {
static pal::MemorySecurityDb m_db;
static SigningEventMonitorProxy signing_event_monitor(*this); static SigningEventMonitorProxy signing_event_monitor(*this);
static generic::GenericSecurityManager m_instance( static generic::GenericSecurityManager m_instance(
pal::vendor::cordio::CordioSecurityManager::get_security_manager(), pal::vendor::cordio::CordioSecurityManager::get_security_manager(),
m_db,
getGap(), getGap(),
signing_event_monitor signing_event_monitor
); );
@ -356,7 +354,10 @@ void BLE::stack_setup()
AttHandlerInit(handlerId); AttHandlerInit(handlerId);
AttsInit(); AttsInit();
AttsIndInit(); AttsIndInit();
AttsSignInit();
AttsAuthorRegister(GattServer::atts_auth_cb);
AttcInit(); AttcInit();
AttcSignInit();
handlerId = WsfOsSetNextHandler(SmpHandler); handlerId = WsfOsSetNextHandler(SmpHandler);
SmpHandlerInit(handlerId); SmpHandlerInit(handlerId);

View File

@ -36,7 +36,8 @@ CordioSecurityManager::CordioSecurityManager() :
_lesc_keys_generated(false), _lesc_keys_generated(false),
_public_key_x(), _public_key_x(),
_pending_privacy_control_blocks(NULL), _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; _use_default_passkey = false;
_default_passkey = 0; _default_passkey = 0;
_lesc_keys_generated = false; _lesc_keys_generated = false;
memset(_peer_csrks, 0, sizeof(_peer_csrks));
#if 0 #if 0
// FIXME: need help from the stack or local calculation // FIXME: need help from the stack or local calculation
@ -68,11 +70,13 @@ ble_error_t CordioSecurityManager::initialize()
ble_error_t CordioSecurityManager::terminate() ble_error_t CordioSecurityManager::terminate()
{ {
cleanup_peer_csrks();
return BLE_ERROR_NONE; return BLE_ERROR_NONE;
} }
ble_error_t CordioSecurityManager::reset() ble_error_t CordioSecurityManager::reset()
{ {
cleanup_peer_csrks();
initialize(); initialize();
return BLE_ERROR_NONE; 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) 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; return BLE_ERROR_NONE;
} }
@ -301,8 +306,11 @@ ble_error_t CordioSecurityManager::set_csrk(
const csrk_t& csrk, const csrk_t& csrk,
sign_count_t sign_counter 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); CordioAttClient::get_client().set_sign_counter(sign_counter);
DmSecSetLocalCsrk(const_cast<uint8_t*>(csrk.data()));
return BLE_ERROR_NONE; return BLE_ERROR_NONE;
} }
@ -312,9 +320,40 @@ ble_error_t CordioSecurityManager::set_peer_csrk(
bool authenticated, bool authenticated,
sign_count_t sign_counter sign_count_t sign_counter
) { ) {
AttsSetCsrk(connection, const_cast<uint8_t*>(csrk.data())); if (connection == 0 || connection > DM_CONN_MAX) {
AttsSetSignCounter(connection, sign_counter); 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; return BLE_ERROR_NONE;
} }
@ -910,6 +949,14 @@ void CordioSecurityManager::process_privacy_control_blocks(bool cb_completed)
_pending_privacy_control_blocks = next; _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 } // cordio
} // vendor } // vendor

View File

@ -565,7 +565,7 @@ uint16_t AttsCccEnabled(dmConnId_t connId, uint8_t idx);
* \return None. * \return None.
*/ */
/*************************************************************************************************/ /*************************************************************************************************/
void AttsSetCsrk(dmConnId_t connId, uint8_t *pCsrk); void AttsSetCsrk(dmConnId_t connId, uint8_t *pCsrk, bool_t authenticated);
/*************************************************************************************************/ /*************************************************************************************************/
/*! /*!

View File

@ -30,6 +30,34 @@ typedef struct {
static unsigned uuidTableEntries = 0; /* current usage of the table */ static unsigned uuidTableEntries = 0; /* current usage of the table */
converted_uuid_table_entry_t convertedUUIDTable[UUID_TABLE_MAX_ENTRIES]; 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() { void custom_reset_128bits_uuid_table() {
uuidTableEntries = 0; 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, error_t custom_add_in_characteristic(uint16_t service_handle,
ble_uuid_t *p_uuid, ble_uuid_t *p_uuid,
uint8_t properties, 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, uint8_t *p_data,
uint16_t length, uint16_t length,
uint16_t max_length, uint16_t max_length,
@ -226,8 +256,8 @@ error_t custom_add_in_characteristic(uint16_t service_handle,
/* Notification requires cccd */ /* Notification requires cccd */
memclr_( &cccd_md, sizeof(ble_gatts_attr_md_t)); memclr_( &cccd_md, sizeof(ble_gatts_attr_md_t));
cccd_md.vloc = BLE_GATTS_VLOC_STACK; cccd_md.vloc = BLE_GATTS_VLOC_STACK;
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); set_perm(cccd_md.read_perm, GattAttribute::Security_t::NONE);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); set_perm(cccd_md.write_perm, update_security);
} }
ble_gatts_char_md_t char_md = {0}; 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 */ /* Always set variable size */
attr_md.vlen = has_variable_len; attr_md.vlen = has_variable_len;
if (char_props.read || char_props.notify || char_props.indicate) { set_perm(attr_md.read_perm, read_security);
switch (requiredSecurity) { set_perm(attr_md.write_perm, write_security);
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;
};
}
ble_gatts_attr_t attr_char_value = {0}; 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 length,
uint16_t max_length, uint16_t max_length,
bool has_variable_len, 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 */ /* Descriptor metadata */
ble_gatts_attr_md_t desc_md = {0}; 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; desc_md.vlen = has_variable_len;
/* Make it readable and writable */ /* Make it readable and writable */
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_md.read_perm); set_perm(desc_md.read_perm, read_security);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_md.write_perm); set_perm(desc_md.write_perm, write_security);
ble_gatts_attr_t attr_desc = {0}; ble_gatts_attr_t attr_desc = {0};

View File

@ -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, error_t custom_add_in_characteristic(uint16_t service_handle,
ble_uuid_t *p_uuid, ble_uuid_t *p_uuid,
uint8_t properties, 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, uint8_t *p_data,
uint16_t length, uint16_t length,
uint16_t max_length, uint16_t max_length,
@ -64,7 +66,9 @@ error_t custom_add_in_descriptor(uint16_t char_handle,
uint16_t length, uint16_t length,
uint16_t max_length, uint16_t max_length,
bool has_variable_len, 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 #ifdef __cplusplus
} }

View File

@ -25,42 +25,43 @@
#include "btle/custom/custom_helper.h" #include "btle/custom/custom_helper.h"
#include "nRF5xn.h" #include "nRF5xn.h"
#include "nrf_ble_gap.h"
namespace { namespace {
static const ble_gatts_rw_authorize_reply_params_t write_auth_queue_full_reply = { static const ble_gatts_rw_authorize_reply_params_t write_auth_queue_full_reply = {
.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE, /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
.params = { /* .params = */ {
.write = { /* .write = */ {
.gatt_status = BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL /* .gatt_status = */ BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL
} }
} }
}; };
static const ble_gatts_rw_authorize_reply_params_t write_auth_invalid_offset_reply = { static const ble_gatts_rw_authorize_reply_params_t write_auth_invalid_offset_reply = {
.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE, /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
.params = { /* .params = */ {
.write = { /* .write = */ {
.gatt_status = BLE_GATT_STATUS_ATTERR_INVALID_OFFSET /* .gatt_status = */ BLE_GATT_STATUS_ATTERR_INVALID_OFFSET
} }
} }
}; };
static const ble_gatts_rw_authorize_reply_params_t write_auth_succes_reply = { static const ble_gatts_rw_authorize_reply_params_t write_auth_succes_reply = {
.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE, /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
.params = { /* .params = */ {
.write = { /* .write = */ {
.gatt_status = BLE_GATT_STATUS_SUCCESS, /* .gatt_status = */ BLE_GATT_STATUS_SUCCESS,
.update = 0 /* .update = */ 0
} }
} }
}; };
static const ble_gatts_rw_authorize_reply_params_t write_auth_invalid_reply = { static const ble_gatts_rw_authorize_reply_params_t write_auth_invalid_reply = {
.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE, /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
.params = { /* .params = */ {
.write = { /* .write = */ {
.gatt_status = BLE_GATT_STATUS_ATTERR_INVALID /* .gatt_status = */ BLE_GATT_STATUS_ATTERR_INVALID
} }
} }
}; };
@ -164,21 +165,25 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
} }
ASSERT_TRUE ( ERROR_NONE == ASSERT_TRUE ( ERROR_NONE ==
custom_add_in_characteristic(BLE_GATT_HANDLE_INVALID, custom_add_in_characteristic(
&nordicUUID, BLE_GATT_HANDLE_INVALID,
p_char->getProperties(), &nordicUUID,
p_char->getRequiredSecurity(), p_char->getProperties(),
p_char->getValueAttribute().getValuePtr(), p_char->getReadSecurityRequirement(),
p_char->getValueAttribute().getLength(), p_char->getWriteSecurityRequirement(),
p_char->getValueAttribute().getMaxLength(), p_char->getUpdateSecurityRequirement(),
p_char->getValueAttribute().hasVariableLength(), p_char->getValueAttribute().getValuePtr(),
userDescriptionDescriptorValuePtr, p_char->getValueAttribute().getLength(),
userDescriptionDescriptorValueLen, p_char->getValueAttribute().getMaxLength(),
presentationFormatDescriptorValuePtr, p_char->getValueAttribute().hasVariableLength(),
presentationFormatDescriptorValueLen, userDescriptionDescriptorValuePtr,
p_char->isReadAuthorizationEnabled(), userDescriptionDescriptorValueLen,
p_char->isWriteAuthorizationEnabled(), presentationFormatDescriptorValuePtr,
&nrfCharacteristicHandles[characteristicCount]), presentationFormatDescriptorValueLen,
p_char->isReadAuthorizationEnabled(),
p_char->isWriteAuthorizationEnabled(),
&nrfCharacteristicHandles[characteristicCount]
),
BLE_ERROR_PARAM_OUT_OF_RANGE ); BLE_ERROR_PARAM_OUT_OF_RANGE );
/* Update the characteristic handle */ /* Update the characteristic handle */
@ -218,7 +223,9 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
p_desc->getLength(), p_desc->getLength(),
p_desc->getMaxLength(), p_desc->getMaxLength(),
p_desc->hasVariableLength(), p_desc->hasVariableLength(),
&nrfDescriptorHandles[descriptorCount]), &nrfDescriptorHandles[descriptorCount],
p_desc->getReadSecurityRequirement(),
p_desc->getWriteSecurityRequirement()),
BLE_ERROR_PARAM_OUT_OF_RANGE); BLE_ERROR_PARAM_OUT_OF_RANGE);
p_descriptors[descriptorCount] = p_desc; 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_error_t nRF5xGattServer::read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP)
{ {
ble_gatts_value_t value = { ble_gatts_value_t value = {
.len = *lengthP, /* .len = */ *lengthP,
.offset = 0, /* .offset = */ 0,
.p_value = buffer, /* .p_value = */ buffer,
}; };
ASSERT_TRUE( ERROR_NONE == 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_error_t returnValue = BLE_ERROR_NONE;
ble_gatts_value_t value = { ble_gatts_value_t value = {
.len = len, /* .len = */ len,
.offset = 0, /* .offset = */ 0,
.p_value = const_cast<uint8_t *>(buffer), /* .p_value = */ const_cast<uint8_t *>(buffer),
}; };
if (localOnly) { 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); error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params);
if (error != ERROR_NONE) { if (error != ERROR_NONE) {
switch (error) { switch (error) {
@ -453,7 +469,7 @@ ble_error_t nRF5xGattServer::reset(void)
@brief Callback handler for events getting pushed up from the SD @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; GattAttribute::Handle_t handle_value;
GattServerEvents::gattEvent_t eventType; GattServerEvents::gattEvent_t eventType;
@ -611,14 +627,14 @@ void nRF5xGattServer::hwCallback(ble_evt_t *p_ble_evt)
// success, signal it to the softdevice // success, signal it to the softdevice
ble_gatts_rw_authorize_reply_params_t reply = { ble_gatts_rw_authorize_reply_params_t reply = {
.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE, /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
.params = { /* .params = */ {
.write = { /* .write = */ {
.gatt_status = BLE_GATT_STATUS_SUCCESS, /* .gatt_status = */ BLE_GATT_STATUS_SUCCESS,
.update = 1, /* .update = */ 1,
.offset = input_req.offset, /* .offset = */ input_req.offset,
.len = input_req.len, /* .len = */ input_req.len,
.p_data = input_req.data /* .p_data = */ input_req.data
} }
} }
}; };
@ -639,12 +655,12 @@ void nRF5xGattServer::hwCallback(ble_evt_t *p_ble_evt)
} }
GattWriteAuthCallbackParams cbParams = { GattWriteAuthCallbackParams cbParams = {
.connHandle = conn_handle, /* .connHandle = */ conn_handle,
.handle = req->attr_handle, /* .handle = */ req->attr_handle,
.offset = req->offset, /* .offset = */ req->offset,
.len = req->length, /* .len = */ req->length,
.data = req->data, /* .data = */ req->data,
.authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member /* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
* set to AUTH_CALLBACK_REPLY_SUCCESS if the client * set to AUTH_CALLBACK_REPLY_SUCCESS if the client
* request is to proceed. */ * 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 ... // FIXME can't use ::write here, this function doesn't take the offset into account ...
ble_gatts_value_t value = { ble_gatts_value_t value = {
.len = req->length, /* .len = */ req->length,
.offset = req->offset, /* .offset = */ req->offset,
.p_value = req->data /* .p_value = */ req->data
}; };
uint32_t update_err = sd_ble_gatts_value_set(conn_handle, req->attr_handle, &value); uint32_t update_err = sd_ble_gatts_value_set(conn_handle, req->attr_handle, &value);
if (update_err) { if (update_err) {
@ -688,25 +704,25 @@ void nRF5xGattServer::hwCallback(ble_evt_t *p_ble_evt)
} }
GattWriteAuthCallbackParams cbParams = { GattWriteAuthCallbackParams cbParams = {
.connHandle = gattsEventP->conn_handle, /* .connHandle = */ gattsEventP->conn_handle,
.handle = handle_value, /* .handle = */ handle_value,
.offset = gattsEventP->params.authorize_request.request.write.offset, /* .offset = */ gattsEventP->params.authorize_request.request.write.offset,
.len = gattsEventP->params.authorize_request.request.write.len, /* .len = */ gattsEventP->params.authorize_request.request.write.len,
.data = gattsEventP->params.authorize_request.request.write.data, /* .data = */ gattsEventP->params.authorize_request.request.write.data,
.authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member /* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
* set to AUTH_CALLBACK_REPLY_SUCCESS if the client * set to AUTH_CALLBACK_REPLY_SUCCESS if the client
* request is to proceed. */ * request is to proceed. */
}; };
ble_gatts_rw_authorize_reply_params_t reply = { ble_gatts_rw_authorize_reply_params_t reply = {
.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE, /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
.params = { /* .params = */ {
.write = { /* .write = */ {
.gatt_status = p_characteristics[characteristicIndex]->authorizeWrite(&cbParams), /* .gatt_status = */ p_characteristics[characteristicIndex]->authorizeWrite(&cbParams),
.update = 1, /* .update = */ 1,
.offset = cbParams.offset, /* .offset = */ cbParams.offset,
.len = cbParams.len, /* .len = */ cbParams.len,
.p_data = cbParams.data /* .p_data = */ cbParams.data
} }
} }
}; };
@ -740,21 +756,21 @@ void nRF5xGattServer::hwCallback(ble_evt_t *p_ble_evt)
} }
case GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ: { case GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ: {
GattReadAuthCallbackParams cbParams = { GattReadAuthCallbackParams cbParams = {
.connHandle = gattsEventP->conn_handle, /* .connHandle = */ gattsEventP->conn_handle,
.handle = handle_value, /* .handle = */ handle_value,
.offset = gattsEventP->params.authorize_request.request.read.offset, /* .offset = */ gattsEventP->params.authorize_request.request.read.offset,
.len = 0, /* .len = */ 0,
.data = NULL, /* .data = */ NULL,
.authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member /* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
* set to AUTH_CALLBACK_REPLY_SUCCESS if the client * set to AUTH_CALLBACK_REPLY_SUCCESS if the client
* request is to proceed. */ * request is to proceed. */
}; };
ble_gatts_rw_authorize_reply_params_t reply = { ble_gatts_rw_authorize_reply_params_t reply = {
.type = BLE_GATTS_AUTHORIZE_TYPE_READ, /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_READ,
.params = { /* .params = */ {
.read = { /* .read = */ {
.gatt_status = p_characteristics[characteristicIndex]->authorizeRead(&cbParams) /* .gatt_status = */ p_characteristics[characteristicIndex]->authorizeRead(&cbParams)
} }
} }
}; };

View File

@ -602,6 +602,11 @@ ble_error_t nRF5xSecurityManager::set_peer_csrk(
return BLE_ERROR_NOT_IMPLEMENTED; return BLE_ERROR_NOT_IMPLEMENTED;
} }
ble_error_t nRF5xSecurityManager::remove_peer_csrk(connection_handle_t connection)
{
return BLE_ERROR_NOT_IMPLEMENTED;
}
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Authentication // Authentication
// //

View File

@ -284,6 +284,11 @@ public:
sign_count_t sign_counter sign_count_t sign_counter
); );
/**
* @see ::ble::pal::SecurityManager::remove_peer_csrk
*/
virtual ble_error_t remove_peer_csrk(connection_handle_t connection);
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Authentication // Authentication

View File

@ -208,7 +208,6 @@ SecurityManager& nRF5xn::getSecurityManager()
const SecurityManager& nRF5xn::getSecurityManager() const const SecurityManager& nRF5xn::getSecurityManager() const
{ {
static ble::pal::MemorySecurityDb m_db;
ble::pal::vendor::nordic::nRF5xSecurityManager &m_pal = ble::pal::vendor::nordic::nRF5xSecurityManager &m_pal =
ble::pal::vendor::nordic::nRF5xSecurityManager::get_security_manager(); ble::pal::vendor::nordic::nRF5xSecurityManager::get_security_manager();
static struct : ble::pal::SigningEventMonitor { static struct : ble::pal::SigningEventMonitor {
@ -217,7 +216,6 @@ const SecurityManager& nRF5xn::getSecurityManager() const
static ble::generic::GenericSecurityManager m_instance( static ble::generic::GenericSecurityManager m_instance(
m_pal, m_pal,
m_db,
const_cast<nRF5xGap&>(getGap()), const_cast<nRF5xGap&>(getGap()),
dummy_signing_event_monitor dummy_signing_event_monitor
); );
@ -233,8 +231,12 @@ nRF5xn::waitForEvent(void)
} }
void nRF5xn::processEvents() { void nRF5xn::processEvents() {
core_util_critical_section_enter();
if (isEventsSignaled) { if (isEventsSignaled) {
isEventsSignaled = false; isEventsSignaled = false;
core_util_critical_section_exit();
intern_softdevice_events_execute(); intern_softdevice_events_execute();
} else {
core_util_critical_section_exit();
} }
} }

View File

@ -22,7 +22,6 @@
#include "ble/BLEInstanceBase.h" #include "ble/BLEInstanceBase.h"
#include "ble/generic/GenericGattClient.h" #include "ble/generic/GenericGattClient.h"
#include "ble/generic/GenericSecurityManager.h" #include "ble/generic/GenericSecurityManager.h"
#include "ble/pal/MemorySecurityDb.h"
#include "ble/pal/SimpleEventQueue.h" #include "ble/pal/SimpleEventQueue.h"
#include "nRF5xPalSecurityManager.h" #include "nRF5xPalSecurityManager.h"

View File

@ -21,24 +21,12 @@
#include "btle_clock.h" #include "btle_clock.h"
#include "ble_flash.h" #include "ble_flash.h"
#include "ble_conn_params.h"
#include "btle_gap.h"
#include "custom/custom_helper.h" #include "custom/custom_helper.h"
#include "ble/GapEvents.h" #include "ble/GapEvents.h"
#include "nRF5xn.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 #ifdef S110
#define IS_LEGACY_DEVICE_MANAGER_ENABLED 1 #define IS_LEGACY_DEVICE_MANAGER_ENABLED 1
#elif defined(S130) || defined(S132) #elif defined(S130) || defined(S132)
@ -52,8 +40,6 @@ extern "C" {
#else #else
#include "nrf_fstorage.h" #include "nrf_fstorage.h"
#include "fds.h" #include "fds.h"
#include "peer_manager.h"
#include "ble_conn_state.h"
#endif #endif
#include "nrf_sdh.h" #include "nrf_sdh.h"
@ -64,6 +50,16 @@ extern "C" {
#include "nRF5xPalGattClient.h" #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 // Make this volatile at it will be set in interrupt context
volatile bool isEventsSignaled = false; 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. extern "C" void SD_EVT_IRQHandler(void); // export the softdevice event handler for registration by nvic-set-vector.
#if NRF_SDK14PLUS_EVENT_HANDLERS #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 #else
static void btle_handler(ble_evt_t *p_ble_evt); void btle_handler(ble_evt_t *p_ble_evt);
#endif #endif
#if !NRF_SDK14PLUS_EVENT_HANDLERS #if !NRF_SDK14PLUS_EVENT_HANDLERS
@ -232,9 +228,6 @@ error_t btle_init(void)
} }
#endif #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) #if (NRF_SD_BLE_API_VERSION <= 2)
ble_gap_addr_t addr; ble_gap_addr_t addr;
if (sd_ble_gap_address_get(&addr) != NRF_SUCCESS) { 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) { if (sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &addr) != NRF_SUCCESS) {
return ERROR_INVALID_PARAM; 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 #endif
// From SDK 14 onwards event handlers are registered differently // 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)); ASSERT_STATUS( softdevice_sys_evt_handler_set(sys_evt_dispatch));
#endif #endif
return btle_gap_init(); return ERROR_NONE;
} }
#if NRF_SDK14PLUS_EVENT_HANDLERS #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 #else
static void btle_handler(ble_evt_t *p_ble_evt) void btle_handler(const ble_evt_t *p_ble_evt)
#endif #endif
{ {
#if NRF_SDK14PLUS_EVENT_HANDLERS #if NRF_SDK14PLUS_EVENT_HANDLERS
(void)p_context; // Keep compiler happy (void)p_context; // Keep compiler happy
#endif #endif
using ble::pal::vendor::nordic::nRF5xGattClient; 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 // In SDK14+, all other modules from the SDK will be registered independently as softdevice events observers
#if !NRF_SDK14PLUS_EVENT_HANDLERS #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. // Forward BLE events to the Connection State module.
// This must be called before any event handler that uses this module. // This must be called before any event handler that uses this module.
ble_conn_state_on_ble_evt(p_ble_evt); 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
#endif #endif
@ -299,42 +286,16 @@ static void btle_handler(ble_evt_t *p_ble_evt)
nRF5xn &ble = nRF5xn::Instance(BLE::DEFAULT_INSTANCE); nRF5xn &ble = nRF5xn::Instance(BLE::DEFAULT_INSTANCE);
nRF5xGap &gap = (nRF5xGap &) ble.getGap(); nRF5xGap &gap = (nRF5xGap &) ble.getGap();
nRF5xGattServer &gattServer = (nRF5xGattServer &) ble.getGattServer(); nRF5xGattServer &gattServer = (nRF5xGattServer &) ble.getGattServer();
nRF5xSecurityManager &securityManager = (nRF5xSecurityManager &) ble.getSecurityManager(); nRF5xSecurityManager &securityManager = nRF5xSecurityManager::get_security_manager();
/* Custom event handler */ /* Custom event handler */
switch (p_ble_evt->header.evt_id) { switch (p_ble_evt->header.evt_id) {
case BLE_GAP_EVT_CONNECTED: { case BLE_GAP_EVT_CONNECTED:
Gap::Handle_t handle = p_ble_evt->evt.gap_evt.conn_handle; gap.on_connection(
#if defined(TARGET_MCU_NRF51_16K_S110) || defined(TARGET_MCU_NRF51_32K_S110) p_ble_evt->evt.gap_evt.conn_handle,
/* Only peripheral role is supported by S110 */ p_ble_evt->evt.gap_evt.params.connected
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
break; break;
}
case BLE_GAP_EVT_DISCONNECTED: { case BLE_GAP_EVT_DISCONNECTED: {
Gap::Handle_t handle = p_ble_evt->evt.gap_evt.conn_handle; 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 #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: case BLE_GAP_EVT_TIMEOUT:
gap.processTimeoutEvent(static_cast<Gap::TimeoutSource_t>(p_ble_evt->evt.gap_evt.params.timeout.src)); gap.processTimeoutEvent(static_cast<Gap::TimeoutSource_t>(p_ble_evt->evt.gap_evt.params.timeout.src));
break; break;
@ -431,21 +388,17 @@ static void btle_handler(ble_evt_t *p_ble_evt)
// BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION)); // BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION));
break; break;
case BLE_GAP_EVT_ADV_REPORT: { case BLE_GAP_EVT_ADV_REPORT:
const ble_gap_evt_adv_report_t *advReport = &p_ble_evt->evt.gap_evt.params.adv_report; gap.on_advertising_packet(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);
break; break;
}
default: default:
break; break;
} }
// Process security manager events
securityManager.sm_handler(p_ble_evt);
gattServer.hwCallback(p_ble_evt); gattServer.hwCallback(p_ble_evt);
} }

View File

@ -23,7 +23,6 @@ extern "C" {
#include "common/common.h" #include "common/common.h"
#include "ble_srv_common.h"
#include "headers/nrf_ble.h" #include "headers/nrf_ble.h"
#if NRF_SD_BLE_API_VERSION >= 5 #if NRF_SD_BLE_API_VERSION >= 5

View File

@ -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

View File

@ -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_

View File

@ -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, &params);
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

View File

@ -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_ */

View File

@ -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)

View File

@ -31,6 +31,32 @@ typedef struct {
static unsigned uuidTableEntries = 0; /* current usage of the table */ static unsigned uuidTableEntries = 0; /* current usage of the table */
converted_uuid_table_entry_t convertedUUIDTable[UUID_TABLE_MAX_ENTRIES]; 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() { void custom_reset_128bits_uuid_table() {
uuidTableEntries = 0; 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, error_t custom_add_in_characteristic(uint16_t service_handle,
ble_uuid_t *p_uuid, ble_uuid_t *p_uuid,
uint8_t properties, 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, uint8_t *p_data,
uint16_t length, uint16_t length,
uint16_t max_length, uint16_t max_length,
@ -227,8 +255,8 @@ error_t custom_add_in_characteristic(uint16_t service_handle,
/* Notification requires cccd */ /* Notification requires cccd */
memclr_( &cccd_md, sizeof(ble_gatts_attr_md_t)); memclr_( &cccd_md, sizeof(ble_gatts_attr_md_t));
cccd_md.vloc = BLE_GATTS_VLOC_STACK; cccd_md.vloc = BLE_GATTS_VLOC_STACK;
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); set_perm(cccd_md.read_perm, GattAttribute::Security_t::NONE);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); set_perm(cccd_md.write_perm, update_security);
} }
ble_gatts_char_md_t char_md = {0}; 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 */ /* Always set variable size */
attr_md.vlen = has_variable_len; attr_md.vlen = has_variable_len;
if (char_props.read || char_props.notify || char_props.indicate) { set_perm(attr_md.read_perm, read_security);
switch (requiredSecurity) { set_perm(attr_md.write_perm, write_security);
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;
};
}
ble_gatts_attr_t attr_char_value = {0}; 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 length,
uint16_t max_length, uint16_t max_length,
bool has_variable_len, 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 */ /* Descriptor metadata */
ble_gatts_attr_md_t desc_md = {0}; 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; desc_md.vlen = has_variable_len;
/* Make it readable and writable */ /* Make it readable and writable */
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_md.read_perm); set_perm(desc_md.read_perm, read_security);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_md.write_perm); set_perm(desc_md.write_perm, write_security);
ble_gatts_attr_t attr_desc = {0}; ble_gatts_attr_t attr_desc = {0};

View File

@ -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, error_t custom_add_in_characteristic(uint16_t service_handle,
ble_uuid_t *p_uuid, ble_uuid_t *p_uuid,
uint8_t properties, 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, uint8_t *p_data,
uint16_t length, uint16_t length,
uint16_t max_length, uint16_t max_length,
@ -61,7 +63,9 @@ error_t custom_add_in_descriptor(uint16_t char_handle,
uint16_t length, uint16_t length,
uint16_t max_length, uint16_t max_length,
bool has_variable_len, 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 #ifdef __cplusplus
} }

View File

@ -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)

View File

@ -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_

View File

@ -23,20 +23,117 @@
#include "ble/BLE.h" #include "ble/BLE.h"
#include "common/common.h" #include "common/common.h"
#include "ble_advdata.h"
#include "headers/ble_hci.h" #include "headers/ble_hci.h"
#include "ble/pal/ConnectionEventMonitor.h"
#include "nRF5xPalSecurityManager.h"
#if (NRF_SD_BLE_API_VERSION >= 3) using ble::pal::vendor::nordic::nRF5xSecurityManager;
#include "peer_manager.h" typedef nRF5xSecurityManager::resolving_list_entry_t resolving_list_entry_t;
#include "peer_data_storage.h" 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 #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 &params) {
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) { void radioNotificationStaticCallback(bool param) {
nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap(); nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap();
gap.processRadioNotificationEvent(param); 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 @brief Sets the advertising parameters and payload for the device
@ -196,6 +293,28 @@ ble_error_t nRF5xGap::startAdvertising(const GapAdvertisingParams &params)
} }
} }
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; adv_para.p_whitelist = &whitelist;
#endif #endif
/* For NRF_SD_BLE_API_VERSION >= 3 nRF5xGap::setWhitelist setups the whitelist. */ /* 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.selective = scanningPolicyMode; /**< If 1, ignore unknown devices (non whitelisted). */
scanParams.p_whitelist = &whitelist; /**< Pointer to whitelist, NULL if none is given. */ scanParams.p_whitelist = &whitelist; /**< Pointer to whitelist, NULL if none is given. */
#else #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.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.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. */ 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) { if (sd_ble_gap_scan_start(&scanParams) != NRF_SUCCESS) {
return BLE_ERROR_PARAM_OUT_OF_RANGE; return BLE_ERROR_PARAM_OUT_OF_RANGE;
@ -313,6 +440,7 @@ ble_error_t nRF5xGap::connect(const Address_t peerAddr,
const GapScanningParams *scanParamsIn) const GapScanningParams *scanParamsIn)
{ {
ble_gap_addr_t addr; ble_gap_addr_t addr;
ble_gap_addr_t* addr_ptr = &addr;
addr.addr_type = peerAddrType; addr.addr_type = peerAddrType;
memcpy(addr.addr, peerAddr, Gap::ADDR_LEN); 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.selective = scanningPolicyMode; /**< If 1, ignore unknown devices (non whitelisted). */
scanParams.p_whitelist = &whitelist; /**< Pointer to whitelist, NULL if none is given. */ 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 #else
/* For NRF_SD_BLE_API_VERSION >= 3 nRF5xGap::setWhitelist setups the whitelist. */ /* 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 #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 #else
uint32_t rc = sd_ble_gap_connect(&addr, &scanParams, &connParams); uint32_t rc = sd_ble_gap_connect(addr_ptr, &scanParams, &connParams);
#endif #endif
if (rc == NRF_SUCCESS) { if (rc == NRF_SUCCESS) {
return BLE_ERROR_NONE; return BLE_ERROR_NONE;
@ -500,7 +656,6 @@ ble_error_t nRF5xGap::reset(void)
/* Clear the internal whitelist */ /* Clear the internal whitelist */
whitelistAddressesSize = 0; whitelistAddressesSize = 0;
return BLE_ERROR_NONE; 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) ble_error_t nRF5xGap::setAddress(AddressType_t type, const Address_t address)
{ {
#if (NRF_SD_BLE_API_VERSION <= 2) using BLEProtocol::AddressType;
uint8_t cycle_mode;
#else
ble_gap_privacy_params_t privacy_params = {0};
#endif
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; 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. #if (NRF_SD_BLE_API_VERSION <= 2)
When using Random Private addresses, the cycle mode must be Auto. uint32_t err = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &dev_addr);
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;
#else #else
privacy_params.privacy_mode = BLE_GAP_PRIVACY_MODE_OFF; uint32_t err = sd_ble_gap_addr_set(&dev_addr);
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);
#endif #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_error_t nRF5xGap::getAddress(AddressType_t *typeP, Address_t address)
{ {
ble_gap_addr_t dev_addr; // FIXME: check if privacy is enabled ?
ble_gap_irk_t irk = {0}; if (typeP == NULL || address == NULL) {
ble_gap_privacy_params_t privacy_params = {0}; return BLE_ERROR_INVALID_PARAM;
privacy_params.p_device_irk = &irk; }
ble_gap_addr_t dev_addr;
#if (NRF_SD_BLE_API_VERSION <= 2) #if (NRF_SD_BLE_API_VERSION <= 2)
if (sd_ble_gap_address_get(&dev_addr) != NRF_SUCCESS) { if (sd_ble_gap_address_get(&dev_addr) != NRF_SUCCESS) {
return BLE_ERROR_PARAM_OUT_OF_RANGE;
}
#else #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) { if (sd_ble_gap_addr_get(&dev_addr) != NRF_SUCCESS) {
#endif
return BLE_ERROR_PARAM_OUT_OF_RANGE; return BLE_ERROR_PARAM_OUT_OF_RANGE;
} }
#endif
if (typeP != NULL) { switch (dev_addr.addr_type) {
*typeP = static_cast<AddressType_t>(dev_addr.addr_type); case BLE_GAP_ADDR_TYPE_PUBLIC:
} *typeP = BLEProtocol::AddressType::PUBLIC;
if (address != NULL) { break;
memcpy(address, dev_addr.addr, ADDR_LEN);
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; return BLE_ERROR_NONE;
} }
@ -824,17 +951,33 @@ ble_error_t nRF5xGap::setWhitelist(const Gap::Whitelist_t &whitelistIn)
} }
whitelistAddressesSize = whitelistIn.size; whitelistAddressesSize = whitelistIn.size;
ble_gap_addr_t* pp_addrs[YOTTA_CFG_WHITELIST_MAX_SIZE];
for (uint32_t i = 0; i < whitelistIn.size; ++i) { 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); whitelistAddresses[i].addr_type = static_cast<uint8_t> (whitelistIn.addresses[i].type);
pp_addrs[i] = &whitelistAddresses[i];
} }
#if (NRF_SD_BLE_API_VERSION >= 3) ble_gap_addr_t** addresses_list_ptr = (whitelistIn.size == 0) ? NULL : pp_addrs;
updateWhiteAndIdentityListInStack();
#endif
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) ble_error_t nRF5xGap::setAdvertisingPolicyMode(Gap::AdvertisingPolicyMode_t mode)
{ {
advertisingPolicyMode = mode; advertisingPolicyMode = mode;
return BLE_ERROR_NONE; return BLE_ERROR_NONE;
} }
@ -973,267 +1115,247 @@ Gap::InitiatorPolicyMode_t nRF5xGap::getInitiatorPolicyMode(void) const
return Gap::INIT_POLICY_IGNORE_WHITELIST; return Gap::INIT_POLICY_IGNORE_WHITELIST;
} }
#if (NRF_SD_BLE_API_VERSION <= 2) ble_error_t nRF5xGap::enablePrivacy(bool enable_privacy)
/**************************************************************************/
/*!
@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_gap_whitelist_t whitelistFromBondTable; if (enable_privacy == _privacy_enabled) {
ble_gap_addr_t *addressPtr[1]; return BLE_ERROR_NONE;
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;
} }
/** ble_error_t err = BLE_ERROR_UNSPECIFIED;
* For every private resolvable address in the local whitelist check if if (enable_privacy == false) {
* there is an IRK for said address in the bond table and add it to the err = setAddress(_non_private_address_type, _non_private_address);
* 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);
} else { } else {
ble_gap_id_key_t * pp_identities[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; err = getAddress(&_non_private_address_type, _non_private_address);
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);
} }
if (retc == NRF_SUCCESS) { if (err) {
if (gapAdrHelper.addrs_cnt == 0) { return err;
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);
}
} }
switch(retc) { #if (NRF_SD_BLE_API_VERSION > 2)
case NRF_SUCCESS: ble_gap_privacy_params_t privacy_config = { 0 };
return BLE_ERROR_NONE; if (sd_ble_gap_privacy_get(&privacy_config)) {
return BLE_ERROR_UNSPECIFIED;
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;
} }
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 #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
);
}

View File

@ -44,6 +44,7 @@
#include "ble/GapAdvertisingData.h" #include "ble/GapAdvertisingData.h"
#include "ble/Gap.h" #include "ble/Gap.h"
#include "ble/GapScanningParams.h" #include "ble/GapScanningParams.h"
#include "ble/pal/ConnectionEventMonitor.h"
#include "nrf_soc.h" #include "nrf_soc.h"
@ -52,8 +53,6 @@ extern "C" {
#include "app_util_platform.h" #include "app_util_platform.h"
} }
#include "btle_security.h"
void radioNotificationStaticCallback(bool param); 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: public:
nRF5xGap();
virtual ~nRF5xGap() { }
/* Functions that must be implemented from Gap */ /* Functions that must be implemented from Gap */
virtual ble_error_t setAddress(AddressType_t type, const Address_t address); virtual ble_error_t setAddress(AddressType_t type, const Address_t address);
virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address); virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address);
@ -129,6 +130,23 @@ public:
return BLE_ERROR_UNSPECIFIED; 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 */ /* 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) #if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams); virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams);
@ -148,39 +166,6 @@ private:
uint8_t whitelistAddressesSize; uint8_t whitelistAddressesSize;
ble_gap_addr_t whitelistAddresses[YOTTA_CFG_WHITELIST_MAX_SIZE]; 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: private:
bool radioNotificationCallbackParam; /* parameter to be passed into the Timeout-generated radio notification callback. */ bool radioNotificationCallbackParam; /* parameter to be passed into the Timeout-generated radio notification callback. */
Timeout radioNotificationTimeout; Timeout radioNotificationTimeout;
@ -262,22 +247,42 @@ private:
radioNotificationTimeout.attach_us(mbed::callback(this, &nRF5xGap::postRadioNotificationCallback), 0); radioNotificationTimeout.attach_us(mbed::callback(this, &nRF5xGap::postRadioNotificationCallback), 0);
} }
friend void radioNotificationStaticCallback(bool param); /* allow invocations of processRadioNotificationEvent() */ 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: 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; 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. * Allow instantiation from nRF5xn when required.
*/ */
friend class nRF5xn; 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 &); nRF5xGap(nRF5xGap const &);
void operator=(nRF5xGap const &); void operator=(nRF5xGap const &);
}; };

View File

@ -29,38 +29,38 @@
namespace { namespace {
static const ble_gatts_rw_authorize_reply_params_t write_auth_queue_full_reply = { static const ble_gatts_rw_authorize_reply_params_t write_auth_queue_full_reply = {
.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE, /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
.params = { /* .params = */ {
.write = { /* .write = */ {
.gatt_status = BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL /* .gatt_status = */ BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL
} }
} }
}; };
static const ble_gatts_rw_authorize_reply_params_t write_auth_invalid_offset_reply = { static const ble_gatts_rw_authorize_reply_params_t write_auth_invalid_offset_reply = {
.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE, /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
.params = { /* .params = */ {
.write = { /* .write = */ {
.gatt_status = BLE_GATT_STATUS_ATTERR_INVALID_OFFSET /* .gatt_status = */ BLE_GATT_STATUS_ATTERR_INVALID_OFFSET
} }
} }
}; };
static const ble_gatts_rw_authorize_reply_params_t write_auth_succes_reply = { static const ble_gatts_rw_authorize_reply_params_t write_auth_succes_reply = {
.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE, /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
.params = { /* .params = */ {
.write = { /* .write = */ {
.gatt_status = BLE_GATT_STATUS_SUCCESS, /* .gatt_status = */ BLE_GATT_STATUS_SUCCESS,
.update = 0 /* .update = */ 0
} }
} }
}; };
static const ble_gatts_rw_authorize_reply_params_t write_auth_invalid_reply = { static const ble_gatts_rw_authorize_reply_params_t write_auth_invalid_reply = {
.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE, /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
.params = { /* .params = */ {
.write = { /* .write = */ {
.gatt_status = BLE_GATT_STATUS_ATTERR_INVALID /* .gatt_status = */ BLE_GATT_STATUS_ATTERR_INVALID
} }
} }
}; };
@ -164,10 +164,13 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
} }
ASSERT_TRUE ( ERROR_NONE == ASSERT_TRUE ( ERROR_NONE ==
custom_add_in_characteristic(BLE_GATT_HANDLE_INVALID, custom_add_in_characteristic(
BLE_GATT_HANDLE_INVALID,
&nordicUUID, &nordicUUID,
p_char->getProperties(), p_char->getProperties(),
p_char->getRequiredSecurity(), p_char->getReadSecurityRequirement(),
p_char->getWriteSecurityRequirement(),
p_char->getUpdateSecurityRequirement(),
p_char->getValueAttribute().getValuePtr(), p_char->getValueAttribute().getValuePtr(),
p_char->getValueAttribute().getLength(), p_char->getValueAttribute().getLength(),
p_char->getValueAttribute().getMaxLength(), p_char->getValueAttribute().getMaxLength(),
@ -178,7 +181,8 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
presentationFormatDescriptorValueLen, presentationFormatDescriptorValueLen,
p_char->isReadAuthorizationEnabled(), p_char->isReadAuthorizationEnabled(),
p_char->isWriteAuthorizationEnabled(), p_char->isWriteAuthorizationEnabled(),
&nrfCharacteristicHandles[characteristicCount]), &nrfCharacteristicHandles[characteristicCount]
),
BLE_ERROR_PARAM_OUT_OF_RANGE ); BLE_ERROR_PARAM_OUT_OF_RANGE );
/* Update the characteristic handle */ /* Update the characteristic handle */
@ -218,7 +222,9 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
p_desc->getLength(), p_desc->getLength(),
p_desc->getMaxLength(), p_desc->getMaxLength(),
p_desc->hasVariableLength(), p_desc->hasVariableLength(),
&nrfDescriptorHandles[descriptorCount]), &nrfDescriptorHandles[descriptorCount],
p_desc->getReadSecurityRequirement(),
p_desc->getWriteSecurityRequirement()),
BLE_ERROR_PARAM_OUT_OF_RANGE); BLE_ERROR_PARAM_OUT_OF_RANGE);
p_descriptors[descriptorCount] = p_desc; 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_error_t nRF5xGattServer::read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP)
{ {
ble_gatts_value_t value = { ble_gatts_value_t value = {
.len = *lengthP, /* .len = */ *lengthP,
.offset = 0, /* .offset = */ 0,
.p_value = buffer, /* .p_value = */ buffer,
}; };
ASSERT_TRUE( ERROR_NONE == 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_error_t returnValue = BLE_ERROR_NONE;
ble_gatts_value_t value = { ble_gatts_value_t value = {
.len = len, /* .len = */ len,
.offset = 0, /* .offset = */ 0,
.p_value = const_cast<uint8_t *>(buffer), /* .p_value = */ const_cast<uint8_t *>(buffer),
}; };
if (localOnly) { 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); error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params);
if (error != ERROR_NONE) { if (error != ERROR_NONE) {
switch (error) { switch (error) {
@ -618,14 +633,14 @@ void nRF5xGattServer::hwCallback(const ble_evt_t *p_ble_evt)
// success, signal it to the softdevice // success, signal it to the softdevice
ble_gatts_rw_authorize_reply_params_t reply = { ble_gatts_rw_authorize_reply_params_t reply = {
.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE, /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
.params = { /* .params = */ {
.write = { /* .write = */ {
.gatt_status = BLE_GATT_STATUS_SUCCESS, /* .gatt_status = */ BLE_GATT_STATUS_SUCCESS,
.update = 1, /* .update = */ 1,
.offset = input_req.offset, /* .offset = */ input_req.offset,
.len = input_req.len, /* .len = */ input_req.len,
.p_data = input_req.data /* .p_data = */ input_req.data
} }
} }
}; };
@ -646,12 +661,12 @@ void nRF5xGattServer::hwCallback(const ble_evt_t *p_ble_evt)
} }
GattWriteAuthCallbackParams cbParams = { GattWriteAuthCallbackParams cbParams = {
.connHandle = conn_handle, /* .connHandle = */ conn_handle,
.handle = req->attr_handle, /* .handle = */ req->attr_handle,
.offset = req->offset, /* .offset = */ req->offset,
.len = req->length, /* .len = */ req->length,
.data = req->data, /* .data = */ req->data,
.authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member /* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
* set to AUTH_CALLBACK_REPLY_SUCCESS if the client * set to AUTH_CALLBACK_REPLY_SUCCESS if the client
* request is to proceed. */ * 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 ... // FIXME can't use ::write here, this function doesn't take the offset into account ...
ble_gatts_value_t value = { ble_gatts_value_t value = {
.len = req->length, /* .len = */ req->length,
.offset = req->offset, /* .offset = */ req->offset,
.p_value = req->data /* .p_value = */ req->data
}; };
uint32_t update_err = sd_ble_gatts_value_set(conn_handle, req->attr_handle, &value); uint32_t update_err = sd_ble_gatts_value_set(conn_handle, req->attr_handle, &value);
if (update_err) { if (update_err) {
@ -695,25 +710,25 @@ void nRF5xGattServer::hwCallback(const ble_evt_t *p_ble_evt)
} }
GattWriteAuthCallbackParams cbParams = { GattWriteAuthCallbackParams cbParams = {
.connHandle = gattsEventP->conn_handle, /* .connHandle = */ gattsEventP->conn_handle,
.handle = handle_value, /* .handle = */ handle_value,
.offset = gattsEventP->params.authorize_request.request.write.offset, /* .offset = */ gattsEventP->params.authorize_request.request.write.offset,
.len = gattsEventP->params.authorize_request.request.write.len, /* .len = */ gattsEventP->params.authorize_request.request.write.len,
.data = gattsEventP->params.authorize_request.request.write.data, /* .data = */ gattsEventP->params.authorize_request.request.write.data,
.authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member /* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
* set to AUTH_CALLBACK_REPLY_SUCCESS if the client * set to AUTH_CALLBACK_REPLY_SUCCESS if the client
* request is to proceed. */ * request is to proceed. */
}; };
ble_gatts_rw_authorize_reply_params_t reply = { ble_gatts_rw_authorize_reply_params_t reply = {
.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE, /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
.params = { /* .params = */ {
.write = { /* .write = */ {
.gatt_status = p_characteristics[characteristicIndex]->authorizeWrite(&cbParams), /* .gatt_status = */ p_characteristics[characteristicIndex]->authorizeWrite(&cbParams),
.update = 1, /* .update = */ 1,
.offset = cbParams.offset, /* .offset = */ cbParams.offset,
.len = cbParams.len, /* .len = */ cbParams.len,
.p_data = cbParams.data /* .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: { case GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ: {
GattReadAuthCallbackParams cbParams = { GattReadAuthCallbackParams cbParams = {
.connHandle = gattsEventP->conn_handle, /* .connHandle = */ gattsEventP->conn_handle,
.handle = handle_value, /* .handle = */ handle_value,
.offset = gattsEventP->params.authorize_request.request.read.offset, /* .offset = */ gattsEventP->params.authorize_request.request.read.offset,
.len = 0, /* .len = */ 0,
.data = NULL, /* .data = */ NULL,
.authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member /* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
* set to AUTH_CALLBACK_REPLY_SUCCESS if the client * set to AUTH_CALLBACK_REPLY_SUCCESS if the client
* request is to proceed. */ * request is to proceed. */
}; };
ble_gatts_rw_authorize_reply_params_t reply = { ble_gatts_rw_authorize_reply_params_t reply = {
.type = BLE_GATTS_AUTHORIZE_TYPE_READ, /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_READ,
.params = { /* .params = */ {
.read = { /* .read = */ {
.gatt_status = p_characteristics[characteristicIndex]->authorizeRead(&cbParams) /* .gatt_status = */ p_characteristics[characteristicIndex]->authorizeRead(&cbParams)
} }
} }
}; };

View File

@ -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 &ltk,
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 &ltk,
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 &ltk,
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_ */

View File

@ -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__

View File

@ -62,8 +62,7 @@ nRF5xn::nRF5xn(void) :
instanceID(BLE::DEFAULT_INSTANCE), instanceID(BLE::DEFAULT_INSTANCE),
gapInstance(), gapInstance(),
gattServerInstance(NULL), gattServerInstance(NULL),
gattClient(&(ble::pal::vendor::nordic::nRF5xGattClient::get_client())), gattClient(&(ble::pal::vendor::nordic::nRF5xGattClient::get_client()))
securityManagerInstance(NULL)
{ {
} }
@ -126,7 +125,7 @@ ble_error_t nRF5xn::init(BLE::InstanceID_t instanceID, FunctionPointerWithContex
return BLE_ERROR_ALREADY_INITIALIZED; return BLE_ERROR_ALREADY_INITIALIZED;
} }
instanceID = instanceID; this->instanceID = instanceID;
/* ToDo: Clear memory contents, reset the SD, etc. */ /* ToDo: Clear memory contents, reset the SD, etc. */
if (btle_init() != ERROR_NONE) { 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. */ /* S110 does not support BLE client features, nothing to reset. */
#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) #if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
error = getGattClient().reset(); error = getGattClient().reset();
@ -214,6 +206,29 @@ ble_error_t nRF5xn::shutdown(void)
return BLE_ERROR_NONE; 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 void
nRF5xn::waitForEvent(void) nRF5xn::waitForEvent(void)
{ {
@ -223,19 +238,18 @@ nRF5xn::waitForEvent(void)
void nRF5xn::processEvents() { void nRF5xn::processEvents() {
core_util_critical_section_enter(); core_util_critical_section_enter();
while (isEventsSignaled) { if (isEventsSignaled) {
isEventsSignaled = false; isEventsSignaled = false;
core_util_critical_section_exit(); 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 // 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 // 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 // This will process any pending events from the Softdevice
nrf_sdh_evts_poll(); nrf_sdh_evts_poll();
#else #else
intern_softdevice_events_execute(); intern_softdevice_events_execute();
#endif #endif
} else {
core_util_critical_section_enter(); core_util_critical_section_exit();
} }
core_util_critical_section_exit();
} }

View File

@ -21,10 +21,12 @@
#include "ble/blecommon.h" #include "ble/blecommon.h"
#include "ble/BLEInstanceBase.h" #include "ble/BLEInstanceBase.h"
#include "ble/generic/GenericGattClient.h" #include "ble/generic/GenericGattClient.h"
#include "ble/generic/GenericSecurityManager.h"
#include "ble/pal/SimpleEventQueue.h"
#include "nRF5xPalSecurityManager.h"
#include "nRF5xGap.h" #include "nRF5xGap.h"
#include "nRF5xGattServer.h" #include "nRF5xGattServer.h"
#include "nRF5xSecurityManager.h"
#include "btle.h" #include "btle.h"
@ -82,18 +84,14 @@ public:
} }
/** /**
* Accessors to Security Manager. This function checks whether a SecurityManager * @see BLEInstanceBase::getSecurityManager
* object was previously instantiated. If such object does not exist, then
* it is created before returning.
*
* @return A reference to GattServer.
*/ */
virtual nRF5xSecurityManager &getSecurityManager() { virtual SecurityManager &getSecurityManager();
if (securityManagerInstance == NULL) {
securityManagerInstance = new nRF5xSecurityManager(); /**
} * @see BLEInstanceBase::getSecurityManager
return *securityManagerInstance; */
} virtual const SecurityManager &getSecurityManager() const;
/** /**
* Accessors to GAP. This function checks whether gapInstance points to an * Accessors to GAP. This function checks whether gapInstance points to an
@ -130,23 +128,6 @@ public:
return *gattServerInstance; 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 waitForEvent(void);
virtual void processEvents(); virtual void processEvents();
@ -170,10 +151,7 @@ private:
* it can be assigned inside a 'const' function. */ * it can be assigned inside a 'const' function. */
ble::generic::GenericGattClient gattClient; 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 #endif

View File

@ -14,8 +14,8 @@
#define MBED_RAM_START 0x20000000 #define MBED_RAM_START 0x20000000
#define MBED_RAM_SIZE 0x10000 #define MBED_RAM_SIZE 0x10000
#else #else
#define MBED_RAM_START 0x20003800 #define MBED_RAM_START 0x200031D0
#define MBED_RAM_SIZE 0xC800 #define MBED_RAM_SIZE 0xCE30
#endif #endif
#define MBED_RAM0_START MBED_RAM_START #define MBED_RAM0_START MBED_RAM_START

View File

@ -30,8 +30,8 @@
#define MBED_RAM_START 0x20000000 #define MBED_RAM_START 0x20000000
#define MBED_RAM_SIZE 0x10000 #define MBED_RAM_SIZE 0x10000
#else #else
#define MBED_RAM_START 0x20003800 #define MBED_RAM_START 0x200031D0
#define MBED_RAM_SIZE 0xC800 #define MBED_RAM_SIZE 0xCE30
#endif #endif
#define MBED_RAM0_START MBED_RAM_START #define MBED_RAM0_START MBED_RAM_START

View File

@ -16,8 +16,8 @@ if (MBED_APP_START == 0) {
define symbol MBED_RAM_START = 0x20000000; define symbol MBED_RAM_START = 0x20000000;
define symbol MBED_RAM_SIZE = 0x10000; define symbol MBED_RAM_SIZE = 0x10000;
} else { } else {
define symbol MBED_RAM_START = 0x20003800; define symbol MBED_RAM_START = 0x20003188;
define symbol MBED_RAM_SIZE = 0xC800; define symbol MBED_RAM_SIZE = 0x3CE78;
} }
define symbol MBED_RAM0_START = MBED_RAM_START; define symbol MBED_RAM0_START = MBED_RAM_START;

Some files were not shown because too many files have changed in this diff Show More