Nordic: Backport security manager pal for NRF5X targets.

pull/6932/head
Vincent Coubard 2018-05-11 11:42:42 +01:00
parent f1c3fdbf8c
commit f7f1272647
4 changed files with 1962 additions and 0 deletions

View File

@ -0,0 +1,188 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm>
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include <stdio.h>
#include <string.h>
#if defined(MBEDTLS_ECDH_C)
#include "mbedtls/platform.h"
#include "mbedtls/ecdh.h"
#include "mbedtls/memory_buffer_alloc.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ecp.h"
#include "platform/NonCopyable.h"
#include "platform/CriticalSectionLock.h"
#include "ble/BLETypes.h"
#include "cmsis.h"
#include "nRF5xCrypto.h"
#include "platform/mbed_assert.h"
#include "nrf_soc.h"
namespace ble {
namespace pal {
namespace vendor {
namespace nordic {
CryptoToolbox::CryptoToolbox() : _initialized(false) {
mbedtls_entropy_init(&_entropy_context);
mbedtls_ecp_group_init(&_group);
int err = mbedtls_ecp_group_load(
&_group,
MBEDTLS_ECP_DP_SECP256R1
);
_initialized = err ? false : true;
}
CryptoToolbox::~CryptoToolbox() {
mbedtls_ecp_group_free(&_group);
mbedtls_entropy_free(&_entropy_context);
}
bool CryptoToolbox::generate_keys(
ArrayView<uint8_t, lesc_key_size_> X,
ArrayView<uint8_t, lesc_key_size_> Y,
ArrayView<uint8_t, lesc_key_size_> secret
) {
mbedtls_mpi secret_key;
mbedtls_ecp_point public_keys;
mbedtls_mpi_init(&secret_key);
mbedtls_ecp_point_init(&public_keys);
int err = mbedtls_ecp_gen_keypair(
&_group,
&secret_key,
&public_keys,
mbedtls_entropy_func,
&_entropy_context
);
if (!err) {
store_mpi(secret, secret_key);
store_mpi(X, public_keys.X);
store_mpi(Y, public_keys.Y);
}
mbedtls_ecp_point_free(&public_keys);
mbedtls_mpi_free(&secret_key);
return err ? false : true;
}
bool CryptoToolbox::generate_shared_secret(
const ArrayView<const uint8_t, lesc_key_size_>& peer_X,
const ArrayView<const uint8_t, lesc_key_size_>& peer_Y,
const ArrayView<const uint8_t, lesc_key_size_>& own_secret,
ArrayView<uint8_t, lesc_key_size_> shared_secret
) {
mbedtls_mpi result;
mbedtls_mpi secret_key;
mbedtls_ecp_point public_keys;
mbedtls_mpi_init(&result);
mbedtls_mpi_init(&secret_key);
mbedtls_ecp_point_init(&public_keys);
load_mpi(secret_key, own_secret);
load_mpi(public_keys.X, peer_X);
load_mpi(public_keys.Y, peer_Y);
mbedtls_mpi_lset( &public_keys.Z, 1 );
int err = mbedtls_ecdh_compute_shared(
&_group,
&result,
&public_keys,
&secret_key,
/* rng function; optional */ NULL,
/* rng param */ NULL
);
if (!err) {
store_mpi(shared_secret, result);
}
mbedtls_ecp_point_free(&public_keys);
mbedtls_mpi_free(&secret_key);
mbedtls_mpi_free(&result);
return err ? false : true;
}
bool CryptoToolbox::ah(
const ArrayView<const uint8_t, irk_size_>& irk,
const ArrayView<const uint8_t, prand_size_>& prand,
ArrayView<uint8_t, hash_size_> hash
) {
// Note copy then swap operation can be optimized.
// Note: the encryption block works in big endian; go figure.
nrf_ecb_hal_data_t ecb_hal_data;
memcpy(ecb_hal_data.key, irk.data(), irk.size());
swap_endian(ecb_hal_data.key, sizeof(ecb_hal_data.key));
memcpy(ecb_hal_data.cleartext, prand.data(), prand.size());
memset(ecb_hal_data.cleartext + prand.size(), 0, sizeof(ecb_hal_data.cleartext) - prand.size());
swap_endian(ecb_hal_data.cleartext, sizeof(ecb_hal_data.cleartext));
uint32_t err = sd_ecb_block_encrypt(&ecb_hal_data);
if (err) {
return false;
}
swap_endian(ecb_hal_data.ciphertext, sizeof(ecb_hal_data.ciphertext));
memcpy(hash.data(), ecb_hal_data.ciphertext, hash.size());
return true;
}
void CryptoToolbox::load_mpi(mbedtls_mpi& dest, const ArrayView<const uint8_t, lesc_key_size_>& src) {
ble::public_key_coord_t src_be = src.data();
swap_endian(src_be.data(), src_be.size());
mbedtls_mpi_read_binary(&dest, src_be.data(), src_be.size());
}
void CryptoToolbox::store_mpi(ArrayView<uint8_t, lesc_key_size_>& dest, const mbedtls_mpi& src) {
mbedtls_mpi_write_binary(&src, dest.data(), dest.size());
swap_endian(dest.data(), dest.size());
}
void CryptoToolbox::swap_endian(uint8_t* buf, size_t len) {
for(size_t low = 0, high = (len - 1); high > low; --high, ++low) {
std::swap(buf[low], buf[high]);
}
}
} // nordic
} // vendor
} // pal
} // ble
#endif //defined(MBEDTLS_ECDH_C)

