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