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 #ifdef NX_SECURE_ENABLE_DTLS
28 #include "nx_packet.h"
29 #include "nx_udp.h"
30 
31 /**************************************************************************/
32 /*                                                                        */
33 /*  FUNCTION                                               RELEASE        */
34 /*                                                                        */
35 /*    _nx_secure_dtls_send_record                         PORTABLE C      */
36 /*                                                           6.1.12       */
37 /*  AUTHOR                                                                */
38 /*                                                                        */
39 /*    Timothy Stapko, Microsoft Corporation                               */
40 /*                                                                        */
41 /*  DESCRIPTION                                                           */
42 /*                                                                        */
43 /*    This function encapsulates the DTLS record layer send functionality */
44 /*    The incoming packet data is wrapped in a DTLS record, which includes*/
45 /*    a header and footer (for encrypted data). Also, all encryption of   */
46 /*    application data is handled here.                                   */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    dtls_session                          Pointer to DTLS session       */
51 /*    send_packet                           Packet data to send           */
52 /*    record_type                           DTLS record type              */
53 /*    wait_option                           Suspension option             */
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    status                                Record send status            */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    _nx_secure_dtls_hash_record           Generate hash of payload      */
62 /*    _nx_secure_tls_record_payload_encrypt Encrypt payload               */
63 /*    _nx_secure_tls_session_iv_size_get    Get IV size for this session  */
64 /*    _nxd_udp_socket_send                  Send UDP packet               */
65 /*    _nxd_udp_socket_source_send           Send UDP packet with specific */
66 /*                                            source address              */
67 /*    nx_secure_tls_packet_release          Release packet                */
68 /*    tx_mutex_get                          Get protection mutex          */
69 /*    tx_mutex_put                          Put protection mutex          */
70 /*                                                                        */
71 /*  CALLED BY                                                             */
72 /*                                                                        */
73 /*    _nx_secure_dtls_client_handshake      DTLS client state machine     */
74 /*    _nx_secure_dtls_send_handshake_record Send DTLS handshake record    */
75 /*    _nx_secure_dtls_server_handshake      DTLS server state machine     */
76 /*    _nx_secure_dtls_session_end           Actual DTLS session end call  */
77 /*    _nx_secure_dtls_session_receive       Receive DTLS data             */
78 /*    _nx_secure_dtls_session_send          Actual DTLS session send call */
79 /*                                                                        */
80 /*  RELEASE HISTORY                                                       */
81 /*                                                                        */
82 /*    DATE              NAME                      DESCRIPTION             */
83 /*                                                                        */
84 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
85 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
86 /*                                            verified memcpy use cases,  */
87 /*                                            released packet securely,   */
88 /*                                            resulting in version 6.1    */
89 /*  07-29-2022     Yuxin Zhou               Modified comment(s), and      */
90 /*                                            checked seq number overflow,*/
91 /*                                            resulting in version 6.1.12 */
92 /*                                                                        */
93 /**************************************************************************/
_nx_secure_dtls_send_record(NX_SECURE_DTLS_SESSION * dtls_session,NX_PACKET * send_packet,UCHAR record_type,ULONG wait_option)94 UINT _nx_secure_dtls_send_record(NX_SECURE_DTLS_SESSION *dtls_session, NX_PACKET *send_packet,
95                                  UCHAR record_type, ULONG wait_option)
96 {
97 UINT                   status;
98 UINT                   message_length;
99 UCHAR                 *mac_secret;
100 UCHAR                 *record_header;
101 UCHAR                  record_hash[NX_SECURE_TLS_MAX_HASH_SIZE];
102 UINT                   hash_length;
103 ULONG                  length;
104 USHORT                 iv_size;
105 UCHAR                 *data;
106 NX_SECURE_TLS_SESSION *tls_session;
107 UCHAR                  epoch_seq_num[8];
108 
109     NX_PARAMETER_NOT_USED(wait_option);
110 
111     /* Pointer to the actual packet data for hashing and encryption. */
112     data = send_packet -> nx_packet_prepend_ptr;
113 
114     /* Length of the data in the packet. */
115     length = send_packet -> nx_packet_length;
116 
117     /* Get a pointer to TLS state. */
118     tls_session = &dtls_session -> nx_secure_dtls_tls_session;
119 
120     /* See if this is an active session, we need to account for the IV if the session cipher
121        uses one. */
122     if (tls_session -> nx_secure_tls_local_session_active)
123     {
124 
125         /* Get the size of the IV used by the session cipher. */
126         status = _nx_secure_tls_session_iv_size_get(tls_session, &iv_size);
127 
128         if (status != NX_SUCCESS)
129         {
130             return(status);
131         }
132 
133         /* Back off the pointer to the point before the IV data allocation
134            (can be 0). Increases length since we are moving the prepend pointer. */
135         send_packet -> nx_packet_prepend_ptr -= iv_size;
136         send_packet -> nx_packet_length += iv_size;
137     }
138 
139     /* Get a pointer to our record header. */
140     record_header = send_packet -> nx_packet_prepend_ptr - NX_SECURE_DTLS_RECORD_HEADER_SIZE;
141 
142     /* Build the TLS record header. */
143     record_header[0] = record_type;
144 
145     /* Set the version number. */
146     record_header[1] = (UCHAR)((tls_session -> nx_secure_tls_protocol_version & 0xFF00) >> 8);
147     record_header[2] = (UCHAR)(tls_session -> nx_secure_tls_protocol_version & 0x00FF);
148 
149     /* DTLS Epoch counter. */
150     record_header[3] = (UCHAR)(dtls_session -> nx_secure_dtls_local_epoch >> 8);
151     record_header[4] = (UCHAR)(dtls_session -> nx_secure_dtls_local_epoch);
152 
153     /* DTLS sequence number. */
154     record_header[5]  = (UCHAR)(tls_session -> nx_secure_tls_local_sequence_number[1] >> 8);
155     record_header[6]  = (UCHAR)(tls_session -> nx_secure_tls_local_sequence_number[1]);
156     record_header[7]  = (UCHAR)(tls_session -> nx_secure_tls_local_sequence_number[0] >> 24);
157     record_header[8]  = (UCHAR)(tls_session -> nx_secure_tls_local_sequence_number[0] >> 16);
158     record_header[9]  = (UCHAR)(tls_session -> nx_secure_tls_local_sequence_number[0] >> 8);
159     record_header[10] = (UCHAR)(tls_session -> nx_secure_tls_local_sequence_number[0]);
160 
161     epoch_seq_num[0] = record_header[10];
162     epoch_seq_num[1] = record_header[9];
163     epoch_seq_num[2] = record_header[8];
164     epoch_seq_num[3] = record_header[7];
165     epoch_seq_num[4] = record_header[6];
166     epoch_seq_num[5] = record_header[5];
167     epoch_seq_num[6] = record_header[4];
168     epoch_seq_num[7] = record_header[3];
169 
170     /* Increment the sequence number. */
171     if ((tls_session -> nx_secure_tls_local_sequence_number[0] + 1) == 0)
172     {
173         /* Check for overflow of the 32-bit number. */
174         tls_session -> nx_secure_tls_local_sequence_number[1]++;
175 
176         if (tls_session -> nx_secure_tls_local_sequence_number[1] == 0)
177         {
178 
179             /* Check for overflow of the 64-bit unsigned number. As it should not reach here
180                in practical, we return a general error to prevent overflow theoretically. */
181             return(NX_NOT_SUCCESSFUL);
182         }
183     }
184     tls_session -> nx_secure_tls_local_sequence_number[0]++;
185 
186     /* DTLS message length. */
187     message_length = length;
188     record_header[11] = (UCHAR)((message_length & 0xFF00) >> 8);
189     record_header[12] = (UCHAR)(message_length & 0x00FF);
190 
191     /* If the session is active, hash and encrypt the record payload using
192        the session keys and chosen ciphersuite. */
193     if (tls_session -> nx_secure_tls_local_session_active)
194     {
195         /* Select our proper MAC secret for hashing. */
196         if (tls_session -> nx_secure_tls_socket_type == NX_SECURE_TLS_SESSION_TYPE_SERVER)
197         {
198             /* If we are a server, we need to use the client's MAC secret. */
199             mac_secret = tls_session -> nx_secure_tls_key_material.nx_secure_tls_server_write_mac_secret;
200         }
201         else
202         {
203             /* We are a client, so use the server's MAC secret. */
204             mac_secret = tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_write_mac_secret;
205         }
206 
207         if (send_packet -> nx_packet_next)
208         {
209 
210             /* Chained packet is not supported. */
211             return(NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL);
212         }
213 
214         /* Generate the hash on the plaintext data. */
215         _nx_secure_dtls_hash_record(dtls_session, tls_session -> nx_secure_tls_local_sequence_number, record_header,
216                                     NX_SECURE_DTLS_RECORD_HEADER_SIZE, data, length, record_hash, &hash_length, mac_secret);
217 
218         if ((hash_length > ((ULONG)(send_packet -> nx_packet_data_end) - (ULONG)(&data[length]))) ||
219             (hash_length > sizeof(record_hash)))
220         {
221 
222             /* Packet buffer is too small. */
223             return(NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL);
224         }
225 
226         /* Append the hash to the plaintext data before encryption. */
227         NX_SECURE_MEMCPY(&data[length], record_hash, hash_length); /* Use case of memcpy is verified. */
228 
229 #ifdef NX_SECURE_KEY_CLEAR
230         NX_SECURE_MEMSET(record_hash, 0, hash_length);
231 #endif /* NX_SECURE_KEY_CLEAR  */
232 
233         send_packet -> nx_packet_append_ptr = send_packet -> nx_packet_append_ptr + hash_length;
234         send_packet -> nx_packet_length = send_packet -> nx_packet_length + hash_length;
235 
236         /* Finally, encrypt the entire record including the hash. Note that the length
237          * can be changed by the encryption as IVs and padding may be added. */
238         _nx_secure_tls_record_payload_encrypt(tls_session, send_packet, (ULONG *)epoch_seq_num, record_type);
239     }
240 
241     /* The encryption above may have changed the payload length, so get the length from
242        the packet and use it to update the record header. */
243     message_length = send_packet -> nx_packet_length;
244 
245     /* Set the length of the record following encryption. */
246     record_header[11] = (UCHAR)((message_length & 0xFF00) >> 8);
247     record_header[12] = (UCHAR)(message_length & 0x00FF);
248 
249     /* Back off the prepend_ptr for TLS Record header. Note the packet_length field is adjusted
250        prior to nx_tcp_socket_send() */
251     send_packet -> nx_packet_prepend_ptr -= NX_SECURE_DTLS_RECORD_HEADER_SIZE;
252 
253     /* Adjust packet length */
254     send_packet -> nx_packet_length += NX_SECURE_DTLS_RECORD_HEADER_SIZE;
255 
256     /* DTLS handshake re-transmit handling. */
257     if ((record_type == NX_SECURE_TLS_HANDSHAKE) ||
258         (record_type == NX_SECURE_TLS_CHANGE_CIPHER_SPEC))
259     {
260         /* See if the list already has entries. */
261         if (dtls_session -> nx_secure_dtls_transmit_sent_head)
262         {
263             /* Other packets are on the list already, add this one to the tail.  */
264             (dtls_session -> nx_secure_dtls_transmit_sent_tail) -> nx_packet_union_next.nx_packet_tcp_queue_next =  send_packet;
265             dtls_session -> nx_secure_dtls_transmit_sent_tail =  send_packet;
266         }
267         else
268         {
269             /* Empty list, just setup the head and tail to the current packet.  */
270             dtls_session -> nx_secure_dtls_transmit_sent_head =  send_packet;
271             dtls_session -> nx_secure_dtls_transmit_sent_tail =  send_packet;
272 
273             /* Setup a timeout for the packet at the head of the list.  */
274             dtls_session -> nx_secure_dtls_handshake_timeout =  NX_SECURE_DTLS_RETRANSMIT_TIMEOUT;
275             dtls_session -> nx_secure_dtls_timeout_retries =  0;
276         }
277 
278         /* Increase the count of packets in the transmit queue. */
279         dtls_session -> nx_secure_dtls_transmit_sent_count++;
280 
281         /* Mark the packet as in the transmit queue so it isn't released by the send. */
282         send_packet -> nx_packet_union_next.nx_packet_tcp_queue_next =  (NX_PACKET *)NX_PACKET_ENQUEUED;
283     }
284 
285     /* Release the protection before suspending on nx_tcp_socket_send. */
286     tx_mutex_put(&_nx_secure_tls_protection);
287 
288     /* If local IP address index is set, call _nxd_udp_socket_source_send
289        to ensure the source IP address is correct.  */
290     if (dtls_session -> nx_secure_dtls_local_ip_address_index == 0xffffffff)
291     {
292 
293         /* Send the UDP packet(s) containing our record. */
294         status = _nxd_udp_socket_send(dtls_session -> nx_secure_dtls_udp_socket, send_packet,
295                                       &dtls_session -> nx_secure_dtls_remote_ip_address,
296                                       dtls_session -> nx_secure_dtls_remote_port);
297     }
298     else
299     {
300 
301         /* Send the UDP packet(s) containing our record. */
302         status = _nxd_udp_socket_source_send(dtls_session -> nx_secure_dtls_udp_socket, send_packet,
303                                              &dtls_session -> nx_secure_dtls_remote_ip_address,
304                                              dtls_session -> nx_secure_dtls_remote_port,
305                                              dtls_session -> nx_secure_dtls_local_ip_address_index);
306     }
307 
308     /* Get the protection after nx_tcp_socket_send. */
309     tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER);
310 
311     if (status != NX_SUCCESS)
312     {
313         nx_secure_tls_packet_release(send_packet);
314         return(NX_SECURE_TLS_TCP_SEND_FAILED);
315     }
316 
317     return(NX_SECURE_TLS_SUCCESS);
318 }
319 #endif /* NX_SECURE_ENABLE_DTLS */
320 
321