243 lines
8.3 KiB
C
243 lines
8.3 KiB
C
/*
|
|
* Copyright (c) 2021, Nordic Semiconductor ASA
|
|
* All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
|
|
* contributors may be used to endorse or promote products derived from this
|
|
* software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* This file implements the security header data injector for the 802.15.4 driver.
|
|
*
|
|
*/
|
|
|
|
#include "mac_features/nrf_802154_security_writer.h"
|
|
|
|
#include "mac_features/nrf_802154_frame_parser.h"
|
|
#include "mac_features/nrf_802154_security_pib.h"
|
|
#include "nrf_802154_config.h"
|
|
#include "nrf_802154_const.h"
|
|
#include "nrf_802154_tx_work_buffer.h"
|
|
#include "nrf_802154_utils_byteorder.h"
|
|
|
|
#include <assert.h>
|
|
#include <stddef.h>
|
|
|
|
#if NRF_802154_SECURITY_WRITER_ENABLED
|
|
|
|
static bool m_frame_counter_injected; ///< Flag that indicates if frame counter was injected.
|
|
|
|
/**
|
|
* @brief Populates the key ID structure with key ID mode and source.
|
|
*
|
|
* @param[in] p_frame_data Pointer to the frame parser data.
|
|
* @param[out] p_key_id Pointer to the @ref nrf_802154_key_id_t structure to be populated.
|
|
*/
|
|
static void key_id_prepare(const nrf_802154_frame_parser_data_t * p_frame_data,
|
|
nrf_802154_key_id_t * p_key_id)
|
|
{
|
|
p_key_id->mode = nrf_802154_frame_parser_sec_ctrl_key_id_mode_get(p_frame_data);
|
|
|
|
switch (p_key_id->mode)
|
|
{
|
|
case KEY_ID_MODE_0:
|
|
/* There is no need to retrieve the key ID as only one key ID with mode 0 is
|
|
* supported. Therefore mode 0 unambiguously identifies the key.
|
|
*/
|
|
break;
|
|
|
|
case KEY_ID_MODE_1:
|
|
/* Fallthrough */
|
|
case KEY_ID_MODE_2:
|
|
/* Fallthrough */
|
|
case KEY_ID_MODE_3:
|
|
p_key_id->p_key_id = (uint8_t *)nrf_802154_frame_parser_key_id_get(p_frame_data);
|
|
break;
|
|
|
|
default:
|
|
/* Key Identifier Mode is encoded on 2 bits and has 4 possible values, all handled in
|
|
* the above cases. Ending up in the default case indicates the frame parser is bugged.
|
|
*/
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Injects frame counter value into given address with security enabled.
|
|
*
|
|
* @param[in] p_frame_data Pointer to the frame parser data.
|
|
* @param[in] p_key_id Pointer to the key identifying which counter shall be retrieved.
|
|
*
|
|
* @retval NRF_802154_SECURITY_ERROR_NONE Frame counter was injected successfully.
|
|
*
|
|
* @returns nrf_802154_security_error_t The security error code that occurred during
|
|
* the frame counter injection.
|
|
*/
|
|
static nrf_802154_security_error_t frame_counter_inject(
|
|
nrf_802154_frame_parser_data_t * p_frame_data,
|
|
nrf_802154_key_id_t * p_key_id)
|
|
{
|
|
uint32_t frame_counter;
|
|
uint8_t * p_frame_counter =
|
|
(uint8_t *)nrf_802154_frame_parser_frame_counter_get(p_frame_data);
|
|
nrf_802154_security_error_t err;
|
|
|
|
err = nrf_802154_security_pib_frame_counter_get_next(&frame_counter, p_key_id);
|
|
|
|
switch (err)
|
|
{
|
|
case NRF_802154_SECURITY_ERROR_NONE:
|
|
if (p_frame_counter != NULL)
|
|
{
|
|
/* Frame counter suppression is off. Inject the frame counter. */
|
|
host_32_to_little(frame_counter, p_frame_counter);
|
|
}
|
|
break;
|
|
|
|
case NRF_802154_SECURITY_ERROR_KEY_NOT_FOUND:
|
|
/* Fallthrough */
|
|
case NRF_802154_SECURITY_ERROR_FRAME_COUNTER_OVERFLOW:
|
|
break;
|
|
|
|
default:
|
|
/* nrf_802154_security_pib_frame_counter_get_next function shall not return other
|
|
* error codes than those handled in the above cases. If it does then it is a bug.
|
|
*/
|
|
assert(false);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* @brief Checks if security is enabled for the given Auxiliary Security Header.
|
|
*
|
|
* @param[in] p_frame_data Pointer to the frame parser data to be checked.
|
|
*
|
|
* @retval true Security is enabled.
|
|
* @retbal false Security is disabled.
|
|
*/
|
|
static bool security_is_enabled(const nrf_802154_frame_parser_data_t * p_frame_data)
|
|
{
|
|
return (NULL != nrf_802154_frame_parser_sec_ctrl_get(p_frame_data)) &&
|
|
(SECURITY_LEVEL_NONE != nrf_802154_frame_parser_sec_ctrl_sec_lvl_get(p_frame_data));
|
|
}
|
|
|
|
bool nrf_802154_security_writer_tx_setup(
|
|
uint8_t * p_frame,
|
|
nrf_802154_transmit_params_t * p_params,
|
|
nrf_802154_transmit_failed_notification_t notify_function)
|
|
{
|
|
nrf_802154_frame_parser_data_t frame_data;
|
|
nrf_802154_key_id_t key_id;
|
|
bool result = false;
|
|
|
|
m_frame_counter_injected = false;
|
|
|
|
if (p_params->frame_props.dynamic_data_is_set)
|
|
{
|
|
// The frame has a frame counter field already set. Pass.
|
|
return true;
|
|
}
|
|
|
|
result = nrf_802154_frame_parser_data_init(p_frame,
|
|
p_frame[PHR_OFFSET] + PHR_SIZE,
|
|
PARSE_LEVEL_AUX_SEC_HDR_END,
|
|
&frame_data);
|
|
assert(result);
|
|
(void)result;
|
|
|
|
do
|
|
{
|
|
if (!security_is_enabled(&frame_data))
|
|
{
|
|
/* Security is not enabled. Pass. */
|
|
result = true;
|
|
break;
|
|
}
|
|
|
|
/* Prepare key ID for key validation. */
|
|
key_id_prepare(&frame_data, &key_id);
|
|
|
|
nrf_802154_security_error_t err = frame_counter_inject(&frame_data, &key_id);
|
|
|
|
switch (err)
|
|
{
|
|
case NRF_802154_SECURITY_ERROR_NONE:
|
|
result = true;
|
|
m_frame_counter_injected = true;
|
|
break;
|
|
|
|
case NRF_802154_SECURITY_ERROR_KEY_NOT_FOUND:
|
|
{
|
|
nrf_802154_transmit_done_metadata_t metadata = {};
|
|
|
|
metadata.frame_props = p_params->frame_props;
|
|
notify_function(p_frame, NRF_802154_TX_ERROR_KEY_ID_INVALID, &metadata);
|
|
result = false;
|
|
}
|
|
break;
|
|
|
|
case NRF_802154_SECURITY_ERROR_FRAME_COUNTER_OVERFLOW:
|
|
{
|
|
nrf_802154_transmit_done_metadata_t metadata = {};
|
|
|
|
metadata.frame_props = p_params->frame_props;
|
|
notify_function(p_frame, NRF_802154_TX_ERROR_FRAME_COUNTER_ERROR, &metadata);
|
|
result = false;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
/* frame_counter_inject function shall not return other error codes than those
|
|
* handled in the above cases. If it does then it is a bug.
|
|
*/
|
|
assert(false);
|
|
result = false;
|
|
}
|
|
}
|
|
while (0);
|
|
|
|
return result;
|
|
}
|
|
|
|
bool nrf_802154_security_writer_tx_started_hook(uint8_t * p_frame)
|
|
{
|
|
if (m_frame_counter_injected)
|
|
{
|
|
/* Mark dynamic data updated in the work buffer. */
|
|
nrf_802154_tx_work_buffer_is_dynamic_data_updated_set();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#endif // NRF_802154_SECURITY_WRITER_ENABLED
|