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