1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** NetX Secure Component */
16 /** */
17 /** Datagram Transport Layer Security (DTLS) */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define NX_SECURE_SOURCE_CODE
23
24 #include "nx_secure_dtls.h"
25
26 /**************************************************************************/
27 /* */
28 /* FUNCTION RELEASE */
29 /* */
30 /* _nx_secure_dtls_session_receive PORTABLE C */
31 /* 6.3.0 */
32 /* AUTHOR */
33 /* */
34 /* Timothy Stapko, Microsoft Corporation */
35 /* */
36 /* DESCRIPTION */
37 /* */
38 /* This function receives data from an active DTLS session, handling */
39 /* all decryption and verification before returning the data to the */
40 /* caller in the supplied NX_PACKET structure. */
41 /* */
42 /* INPUT */
43 /* */
44 /* dtls_session DTLS session control block */
45 /* packet_ptr_ptr Pointer to return packet */
46 /* wait_option Indicates how long the caller */
47 /* should wait for a packet */
48 /* */
49 /* OUTPUT */
50 /* */
51 /* status Completion status */
52 /* */
53 /* CALLS */
54 /* */
55 /* _nx_secure_dtls_packet_allocate Allocate internal DTLS packet */
56 /* _nx_secure_dtls_process_record Process DTLS record data */
57 /* _nx_secure_dtls_send_record Send the DTLS record */
58 /* _nx_secure_tls_map_error_to_alert Map internal error to alert */
59 /* _nx_secure_tls_send_alert Send TLS alert */
60 /* nx_secure_tls_packet_release Release packet */
61 /* nx_udp_socket_receive Receive UDP data */
62 /* nxd_udp_source_extract Extract UDP information */
63 /* tx_mutex_get Get protection mutex */
64 /* tx_mutex_put Put protection mutex */
65 /* tx_thread_preemption_change Disable thread preemption */
66 /* tx_thread_sleep Thread sleep */
67 /* */
68 /* CALLED BY */
69 /* */
70 /* Application Code */
71 /* _nx_secure_dtls_session_start Actual DTLS session start call*/
72 /* _nx_secure_dtls_session_end End of a session */
73 /* */
74 /* RELEASE HISTORY */
75 /* */
76 /* DATE NAME DESCRIPTION */
77 /* */
78 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
79 /* 09-30-2020 Timothy Stapko Modified comment(s), */
80 /* released packet securely, */
81 /* resulting in version 6.1 */
82 /* 01-31-2022 Timothy Stapko Modified comment(s), */
83 /* fixed out-of-order handling,*/
84 /* resulting in version 6.1.10 */
85 /* 07-29-2022 Yuxin Zhou Modified comment(s), */
86 /* fixed compiler errors when */
87 /* IPv4 is disabled, */
88 /* resulting in version 6.1.12 */
89 /* 10-31-2023 Tiejun Zhou Modified comment(s), and */
90 /* released packet on failure, */
91 /* resulting in version 6.3.0 */
92 /* */
93 /**************************************************************************/
_nx_secure_dtls_session_receive(NX_SECURE_DTLS_SESSION * dtls_session,NX_PACKET ** packet_ptr_ptr,ULONG wait_option)94 UINT _nx_secure_dtls_session_receive(NX_SECURE_DTLS_SESSION *dtls_session,
95 NX_PACKET **packet_ptr_ptr, ULONG wait_option)
96 {
97 #ifdef NX_SECURE_ENABLE_DTLS
98 UINT status;
99 NX_PACKET *packet_ptr = NX_NULL;
100 NX_PACKET *send_packet = NX_NULL;
101 ULONG bytes_processed;
102 #if 0
103 UINT remote_port;
104 #endif
105 ULONG packet_length;
106 UINT error_number;
107 UINT alert_number;
108 UINT alert_level;
109 NX_SECURE_TLS_SESSION *tls_session;
110 NX_UDP_SOCKET *udp_socket;
111 UINT old_threshold;
112 NXD_ADDRESS source_address;
113 UINT source_port;
114
115
116 /* Process all records in the packet we received - decrypt, authenticate, and
117 * strip TLS record header/footer, placing data in the return packet.
118 */
119
120 /* Get a working pointer to our internal TLS session. */
121 tls_session = &(dtls_session -> nx_secure_dtls_tls_session);
122
123 status = NX_CONTINUE;
124
125 /* Continue processing UDP datagrams until we get a valid DTLS record or an error. */
126 while (status == NX_CONTINUE)
127 {
128
129
130 #ifndef NX_SECURE_TLS_SERVER_DISABLED
131 /* If we are a server, the UDP packet was assigned to the session queue in
132 the UDP receive callback. */
133 if (tls_session -> nx_secure_tls_socket_type == NX_SECURE_TLS_SESSION_TYPE_SERVER)
134 {
135 /* We received a UDP packet in the receive callback. Use the head of the queue
136 for the next packet and remove it from the queue. */
137
138 /* Get the mutex. */
139 tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER);
140
141 /* If we don't have a packet yet, don't do anything. */
142 if (dtls_session -> nx_secure_dtls_receive_queue_head == NX_NULL)
143 {
144 if (wait_option == NX_NO_WAIT)
145 {
146
147 /* No packet. */
148 tx_mutex_put(&_nx_secure_tls_protection);
149 return(NX_NO_PACKET);
150 }
151
152 /* Disable preemption before waiting for packet. */
153 tx_thread_preemption_change(tx_thread_identify(), 0, &old_threshold);
154
155 if (dtls_session -> nx_secure_dtls_thread_suspended)
156 {
157
158 /* Another thread is already suspended. */
159 tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold);
160 tx_mutex_put(&_nx_secure_tls_protection);
161 return(NX_ALREADY_SUSPENDED);
162 }
163
164 /* Set thread waiting for packet. */
165 dtls_session -> nx_secure_dtls_thread_suspended = tx_thread_identify();
166
167 /* Release mutex. */
168 tx_mutex_put(&_nx_secure_tls_protection);
169
170 /* Sleep to wait for packet. */
171 /* The wait process could be aborted if packet received.
172 * And then dtls_session -> nx_secure_dtls_thread_suspended is cleared. */
173 tx_thread_sleep(wait_option);
174
175 /* Get mutex. */
176 tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER);
177
178 /* Restore preemption . */
179 tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold);
180
181 if (!dtls_session -> nx_secure_dtls_session_in_use)
182 {
183
184 /* Session is not in use. */
185 tx_mutex_put(&_nx_secure_tls_protection);
186 return(NX_SECURE_TLS_SESSION_UNINITIALIZED);
187 }
188
189 if ((volatile NX_PACKET *)dtls_session -> nx_secure_dtls_receive_queue_head == NX_NULL)
190 {
191
192 /* Still no packet. */
193 dtls_session -> nx_secure_dtls_thread_suspended = NX_NULL;
194 tx_mutex_put(&_nx_secure_tls_protection);
195 return(NX_NO_PACKET);
196 }
197 }
198
199 /* Get the received packet. */
200 packet_ptr = dtls_session -> nx_secure_dtls_receive_queue_head;
201
202 /* Remove the packet from the queue. */
203 dtls_session -> nx_secure_dtls_receive_queue_head = packet_ptr -> nx_packet_queue_next;
204 packet_ptr -> nx_packet_queue_next = NX_NULL;
205
206 /* Release the protection. */
207 tx_mutex_put(&_nx_secure_tls_protection);
208
209 status = NX_SUCCESS;
210 }
211 else
212 #endif
213 {
214 /* If we are a client, just receive the UDP packet directly. */
215 udp_socket = dtls_session -> nx_secure_dtls_udp_socket;
216
217 status = nx_udp_socket_receive(udp_socket, &packet_ptr, wait_option);
218
219 if (status)
220 {
221 /* Error in socket receive. */
222 return(status);
223 }
224
225 /* Extract the source IP address and port. */
226 status = nxd_udp_source_extract(packet_ptr, &source_address, &source_port);
227
228 /* With DTLS, we need to send back to the remote host on the port they used to send us data.
229 Check if the source IP address is same as the stored remote IP address,
230 and if the source port is same as the stored remote port. */
231 if ((status) ||
232 (source_port != dtls_session -> nx_secure_dtls_remote_port) ||
233 (source_address.nxd_ip_version != dtls_session -> nx_secure_dtls_remote_ip_address.nxd_ip_version))
234 {
235 status = NX_CONTINUE;
236 }
237 else
238 {
239 #ifndef NX_DISABLE_IPV4
240 if (dtls_session -> nx_secure_dtls_remote_ip_address.nxd_ip_version == NX_IP_VERSION_V4)
241 {
242
243 /* Compare the IPv4 address. */
244 if (dtls_session -> nx_secure_dtls_remote_ip_address.nxd_ip_address.v4 != source_address.nxd_ip_address.v4)
245 {
246 status = NX_CONTINUE;
247 }
248 }
249 #endif /* !NX_DISABLE_IPV4 */
250
251 #ifdef FEATURE_NX_IPV6
252 if (dtls_session -> nx_secure_dtls_remote_ip_address.nxd_ip_version == NX_IP_VERSION_V6)
253 {
254
255 /* Compare the IPv6 address. */
256 if ((dtls_session -> nx_secure_dtls_remote_ip_address.nxd_ip_address.v6[0] != source_address.nxd_ip_address.v6[0]) ||
257 (dtls_session -> nx_secure_dtls_remote_ip_address.nxd_ip_address.v6[1] != source_address.nxd_ip_address.v6[1]) ||
258 (dtls_session -> nx_secure_dtls_remote_ip_address.nxd_ip_address.v6[2] != source_address.nxd_ip_address.v6[2]) ||
259 (dtls_session -> nx_secure_dtls_remote_ip_address.nxd_ip_address.v6[3] != source_address.nxd_ip_address.v6[3]))
260 {
261 status = NX_CONTINUE;
262 }
263 }
264 #endif /* FEATURE_NX_IPV6 */
265 }
266
267 if (status)
268 {
269
270 /* This packet is from unkown address or port. Ignore it. */
271 nx_secure_tls_packet_release(packet_ptr);
272 status = NX_CONTINUE;
273 continue;
274 }
275 }
276
277 /* Set local IP address index. It will be used to send record. */
278 if (dtls_session -> nx_secure_dtls_local_ip_address_index == 0xffffffff)
279 {
280 if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4)
281 {
282 dtls_session -> nx_secure_dtls_local_ip_address_index = packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_index;
283 }
284 #ifdef FEATURE_NX_IPV6
285 else if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6)
286 {
287 if (packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr)
288 {
289 dtls_session -> nx_secure_dtls_local_ip_address_index = packet_ptr->nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_index;
290 }
291 }
292 #endif /* FEATURE_NX_IPV6 */
293 }
294
295 /* Process all records in the packet we received - decrypt, authenticate, and
296 * strip TLS record header/footer, placing data in the return packet.
297 */
298 if (packet_ptr -> nx_packet_next)
299 {
300
301 /* Chained packet is not supported. */
302 status = NX_SECURE_TLS_INVALID_PACKET;
303 }
304 else
305 {
306
307 packet_length = packet_ptr -> nx_packet_length;
308 bytes_processed = 0;
309 while (packet_length > 0)
310 {
311 /* If we have multiple records in the datagram, advance the pointer.
312 If only a single record, bytes_processed is 0. */
313 packet_ptr -> nx_packet_prepend_ptr += bytes_processed;
314
315 /* Get the protection. */
316 tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER);
317
318 /* The UDP datagram may contain more than one DTLS record... */
319 status = _nx_secure_dtls_process_record(dtls_session, packet_ptr, 0, &bytes_processed, wait_option);
320
321 /* Release the protection. */
322 tx_mutex_put(&_nx_secure_tls_protection);
323
324 if (status && (status != NX_CONTINUE))
325 {
326
327 /* Error status, just break. */
328 break;
329 }
330
331 if (bytes_processed > packet_length)
332 {
333 break;
334 }
335
336 /* Advance the packet pointer to the next DTLS record in the datagram. */
337 packet_length -= bytes_processed;
338 }
339 }
340
341 if (status != NX_SUCCESS)
342 {
343
344 /* Clear out the packet, we don't want any of the data in it. */
345 nx_secure_tls_packet_release(packet_ptr);
346
347 if (status == NX_SECURE_TLS_ALERT_RECEIVED)
348 {
349 /* See if the alert was a CloseNotify */
350 if(tls_session -> nx_secure_tls_received_alert_level == NX_SECURE_TLS_ALERT_LEVEL_WARNING &&
351 tls_session -> nx_secure_tls_received_alert_value == NX_SECURE_TLS_ALERT_CLOSE_NOTIFY)
352 {
353 /* Close the connection */
354 status = NX_SECURE_TLS_CLOSE_NOTIFY_RECEIVED;
355 }
356 /* Dont send alert to remote host if we recevied an alert */
357 }
358 else if (status != NX_CONTINUE)
359 {
360 /* Error status, send alert back to remote host. */
361 /* Get our alert number and level from our status. */
362 error_number = status;
363
364 /* Get the protection. */
365 tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER);
366
367 _nx_secure_tls_map_error_to_alert(error_number, &alert_number, &alert_level);
368
369 /* Release the protection before suspending on nx_packet_allocate. */
370 tx_mutex_put(&_nx_secure_tls_protection);
371
372 status = _nx_secure_dtls_packet_allocate(dtls_session,
373 tls_session -> nx_secure_tls_packet_pool,
374 &send_packet, wait_option);
375
376 if (status == NX_SUCCESS)
377 {
378
379 /* Get the protection after nx_packet_allocate. */
380 tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER);
381
382 _nx_secure_tls_send_alert(tls_session, send_packet, (UCHAR)alert_number, (UCHAR)alert_level);
383 if (_nx_secure_dtls_send_record(dtls_session, send_packet, NX_SECURE_TLS_ALERT, wait_option) != NX_SUCCESS)
384 {
385
386 /* Release packet on send error. */
387 nx_secure_tls_packet_release(send_packet);
388 }
389
390 /* Release the protection. */
391 tx_mutex_put(&_nx_secure_tls_protection);
392 }
393 status = error_number;
394 return(status);
395 }
396 }
397 }
398
399 /* Return our completed packet. */
400 *packet_ptr_ptr = packet_ptr;
401
402 return(status);
403 #else
404 NX_PARAMETER_NOT_USED(dtls_session);
405 NX_PARAMETER_NOT_USED(packet_ptr_ptr);
406 NX_PARAMETER_NOT_USED(wait_option);
407
408 return(NX_NOT_SUPPORTED);
409 #endif /* NX_SECURE_ENABLE_DTLS */
410 }
411
412