View File

@ -0,0 +1,146 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef NRF5X_CRYPTO_
#define NRF5X_CRYPTO_
#include <stdint.h>
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_ECDH_C)
#include "mbedtls/platform.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ecp.h"
#include "platform/NonCopyable.h"
#include "ble/BLETypes.h"
namespace ble {
namespace pal {
namespace vendor {
namespace nordic {
/**
* Toolbox of cryptographic functions used in BLE.
*/
class CryptoToolbox : mbed::NonCopyable<CryptoToolbox> {
public:
/**
* Size of the Key used in lesc crypto operations.
*/
static const ptrdiff_t lesc_key_size_ = public_key_coord_t::size_;
/**
* Size of an IRK.
*/
static const ptrdiff_t irk_size_ = irk_t::size_;
/**
* Size of the hash generated by ah.
*/
static const ptrdiff_t hash_size_ = 3;
/**
* Size of prand.
*/
static const ptrdiff_t prand_size_ = 3;
/**
* Create a new CryptoToolbox.
*/
CryptoToolbox();
/**
* Destroy a CryptoTioolbox object.
*/
~CryptoToolbox();
/**
* Generate lesc public and private keys.
* @param[out] X The component X of the public key.
* @param[out] Y The component Y of the public key.
* @param[out] secret The secret key.
* @return true if the shared secret has been successfully generated and
* false otherwise.
*/
bool generate_keys(
ArrayView<uint8_t, lesc_key_size_> X,
ArrayView<uint8_t, lesc_key_size_> Y,
ArrayView<uint8_t, lesc_key_size_> secret
);
/**
* Generate a shared secret from a peer public key and a local secret key.
* @param[in] peer_X The component X of the peer public key.
* @param[in] peer_Y The component Y of the peer public key.
* @param[in] own_secret The local secret key.
* @param[out] shared_secret The shared secret generated.
* @return true if the shared secret has been successfully generated and
* false otherwise.
*/
bool generate_shared_secret(
const ArrayView<const uint8_t, lesc_key_size_>& peer_X,
const ArrayView<const uint8_t, lesc_key_size_>& peer_Y,
const ArrayView<const uint8_t, lesc_key_size_>& own_secret,
ArrayView<uint8_t, lesc_key_size_> shared_secret
);
/**
* Execute the function ah. This function can be used to generate private
* resolvable addresses and resolve them.
*
* @note all parameters passed and return by this fucntion are in little
* endian.
*
* @param[in] irk The key used to create hash.
* @param[in] prand The random part from which the hash will be generated.
* @param[out] hash The hash generated.
*
* @return true in case of success and false otherwise.
*/
bool ah(
const ArrayView<const uint8_t, irk_size_>& irk,
const ArrayView<const uint8_t, prand_size_>& prand,
ArrayView<uint8_t, hash_size_> hash
);
private:
void load_mpi(mbedtls_mpi& dest, const ArrayView<const uint8_t, lesc_key_size_>& src);
void store_mpi(ArrayView<uint8_t, lesc_key_size_>& dest, const mbedtls_mpi& src);
void swap_endian(uint8_t* buf, size_t len);
bool _initialized;
mbedtls_entropy_context _entropy_context;
mbedtls_ecp_group _group;
};
} // nordic
} // vendor
} // pal
} // ble
#endif // defined(MBEDTLS_ECDH_C)
#endif // NRF5X_CRYPTO_

View File

