mirror of https://github.com/ARMmbed/mbed-os.git
handling OOB data generation and verification now pushed down to PAL level
parent
a6e27b1b86
commit
b8ba99a184
|
@ -238,8 +238,7 @@ public:
|
|||
_default_key_distribution(pal::KeyDistribution::KEY_DISTRIBUTION_ALL),
|
||||
_pairing_authorisation_required(false),
|
||||
_legacy_pairing_allowed(true),
|
||||
_master_sends_keys(false),
|
||||
_public_keys_generated(false) {
|
||||
_master_sends_keys(false) {
|
||||
_pal.set_event_handler(this);
|
||||
}
|
||||
|
||||
|
@ -321,17 +320,6 @@ private:
|
|||
const csrk_t *csrk
|
||||
);
|
||||
|
||||
#if defined(MBEDTLS_CMAC_C)
|
||||
/**
|
||||
* Generate local OOB data to be sent to the application which sends it to the peer.
|
||||
*
|
||||
* @param[in] connectionHandle Handle to identify the connection.
|
||||
*/
|
||||
void generate_secure_connections_oob(
|
||||
connection_handle_t connection
|
||||
);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Updates the entry for the connection with OOB data presence.
|
||||
*
|
||||
|
@ -341,26 +329,6 @@ private:
|
|||
connection_handle_t connection
|
||||
);
|
||||
|
||||
#if defined(MBEDTLS_CMAC_C)
|
||||
/**
|
||||
* Calculate the confirmation value for secure connections OOB data based
|
||||
* on local public key and a random number.
|
||||
* @see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part H - 2.2.6
|
||||
|
||||
* @param[in] U public key x component
|
||||
* @param[in] V public key y component
|
||||
* @param[in] X random number
|
||||
* @param[out] confirm confirmation value
|
||||
* @return true if cryptography functioned worked
|
||||
*/
|
||||
static bool crypto_toolbox_f4(
|
||||
const public_key_t &U,
|
||||
const public_key_t &V,
|
||||
const oob_lesc_value_t &X,
|
||||
oob_confirm_t &confirm
|
||||
);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Set the MITM protection setting on the database entry
|
||||
*
|
||||
|
@ -477,13 +445,6 @@ private:
|
|||
bool _pairing_authorisation_required;
|
||||
bool _legacy_pairing_allowed;
|
||||
bool _master_sends_keys;
|
||||
bool _public_keys_generated;
|
||||
|
||||
/** There is always only one OOB data set stored at a time */
|
||||
address_t _peer_sc_oob_address;
|
||||
oob_lesc_value_t _peer_sc_oob_random;
|
||||
oob_confirm_t _peer_sc_oob_confirm;
|
||||
oob_lesc_value_t _local_sc_oob_random;
|
||||
|
||||
static const size_t MAX_CONTROL_BLOCKS = 5;
|
||||
ControlBlock_t _control_blocks[MAX_CONTROL_BLOCKS];
|
||||
|
@ -593,25 +554,18 @@ public:
|
|||
connection_handle_t connection
|
||||
);
|
||||
|
||||
/** @copydoc ble::pal::SecurityManager::on_oob_data_verification_request
|
||||
/** @copydoc ble::pal::SecurityManager::on_secure_connections_oob_generated
|
||||
*/
|
||||
virtual void on_oob_data_verification_request(
|
||||
connection_handle_t connection,
|
||||
const public_key_coord_t &peer_public_key_x,
|
||||
const public_key_coord_t &peer_public_key_y
|
||||
virtual void on_secure_connections_oob_generated(
|
||||
const address_t &local_address,
|
||||
const oob_lesc_value_t &random,
|
||||
const oob_confirm_t &confirm
|
||||
);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Keys
|
||||
//
|
||||
|
||||
/** @copydoc ble::pal::SecurityManager::on_public_key_generated
|
||||
*/
|
||||
virtual void on_public_key_generated(
|
||||
const public_key_coord_t &public_key_x,
|
||||
const public_key_coord_t &public_key_y
|
||||
);
|
||||
|
||||
/** @copydoc ble::pal::SecurityManager::on_secure_connections_ltk_generated
|
||||
*/
|
||||
virtual void on_secure_connections_ltk_generated(
|
||||
|
|
|
@ -240,24 +240,6 @@ public:
|
|||
_local_csrk = csrk;
|
||||
}
|
||||
|
||||
/* public key */
|
||||
|
||||
virtual const public_key_coord_t& get_public_key_x() {
|
||||
return _public_key_x;
|
||||
}
|
||||
|
||||
virtual const public_key_coord_t& get_public_key_y() {
|
||||
return _public_key_y;
|
||||
}
|
||||
|
||||
virtual void set_public_key(
|
||||
const public_key_coord_t &public_key_x,
|
||||
const public_key_coord_t &public_key_y
|
||||
) {
|
||||
_public_key_x = public_key_x;
|
||||
_public_key_y = public_key_y;
|
||||
}
|
||||
|
||||
/* list management */
|
||||
|
||||
virtual entry_handle_t open_entry(
|
||||
|
@ -362,8 +344,6 @@ private:
|
|||
entry_t _entries[MAX_ENTRIES];
|
||||
SecurityEntryIdentity_t _local_identity;
|
||||
csrk_t _local_csrk;
|
||||
public_key_coord_t _public_key_x;
|
||||
public_key_coord_t _public_key_y;
|
||||
};
|
||||
|
||||
} /* namespace pal */
|
||||
|
|
|
@ -371,7 +371,7 @@ public:
|
|||
* Request OOB data from the user application.
|
||||
*
|
||||
* @param[in] connection connection handle
|
||||
* @note shall be followed by: pal::SecurityManager::legacy_pairing_oob_data_request_reply
|
||||
* @note shall be followed by: pal::SecurityManager::legacy_pairing_oob_request_reply
|
||||
* or a cancellation of the procedure.
|
||||
*/
|
||||
virtual void on_legacy_pairing_oob_request(
|
||||
|
@ -379,32 +379,24 @@ public:
|
|||
) = 0;
|
||||
|
||||
/**
|
||||
* Request OOB data to be verified against received public keys.
|
||||
* Send OOB data to the application for transport to the peer.
|
||||
*
|
||||
* @param[in] public_key_x newly generated public key (x coordinate)
|
||||
* @param[in] public_key_y newly generated public key (y coordinate)
|
||||
* @param[in] address address of the local device
|
||||
* @param[in] random random number used to generate the confirmation
|
||||
* @param[in] confirm confirmation value to be use for authentication
|
||||
* in secure connections pairing
|
||||
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
|
||||
*/
|
||||
virtual void on_oob_data_verification_request(
|
||||
connection_handle_t connection,
|
||||
const public_key_coord_t &peer_public_key_x,
|
||||
const public_key_coord_t &peer_public_key_y
|
||||
virtual void on_secure_connections_oob_generated(
|
||||
const address_t &local_address,
|
||||
const oob_lesc_value_t &random,
|
||||
const oob_confirm_t &confirm
|
||||
) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Keys
|
||||
//
|
||||
|
||||
/**
|
||||
* Provide the local public key.
|
||||
*
|
||||
* @param[in] public_key_x newly generated public key (x coordinate)
|
||||
* @param[in] public_key_y newly generated public key (y coordinate)
|
||||
*/
|
||||
virtual void on_public_key_generated(
|
||||
const public_key_coord_t &public_key_x,
|
||||
const public_key_coord_t &public_key_y
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Store the results of key generation of the stage 2 of secure connections pairing
|
||||
* @see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part H - 2.3.5.6.5
|
||||
|
@ -863,14 +855,6 @@ public:
|
|||
const csrk_t &csrk
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Generate the Public key. This will also generate the private key.
|
||||
* Public key will be returned as an event handler callback when it's ready.
|
||||
*
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t generate_public_key() = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Authentication
|
||||
//
|
||||
|
@ -931,7 +915,7 @@ public:
|
|||
* @param[in] oob_data pointer to out of band data
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
*/
|
||||
virtual ble_error_t legacy_pairing_oob_data_request_reply(
|
||||
virtual ble_error_t legacy_pairing_oob_request_reply(
|
||||
connection_handle_t connection,
|
||||
const oob_tk_t &oob_data
|
||||
) = 0;
|
||||
|
@ -963,20 +947,38 @@ public:
|
|||
) = 0;
|
||||
|
||||
/**
|
||||
* Notify the stack that the OOB data has been verified and supply the peer's random number.
|
||||
* If the verification failed this will not be called and cancel_pairing will be called instead.
|
||||
* Generate local OOB data to be sent to the application which sends it to the peer.
|
||||
*
|
||||
* @param[in] connection connection handle
|
||||
* @param[in] local_random random number sent from the local device to be used in further
|
||||
* calculations by the stack, set to 0 if peer reported no OOB present
|
||||
* @param[in] peer_random random number from the peer to be used in further
|
||||
* calculations by the stack, set to 0 if no OOB data received
|
||||
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure
|
||||
* @param[in] connectionHandle Handle to identify the connection.
|
||||
*/
|
||||
virtual ble_error_t oob_data_verified(
|
||||
connection_handle_t connection,
|
||||
const oob_lesc_value_t &local_random,
|
||||
const oob_lesc_value_t &peer_random
|
||||
virtual ble_error_t generate_secure_connections_oob(
|
||||
connection_handle_t connection
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Supply the stack with the OOB data for secure connections.
|
||||
*
|
||||
* @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 secure_connections_oob_received(
|
||||
const address_t &address,
|
||||
const oob_lesc_value_t &random,
|
||||
const oob_confirm_t &confirm
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Supply the stack with the OOB data for secure connections.
|
||||
*
|
||||
* @param[in] address address of the peer device oob data is needed for
|
||||
* @return True if oob data present, false if not or if the functionality
|
||||
* is not implemented.
|
||||
*/
|
||||
virtual bool is_secure_connectinos_oob_present(
|
||||
const address_t &address
|
||||
) = 0;
|
||||
|
||||
/* Entry points for the underlying stack to report events back to the user. */
|
||||
|
|
|
@ -286,33 +286,6 @@ public:
|
|||
*/
|
||||
virtual void set_local_csrk(const csrk_t &csrk) = 0;
|
||||
|
||||
/* public keys */
|
||||
|
||||
/**
|
||||
* Return local public key.
|
||||
*
|
||||
* @return ref to x component of public key
|
||||
*/
|
||||
virtual const public_key_coord_t& get_public_key_x() = 0;
|
||||
|
||||
/**
|
||||
* Return local public key.
|
||||
*
|
||||
* @return ref to y component of public key
|
||||
*/
|
||||
virtual const public_key_coord_t& get_public_key_y() = 0;
|
||||
|
||||
/**
|
||||
* Set local public key.
|
||||
*
|
||||
* @param[in] public_key_x new public key value of the x coordinate
|
||||
* @param[in] public_key_y new public key value of the y coordinate
|
||||
*/
|
||||
virtual void set_public_key(
|
||||
const public_key_coord_t &public_key_x,
|
||||
const public_key_coord_t &public_key_y
|
||||
) = 0;
|
||||
|
||||
/* list management */
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,9 +17,6 @@
|
|||
#include "ble/SecurityManager.h"
|
||||
#include "ble/pal/PalSecurityManager.h"
|
||||
#include "ble/generic/GenericSecurityManager.h"
|
||||
#if defined(MBEDTLS_CMAC_C)
|
||||
#include "mbedtls/cmac.h"
|
||||
#endif
|
||||
|
||||
using ble::pal::advertising_peer_address_type_t;
|
||||
using ble::pal::AuthenticationMask;
|
||||
|
@ -71,14 +68,11 @@ ble_error_t GenericSecurityManager::init(
|
|||
_connection_monitor.set_connection_event_handler(this);
|
||||
_pal.set_event_handler(this);
|
||||
|
||||
_pal.generate_public_key();
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t GenericSecurityManager::reset(void) {
|
||||
_db.sync();
|
||||
_public_keys_generated = false;
|
||||
SecurityManager::reset();
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
|
@ -519,11 +513,7 @@ ble_error_t GenericSecurityManager::setOOBDataUsage(
|
|||
cb->attempt_oob = useOOB;
|
||||
cb->oob_mitm_protection = OOBProvidesMITM;
|
||||
|
||||
#if defined(MBEDTLS_CMAC_C)
|
||||
if (_public_keys_generated) {
|
||||
generate_secure_connections_oob(connection);
|
||||
}
|
||||
#endif
|
||||
_pal.generate_secure_connections_oob(connection);
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
@ -562,7 +552,7 @@ ble_error_t GenericSecurityManager::legacyPairingOobReceived(
|
|||
return BLE_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
return _pal.legacy_pairing_oob_data_request_reply(cb->connection, *tk);
|
||||
return _pal.legacy_pairing_oob_request_reply(cb->connection, *tk);
|
||||
}
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
@ -573,10 +563,7 @@ ble_error_t GenericSecurityManager::oobReceived(
|
|||
const oob_confirm_t *confirm
|
||||
) {
|
||||
if (address && random && confirm) {
|
||||
_peer_sc_oob_address = *address;
|
||||
_peer_sc_oob_random = *random;
|
||||
_peer_sc_oob_confirm = *confirm;
|
||||
return BLE_ERROR_NONE;
|
||||
return _pal.secure_connections_oob_received(*address, *random, *confirm);
|
||||
}
|
||||
|
||||
return BLE_ERROR_INVALID_PARAM;
|
||||
|
@ -697,40 +684,6 @@ void GenericSecurityManager::return_csrk_cb(
|
|||
);
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_CMAC_C)
|
||||
void GenericSecurityManager::generate_secure_connections_oob(
|
||||
connection_handle_t connection
|
||||
) {
|
||||
oob_confirm_t confirm;
|
||||
oob_lesc_value_t random;
|
||||
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
ble_error_t ret = get_random_data(random.buffer(), random.size());
|
||||
if (ret != BLE_ERROR_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
crypto_toolbox_f4(
|
||||
_db.get_public_key_x(),
|
||||
_db.get_public_key_y(),
|
||||
random,
|
||||
confirm
|
||||
);
|
||||
|
||||
eventHandler->oobGenerated(
|
||||
&cb->local_address,
|
||||
&random,
|
||||
&confirm
|
||||
);
|
||||
|
||||
_local_sc_oob_random = random;
|
||||
}
|
||||
#endif
|
||||
|
||||
void GenericSecurityManager::update_oob_presence(connection_handle_t connection) {
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (!cb) {
|
||||
|
@ -743,45 +696,10 @@ void GenericSecurityManager::update_oob_presence(connection_handle_t connection)
|
|||
cb->oob_present = cb->attempt_oob;
|
||||
|
||||
if (_default_authentication.get_secure_connections()) {
|
||||
cb->oob_present = false;
|
||||
#if defined(MBEDTLS_CMAC_C)
|
||||
if (cb->peer_address == _peer_sc_oob_address) {
|
||||
cb->oob_present = true;
|
||||
}
|
||||
#endif
|
||||
cb->oob_present = _pal.is_secure_connectinos_oob_present(cb->peer_address);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_CMAC_C)
|
||||
bool GenericSecurityManager::crypto_toolbox_f4(
|
||||
const public_key_coord_t& U,
|
||||
const public_key_coord_t& V,
|
||||
const oob_lesc_value_t& X,
|
||||
oob_confirm_t& confirm
|
||||
) {
|
||||
|
||||
mbedtls_cipher_context_t context;
|
||||
const mbedtls_cipher_info_t *info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB);
|
||||
const unsigned char Z = 0;
|
||||
bool success = false;
|
||||
|
||||
mbedtls_cipher_init(&context);
|
||||
|
||||
/* it's either this chaining or a goto */
|
||||
if (mbedtls_cipher_setup(&context, info) == 0
|
||||
&& mbedtls_cipher_cmac_starts(&context, X.data(), 128) == 0
|
||||
&& mbedtls_cipher_cmac_update(&context, U.data(), 16) == 0
|
||||
&& mbedtls_cipher_cmac_update(&context, V.data(), 16) == 0
|
||||
&& mbedtls_cipher_cmac_update(&context, &Z, 1) == 0
|
||||
&& mbedtls_cipher_cmac_finish(&context, &confirm[0]) == 0) {
|
||||
success = true;
|
||||
}
|
||||
|
||||
mbedtls_cipher_free(&context);
|
||||
return success;
|
||||
}
|
||||
#endif
|
||||
|
||||
void GenericSecurityManager::set_mitm_performed(connection_handle_t connection, bool enable) {
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
if (cb) {
|
||||
|
@ -1031,44 +949,18 @@ void GenericSecurityManager::on_legacy_pairing_oob_request(connection_handle_t c
|
|||
eventHandler->legacyPairingOobRequest(connection);
|
||||
}
|
||||
|
||||
void GenericSecurityManager::on_oob_data_verification_request(
|
||||
connection_handle_t connection,
|
||||
const public_key_coord_t &peer_public_key_x,
|
||||
const public_key_coord_t &peer_public_key_y
|
||||
void GenericSecurityManager::on_secure_connections_oob_generated(
|
||||
const address_t &local_address,
|
||||
const oob_lesc_value_t &random,
|
||||
const oob_confirm_t &confirm
|
||||
) {
|
||||
#if defined(MBEDTLS_CMAC_C)
|
||||
ControlBlock_t *cb = get_control_block(connection);
|
||||
|
||||
oob_confirm_t confirm_verify;
|
||||
|
||||
crypto_toolbox_f4(
|
||||
peer_public_key_x,
|
||||
peer_public_key_y,
|
||||
_peer_sc_oob_random,
|
||||
confirm_verify
|
||||
);
|
||||
|
||||
if (cb && (cb->peer_address == _peer_sc_oob_address)
|
||||
&& (confirm_verify == _peer_sc_oob_confirm)) {
|
||||
_pal.oob_data_verified(connection, _local_sc_oob_random, _peer_sc_oob_random);
|
||||
} else {
|
||||
_pal.cancel_pairing(connection, pairing_failure_t::CONFIRM_VALUE_FAILED);
|
||||
}
|
||||
#endif
|
||||
eventHandler->oobGenerated(&local_address, &random, &confirm);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Keys
|
||||
//
|
||||
|
||||
void GenericSecurityManager::on_public_key_generated(
|
||||
const public_key_coord_t &public_key_x,
|
||||
const public_key_coord_t &public_key_y
|
||||
) {
|
||||
_db.set_public_key(public_key_x, public_key_y);
|
||||
_public_keys_generated = true;
|
||||
}
|
||||
|
||||
void GenericSecurityManager::on_secure_connections_ltk_generated(
|
||||
connection_handle_t connection,
|
||||
const ltk_t <k
|
||||
|
|
|
@ -273,9 +273,9 @@ public:
|
|||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::legacy_pairing_oob_data_request_reply
|
||||
* @see ::ble::pal::SecurityManager::legacy_pairing_oob_request_reply
|
||||
*/
|
||||
virtual ble_error_t legacy_pairing_oob_data_request_reply(
|
||||
virtual ble_error_t legacy_pairing_oob_request_reply(
|
||||
connection_handle_t connection,
|
||||
const oob_tk_t &oob_data
|
||||
);
|
||||
|
@ -295,12 +295,26 @@ public:
|
|||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::oob_data_verified
|
||||
* @see ::ble::pal::SecurityManager::generate_secure_connections_oob
|
||||
*/
|
||||
virtual ble_error_t oob_data_verified(
|
||||
connection_handle_t connection,
|
||||
const oob_lesc_value_t &local_random,
|
||||
const oob_lesc_value_t &peer_random
|
||||
virtual ble_error_t generate_secure_connections_oob(
|
||||
connection_handle_t connection
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::secure_connections_oob_received
|
||||
*/
|
||||
virtual ble_error_t secure_connections_oob_received(
|
||||
const address_t &address,
|
||||
const oob_lesc_value_t &random,
|
||||
const oob_confirm_t &confirm
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::ble::pal::SecurityManager::is_secure_connectinos_oob_present
|
||||
*/
|
||||
virtual bool is_secure_connectinos_oob_present(
|
||||
const address_t &address
|
||||
);
|
||||
|
||||
// singleton of the ARM Cordio Security Manager
|
||||
|
|
|
@ -364,7 +364,7 @@ ble_error_t CordioSecurityManager::passkey_request_reply(
|
|||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t CordioSecurityManager::legacy_pairing_oob_data_request_reply(
|
||||
ble_error_t CordioSecurityManager::legacy_pairing_oob_request_reply(
|
||||
connection_handle_t connection,
|
||||
const oob_tk_t &oob_data
|
||||
) {
|
||||
|
@ -394,15 +394,26 @@ ble_error_t CordioSecurityManager::send_keypress_notification(
|
|||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t CordioSecurityManager::oob_data_verified(
|
||||
connection_handle_t connection,
|
||||
const oob_lesc_value_t &local_random,
|
||||
const oob_lesc_value_t &peer_random
|
||||
ble_error_t CordioSecurityManager::generate_secure_connections_oob(
|
||||
connection_handle_t connection
|
||||
) {
|
||||
// FIXME:
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
ble_error_t CordioSecurityManager::secure_connections_oob_received(
|
||||
const address_t &address,
|
||||
const oob_lesc_value_t &random,
|
||||
const oob_confirm_t &confirm
|
||||
) {
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
bool CordioSecurityManager::is_secure_connectinos_oob_present(
|
||||
const address_t &address
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CordioSecurityManager& CordioSecurityManager::get_security_manager()
|
||||
{
|
||||
static CordioSecurityManager _security_manager;
|
||||
|
|
Loading…
Reference in New Issue