/* 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 #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 doesn’t 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 SecurityManagerShutdownCallback_t; typedef CallChainOfFunctionPointersWithContext 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 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__*/