1 /*
2 * Copyright (c) 2021 - 2023, Nordic Semiconductor ASA
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice, this
11 * list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 *
33 */
34
35 /**
36 * @file
37 * This file implements the security header data injector for the 802.15.4 driver.
38 *
39 */
40
41 #include "mac_features/nrf_802154_security_writer.h"
42
43 #include "mac_features/nrf_802154_frame_parser.h"
44 #include "mac_features/nrf_802154_security_pib.h"
45 #include "nrf_802154_config.h"
46 #include "nrf_802154_const.h"
47 #include "nrf_802154_tx_work_buffer.h"
48 #include "nrf_802154_utils_byteorder.h"
49
50 #include <assert.h>
51 #include <stddef.h>
52
53 #if NRF_802154_SECURITY_WRITER_ENABLED
54
55 static bool m_frame_counter_injected; ///< Flag that indicates if frame counter was injected.
56
57 /**
58 * @brief Populates the key ID structure with key ID mode and source.
59 *
60 * @param[in] p_frame_data Pointer to the frame parser data.
61 * @param[out] p_key_id Pointer to the @ref nrf_802154_key_id_t structure to be populated.
62 */
key_id_prepare(const nrf_802154_frame_parser_data_t * p_frame_data,nrf_802154_key_id_t * p_key_id)63 static void key_id_prepare(const nrf_802154_frame_parser_data_t * p_frame_data,
64 nrf_802154_key_id_t * p_key_id)
65 {
66 p_key_id->mode = nrf_802154_frame_parser_sec_ctrl_key_id_mode_get(p_frame_data);
67
68 switch (p_key_id->mode)
69 {
70 case KEY_ID_MODE_0:
71 /* There is no need to retrieve the key ID as only one key ID with mode 0 is
72 * supported. Therefore mode 0 unambiguously identifies the key.
73 */
74 break;
75
76 case KEY_ID_MODE_1:
77 /* Fallthrough */
78 case KEY_ID_MODE_2:
79 /* Fallthrough */
80 case KEY_ID_MODE_3:
81 p_key_id->p_key_id = (uint8_t *)nrf_802154_frame_parser_key_id_get(p_frame_data);
82 break;
83
84 default:
85 /* Key Identifier Mode is encoded on 2 bits and has 4 possible values, all handled in
86 * the above cases. Ending up in the default case indicates the frame parser is bugged.
87 */
88 assert(false);
89 }
90 }
91
92 /**
93 * @brief Injects frame counter value into given address with security enabled.
94 *
95 * @param[in] p_frame_data Pointer to the frame parser data.
96 * @param[in] p_key_id Pointer to the key identifying which counter shall be retrieved.
97 *
98 * @retval NRF_802154_SECURITY_ERROR_NONE Frame counter was injected successfully.
99 *
100 * @returns nrf_802154_security_error_t The security error code that occurred during
101 * the frame counter injection.
102 */
frame_counter_inject(nrf_802154_frame_parser_data_t * p_frame_data,nrf_802154_key_id_t * p_key_id)103 static nrf_802154_security_error_t frame_counter_inject(
104 nrf_802154_frame_parser_data_t * p_frame_data,
105 nrf_802154_key_id_t * p_key_id)
106 {
107 uint32_t frame_counter;
108 uint8_t * p_frame_counter =
109 (uint8_t *)nrf_802154_frame_parser_frame_counter_get(p_frame_data);
110 nrf_802154_security_error_t err;
111
112 err = nrf_802154_security_pib_frame_counter_get_next(&frame_counter, p_key_id);
113
114 switch (err)
115 {
116 case NRF_802154_SECURITY_ERROR_NONE:
117 if (p_frame_counter != NULL)
118 {
119 /* Frame counter suppression is off. Inject the frame counter. */
120 host_32_to_little(frame_counter, p_frame_counter);
121 }
122 break;
123
124 case NRF_802154_SECURITY_ERROR_KEY_NOT_FOUND:
125 /* Fallthrough */
126 case NRF_802154_SECURITY_ERROR_FRAME_COUNTER_OVERFLOW:
127 break;
128
129 default:
130 /* nrf_802154_security_pib_frame_counter_get_next function shall not return other
131 * error codes than those handled in the above cases. If it does then it is a bug.
132 */
133 assert(false);
134 }
135
136 return err;
137 }
138
139 /**
140 * @brief Checks if security is enabled for the given Auxiliary Security Header.
141 *
142 * @param[in] p_frame_data Pointer to the frame parser data to be checked.
143 *
144 * @retval true Security is enabled.
145 * @retbal false Security is disabled.
146 */
security_is_enabled(const nrf_802154_frame_parser_data_t * p_frame_data)147 static bool security_is_enabled(const nrf_802154_frame_parser_data_t * p_frame_data)
148 {
149 return (NULL != nrf_802154_frame_parser_sec_ctrl_get(p_frame_data)) &&
150 (SECURITY_LEVEL_NONE != nrf_802154_frame_parser_sec_ctrl_sec_lvl_get(p_frame_data));
151 }
152
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)153 bool nrf_802154_security_writer_tx_setup(
154 uint8_t * p_frame,
155 nrf_802154_transmit_params_t * p_params,
156 nrf_802154_transmit_failed_notification_t notify_function)
157 {
158 nrf_802154_frame_parser_data_t frame_data;
159 nrf_802154_key_id_t key_id;
160 bool result = false;
161
162 key_id.p_key_id = NULL;
163 m_frame_counter_injected = false;
164
165 if (p_params->frame_props.dynamic_data_is_set)
166 {
167 // The frame has a frame counter field already set. Pass.
168 return true;
169 }
170
171 result = nrf_802154_frame_parser_data_init(p_frame,
172 p_frame[PHR_OFFSET] + PHR_SIZE,
173 PARSE_LEVEL_AUX_SEC_HDR_END,
174 &frame_data);
175 assert(result);
176 (void)result;
177
178 do
179 {
180 if (!security_is_enabled(&frame_data))
181 {
182 /* Security is not enabled. Pass. */
183 result = true;
184 break;
185 }
186
187 /* Prepare key ID for key validation. */
188 key_id_prepare(&frame_data, &key_id);
189
190 nrf_802154_security_error_t err = frame_counter_inject(&frame_data, &key_id);
191
192 switch (err)
193 {
194 case NRF_802154_SECURITY_ERROR_NONE:
195 result = true;
196 m_frame_counter_injected = true;
197 break;
198
199 case NRF_802154_SECURITY_ERROR_KEY_NOT_FOUND:
200 {
201 nrf_802154_transmit_done_metadata_t metadata = {};
202
203 metadata.frame_props = p_params->frame_props;
204 notify_function(p_frame, NRF_802154_TX_ERROR_KEY_ID_INVALID, &metadata);
205 result = false;
206 }
207 break;
208
209 case NRF_802154_SECURITY_ERROR_FRAME_COUNTER_OVERFLOW:
210 {
211 nrf_802154_transmit_done_metadata_t metadata = {};
212
213 metadata.frame_props = p_params->frame_props;
214 notify_function(p_frame, NRF_802154_TX_ERROR_FRAME_COUNTER_ERROR, &metadata);
215 result = false;
216 }
217 break;
218
219 default:
220 /* frame_counter_inject function shall not return other error codes than those
221 * handled in the above cases. If it does then it is a bug.
222 */
223 assert(false);
224 result = false;
225 }
226 }
227 while (0);
228
229 return result;
230 }
231
nrf_802154_security_writer_tx_started_hook(uint8_t * p_frame)232 bool nrf_802154_security_writer_tx_started_hook(uint8_t * p_frame)
233 {
234 if (m_frame_counter_injected)
235 {
236 /* Mark dynamic data updated in the work buffer. */
237 nrf_802154_tx_work_buffer_is_dynamic_data_updated_set();
238 }
239
240 return true;
241 }
242
243 #endif // NRF_802154_SECURITY_WRITER_ENABLED
244