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