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