@ -0,0 +1,403 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef NRF5X_PAL_SECURITY_MANAGER_
#define NRF5X_PAL_SECURITY_MANAGER_
#include "ble/BLETypes.h"
#include "ble/pal/PalSecurityManager.h"
#include "nrf_ble.h"
#include "nRF5xCrypto.h"
namespace ble {
namespace pal {
namespace vendor {
namespace nordic {
class nRF5xSecurityManager : public ::ble::pal::SecurityManager {
public:
nRF5xSecurityManager();
virtual ~nRF5xSecurityManager();
////////////////////////////////////////////////////////////////////////////
// SM lifecycle management
//
/**
* @see ::ble::pal::SecurityManager::initialize
*/
virtual ble_error_t initialize();
/**
* @see ::ble::pal::SecurityManager::terminate
*/
virtual ble_error_t terminate();
/**
* @see ::ble::pal::SecurityManager::reset
*/
virtual ble_error_t reset() ;
////////////////////////////////////////////////////////////////////////////
// Resolving list management
//
/**
* @see ::ble::pal::SecurityManager::read_resolving_list_capacity
*/
virtual uint8_t read_resolving_list_capacity();
/**
* @see ::ble::pal::SecurityManager::add_device_to_resolving_list
*/
virtual ble_error_t add_device_to_resolving_list(
advertising_peer_address_type_t peer_identity_address_type,
const address_t &peer_identity_address,
const irk_t &peer_irk
);
/**
* @see ::ble::pal::SecurityManager::remove_device_from_resolving_list
*/
virtual ble_error_t remove_device_from_resolving_list(
advertising_peer_address_type_t peer_identity_address_type,
const address_t &peer_identity_address
);
/**
* @see ::ble::pal::SecurityManager::clear_resolving_list
*/
virtual ble_error_t clear_resolving_list();
/**
* An entry of the resolving list stored in the SecurityManager.
*/
struct resolving_list_entry_t {
resolving_list_entry_t() :
peer_identity_address_type(
advertising_peer_address_type_t::PUBLIC_ADDRESS
)
{ }
irk_t peer_irk;
address_t peer_identity_address;
advertising_peer_address_type_t peer_identity_address_type;
};
/**
* Return the IRKs present in the resolving list
* @param count The number of entries present in the resolving list.
* @param pointer to the first entry of the resolving list.
*/
ArrayView<resolving_list_entry_t> get_resolving_list();
/**
* Try to resolve a private resolvable address.
*
* @param resolvable_address The address to resolve.
*
* @return Pointer to the entry found if any.
*/
const resolving_list_entry_t* resolve_address(
const address_t& resolvable_address
);
////////////////////////////////////////////////////////////////////////////
// Pairing
//
/**
* @see ::ble::pal::SecurityManager::send_pairing_request
*/
virtual ble_error_t send_pairing_request(
connection_handle_t connection,
bool oob_data_flag,
AuthenticationMask authentication_requirements,
KeyDistribution initiator_dist,
KeyDistribution responder_dist
);
/**
* @see ::ble::pal::SecurityManager::send_pairing_response
*/
virtual ble_error_t send_pairing_response(
connection_handle_t connection,
bool oob_data_flag,
AuthenticationMask authentication_requirements,
KeyDistribution initiator_dist,
KeyDistribution responder_dist
);
/**
* @see ::ble::pal::SecurityManager::cancel_pairing
*/
virtual ble_error_t cancel_pairing(
connection_handle_t connection, pairing_failure_t reason
);
////////////////////////////////////////////////////////////////////////////
// Feature support
//
/**
* @see ::ble::pal::SecurityManager::get_secure_connections_support
*/
virtual ble_error_t get_secure_connections_support(
bool &enabled
);
/**
* @see ::ble::pal::SecurityManager::set_io_capability
*/
virtual ble_error_t set_io_capability(io_capability_t io_capability);
////////////////////////////////////////////////////////////////////////////
// Security settings
//
/**
* @see ::ble::pal::SecurityManager::set_authentication_timeout
*/
virtual ble_error_t set_authentication_timeout(
connection_handle_t, uint16_t timeout_in_10ms
);
/**
* @see ::ble::pal::SecurityManager::get_authentication_timeout
*/
virtual ble_error_t get_authentication_timeout(
connection_handle_t, uint16_t &timeout_in_10ms
);
/**
* @see ::ble::pal::SecurityManager::set_encryption_key_requirements
*/
virtual ble_error_t set_encryption_key_requirements(
uint8_t min_encryption_key_size,
uint8_t max_encryption_key_size
);
/**
* @see ::ble::pal::SecurityManager::slave_security_request
*/
virtual ble_error_t slave_security_request(
connection_handle_t connection,
AuthenticationMask authentication
);
////////////////////////////////////////////////////////////////////////////
// Encryption
//
/**
* @see ::ble::pal::SecurityManager::enable_encryption
*/
virtual ble_error_t enable_encryption(
connection_handle_t connection,
const ltk_t &ltk,
const rand_t &rand,
const ediv_t &ediv,
bool mitm
);
/**
* @see ::ble::pal::SecurityManager::enable_encryption
*/
virtual ble_error_t enable_encryption(
connection_handle_t connection,
const ltk_t &ltk,
bool mitm
) ;
/**
* @see ::ble::pal::SecurityManager::encrypt_data
*/
virtual ble_error_t encrypt_data(
const byte_array_t<16> &key,
encryption_block_t &data
);
////////////////////////////////////////////////////////////////////////////
// Privacy
//
/**
* @see ::ble::pal::SecurityManager::set_private_address_timeout
*/
virtual ble_error_t set_private_address_timeout(uint16_t timeout_in_seconds);
////////////////////////////////////////////////////////////////////////////
// Keys
//
/**
* @see ::ble::pal::SecurityManager::set_ltk
*/
virtual ble_error_t set_ltk(
connection_handle_t connection,
const ltk_t &ltk,
bool mitm,
bool secure_connections
);
/**
* @see ::ble::pal::SecurityManager::set_ltk_not_found
*/
virtual ble_error_t set_ltk_not_found(
connection_handle_t connection
);
/**
* @see ::ble::pal::SecurityManager::set_irk
*/
virtual ble_error_t set_irk(const irk_t &irk);
/**
* @see ::ble::pal::SecurityManager::set_csrk
*/
virtual ble_error_t set_csrk(const csrk_t &csrk, sign_count_t sign_counter);
/**
* @see ::ble::pal::SecurityManager::set_peer_csrk
*/
virtual ble_error_t set_peer_csrk(
connection_handle_t connection,
const csrk_t &csrk,
bool authenticated,
sign_count_t sign_counter
);
////////////////////////////////////////////////////////////////////////////
// Authentication
//
/**
* @see ::ble::pal::SecurityManager::get_random_data
*/
virtual ble_error_t get_random_data(byte_array_t<8> &random_data);
////////////////////////////////////////////////////////////////////////////
// MITM
//
/**
* @see ::ble::pal::SecurityManager::set_display_passkey
*/
virtual ble_error_t set_display_passkey(passkey_num_t passkey);
/**
* @see ::ble::pal::SecurityManager::passkey_request_reply
*/
virtual ble_error_t passkey_request_reply(
connection_handle_t connection,
passkey_num_t passkey
);
/**
* @see ::ble::pal::SecurityManager::secure_connections_oob_request_reply
*/
virtual ble_error_t secure_connections_oob_request_reply(
connection_handle_t connection,
const oob_lesc_value_t &local_random,
const oob_lesc_value_t &peer_random,
const oob_confirm_t &peer_confirm
);
/**
* @see ::ble::pal::SecurityManager::legacy_pairing_oob_request_reply
*/
virtual ble_error_t legacy_pairing_oob_request_reply(
connection_handle_t connection,
const oob_tk_t &oob_data
);
/**
* @see ::ble::pal::SecurityManager::confirmation_entered
*/
virtual ble_error_t confirmation_entered(
connection_handle_t connection, bool confirmation
);
/**
* @see ::ble::pal::SecurityManager::send_keypress_notification
*/
virtual ble_error_t send_keypress_notification(
connection_handle_t connection, Keypress_t keypress
);
/**
* @see ::ble::pal::SecurityManager::generate_secure_connections_oob
*/
virtual ble_error_t generate_secure_connections_oob();
// singleton of nordic Security Manager
static nRF5xSecurityManager& get_security_manager();
// Event handler
bool sm_handler(const ble_evt_t *evt);
private:
csrk_t _csrk;
sign_count_t _sign_counter;
io_capability_t _io_capability;
uint8_t _min_encryption_key_size;
uint8_t _max_encryption_key_size;
struct pairing_control_block_t;
ble_gap_sec_params_t make_security_params(
bool oob_data_flag,
AuthenticationMask authentication_requirements,
KeyDistribution initiator_dist,
KeyDistribution responder_dist
);
ble_gap_sec_keyset_t make_keyset(
pairing_control_block_t& pairing_cb,
KeyDistribution initiator_dist,
KeyDistribution responder_dist
);
pairing_control_block_t* allocate_pairing_cb(connection_handle_t connection);
void release_pairing_cb(pairing_control_block_t* pairing_cb);
pairing_control_block_t* get_pairing_cb(connection_handle_t connection);
void release_all_pairing_cb();
pairing_control_block_t* _control_blocks;
#if defined(MBEDTLS_ECDH_C)
CryptoToolbox _crypto;
ble::public_key_coord_t X;
ble::public_key_coord_t Y;
ble::public_key_coord_t secret;
#endif
static const size_t MAX_RESOLVING_LIST_ENTRIES = BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT;
size_t resolving_list_entry_count;
resolving_list_entry_t resolving_list[MAX_RESOLVING_LIST_ENTRIES];
};
} // nordic
} // vendor
} // pal
} // ble
#endif /* NRF5X_PAL_SECURITY_MANAGER_ */