mbed-os/features/FEATURE_BLE/ble/SecurityManager.h

1033 lines
44 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/* mbed Microcontroller Library
* Copyright (c) 2006-2015 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 __SECURITY_MANAGER_H__
#define __SECURITY_MANAGER_H__
#include <stdint.h>
#include "Gap.h"
#include "CallChainOfFunctionPointersWithContext.h"
#include "ble/BLETypes.h"
class SecurityManagerEventHandler;
class LegacySecurityManagerEventHandler;
using ble::connection_handle_t;
using ble::pairing_failure_t;
using ble::link_encryption_t;
using ble::csrk_t;
using ble::oob_tk_t;
using ble::oob_rand_t;
using ble::oob_confirm_t;
using ble::address_t;
class SecurityManager {
public:
enum Keypress_t {
KEYPRESS_STARTED, /**< Passkey entry started */
KEYPRESS_ENTERED, /**< Passkey digit entered */
KEYPRESS_ERASED, /**< Passkey digit erased */
KEYPRESS_CLEARED, /**< Passkey cleared */
KEYPRESS_COMPLETED, /**< Passkey entry completed */
};
enum SecurityMode_t {
SECURITY_MODE_NO_ACCESS,
SECURITY_MODE_ENCRYPTION_OPEN_LINK, /**< Require no protection, open link. */
SECURITY_MODE_ENCRYPTION_NO_MITM, /**< Require encryption, but no MITM protection. */
SECURITY_MODE_ENCRYPTION_WITH_MITM, /**< Require encryption and MITM protection. */
SECURITY_MODE_SIGNED_NO_MITM, /**< Require signing or encryption, but no MITM protection. */
SECURITY_MODE_SIGNED_WITH_MITM, /**< Require signing or encryption, and MITM protection. */
};
/**
* @brief Defines possible security status or states.
*
* @details Defines possible security status or states of a link when requested by getLinkSecurity().
*/
enum LinkSecurityStatus_t {
NOT_ENCRYPTED, /**< The link is not secured. */
ENCRYPTION_IN_PROGRESS, /**< Link security is being established.*/
ENCRYPTED /**< The link is secure.*/
};
enum SecurityIOCapabilities_t {
IO_CAPS_DISPLAY_ONLY = 0x00, /**< Display only. */
IO_CAPS_DISPLAY_YESNO = 0x01, /**< Display and yes/no entry. */
IO_CAPS_KEYBOARD_ONLY = 0x02, /**< Keyboard only. */
IO_CAPS_NONE = 0x03, /**< No I/O capabilities. */
IO_CAPS_KEYBOARD_DISPLAY = 0x04, /**< Keyboard and display. */
};
enum SecurityCompletionStatus_t {
SEC_STATUS_SUCCESS = 0x00, /**< Procedure completed with success. */
SEC_STATUS_TIMEOUT = 0x01, /**< Procedure timed out. */
SEC_STATUS_PDU_INVALID = 0x02, /**< Invalid PDU received. */
SEC_STATUS_PASSKEY_ENTRY_FAILED = 0x81, /**< Passkey entry failed (user cancelled or other). */
SEC_STATUS_OOB_NOT_AVAILABLE = 0x82, /**< Out of Band Key not available. */
SEC_STATUS_AUTH_REQ = 0x83, /**< Authentication requirements not met. */
SEC_STATUS_CONFIRM_VALUE = 0x84, /**< Confirm value failed. */
SEC_STATUS_PAIRING_NOT_SUPP = 0x85, /**< Pairing not supported. */
SEC_STATUS_ENC_KEY_SIZE = 0x86, /**< Encryption key size. */
SEC_STATUS_SMP_CMD_UNSUPPORTED = 0x87, /**< Unsupported SMP command. */
SEC_STATUS_UNSPECIFIED = 0x88, /**< Unspecified reason. */
SEC_STATUS_REPEATED_ATTEMPTS = 0x89, /**< Too little time elapsed since last attempt. */
SEC_STATUS_INVALID_PARAMS = 0x8A, /**< Invalid parameters. */
SEC_STATUS_DHKEY_CHECK_FAILED = 0x8B, /**< DHKey received doesnt match locally calculated one. */
SEC_STATUS_COMPARISON_FAILED = 0x8C, /**< Values in the numeric comparison protocol do not match. */
};
/**
* Declaration of type containing a passkey to be used during pairing. This
* is passed into initializeSecurity() to specify a pre-programmed passkey
* for authentication instead of generating a random one.
*/
static const unsigned PASSKEY_LEN = 6;
typedef uint8_t Passkey_t[PASSKEY_LEN]; /**< 6-digit passkey in ASCII ('0'-'9' digits only). */
typedef FunctionPointerWithContext<const SecurityManager *> SecurityManagerShutdownCallback_t;
typedef CallChainOfFunctionPointersWithContext<const SecurityManager *> SecurityManagerShutdownCallbackChain_t;
/* legacy callbacks, please use SecurityManagerEventHandler instead */
typedef void (*HandleSpecificEvent_t)(connection_handle_t connectionHandle);
typedef void (*SecuritySetupInitiatedCallback_t)(connection_handle_t, bool allowBonding, bool requireMITM, SecurityIOCapabilities_t iocaps);
typedef void (*SecuritySetupCompletedCallback_t)(connection_handle_t, SecurityCompletionStatus_t status);
typedef void (*LinkSecuredCallback_t)(connection_handle_t connectionHandle, SecurityMode_t securityMode);
typedef void (*PasskeyDisplayCallback_t)(connection_handle_t connectionHandle, const Passkey_t passkey);
/** The stack will use these functions to signal events to the application,
* subclass to override handlers. Use SecurityManager::setSecurityManagerEventHandler
* to set the interface implementation to be used. */
class SecurityManagerEventHandler {
public:
SecurityManagerEventHandler() {};
virtual ~SecurityManagerEventHandler() {};
////////////////////////////////////////////////////////////////////////////
// Pairing
//
/**
* Request application to accept or reject pairing. Application should respond by
* calling the appropriate function: acceptPairingRequest or cancelPairingRequest
*
* @param[in] connectionHandle connection connectionHandle
*/
virtual void pairingRequest(connection_handle_t connectionHandle) {
(void)connectionHandle;
}
/**
* Indicate to the application that pairing has completed.
*
* @param[in] connectionHandle connection connectionHandle
* @param[in] result result of the pairing indicating success or reason for failure
*/
virtual void pairingResult(connection_handle_t connectionHandle, SecurityCompletionStatus_t result) {
(void)connectionHandle;
(void)result;
}
////////////////////////////////////////////////////////////////////////////
// Security
//
/**
* Indicate to the application that the set timeout time has elapsed without
* receiving a packet with a valid MIC.
*
* @param[in] connectionHandle connection connectionHandle
*/
virtual void validMicTimeout(connection_handle_t connectionHandle) {
(void)connectionHandle;
}
/**
* Deliver the requested whitelist to the application.
*
* @param[in] whitelist whitelist created based on the bonding table,
* caller transfers the memory ownership
*/
virtual void whitelistFromBondTable(Gap::Whitelist_t* whitelist) {
if (whitelist) {
delete whitelist;
}
}
////////////////////////////////////////////////////////////////////////////
// Encryption
//
/**
* Inform the device of the encryption state of a given link.
*
* @param[in] connectionHandle connection connectionHandle
* @param[in] result encryption state of the link
*/
virtual void linkEncryptionResult(connection_handle_t connectionHandle, link_encryption_t result) {
(void)connectionHandle;
(void)result;
}
////////////////////////////////////////////////////////////////////////////
// MITM
//
/**
* Display the given passkey on the local device.
*
* @param[in] connectionHandle connection connectionHandle
* @param[in] passkey 6 digit passkey to be displayed
*/
virtual void passkeyDisplay(connection_handle_t connectionHandle, const SecurityManager::Passkey_t passkey) {
(void)connectionHandle;
(void)passkey;
}
/**
* Indicate to the application that a confirmation is required. The application should
* proceed by supplying the confirmation confirmationEntered function.
*
* @param[in] connectionHandle connection connectionHandle
*/
virtual void confirmationRequest(connection_handle_t connectionHandle) {
(void)connectionHandle;
}
/**
* Indicate to the application that a passkey is required. The application should
* proceed by supplying the passkey through the passkeyEntered function.
*
* @param[in] connectionHandle connection connectionHandle
*/
virtual void passkeyRequest(connection_handle_t connectionHandle) {
(void)connectionHandle;
}
/**
* Notify the application that a key was pressed by the peer during passkey entry.
*
* @param[in] connectionHandle connection connectionHandle
* @param[in] keypress type of keypress event
*/
virtual void keypressNotification(connection_handle_t connectionHandle, SecurityManager::Keypress_t keypress) {
(void)connectionHandle;
(void)keypress;
}
/**
* Indicate to the application it needs to return out of band data to the stack.
*
* @param[in] connectionHandle connection connectionHandle
*/
virtual void legacyPairingOobRequest(connection_handle_t connectionHandle) {
(void)connectionHandle;
}
/**
* Indicate to the application it needs to return out of band data to the stack.
*
* @param[in] connectionHandle connection connectionHandle
*/
virtual void oobRequest(connection_handle_t connectionHandle) {
(void)connectionHandle;
}
/**
* Indicate that the application needs to send OOB data to the peer.
*
* @param[in] address address that will be used in the pairing
* @param[in] temporaryKey temporary key to be used in legacy pairing
*/
virtual void legacyPairingOobGenerated(const address_t *address,
const oob_tk_t *temporaryKey) {
(void)address;
(void)temporaryKey;
}
/**
* Indicate that the application needs to send OOB data to the peer.
*
* @param[in] connectionHandle connection connectionHandle
* @param[in] address address that will be used in the pairing
* @param[in] random random number used to generate the confirmation
* @param[in] confirm confirmation value to be use for authentication
* in secure connections pairing
*/
virtual void oobGenerated(const address_t *address,
const oob_rand_t *random,
const oob_confirm_t *confirm) {
(void)address;
(void)random;
(void)confirm;
}
////////////////////////////////////////////////////////////////////////////
// Keys
//
/**
* Deliver the signing key to the application.
*
* @param[in] connectionHandle connection connectionHandle
* @param[in] csrk signing key, pointer only valid during call
* @param[in] authenticated indicates if the signing key is authenticated
*/
virtual void signingKey(connection_handle_t connectionHandle, const csrk_t *csrk, bool authenticated) {
(void)connectionHandle;
(void)csrk;
(void)authenticated;
}
};
/*
* The following functions are meant to be overridden in the platform-specific sub-class.
*/
public:
////////////////////////////////////////////////////////////////////////////
// SM lifecycle management
//
/**
* Enable the BLE 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.
* Calling this API is a prerequisite for encryption and pairing (bonding).
*
* @param[in] enableBonding Allow for bonding.
* @param[in] requireMITM Require protection for man-in-the-middle attacks.
* @param[in] iocaps To specify the I/O 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.
* @param[in] signing Generate and distribute signing key during pairing
*
* @return BLE_ERROR_NONE on success.
*/
virtual ble_error_t init(bool enableBonding = true,
bool requireMITM = true,
SecurityIOCapabilities_t iocaps = IO_CAPS_NONE,
const Passkey_t passkey = NULL,
bool signing = true) {
/* Avoid compiler warnings about unused variables. */
(void)enableBonding;
(void)requireMITM;
(void)iocaps;
(void)passkey;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Notify all registered onShutdown callbacks that the SecurityManager is
* about to be shutdown and clear all SecurityManager state of the
* associated object.
*
* This function is meant to be overridden in the platform-specific
* sub-class. Nevertheless, the sub-class is only expected to reset its
* state and not the data held in SecurityManager members. This shall be
* achieved by a call to SecurityManager::reset() from the sub-class'
* reset() implementation.
*
* @return BLE_ERROR_NONE on success.
*/
virtual ble_error_t reset(void) {
/* Notify that the instance is about to shutdown */
shutdownCallChain.call(this);
shutdownCallChain.clear();
eventHandler = &defaultEventHandler;
return BLE_ERROR_NONE;
}
/**
* Normally all bonding information is lost when device is reset, this requests that the stack
* attempts to save the information and reload it during initialisation. This is not guaranteed.
*
* @param[in] enable if true the stack will attempt to preserve bonding information on reset.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t preserveBondingStateOnReset(bool enable) {
/* Avoid compiler warnings about unused variables */
(void) enable;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
////////////////////////////////////////////////////////////////////////////
// List management
//
/**
* Delete all peer device context and all related bonding information from
* the database within the security manager.
*
* @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 or
* application registration.
*/
virtual ble_error_t purgeAllBondingState(void) {
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Create a list of addresses from all peers in the bond table and generate
* an event which returns it as a whitelist. Pass in the container for the whitelist.
* This will be returned by the event.
*
* @param[in] whitelist Preallocated whitelist which will be filled up to its capacity.
* If whitelist already contains entries this will be appended to.
* Ownership of memory is trasnferred from the caller. It will be
* returned in the generated event.
*
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
*/
virtual ble_error_t generateWhitelistFromBondTable(Gap::Whitelist_t *whitelist) const {
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
////////////////////////////////////////////////////////////////////////////
// Pairing
//
/**
* Request pairing with the peer. Called by the master.
* @note Slave can call requestAuthentication or setLinkEncryption to achieve security.
*
* @param[in] connectionHandle Handle to identify the connection.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t requestPairing(connection_handle_t connectionHandle) {
(void) connectionHandle;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Accept the pairing request. Called as a result of pairingRequest being called
* on the event handler.
*
* @param[in] connectionHandle Handle to identify the connection.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t acceptPairingRequest(connection_handle_t connectionHandle) {
(void) connectionHandle;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Reject pairing request if the local device is the slave or cancel an outstanding
* pairing request if master.
*
* @param[in] connectionHandle Handle to identify the connection.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t canceltPairingRequest(connection_handle_t connectionHandle) {
(void) connectionHandle;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Tell the stack whether the application needs to authorise pairing requests or should
* they be automatically accepted.
*
* @param[in] required If set to true, pairingRequest in the event handler will
* will be called and will require an action from the application
* to continue with pairing by calling acceptPairingRequest
* or canceltPairingRequest if the user wishes to reject it.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t setPairingRequestAuthorisation(bool required = true) {
(void) required;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
////////////////////////////////////////////////////////////////////////////
// Feature support
//
/**
* Allow of disallow the use of legacy pairing in case the application only wants
* to force the use of Secure Connections. If legacy pairing is disallowed and either
* side doesn't support Secure Connections the pairing will fail.
*
* @param[out] allow If true legacy pairing will be used if either side doesn't support Secure Connections.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t allowLegacyPairing(bool allow = true) {
(void) allow;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Check if the Secure Connections feature is supported by the stack and controller.
*
* @param[out] enabled true if SC are supported
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t getSecureConnectionsSupport(bool *enabled) {
(void) enabled;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
////////////////////////////////////////////////////////////////////////////
// Security settings
//
/**
* Set the IO capability of the local device.
*
* @param[in] iocaps type of IO capabilities available on the local device
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t setIoCapability(SecurityIOCapabilities_t iocaps) {
(void) iocaps;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Set the passkey that is displayed on the local device instead of using
* a randomly generated one
*
* @param[in] passkey ASCII string of 6 digits
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t setDisplayPasskey(const Passkey_t passkey) {
(void) passkey;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Set the time after which an event will be generated unless we received a packet with
* a valid MIC.
* @param[in] connection connection handle
* @param[in] timeout_in_10ms time measured in units of 10 milliseconds
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t setAuthenticationTimeout(connection_handle_t connectionHandle, uint32_t timeout_in_ms) {
(void) connectionHandle;
(void) timeout_in_ms;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Get the time after which an event will be generated unless we received a packet with
* a valid MIC.
* @param[in] connection connection handle
* @param[out] timeout_in_10ms time measured in units of 10 milliseconds
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t getAuthenticationTimeout(connection_handle_t connectionHandle, uint32_t *timeout_in_ms) {
(void) connectionHandle;
(void) timeout_in_ms;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* 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 Requested security mode.
*
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t setLinkSecurity(connection_handle_t connectionHandle, SecurityMode_t securityMode) {
/* Avoid compiler warnings about unused variables. */
(void)connectionHandle;
(void)securityMode;
return BLE_ERROR_NOT_IMPLEMENTED;
}
/**
* Set whether or not we want to send and receive keypress notifications
* during passkey entry.
*
* @param[in] enabled if true pairing will try to enable keypress notifications
* (dependent on other side supporting it)
*
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t setKeypressNotification(bool enabled = true) {
(void)enabled;
return BLE_ERROR_NOT_IMPLEMENTED;
}
/**
* Request generation and exchange of signing keys so that packet signing can be utilised
* on this connection.
* @note This does not generate a signingKey event. Use getSigningKey for that.
*
* @param[in] connectionHandle Handle to identify the connection.
* @param[in] enabled If set to true, signing keys will be exchanged
* during subsequent pairing.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t enableSigning(connection_handle_t connectionHandle, bool enabled = true) {
(void) enabled;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Give a hint to the stack that the master/slave role might change in the future.
*
* @param[in] enable If set to true it hints the roles are likely to swap in the future.
*
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t setHintFutureRoleReversal(bool enable = true) {
(void)enable;
return BLE_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////////
// Encryption
//
/**
* Current state of encryption on the link.
*
* @param[in] connectionHandle Handle to identify the connection.
* @param[out] encryption
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t getLinkEncryption(connection_handle_t connectionHandle, link_encryption_t *encryption) {
(void)connectionHandle;
(void)encryption;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Enabled or disable encryption on the link. The result of this request will be indicated
* by a call to linkEncryptionResult in the event handler when the action is completed.
*
* @param[in] connectionHandle Handle to identify the connection.
* @param[in] encryption
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t setLinkEncryption(connection_handle_t connectionHandle, link_encryption_t encryption) {
(void)connectionHandle;
(void)encryption;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Return the size of the encryption key used on this link.
*
* @param[in] connectionHandle Handle to identify the connection.
* @param[out] size Size of the encryption key in bytes
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t getEncryptionKeySize(connection_handle_t connectionHandle, uint8_t *byteSize) {
(void) connectionHandle;
(void) byteSize;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Set the requirements for encryption key size. If the peer cannot comply with the requirements
* paring will fail.
*
* @param[in] minimumByteSize Smallest allowed encryption key size in bytes. (no smaller than 7)
* @param[in] maximumByteSize Largest allowed encryption key size in bytes. (no larger than 16)
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t setEncryptionKeyRequirements(uint8_t minimumByteSize, uint8_t maximumByteSize) {
(void) minimumByteSize;
(void) maximumByteSize;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
////////////////////////////////////////////////////////////////////////////
// Privacy
//
/**
* Set the time after which the private adress will be regenerated.
*
* @param[in] timeout_in_seconds How often (in seconds) the private address should be regenerated.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t setPrivateAddressTimeout(uint16_t timeout_in_seconds) {
(void) timeout_in_seconds;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
////////////////////////////////////////////////////////////////////////////
// Authentication
//
/**
* Request that the link be authenticated (keys with MITM protection). This might trigger encryption
* or pairing/re-pairing. The success will be indicated through an event indicating security level change.
*
* @param[in] connectionHandle Handle to identify the connection.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t requestAuthentication(connection_handle_t connectionHandle) {
(void) connectionHandle;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
////////////////////////////////////////////////////////////////////////////
// MITM
//
/**
* Enable OOB data usage during paring.
*
* @param[in] connectionHandle Handle to identify the connection.
* @param[in] useOOB If set to true, authenticate using OOB data.
* @param[in] OOBProvidesMITM If set to true keys exchanged during pairing using OOB data
* will provide MITM protection. This indicates that the form
* of exchange used by the OOB data itself provides MITM protection.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t setOOBDataUsage(connection_handle_t connectionHandle, bool useOOB, bool OOBProvidesMITM = true) {
/* Avoid compiler warnings about unused variables */
(void) connectionHandle;
(void) useOOB;
(void) OOBProvidesMITM;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Report to the stack if the passkey matches or not. Used during pairing to provide MITM protection.
*
* @param[in] connectionHandle Handle to identify the connection.
* @param[in] confirmation True value indicates the passkey displayed matches.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t confirmationEntered(connection_handle_t connectionHandle, bool confirmation) {
(void) connectionHandle;
(void) confirmation;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Supply the stack with the user entered passkey.
*
* @param[in] connectionHandle Handle to identify the connection.
* @param[in] passkey ASCII string of digits entered by the user.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t passkeyEntered(connection_handle_t connectionHandle, Passkey_t passkey) {
(void) connectionHandle;
(void) passkey;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Send a notification to the peer that the user pressed a key on the local device.
* @note This will only be delivered if the keypress notifications have been enabled during pairing.
*
* @param[in] connectionHandle Handle to identify the connection.
* @param[in] keypress Type of keypress event.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t sendKeypressNotification(connection_handle_t connectionHandle, Keypress_t keypress) {
(void) connectionHandle;
(void) keypress;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Supply the stack with the OOB data for legacy connections.
*
* @param[in] connectionHandle Handle to identify the connection.
* @param[in] address address of the peer device this data comes from
* @param[in] tk pointer to out of band data received containing the temporary key.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t legacyPairingOobReceived(const address_t *address, const oob_tk_t *tk) {
(void) address;
(void) tk;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* Supply the stack with the OOB data for secure connections.
*
* @param[in] connectionHandle Handle to identify the connection.
* @param[in] address address of the peer device this data comes from
* @param[in] random random number used to generate the confirmation
* @param[in] confirm confirmation value to be use for authentication
* in secure connections pairing
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t oobReceived(const address_t *address, const oob_rand_t *random, const oob_confirm_t *confirm) {
(void) address;
(void) random;
(void) confirm;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
////////////////////////////////////////////////////////////////////////////
// Keys
//
/**
* Retrieves a signing key through a signingKey event.
* If a signing key is not present, pairing/authentication will be attempted.
* @note This will attempt to retrieve the key even if enableSigning hasn't been called prior to pairing.
*
* @param[in] connectionHandle Handle to identify the connection.
* @param[in] authenticated Whether the signing key needs to be authenticated
* (provide MITM protection).
*
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t getSigningKey(connection_handle_t connectionHandle, bool authenticated) {
(void)connectionHandle;
(void)authenticated;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/* Event callback handlers. */
public:
/**
* Setup a callback to be invoked to notify the user application that the
* SecurityManager instance is about to shutdown (possibly as a result of a call
* to BLE::shutdown()).
*
* @note It is possible to chain together multiple onShutdown callbacks
* (potentially from different modules of an application) to be notified
* before the SecurityManager is shutdown.
*
* @note It is also possible to set up a callback into a member function of
* some object.
*
* @note It is possible to unregister a callback using onShutdown().detach(callback)
*/
void onShutdown(const SecurityManagerShutdownCallback_t& callback) {
shutdownCallChain.add(callback);
}
template <typename T>
void onShutdown(T *objPtr, void (T::*memberPtr)(const SecurityManager *)) {
shutdownCallChain.add(objPtr, memberPtr);
}
/**
* Provide access to the callchain of shutdown event callbacks.
* It is possible to register callbacks using onShutdown().add(callback).
* It is possible to unregister callbacks using onShutdown().detach(callback).
*
* @return The shutdown event callbacks chain
*/
SecurityManagerShutdownCallbackChain_t& onShutdown() {
return shutdownCallChain;
}
/**
* Assign the event handler implementation that will be used by the stack to signal events
* back to the application.
*
* @param[in] handler Event Handler interface implementation.
*/
virtual void setSecurityManagerEventHandler(SecurityManagerEventHandler* handler) {
if (handler) {
eventHandler = handler;
} else {
eventHandler = &defaultEventHandler;
}
}
protected:
SecurityManager() {
eventHandler = &defaultEventHandler;
}
virtual ~SecurityManager() { };
public:
/**
* @deprecated use generateWhitelistFromBondTable instead
*
* Get a list of addresses from all peers in the bond table.
*
* @param[in,out] addresses
* (on input) addresses.capacity contains the maximum
* number of addresses to be returned.
* (on output) The populated table with copies of the
* addresses in the implementation's whitelist.
*
* @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 or
* application registration.
*/
virtual ble_error_t getAddressesFromBondTable(Gap::Whitelist_t &addresses) const {
/* Avoid compiler warnings about unused variables */
(void) addresses;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
/**
* @deprecated
*
* Get the security status of a connection.
*
* @param[in] connectionHandle Handle to identify the connection.
* @param[out] securityStatusP Security status.
*
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
ble_error_t getLinkSecurity(connection_handle_t connectionHandle, LinkSecurityStatus_t *securityStatus) {
link_encryption_t encryption(link_encryption_t::NOT_ENCRYPTED);
ble_error_t status = getLinkEncryption(connectionHandle, &encryption);
/* legacy support limits the return values */
if (encryption.value() == link_encryption_t::ENCRYPTED_WITH_MITM) {
*securityStatus = ENCRYPTED;
} else {
*securityStatus = (LinkSecurityStatus_t)encryption.value();
}
return status;
}
/**
* @deprecated
*
* To indicate that a security procedure for the link has started.
*/
virtual void onSecuritySetupInitiated(SecuritySetupInitiatedCallback_t callback) {
defaultEventHandler.securitySetupInitiatedCallback = callback;
}
/**
* @deprecated
*
* To indicate that the security procedure for the link has completed.
*/
virtual void onSecuritySetupCompleted(SecuritySetupCompletedCallback_t callback) {
defaultEventHandler.securitySetupCompletedCallback = callback;
}
/**
* @deprecated
*
* To indicate that the link with the peer is secured. For bonded devices,
* subsequent reconnections with a bonded peer will result only in this callback
* when the link is secured; setup procedures will not occur (unless the
* bonding information is either lost or deleted on either or both sides).
*/
virtual void onLinkSecured(LinkSecuredCallback_t callback) {
defaultEventHandler.linkSecuredCallback = callback;
}
/**
* @deprecated
*
* To indicate that device context is stored persistently.
*/
virtual void onSecurityContextStored(HandleSpecificEvent_t callback) {
defaultEventHandler.securityContextStoredCallback = callback;
}
/** @deprecated
*
* To set the callback for when the passkey needs to be displayed on a peripheral with DISPLAY capability.
*/
virtual void onPasskeyDisplay(PasskeyDisplayCallback_t callback) {
defaultEventHandler.passkeyDisplayCallback = callback;
}
/* Entry points for the underlying stack to report events back to the user. */
public:
/** @deprecated */
void processSecuritySetupInitiatedEvent(connection_handle_t connectionHandle, bool allowBonding, bool requireMITM, SecurityIOCapabilities_t iocaps) {
if (defaultEventHandler.securitySetupInitiatedCallback) {
defaultEventHandler.securitySetupInitiatedCallback(connectionHandle, allowBonding, requireMITM, iocaps);
}
}
/** @deprecated */
void processSecuritySetupCompletedEvent(connection_handle_t connectionHandle, SecurityCompletionStatus_t status) {
eventHandler->pairingResult(connectionHandle, status);
}
/** @deprecated */
void processLinkSecuredEvent(connection_handle_t connectionHandle, SecurityMode_t securityMode) {
if (securityMode == SECURITY_MODE_ENCRYPTION_NO_MITM) {
eventHandler->linkEncryptionResult(connectionHandle, link_encryption_t::ENCRYPTED);
} else {
eventHandler->linkEncryptionResult(connectionHandle, link_encryption_t::NOT_ENCRYPTED);
}
}
/** @deprecated */
void processSecurityContextStoredEvent(connection_handle_t connectionHandle) {
if (defaultEventHandler.securityContextStoredCallback) {
defaultEventHandler.securityContextStoredCallback(connectionHandle);
}
}
/** @deprecated */
void processPasskeyDisplayEvent(connection_handle_t connectionHandle, const Passkey_t passkey) {
eventHandler->passkeyDisplay(connectionHandle, passkey);
}
private:
/* Legacy compatibility with old callbacks (from both sides so any
* combination of new and old works) */
class LegacySecurityManagerEventHandler : public SecurityManagerEventHandler {
public:
LegacySecurityManagerEventHandler() :
securitySetupInitiatedCallback(),
securitySetupCompletedCallback(),
linkSecuredCallback(),
securityContextStoredCallback(),
passkeyDisplayCallback() { };
virtual void pairingResult(connection_handle_t connectionHandle, SecurityCompletionStatus_t result) {
if (securitySetupCompletedCallback) {
securitySetupCompletedCallback(connectionHandle, result);
}
}
virtual void linkEncryptionResult(connection_handle_t connectionHandle, link_encryption_t result) {
if (linkSecuredCallback) {
SecurityManager::SecurityMode_t securityMode;
if (result == link_encryption_t::ENCRYPTED) {
securityMode = SECURITY_MODE_ENCRYPTION_NO_MITM;
} else if (result == link_encryption_t::ENCRYPTED_WITH_MITM) {
securityMode = SECURITY_MODE_ENCRYPTION_WITH_MITM;
} else {
securityMode = SECURITY_MODE_ENCRYPTION_OPEN_LINK;
}
linkSecuredCallback(connectionHandle, securityMode);
}
};
virtual void passkeyDisplay(connection_handle_t connectionHandle, const SecurityManager::Passkey_t passkey) {
if (passkeyDisplayCallback) {
passkeyDisplayCallback(connectionHandle, passkey);
}
};
SecurityManager::SecuritySetupInitiatedCallback_t securitySetupInitiatedCallback;
SecurityManager::SecuritySetupCompletedCallback_t securitySetupCompletedCallback;
SecurityManager::LinkSecuredCallback_t linkSecuredCallback;
SecurityManager::HandleSpecificEvent_t securityContextStoredCallback;
SecurityManager::PasskeyDisplayCallback_t passkeyDisplayCallback;
};
private:
SecurityManagerShutdownCallbackChain_t shutdownCallChain;
protected:
SecurityManagerEventHandler* eventHandler;
LegacySecurityManagerEventHandler defaultEventHandler;
};
#endif /*__SECURITY_MANAGER_H__*/