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 #include "nx_udp.h"
27
28 /**************************************************************************/
29 /* */
30 /* FUNCTION RELEASE */
31 /* */
32 /* _nx_secure_dtls_receive_callback PORTABLE C */
33 /* 6.1 */
34 /* AUTHOR */
35 /* */
36 /* Timothy Stapko, Microsoft Corporation */
37 /* */
38 /* DESCRIPTION */
39 /* */
40 /* This function serves as the notification callback provided to NetX */
41 /* that is invoked when a UDP packet has been received. It checks the */
42 /* DTLS session cache for a matching client (based on IP address and */
43 /* port) and then invokes the application callback with the */
44 /* appropriate session object. If a previous session was not found, a */
45 /* new session is allocated (if available) and the DTLS handshake is */
46 /* initiated. Once the handshake is complete the user callback is */
47 /* invoked as above. */
48 /* */
49 /* INPUT */
50 /* */
51 /* socket_ptr UDP socket */
52 /* */
53 /* OUTPUT */
54 /* */
55 /* N/A */
56 /* */
57 /* CALLS */
58 /* */
59 /* _nxd_udp_source_extract Extract IP address and port */
60 /* _nx_udp_socket_port_get Get local port */
61 /* nx_secure_dtls_session_cache_find Check DTLS session cache */
62 /* nx_secure_dtls_session_cache_get_new Get new DTLS session */
63 /* nx_secure_tls_packet_release Release packet */
64 /* nx_packet_allocate Allocate packet */
65 /* _nxd_udp_socket_send Send UDP packet */
66 /* nx_udp_socket_receive Receive packet */
67 /* tx_thread_wait_abort Abort wait process */
68 /* tx_mutex_get Get protection mutex */
69 /* tx_mutex_put Put protection mutex */
70 /* [nx_secure_dtls_error_notify] Notify application of error */
71 /* [nx_secure_dtls_receive_notify] Notify application of packet */
72 /* receive */
73 /* */
74 /* CALLED BY */
75 /* */
76 /* Application Code */
77 /* */
78 /* RELEASE HISTORY */
79 /* */
80 /* DATE NAME DESCRIPTION */
81 /* */
82 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
83 /* 09-30-2020 Timothy Stapko Modified comment(s), */
84 /* released packet securely, */
85 /* resulting in version 6.1 */
86 /* */
87 /**************************************************************************/
_nx_secure_dtls_receive_callback(NX_UDP_SOCKET * socket_ptr)88 VOID _nx_secure_dtls_receive_callback(NX_UDP_SOCKET *socket_ptr)
89 {
90 #ifdef NX_SECURE_ENABLE_DTLS
91 TX_INTERRUPT_SAVE_AREA
92
93 NXD_ADDRESS ip_address;
94 UINT remote_port;
95 UINT local_port;
96 UINT status;
97 ULONG packet_type;
98 NX_PACKET *packet_ptr;
99 UCHAR *send_data;
100 NX_PACKET *temp_packet_ptr;
101 NX_SECURE_DTLS_SERVER *dtls_server;
102 NX_SECURE_DTLS_SESSION *dtls_session;
103
104 if(socket_ptr -> nx_udp_socket_receive_head == NX_NULL)
105 {
106 return;
107 }
108
109 /* Extract IP address and port from received packet. */
110 socket_ptr -> nx_udp_socket_receive_head -> nx_packet_prepend_ptr += sizeof(NX_UDP_HEADER);
111 status = _nxd_udp_source_extract(socket_ptr->nx_udp_socket_receive_head, &ip_address, &remote_port);
112 socket_ptr -> nx_udp_socket_receive_head -> nx_packet_prepend_ptr -= sizeof(NX_UDP_HEADER);
113
114 if(status != NX_SUCCESS)
115 {
116 return;
117 }
118
119 /* Extract local port from socket. */
120 status = _nx_udp_socket_port_get(socket_ptr, &local_port);
121
122 if(status != NX_SUCCESS)
123 {
124 return;
125 }
126
127 /* Get the DTLS server from our UDP socket so we can access the session cache. */
128 dtls_server = (NX_SECURE_DTLS_SERVER*)(socket_ptr -> nx_udp_socket_reserved_ptr);
129
130 /* Check session cache for existing DTLS session. */
131 status = nx_secure_dtls_session_cache_find(dtls_server, &dtls_session, &ip_address, remote_port, local_port);
132
133 /* Do we have an established session? */
134 if(status == NX_SECURE_DTLS_SESSION_NOT_FOUND)
135 {
136
137 /* If received packet is ALERT, just drop it. */
138 if ((socket_ptr -> nx_udp_socket_receive_head -> nx_packet_length < NX_SECURE_DTLS_RECORD_HEADER_SIZE) ||
139 (socket_ptr -> nx_udp_socket_receive_head -> nx_packet_prepend_ptr[8] == NX_SECURE_TLS_ALERT))
140 {
141
142 /* Lockout interrupts. */
143 TX_DISABLE
144
145 /* Remove the header packet from the queue. */
146 packet_ptr = socket_ptr -> nx_udp_socket_receive_head;
147 socket_ptr -> nx_udp_socket_receive_head = packet_ptr -> nx_packet_queue_next;
148 packet_ptr -> nx_packet_queue_next = NX_NULL;
149
150 /* If this was the last packet, set the tail pointer to NULL. */
151 if (socket_ptr -> nx_udp_socket_receive_head == NX_NULL)
152 {
153 socket_ptr -> nx_udp_socket_receive_tail = NX_NULL;
154 }
155
156 /* Decrease the queued packet count. */
157 socket_ptr -> nx_udp_socket_receive_count--;
158
159 /* Restore interrupts. */
160 TX_RESTORE
161
162 /* Release the packet. */
163 nx_secure_tls_packet_release(packet_ptr);
164
165 return;
166 }
167
168 /* Get a new session. */
169 status = nx_secure_dtls_session_cache_get_new(dtls_server, &dtls_session, &ip_address, remote_port, local_port);
170
171 /* Make sure we got a session. */
172 if(status == NX_SECURE_TLS_NO_FREE_DTLS_SESSIONS)
173 {
174 /* No session? Drop the connection with an internal error alert.
175 See RFC 5246 Sec. 7.2.2 - internal error is used for memory allocation failures.
176
177 We don't have a DTLS session, so build a simple DTLS alert record to send. */
178
179 /* Lockout interrupts. */
180 TX_DISABLE
181
182 /* Remove the header packet from the queue. */
183 packet_ptr = socket_ptr -> nx_udp_socket_receive_head;
184 socket_ptr -> nx_udp_socket_receive_head = packet_ptr -> nx_packet_queue_next;
185 packet_ptr -> nx_packet_queue_next = NX_NULL;
186
187 /* If this was the last packet, set the tail pointer to NULL. */
188 if (socket_ptr -> nx_udp_socket_receive_head == NX_NULL)
189 {
190 socket_ptr -> nx_udp_socket_receive_tail = NX_NULL;
191 }
192
193 /* Decrease the queued packet count. */
194 socket_ptr -> nx_udp_socket_receive_count--;
195
196 /* Restore interrupts. */
197 TX_RESTORE
198
199 /* Release the packet. */
200 nx_secure_tls_packet_release(packet_ptr);
201
202 /* Get a packet to send the alert to the client. */
203 if (ip_address.nxd_ip_version == NX_IP_VERSION_V4)
204 {
205 packet_type = NX_IPv4_UDP_PACKET;
206 }
207 else
208 {
209 packet_type = NX_IPv6_UDP_PACKET;
210 }
211
212 status = nx_packet_allocate(socket_ptr->nx_udp_socket_ip_ptr->nx_ip_default_packet_pool,
213 &packet_ptr, packet_type, NX_NO_WAIT);
214 if(status != NX_SUCCESS)
215 {
216 return;
217 }
218
219 if (((ULONG)(packet_ptr -> nx_packet_data_end) - (ULONG)(packet_ptr -> nx_packet_append_ptr)) < 15)
220 {
221
222 /* Packet buffer too small. */
223 nx_secure_tls_packet_release(packet_ptr);
224 return;
225 }
226
227 send_data = packet_ptr -> nx_packet_append_ptr;
228
229 /* Build the DTLS record header. */
230 send_data[0] = NX_SECURE_TLS_ALERT;
231
232 /* Set the version number - use DTLS 1.2. */
233 send_data[1] = (UCHAR)(NX_SECURE_DTLS_VERSION_MAJOR);
234 send_data[2] = (UCHAR)(NX_SECURE_DTLS_VERSION_MINOR_1_2);
235
236 /* DTLS Epoch counter. */
237 send_data[3] = 0;
238 send_data[4] = 0;
239
240 /* DTLS sequence number. */
241 send_data[5] = 0;
242 send_data[6] = 0;
243 send_data[7] = 0;
244 send_data[8] = 0;
245 send_data[9] = 0;
246 send_data[10] = 0;
247
248 /* DTLS message length - 2 bytes for the alert. */
249 send_data[11] = 0;
250 send_data[12] = 2;
251
252 /* Populate the record with the alert level and alert number to send to the remote host. */
253 send_data[13] = (UCHAR)(NX_SECURE_TLS_ALERT_LEVEL_FATAL);
254 send_data[14] = (UCHAR)(NX_SECURE_TLS_ALERT_INTERNAL_ERROR);
255
256 /* Make sure the caller has the right length of data to send. */
257 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr + 15;
258 packet_ptr -> nx_packet_length = 15;
259
260 /* Send the UDP packet containing our record. */
261 status = _nxd_udp_socket_send(socket_ptr, packet_ptr, &ip_address, remote_port);
262
263 /* Notify the application that we had to drop an incoming connection. */
264 if(dtls_server->nx_secure_dtls_error_notify != NX_NULL)
265 {
266 dtls_server->nx_secure_dtls_error_notify(NX_NULL, NX_SECURE_TLS_NO_FREE_DTLS_SESSIONS);
267 }
268
269 return;
270 }
271
272 /* Receive our packet. */
273 status = nx_udp_socket_receive(socket_ptr, &packet_ptr, NX_NO_WAIT);
274 if (status)
275 {
276 return;
277 }
278
279 /* New session, retrieve the UDP packet and place in our session receive queue. */
280 dtls_session -> nx_secure_dtls_receive_queue_head = packet_ptr;
281
282 /* Make sure the queue pointer is cleared. */
283 packet_ptr -> nx_packet_queue_next = NX_NULL;
284
285 /* Notify the application of a new connection - it is up to the application to call
286 nx_secure_dtls_session_start to kick off the handshake! */
287 dtls_server -> nx_secure_dtls_connect_notify(dtls_session, &ip_address, remote_port);
288 }
289 else
290 {
291
292 /* Receive our packet. */
293 status = nx_udp_socket_receive(socket_ptr, &packet_ptr, NX_NO_WAIT);
294 if (status)
295 {
296 return;
297 }
298
299 /* Get the protection before modifying the queue pointer. */
300 tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER);
301
302 if (!dtls_session -> nx_secure_dtls_session_in_use)
303 {
304
305 /* Session is not in use. */
306 tx_mutex_put(&_nx_secure_tls_protection);
307 return;
308 }
309
310 /* Established session, make sure that we append to the end of the receive queue. */
311 if (dtls_session -> nx_secure_dtls_receive_queue_head == NX_NULL)
312 {
313 dtls_session -> nx_secure_dtls_receive_queue_head = packet_ptr;
314 }
315 else
316 {
317 temp_packet_ptr = dtls_session -> nx_secure_dtls_receive_queue_head;
318 while(temp_packet_ptr -> nx_packet_queue_next != NX_NULL)
319 {
320 temp_packet_ptr = temp_packet_ptr -> nx_packet_queue_next;
321 }
322
323 temp_packet_ptr -> nx_packet_queue_next = packet_ptr;
324 }
325
326 /* Make sure the queue pointer is cleared. */
327 packet_ptr -> nx_packet_queue_next = NX_NULL;
328
329 /* Is there any thread waiting for packet? */
330 if (dtls_session -> nx_secure_dtls_thread_suspended)
331 {
332 /* Yes. Just abort it. */
333 tx_thread_wait_abort(dtls_session -> nx_secure_dtls_thread_suspended);
334 dtls_session -> nx_secure_dtls_thread_suspended = NX_NULL;
335 }
336
337 /* If the handshake isn't finished, don't notify application. */
338 if (dtls_session -> nx_secure_dtls_tls_session.nx_secure_tls_server_state < NX_SECURE_TLS_SERVER_STATE_HANDSHAKE_FINISHED)
339 {
340
341 /* Release the protection. */
342 tx_mutex_put(&_nx_secure_tls_protection);
343 return;
344 }
345
346 /* Release the protection. */
347 tx_mutex_put(&_nx_secure_tls_protection);
348
349 /* Invoke the session callback to notify application of packet receive. */
350 dtls_server -> nx_secure_dtls_receive_notify(dtls_session);
351 }
352 #else
353 NX_PARAMETER_NOT_USED(socket_ptr);
354
355 return;
356 #endif /* NX_SECURE_ENABLE_DTLS */
357 }
358
359