1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** NetX Secure Component */
16 /** */
17 /** Datagram Transport Layer Security (DTLS) */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define NX_SECURE_SOURCE_CODE
23
24 #include "nx_secure_dtls.h"
25
26
27 #ifdef NX_SECURE_ENABLE_DTLS
28 /**************************************************************************/
29 /* */
30 /* FUNCTION RELEASE */
31 /* */
32 /* _nx_secure_dtls_process_header PORTABLE C */
33 /* 6.1.10 */
34 /* AUTHOR */
35 /* */
36 /* Timothy Stapko, Microsoft Corporation */
37 /* */
38 /* DESCRIPTION */
39 /* */
40 /* This function processes an NX_PACKET data structure, extracting */
41 /* and parsing a DTLS header received from a remote host. */
42 /* */
43 /* INPUT */
44 /* */
45 /* dtls_session Pointer to DTLS control block */
46 /* packet_ptr Pointer to incoming packet */
47 /* record_offset Offset of current record */
48 /* message_type Return message type value */
49 /* length Return message length value */
50 /* header_data Pointer to header to parse */
51 /* header_length Length of header data (bytes) */
52 /* */
53 /* OUTPUT */
54 /* */
55 /* status Completion status */
56 /* */
57 /* CALLS */
58 /* */
59 /* _nx_secure_tls_check_protocol_version Check incoming TLS version */
60 /* nx_packet_data_extract_offset Extract data from NX_PACKET */
61 /* */
62 /* CALLED BY */
63 /* */
64 /* _nx_secure_dtls_process_record Process DTLS record data */
65 /* */
66 /* RELEASE HISTORY */
67 /* */
68 /* DATE NAME DESCRIPTION */
69 /* */
70 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
71 /* 09-30-2020 Timothy Stapko Modified comment(s), */
72 /* verified memcpy use cases, */
73 /* resulting in version 6.1 */
74 /* 01-31-2022 Timothy Stapko Modified comment(s), */
75 /* fixed out-of-order handling,*/
76 /* resulting in version 6.1.10 */
77 /* */
78 /**************************************************************************/
_nx_secure_dtls_process_header(NX_SECURE_DTLS_SESSION * dtls_session,NX_PACKET * packet_ptr,ULONG record_offset,USHORT * message_type,UINT * length,UCHAR * header_data,USHORT * header_length)79 UINT _nx_secure_dtls_process_header(NX_SECURE_DTLS_SESSION *dtls_session, NX_PACKET *packet_ptr,
80 ULONG record_offset, USHORT *message_type, UINT *length,
81 UCHAR *header_data, USHORT *header_length)
82 {
83 ULONG bytes_copied;
84 UINT status;
85 USHORT protocol_version;
86 ULONG remaining_bytes = NX_SECURE_DTLS_RECORD_HEADER_SIZE;
87 ULONG remote_sequence_number[2];
88 USHORT remote_epoch;
89 NX_SECURE_TLS_SESSION *tls_session;
90
91
92 /* Obtain a reference to the internal TLS state for ease of use. */
93 tls_session = &dtls_session -> nx_secure_dtls_tls_session;
94
95 *header_length = NX_SECURE_DTLS_RECORD_HEADER_SIZE;
96
97 while (remaining_bytes)
98 {
99
100 /* Check the packet. */
101 if (packet_ptr == NX_NULL)
102 {
103
104 /* There was an error in extracting the header from the supplied packet. */
105 return(NX_SECURE_TLS_INVALID_PACKET);
106 }
107
108 /* Process the TLS record header, which will set the state. */
109 status = nx_packet_data_extract_offset(packet_ptr, record_offset, &header_data[NX_SECURE_DTLS_RECORD_HEADER_SIZE - remaining_bytes],
110 remaining_bytes, &bytes_copied);
111
112 /* Make sure we actually got a header. */
113 if (status != NX_SUCCESS)
114 {
115
116 /* There was an error in extracting the header from the supplied packet. */
117 return(NX_SECURE_TLS_INVALID_PACKET);
118 }
119
120 record_offset = 0;
121 remaining_bytes -= bytes_copied;
122
123 packet_ptr = packet_ptr -> nx_packet_queue_next;
124 }
125
126 /* Extract message type from packet/record. */
127 *message_type = header_data[0];
128
129 /* Extract the protocol version. */
130 protocol_version = (USHORT)(((USHORT)header_data[1] << 8) | header_data[2]);
131
132 /* Get the length of the DTLS data. */
133 *length = (UINT)(((UINT)header_data[11] << 8) + header_data[12]);
134
135 /* Epoch and sequence number handling.
136 * | 2 | 6 |
137 * | Epoch | Sequence number |
138 * --------------------------------
139 * | seq[0] | seq[1] |
140 * --------------------------------
141 * The epoch is at the beginning of the sequence number (first 2 bytes) for
142 * network byte ordering. This means that the epoch is in the bottom 2 bytes
143 * of the first ULONG of the sequence number. In DTLS, the sequence number
144 * is tied to the epoch - epoch and sequence start at 0, but when the epoch
145 * is advanced (when the ChangeCipherSpec message is sent), the sequence is
146 * reset to 0.
147 *
148 * To handle the message ordering properly, the epochs must match (the CCS
149 * message changes the epoch after being sent or received so new messages
150 * should all have the new epoch). When the epochs match, the sequence numbers
151 * can be compared. We have 2 cases to handle:
152 * 1) The incoming sequence number is less than or equal to the local count.
153 * - This is a retransmission of an earlier message and should be ignored (handshake)
154 * - If the earlier message was NOT seen, check the sliding window to accept/ignore
155 * 2) The incoming sequence is greater than the local count + 1
156 * - A message was dropped. We need to handle the out-of-order
157 * message.
158 * - During the handshake, accept this record as the next valid message
159 * - During the session, accept and update the sliding window.
160 */
161
162
163 /* Get epoch and sequence number from header. */
164 NX_SECURE_MEMCPY((UCHAR *)&remote_sequence_number[0], &header_data[3], 4); /* Use case of memcpy is verified. */
165 NX_SECURE_MEMCPY((UCHAR *)&remote_sequence_number[1], &header_data[7], 4); /* Use case of memcpy is verified. */
166
167 /* Swap endianness for comparisons. */
168 NX_CHANGE_ULONG_ENDIAN(remote_sequence_number[0]);
169 NX_CHANGE_ULONG_ENDIAN(remote_sequence_number[1]);
170 NX_CHANGE_ULONG_ENDIAN(tls_session -> nx_secure_tls_remote_sequence_number[0]);
171 NX_CHANGE_ULONG_ENDIAN(tls_session -> nx_secure_tls_remote_sequence_number[1]);
172
173 /* The remote epoch is the top 2 bytes of the incoming 8-byte sequence number. */
174 remote_epoch = (USHORT)(remote_sequence_number[0] >> 16);
175
176 /* Clear out epoch bytes in sequence number before comparing. */
177 remote_sequence_number[0] = (remote_sequence_number[0] & 0x0000FFFF);
178
179 /* If the epochs do not match, then ignore. */
180 if (remote_epoch != dtls_session -> nx_secure_dtls_remote_epoch)
181 {
182 NX_CHANGE_ULONG_ENDIAN(tls_session -> nx_secure_tls_remote_sequence_number[0]);
183 NX_CHANGE_ULONG_ENDIAN(tls_session -> nx_secure_tls_remote_sequence_number[1]);
184 return(NX_SECURE_TLS_INVALID_EPOCH);
185 }
186
187 /* Now check the sequence number against what we already received to see if it is a new message
188 or a retransmission from the remote host. */
189
190 /* Sliding window (RFC 6347, Section 4.1.2.6):
191 Duplicates are rejected through the use of a sliding receive window.
192 (How the window is implemented is a local matter, but the following
193 text describes the functionality that the implementation must
194 exhibit.) A minimum window size of 32 MUST be supported, but a
195 window size of 64 is preferred and SHOULD be employed as the default.
196 Another window size (larger than the minimum) MAY be chosen by the
197 receiver. (The receiver does not notify the sender of the window
198 size.)
199
200 The "right" edge of the window represents the highest validated
201 sequence number value received on this session. Records that contain
202 sequence numbers lower than the "left" edge of the window are
203 rejected. Packets falling within the window are checked against a
204 list of received packets within the window. An efficient means for
205 performing this check, based on the use of a bit mask, is described
206 in Section 3.4.3 of [ESP].
207
208 If the received record falls within the window and is new, or if the
209 packet is to the right of the window, then the receiver proceeds to
210 MAC verification. If the MAC validation fails, the receiver MUST
211 discard the received record as invalid. The receive window is
212 updated only if the MAC verification succeeds.
213 */
214
215 /* Handshake messages. No sliding window check. */
216 if (remote_epoch == 0 && (remote_sequence_number[0] > 0 || remote_sequence_number[1] > 0))
217 {
218 if (remote_sequence_number[0] < tls_session -> nx_secure_tls_remote_sequence_number[0] ||
219 remote_sequence_number[1] <= tls_session -> nx_secure_tls_remote_sequence_number[1])
220 {
221
222 NX_CHANGE_ULONG_ENDIAN(tls_session -> nx_secure_tls_remote_sequence_number[0]);
223 NX_CHANGE_ULONG_ENDIAN(tls_session -> nx_secure_tls_remote_sequence_number[1]);
224
225 return(NX_SECURE_TLS_REPEAT_MESSAGE_RECEIVED);
226 }
227
228 /* Update the current sequence number to match what we just received. */
229 tls_session -> nx_secure_tls_remote_sequence_number[0] = remote_sequence_number[0];
230 tls_session -> nx_secure_tls_remote_sequence_number[1] = remote_sequence_number[1];
231
232 /* The sequence number is larger than our current. This is a valid handshake record or
233 out-of-order newer application data record. Update the current sequence number after the MAC check. */
234 /* Swap back now that comparisons are done. */
235 NX_CHANGE_ULONG_ENDIAN(tls_session -> nx_secure_tls_remote_sequence_number[0]);
236 NX_CHANGE_ULONG_ENDIAN(tls_session -> nx_secure_tls_remote_sequence_number[1]);
237
238 }
239 else if (remote_epoch > 0 && (remote_sequence_number[0] > 0 || remote_sequence_number[1] > 0))
240 {
241 /* Changed our Epoch, so new sequence number */
242 if (remote_sequence_number[0] < tls_session -> nx_secure_tls_remote_sequence_number[0] ||
243 remote_sequence_number[1] <= tls_session -> nx_secure_tls_remote_sequence_number[1])
244 {
245 /* Incoming number is less than the "right" side of our sliding window. Check if
246 it falls in the sliding window (greater than the "left" side and not seen yet). */
247 status = _nx_secure_dtls_session_sliding_window_check(dtls_session, remote_sequence_number);
248
249 if(status == NX_FALSE)
250 {
251 NX_CHANGE_ULONG_ENDIAN(tls_session -> nx_secure_tls_remote_sequence_number[0]);
252 NX_CHANGE_ULONG_ENDIAN(tls_session -> nx_secure_tls_remote_sequence_number[1]);
253 return(NX_SECURE_TLS_REPEAT_MESSAGE_RECEIVED);
254 }
255 }
256
257 /* Update the sliding window with the new sequence number. This updates the sequence number as well. */
258 status = _nx_secure_dtls_session_sliding_window_update(dtls_session, remote_sequence_number);
259
260 NX_CHANGE_ULONG_ENDIAN(tls_session -> nx_secure_tls_remote_sequence_number[0]);
261 NX_CHANGE_ULONG_ENDIAN(tls_session -> nx_secure_tls_remote_sequence_number[1]);
262
263 if(status != NX_SUCCESS)
264 {
265 return(status);
266 }
267
268 }
269 else if (remote_epoch == 0)
270 {
271 /* Remote epoch of 0 with sequence number of 0 indicates start of new session. */
272 #ifndef NX_SECURE_TLS_CLIENT_DISABLED
273 if ((tls_session -> nx_secure_tls_socket_type == NX_SECURE_TLS_SESSION_TYPE_CLIENT) &&
274 (tls_session -> nx_secure_tls_client_state != NX_SECURE_TLS_CLIENT_STATE_IDLE))
275 {
276
277 /* Invalid sequence number. */
278 NX_CHANGE_ULONG_ENDIAN(tls_session -> nx_secure_tls_remote_sequence_number[0]);
279 NX_CHANGE_ULONG_ENDIAN(tls_session -> nx_secure_tls_remote_sequence_number[1]);
280 return(NX_SECURE_TLS_OUT_OF_ORDER_MESSAGE);
281 }
282 #endif /* NX_SECURE_TLS_CLIENT_DISABLED */
283
284 #ifndef NX_SECURE_TLS_SERVER_DISABLED
285 if ((tls_session -> nx_secure_tls_socket_type == NX_SECURE_TLS_SESSION_TYPE_SERVER) &&
286 (tls_session -> nx_secure_tls_server_state != NX_SECURE_TLS_SERVER_STATE_IDLE))
287 {
288
289 /* Invalid sequence number. */
290 NX_CHANGE_ULONG_ENDIAN(tls_session -> nx_secure_tls_remote_sequence_number[0]);
291 NX_CHANGE_ULONG_ENDIAN(tls_session -> nx_secure_tls_remote_sequence_number[1]);
292 return(NX_SECURE_TLS_OUT_OF_ORDER_MESSAGE);
293 }
294 #endif /* NX_SECURE_TLS_SERVER_DISABLED */
295 }
296
297 /* Check the protocol version, except when we haven't established a version yet */
298 if (tls_session -> nx_secure_tls_protocol_version != 0)
299 {
300 /* Check the record's protocol version against the current session. */
301 status = _nx_secure_tls_check_protocol_version(tls_session, protocol_version, NX_SECURE_DTLS);
302 }
303
304 return(status);
305 }
306 #endif /* NX_SECURE_ENABLE_DTLS */
307
308