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