mirror of https://github.com/ARMmbed/mbed-os.git
496 lines
18 KiB
C
496 lines
18 KiB
C
/*
|
|
* Copyright (c) 2016-2018, Arm Limited and affiliates.
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* 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 "nsconfig.h"
|
|
#include <string.h>
|
|
#include "ns_types.h"
|
|
#include "ns_trace.h"
|
|
#include "nsdynmemLIB.h"
|
|
#include "mac_api.h"
|
|
#include "sw_mac.h"
|
|
#include "mac_common_defines.h"
|
|
#include "common_functions.h"
|
|
#include "MAC/IEEE802_15_4/mac_defines.h"
|
|
#include "MAC/IEEE802_15_4/mac_security_mib.h"
|
|
|
|
#define TRACE_GROUP "mMIB"
|
|
/**
|
|
* Allocate device description table based on size
|
|
*/
|
|
static mlme_device_descriptor_t *mac_sec_mib_device_description_table_allocate(uint8_t table_size)
|
|
{
|
|
mlme_device_descriptor_t *table_ptr = ns_dyn_mem_alloc(sizeof(mlme_device_descriptor_t) * table_size);
|
|
if (table_ptr) {
|
|
memset(table_ptr, 0xff, (sizeof(mlme_device_descriptor_t) * table_size));
|
|
}
|
|
return table_ptr;
|
|
}
|
|
|
|
static mlme_key_descriptor_t *mac_sec_mib_key_description_table_allocate(uint8_t table_size)
|
|
{
|
|
mlme_key_descriptor_t *table_ptr = ns_dyn_mem_alloc(sizeof(mlme_key_descriptor_t) * table_size);
|
|
if (table_ptr) {
|
|
memset(table_ptr, 0, (sizeof(mlme_key_descriptor_t) * table_size));
|
|
}
|
|
return table_ptr;
|
|
}
|
|
|
|
static mlme_key_device_descriptor_t *mac_sec_mib_key_device_description_table_allocate(uint16_t list_size)
|
|
{
|
|
mlme_key_device_descriptor_t *table_ptr = ns_dyn_mem_alloc(sizeof(mlme_key_device_descriptor_t) * list_size);
|
|
if (table_ptr) {
|
|
memset(table_ptr, 0, (sizeof(mlme_key_device_descriptor_t) * list_size));
|
|
}
|
|
return table_ptr;
|
|
}
|
|
|
|
static mlme_key_usage_descriptor_t *mac_sec_mib_key_usage_table_allocate(uint16_t list_size)
|
|
{
|
|
|
|
mlme_key_usage_descriptor_t *table_ptr = ns_dyn_mem_alloc(sizeof(mlme_key_usage_descriptor_t) * list_size);
|
|
if (table_ptr) {
|
|
memset(table_ptr, 0, (sizeof(mlme_key_usage_descriptor_t) * list_size));
|
|
}
|
|
return table_ptr;
|
|
}
|
|
|
|
|
|
static mlme_key_id_lookup_descriptor_t *mac_sec_mib_key_lookup_table_allocate(uint16_t list_size)
|
|
{
|
|
|
|
mlme_key_id_lookup_descriptor_t *table_ptr = ns_dyn_mem_alloc(sizeof(mlme_key_id_lookup_descriptor_t) * list_size);
|
|
if (table_ptr) {
|
|
memset(table_ptr, 0, (sizeof(mlme_key_id_lookup_descriptor_t) * list_size));
|
|
}
|
|
return table_ptr;
|
|
}
|
|
|
|
static mlme_device_descriptor_t *mac_sec_mib_device_description_get_by_mac16(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint16_t mac16)
|
|
{
|
|
|
|
mlme_device_descriptor_t *device_table = rf_mac_setup->device_description_table;
|
|
if (!device_table) {
|
|
return NULL;
|
|
}
|
|
|
|
for (int i = 0; i < rf_mac_setup->device_description_table_size; i++) {
|
|
if (device_table->ShortAddress == mac16) {
|
|
return device_table;
|
|
}
|
|
device_table++;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static mlme_device_descriptor_t *mac_sec_mib_device_description_get_by_mac64(protocol_interface_rf_mac_setup_s *rf_mac_setup, const uint8_t *mac64)
|
|
{
|
|
|
|
mlme_device_descriptor_t *device_table = rf_mac_setup->device_description_table;
|
|
if (!device_table) {
|
|
return NULL;
|
|
}
|
|
|
|
for (int i = 0; i < rf_mac_setup->device_description_table_size; i++) {
|
|
if (memcmp(device_table->ExtAddress, mac64, 8) == 0) {
|
|
return device_table;
|
|
}
|
|
device_table++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//Remove entry from the list
|
|
static void mac_sec_mib_key_device_description_remove_from_list(mlme_key_descriptor_t *key_descpription_table, uint8_t device_descriptor_handle)
|
|
{
|
|
bool removed_entry = false;
|
|
mlme_key_device_descriptor_t *cur, *prev;
|
|
prev = NULL;
|
|
cur = key_descpription_table->KeyDeviceList;
|
|
for (uint8_t i = 0; i < key_descpription_table->KeyDeviceListEntries; i++) {
|
|
if (removed_entry) {
|
|
//copy current to last one
|
|
*prev = *cur;
|
|
} else if (cur->DeviceDescriptorHandle == device_descriptor_handle) {
|
|
removed_entry = true;
|
|
//tr_debug("Remove user %u from key", device_descriptor_handle);
|
|
}
|
|
prev = cur;
|
|
cur++;
|
|
}
|
|
|
|
if (removed_entry) {
|
|
key_descpription_table->KeyDeviceListEntries--;
|
|
}
|
|
}
|
|
|
|
static void mac_sec_mib_device_description_remove(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t device_handle)
|
|
{
|
|
for (uint8_t i = 0; i < rf_mac_setup->key_description_table_size; i++) {
|
|
mac_sec_mib_key_device_description_remove_from_list(&rf_mac_setup->key_description_table[i], device_handle);
|
|
}
|
|
}
|
|
|
|
|
|
static int8_t mac_sec_mib_device_description_table_deinit(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
ns_dyn_mem_free(rf_mac_setup->device_description_table);
|
|
rf_mac_setup->device_description_table = NULL;
|
|
rf_mac_setup->device_description_table_size = 0;
|
|
return 0;
|
|
}
|
|
|
|
static void mac_sec_mib_security_material_free(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
ns_dyn_mem_free(rf_mac_setup->key_description_table);
|
|
ns_dyn_mem_free(rf_mac_setup->key_device_desc_buffer);
|
|
ns_dyn_mem_free(rf_mac_setup->key_usage_list_buffer);
|
|
ns_dyn_mem_free(rf_mac_setup->key_lookup_buffer);
|
|
rf_mac_setup->key_usage_list_buffer = NULL;
|
|
rf_mac_setup->key_description_table = NULL;
|
|
rf_mac_setup->key_lookup_buffer = NULL;
|
|
rf_mac_setup->key_device_desc_buffer = NULL;
|
|
rf_mac_setup->key_description_table_size = 0;
|
|
rf_mac_setup->key_lookup_list_size = 0;
|
|
rf_mac_setup->key_usage_list_size = 0;
|
|
}
|
|
|
|
static int8_t mac_sec_mib_key_description_table_deinit(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
mac_sec_mib_security_material_free(rf_mac_setup);
|
|
return 0;
|
|
}
|
|
|
|
static int8_t mac_sec_mib_device_description_table_init(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t table_size)
|
|
{
|
|
|
|
rf_mac_setup->device_description_table = mac_sec_mib_device_description_table_allocate(table_size);
|
|
if (!rf_mac_setup->device_description_table) {
|
|
return -1;
|
|
}
|
|
|
|
rf_mac_setup->device_description_table_size = table_size;
|
|
return 0;
|
|
}
|
|
|
|
static int8_t mac_sec_mib_key_description_table_init(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t table_size, uint8_t device_decription_size, uint8_t key_lookup_size, uint8_t key_usage_size)
|
|
{
|
|
|
|
rf_mac_setup->key_description_table = mac_sec_mib_key_description_table_allocate(table_size);
|
|
rf_mac_setup->key_device_desc_buffer = mac_sec_mib_key_device_description_table_allocate(device_decription_size * table_size);
|
|
rf_mac_setup->key_usage_list_buffer = mac_sec_mib_key_usage_table_allocate(key_usage_size * table_size);
|
|
rf_mac_setup->key_lookup_buffer = mac_sec_mib_key_lookup_table_allocate(key_lookup_size * table_size);
|
|
|
|
if (!rf_mac_setup->key_lookup_buffer || !rf_mac_setup->key_description_table || !rf_mac_setup->key_device_desc_buffer || !rf_mac_setup->key_usage_list_buffer) {
|
|
mac_sec_mib_security_material_free(rf_mac_setup);
|
|
return -1;
|
|
}
|
|
|
|
//SET description buffer sizes
|
|
rf_mac_setup->key_description_table_size = table_size;
|
|
rf_mac_setup->key_lookup_list_size = key_lookup_size;
|
|
rf_mac_setup->key_usage_list_size = key_usage_size;
|
|
|
|
mlme_key_descriptor_t *key_descriptor_list = rf_mac_setup->key_description_table;
|
|
mlme_key_device_descriptor_t *key_device_decription = rf_mac_setup->key_device_desc_buffer;
|
|
mlme_key_usage_descriptor_t *key_usage_ptr = rf_mac_setup->key_usage_list_buffer;
|
|
mlme_key_id_lookup_descriptor_t *key_lookup = rf_mac_setup->key_lookup_buffer;
|
|
|
|
|
|
for (uint8_t i = 0; i < rf_mac_setup->key_description_table_size; i++) {
|
|
|
|
//Update Pointer values after first init
|
|
if (i) {
|
|
key_device_decription += device_decription_size;
|
|
key_usage_ptr += key_usage_size;
|
|
key_lookup += key_lookup_size;
|
|
key_descriptor_list++;
|
|
}
|
|
key_descriptor_list->KeyDeviceListSize = device_decription_size;
|
|
key_descriptor_list->KeyDeviceList = key_device_decription;
|
|
key_descriptor_list->KeyUsageList = key_usage_ptr;
|
|
key_descriptor_list->KeyIdLookupList = key_lookup;
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
int8_t mac_sec_mib_device_description_set(uint8_t atribute_index, mlme_device_descriptor_t *device_descriptor, protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
|
|
//validate index to list size
|
|
if (!rf_mac_setup || !device_descriptor || atribute_index >= rf_mac_setup->device_description_table_size) {
|
|
tr_debug("Too many Devices");
|
|
return -1;
|
|
}
|
|
|
|
mlme_device_descriptor_t *device_ptr = rf_mac_setup->device_description_table + atribute_index;
|
|
|
|
//Copy description
|
|
if (memcmp(device_ptr->ExtAddress, device_descriptor->ExtAddress, 8)) {
|
|
//Remove last handles key user's
|
|
mac_sec_mib_device_description_remove(rf_mac_setup, atribute_index);
|
|
//tr_debug("Over write %u, mac16 %x mac64: %s, %"PRIu32, atribute_index, device_ptr->ShortAddress, trace_array(device_ptr->ExtAddress, 8), device_ptr->FrameCounter);
|
|
}
|
|
|
|
//tr_debug("Set %u, mac16 %x mac64: %s, %"PRIu32, atribute_index, device_descriptor->ShortAddress, trace_array(device_descriptor->ExtAddress, 8), device_descriptor->FrameCounter);
|
|
|
|
*device_ptr = *device_descriptor;
|
|
return 0;
|
|
}
|
|
|
|
int8_t mac_sec_mib_key_description_set(uint8_t atribute_index, mlme_key_descriptor_entry_t *key_descriptor, protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
|
|
//validate index to list size
|
|
if (!rf_mac_setup || !key_descriptor || atribute_index >= rf_mac_setup->key_description_table_size) {
|
|
return -1;
|
|
}
|
|
|
|
if (key_descriptor->KeyDeviceListEntries > rf_mac_setup->key_description_table_size || (key_descriptor->KeyDeviceListEntries && !key_descriptor->KeyDeviceList)) {
|
|
return -1;
|
|
}
|
|
|
|
if (key_descriptor->KeyIdLookupListEntries > rf_mac_setup->key_lookup_list_size || (key_descriptor->KeyIdLookupListEntries && !key_descriptor->KeyIdLookupList)) {
|
|
return -1;
|
|
}
|
|
|
|
if (key_descriptor->KeyUsageListEntries > rf_mac_setup->key_usage_list_size || (key_descriptor->KeyUsageListEntries && !key_descriptor->KeyUsageList)) {
|
|
return -1;
|
|
}
|
|
|
|
mlme_key_descriptor_t *key_ptr = rf_mac_setup->key_description_table + atribute_index;
|
|
|
|
//Copy description
|
|
tr_debug("Set key %"PRIu8, atribute_index);
|
|
|
|
memcpy(key_ptr->Key, key_descriptor->Key, 16);
|
|
key_ptr->KeyDeviceListEntries = key_descriptor->KeyDeviceListEntries;
|
|
key_ptr->unique_key_descriptor = false;
|
|
|
|
if (key_ptr->KeyDeviceListEntries) {
|
|
memcpy(key_ptr->KeyDeviceList, key_descriptor->KeyDeviceList, sizeof(mlme_key_device_descriptor_t) * key_ptr->KeyDeviceListEntries);
|
|
//Check unique key
|
|
if (key_ptr->KeyDeviceListEntries == 1) {
|
|
key_ptr->unique_key_descriptor = key_descriptor->KeyDeviceList->UniqueDevice;
|
|
}
|
|
}
|
|
|
|
key_ptr->KeyIdLookupListEntries = key_descriptor->KeyIdLookupListEntries;
|
|
|
|
if (key_ptr->KeyIdLookupListEntries) {
|
|
memcpy(key_ptr->KeyIdLookupList, key_descriptor->KeyIdLookupList, sizeof(mlme_key_id_lookup_descriptor_t) * key_ptr->KeyIdLookupListEntries);
|
|
}
|
|
|
|
key_ptr->KeyUsageListEntries = key_descriptor->KeyUsageListEntries;
|
|
|
|
if (key_ptr->KeyUsageListEntries) {
|
|
memcpy(key_ptr->KeyUsageList, key_descriptor->KeyUsageList, sizeof(mlme_key_usage_descriptor_t) * key_ptr->KeyUsageListEntries);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
mlme_device_descriptor_t *mac_sec_mib_device_description_get_attribute_index(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t attribute_index)
|
|
{
|
|
if (!rf_mac_setup || attribute_index >= rf_mac_setup->device_description_table_size) {
|
|
return NULL;
|
|
}
|
|
return rf_mac_setup->device_description_table + attribute_index;
|
|
}
|
|
|
|
mlme_device_descriptor_t *mac_sec_mib_device_description_get(protocol_interface_rf_mac_setup_s *rf_mac_setup, const uint8_t *address, uint8_t type)
|
|
{
|
|
if (rf_mac_setup) {
|
|
if (type == MAC_ADDR_MODE_16_BIT) {
|
|
uint16_t short_id = common_read_16_bit(address);
|
|
return mac_sec_mib_device_description_get_by_mac16(rf_mac_setup, short_id);
|
|
} else if (type == MAC_ADDR_MODE_64_BIT) {
|
|
return mac_sec_mib_device_description_get_by_mac64(rf_mac_setup, address);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
uint8_t mac_mib_device_descption_attribute_get_by_descriptor(protocol_interface_rf_mac_setup_s *rf_mac_setup, mlme_device_descriptor_t *descriptor)
|
|
{
|
|
if (!rf_mac_setup || !descriptor) {
|
|
return 0xff;
|
|
}
|
|
mlme_device_descriptor_t *device_table = rf_mac_setup->device_description_table;
|
|
for (uint8_t i = 0; i < rf_mac_setup->device_description_table_size; i++) {
|
|
if (device_table == descriptor) {
|
|
return i;
|
|
}
|
|
device_table++;
|
|
}
|
|
return 0xff;
|
|
}
|
|
|
|
|
|
static bool mac_sec_key_description_lookup_validate(mlme_key_descriptor_t *key_description, uint8_t *lookupdata)
|
|
{
|
|
uint8_t lookup_length;
|
|
mlme_key_id_lookup_descriptor_t *cur_lookup_ptr = key_description->KeyIdLookupList;
|
|
|
|
for (uint8_t i = 0; i < key_description->KeyIdLookupListEntries; i++) {
|
|
if (cur_lookup_ptr->LookupDataSize) {
|
|
lookup_length = 9;
|
|
} else {
|
|
lookup_length = 5;
|
|
}
|
|
|
|
if (memcmp(cur_lookup_ptr->LookupData, lookupdata, lookup_length) == 0) {
|
|
return true;
|
|
}
|
|
cur_lookup_ptr++;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
mlme_key_descriptor_t *mac_sec_key_description_get(protocol_interface_rf_mac_setup_s *rf_mac_setup, mlme_security_t *key_source, uint8_t address_mode, uint8_t *address_ptr, uint16_t pan_id)
|
|
{
|
|
if (!rf_mac_setup || !key_source) {
|
|
return NULL;
|
|
}
|
|
|
|
mlme_key_descriptor_t *key_description;
|
|
uint8_t lookup_data[9];
|
|
memset(lookup_data, 0, 9);
|
|
|
|
switch (key_source->KeyIdMode) {
|
|
case MAC_KEY_ID_MODE_IMPLICIT:
|
|
if (address_mode == MAC_ADDR_MODE_64_BIT) {
|
|
memcpy(lookup_data, address_ptr, 8);
|
|
} else if (address_mode == MAC_ADDR_MODE_16_BIT) {
|
|
common_write_16_bit(pan_id, lookup_data);
|
|
memcpy(&lookup_data[2], address_ptr, 2);
|
|
} else {
|
|
return NULL; //Not supported this yet
|
|
}
|
|
break;
|
|
case MAC_KEY_ID_MODE_IDX:
|
|
//SET Default keysource
|
|
memcpy(lookup_data, rf_mac_setup->mac_default_key_source, 8);
|
|
lookup_data[8] = key_source->KeyIndex;
|
|
break;
|
|
|
|
case MAC_KEY_ID_MODE_SRC4_IDX:
|
|
memcpy(lookup_data, key_source->Keysource, 4);
|
|
lookup_data[4] = key_source->KeyIndex;
|
|
break;
|
|
|
|
case MAC_KEY_ID_MODE_SRC8_IDX:
|
|
memcpy(lookup_data, key_source->Keysource, 8);
|
|
lookup_data[8] = key_source->KeyIndex;
|
|
break;
|
|
}
|
|
key_description = rf_mac_setup->key_description_table;
|
|
for (uint8_t i = 0; i < rf_mac_setup->key_description_table_size; i++) {
|
|
|
|
if (mac_sec_key_description_lookup_validate(key_description, lookup_data)) {
|
|
return key_description;
|
|
}
|
|
key_description++;
|
|
}
|
|
|
|
//tr_debug("LookuPdata search fail %s", trace_array(lookup_data, 9));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int8_t mac_sec_mib_init(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_description_storage_size_t *storage_sizes)
|
|
{
|
|
|
|
if (!rf_mac_setup || !storage_sizes) {
|
|
return -1;
|
|
}
|
|
|
|
mac_sec_mib_deinit(rf_mac_setup);
|
|
if (mac_sec_mib_device_description_table_init(rf_mac_setup, storage_sizes->device_decription_table_size) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (mac_sec_mib_key_description_table_init(rf_mac_setup, storage_sizes->key_description_table_size, storage_sizes->device_decription_table_size, storage_sizes->key_lookup_size, storage_sizes->key_usage_size)) {
|
|
mac_sec_mib_deinit(rf_mac_setup);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void mac_sec_mib_deinit(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
if (!rf_mac_setup) {
|
|
return;
|
|
}
|
|
mac_sec_mib_device_description_table_deinit(rf_mac_setup);
|
|
mac_sec_mib_key_description_table_deinit(rf_mac_setup);
|
|
|
|
}
|
|
|
|
//allocate new entry and update entries size
|
|
mlme_key_device_descriptor_t *mac_sec_mib_key_device_description_list_update(mlme_key_descriptor_t *key_descpription_table)
|
|
{
|
|
if (!key_descpription_table || key_descpription_table->KeyDeviceListEntries == key_descpription_table->KeyDeviceListSize) {
|
|
return NULL;
|
|
}
|
|
mlme_key_device_descriptor_t *new_entry = key_descpription_table->KeyDeviceList;
|
|
new_entry += key_descpription_table->KeyDeviceListEntries++;
|
|
new_entry->Blacklisted = false;
|
|
new_entry->UniqueDevice = false;
|
|
return new_entry;
|
|
}
|
|
|
|
//Discover device entry from the list
|
|
mlme_key_device_descriptor_t *mac_sec_mib_key_device_description_discover_from_list(mlme_key_descriptor_t *key_description_table, uint8_t device_descriptor_handle)
|
|
{
|
|
if (key_description_table) {
|
|
mlme_key_device_descriptor_t *entry = key_description_table->KeyDeviceList;
|
|
for (uint8_t i = 0; i < key_description_table->KeyDeviceListEntries; i++) {
|
|
if (entry->DeviceDescriptorHandle == device_descriptor_handle) {
|
|
return entry;
|
|
}
|
|
entry++;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//Black list device from key descriptior list
|
|
|
|
void mac_sec_mib_device_description_blacklist(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t device_handle)
|
|
{
|
|
|
|
if (!rf_mac_setup) {
|
|
return;
|
|
}
|
|
mlme_key_device_descriptor_t *descriptor;
|
|
for (uint8_t i = 0; i < rf_mac_setup->key_description_table_size; i++) {
|
|
descriptor = mac_sec_mib_key_device_description_discover_from_list(&rf_mac_setup->key_description_table[i], device_handle);
|
|
if (descriptor) {
|
|
tr_debug("Black listed device %u", device_handle);
|
|
descriptor->Blacklisted = true;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|