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