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 /**    Transport Layer Security (TLS)                                     */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 #define NX_SECURE_SOURCE_CODE
23 
24 #include "nx_secure_tls.h"
25 
26 
27 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
28 UINT _nx_secure_tls_send_clienthello_psk_extension(NX_SECURE_TLS_SESSION *tls_session,
29                                                    UCHAR *packet_buffer, ULONG *packet_offset,
30                                                    ULONG extension_length_offset, ULONG total_extensions_length,
31                                                    ULONG *extension_length, ULONG available_size);
32 #endif
33 
34 #ifndef NX_SECURE_TLS_CLIENT_DISABLED
35 /**************************************************************************/
36 /*                                                                        */
37 /*  FUNCTION                                               RELEASE        */
38 /*                                                                        */
39 /*    _nx_secure_tls_send_clienthello                     PORTABLE C      */
40 /*                                                           6.2.1        */
41 /*  AUTHOR                                                                */
42 /*                                                                        */
43 /*    Timothy Stapko, Microsoft Corporation                               */
44 /*                                                                        */
45 /*  DESCRIPTION                                                           */
46 /*                                                                        */
47 /*    This function populates an NX_PACKET with a ClientHello message,    */
48 /*    which kicks off a TLS handshake when sent to a remote TLS server.   */
49 /*                                                                        */
50 /*  INPUT                                                                 */
51 /*                                                                        */
52 /*    tls_session                           TLS control block             */
53 /*    send_packet                           Outgoing TLS packet           */
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    status                                Completion status             */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    _nx_secure_tls_handshake_hash_init    Initialize the finished hash  */
62 /*    _nx_secure_tls_newest_supported_version                             */
63 /*                                          Get the version of TLS to use */
64 /*    _nx_secure_tls_send_clienthello_extensions                          */
65 /*                                          Send TLS ClientHello extension*/
66 /*    [nx_secure_tls_session_time_function] Get the current time for the  */
67 /*                                            TLS timestamp               */
68 /*                                                                        */
69 /*  CALLED BY                                                             */
70 /*                                                                        */
71 /*    _nx_secure_tls_client_handshake       TLS client state machine      */
72 /*    _nx_secure_tls_session_renegotiate    Renegotiate TLS session       */
73 /*    _nx_secure_tls_session_start          Start TLS session             */
74 /*                                                                        */
75 /*  RELEASE HISTORY                                                       */
76 /*                                                                        */
77 /*    DATE              NAME                      DESCRIPTION             */
78 /*                                                                        */
79 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
80 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
81 /*                                            verified memcpy use cases,  */
82 /*                                            resulting in version 6.1    */
83 /*  04-25-2022     Zhen Kong                Modified comment(s), removed  */
84 /*                                            the code to copy session id,*/
85 /*                                            resulting in version 6.1.11 */
86 /*  03-08-2023     Yanwu Cai                Modified comment(s),          */
87 /*                                            fixed compile errors,       */
88 /*                                            resulting in version 6.2.1  */
89 /*                                                                        */
90 /**************************************************************************/
_nx_secure_tls_send_clienthello(NX_SECURE_TLS_SESSION * tls_session,NX_PACKET * send_packet)91 UINT _nx_secure_tls_send_clienthello(NX_SECURE_TLS_SESSION *tls_session, NX_PACKET *send_packet)
92 {
93 ULONG                       length;
94 ULONG                       extension_offset;
95 UINT                        gmt_time;
96 UINT                        random_value;
97 UINT                        i;
98 USHORT                      ciphersuite;
99 USHORT                      ciphersuites_length;
100 UCHAR                      *ciphersuites_length_ptr;
101 UCHAR                      *packet_buffer;
102 USHORT                      protocol_version;
103 USHORT                      newest_version;
104 UINT                        status;
105 UINT                        fallback_enabled = NX_FALSE;
106 const NX_SECURE_TLS_CRYPTO *crypto_table;
107 ULONG                      extension_length, total_extensions_length;
108 
109 
110     /* ClientHello structure:
111      * |     2       |          4 + 28          |    1       |   <SID len>  |   2    | <CS Len>     |    1    | <Comp Len>  |    2    | <Ext. Len> |
112      * | TLS version |  Random (time + random)  | SID length |  Session ID  | CS Len | Ciphersuites |Comp Len | Compression |Ext. Len | Extensions |
113      */
114 
115     packet_buffer = send_packet -> nx_packet_append_ptr;
116 
117     /* Initialize the handshake hashes used for the Finished message. */
118 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
119     if(!tls_session->nx_secure_tls_1_3)
120 #endif
121     {
122         _nx_secure_tls_handshake_hash_init(tls_session);
123     }
124 
125     /* Use our length as an index into the buffer. */
126     length = 0;
127 
128     /* First two bytes of the hello following the header are the TLS major and minor version numbers. */
129     /* For TLS 1.2 is always enabled, there is no need to check returned protocol_version. */
130     _nx_secure_tls_protocol_version_get(tls_session, &protocol_version, NX_SECURE_TLS);
131 
132     /* Get the newest supported version to see if we have a version fallback. */
133     _nx_secure_tls_newest_supported_version(tls_session, &newest_version, NX_SECURE_TLS);
134     if(protocol_version != newest_version)
135     {
136         /* The version we are using is not the latest, indicate fallback with SCSV. */
137         fallback_enabled = NX_TRUE;
138     }
139 
140     /* Length of the ciphersuites list that follows. The client can send any number of suites for the
141      * server to choose from, with a 2-byte length field. */
142     crypto_table = tls_session -> nx_secure_tls_crypto_table;
143 
144     ciphersuites_length = (USHORT)((crypto_table -> nx_secure_tls_ciphersuite_lookup_table_size << 1));
145 
146 #ifdef NX_SECURE_TLS_USE_SCSV_CIPHPERSUITE
147     /* If this is an initial handshake (and not a response to a HelloRequest for session re-negotiation)
148        then include the length of the SCSV pseudo-ciphersuite (if enabled). */
149 #ifndef NX_SECURE_TLS_DISABLE_SECURE_RENEGOTIATION
150     if (!tls_session -> nx_secure_tls_renegotiation_handshake && tls_session -> nx_secure_tls_client_state != NX_SECURE_TLS_CLIENT_STATE_RENEGOTIATING)
151 #endif
152     {
153         ciphersuites_length = (USHORT)(ciphersuites_length + 2);
154     }
155 #endif
156 
157     /* If we are falling back to an earlier TLS version, include the fallback notification SCSV. */
158     if(fallback_enabled)
159     {
160         ciphersuites_length = (USHORT)(ciphersuites_length + 2);
161     }
162 
163     if (((ULONG)(send_packet -> nx_packet_data_end) - (ULONG)(send_packet -> nx_packet_append_ptr)) <
164         (9u + sizeof(tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_random) +
165          tls_session -> nx_secure_tls_session_id_length + ciphersuites_length))
166     {
167 
168         /* Packet buffer is too small. */
169         return(NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL);
170     }
171 
172     packet_buffer[length]     = (UCHAR)((protocol_version & 0xFF00) >> 8);
173     packet_buffer[length + 1] = (UCHAR)(protocol_version & 0x00FF);
174     tls_session -> nx_secure_tls_protocol_version = protocol_version;
175     length += 2;
176 
177     /* Set the Client random data, used in key generation. First 4 bytes is GMT time. */
178     gmt_time = 0;
179     if (tls_session -> nx_secure_tls_session_time_function != NX_NULL)
180     {
181         gmt_time = tls_session -> nx_secure_tls_session_time_function();
182     }
183     NX_CHANGE_ULONG_ENDIAN(gmt_time);
184     NX_SECURE_MEMCPY(tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_random, (UCHAR *)&gmt_time, sizeof(gmt_time)); /* Use case of memcpy is verified. lgtm[cpp/banned-api-usage-required-any] */
185 
186 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
187     if (tls_session -> nx_secure_tls_client_state == NX_SECURE_TLS_CLIENT_STATE_HELLO_RETRY)
188     {
189         NX_SECURE_MEMCPY(&packet_buffer[length], tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_random,
190                          sizeof(tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_random)); /* Use case of memcpy is verified. */
191     }
192     else
193 #endif
194     {
195 
196         /* Next 28 bytes is random data. */
197         for (i = 4; i <= 28; i += (UINT)sizeof(random_value))
198         {
199             random_value = (UINT)NX_RAND();
200             tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_random[i] =     (UCHAR)(random_value);
201             tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_random[i + 1] = (UCHAR)(random_value >> 8);
202             tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_random[i + 2] = (UCHAR)(random_value >> 16);
203             tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_random[i + 3] = (UCHAR)(random_value >> 24);
204         }
205 
206         /* Copy the random data into the packet. */
207         NX_SECURE_MEMCPY(&packet_buffer[length], tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_random, /* lgtm[cpp/banned-api-usage-required-any] */
208                          sizeof(tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_random)); /* Use case of memcpy is verified. */
209     }
210     length += sizeof(tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_random);
211 
212     /* Session ID length is one byte. As session resumption is not implemented yet, ClientHello doesn't include Session ID now. */
213     tls_session -> nx_secure_tls_session_id_length  = 0;
214     packet_buffer[length] = tls_session -> nx_secure_tls_session_id_length;
215     length++;
216 
217     /* TLS 1.0-1.2. */
218     ciphersuites_length_ptr = &packet_buffer[length];
219     length += 2;
220 
221     /* Our chosen ciphersuites. In sending a ClientHello, we need to include all the ciphersuites
222      * we are interested in speaking. This will be a list of ciphersuites the user has chosen to support
223      * and all of them will be presented to the remote server in this initial message. */
224 
225     ciphersuites_length = 0;
226     for (i = 0; i < crypto_table -> nx_secure_tls_ciphersuite_lookup_table_size; i++)
227     {
228 
229         ciphersuite = crypto_table -> nx_secure_tls_ciphersuite_lookup_table[i].nx_secure_tls_ciphersuite;
230 
231 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
232          if ((tls_session -> nx_secure_tls_1_3 == NX_FALSE) && ((ciphersuite >> 8) == 0x13))
233         {
234 
235             /* Ciphersuites for TLS 1.3 can not be used by TLS 1.2. */
236             continue;
237         }
238 #endif
239         packet_buffer[length] = (UCHAR)((ciphersuite & 0xFF00) >> 8);
240         packet_buffer[length + 1] = (UCHAR)(ciphersuite & 0x00FF);
241         length += 2;
242         ciphersuites_length = (USHORT)(ciphersuites_length + 2);
243     }
244 
245 #ifdef NX_SECURE_TLS_USE_SCSV_CIPHPERSUITE
246     /* Only send SCSV on initial ClientHello. The SCSV is used for compatibility with OLD TLS 1.0
247        and SSLv3.0 servers and generally shouldn't be needed. */
248 #ifndef NX_SECURE_TLS_DISABLE_SECURE_RENEGOTIATION
249     if (!tls_session -> nx_secure_tls_renegotiation_handshake && tls_session -> nx_secure_tls_client_state != NX_SECURE_TLS_CLIENT_STATE_RENEGOTIATING)
250 #endif
251     {
252         /* For the secure rengotiation indication extension, we need to send a
253            Signalling Ciphersuite Value (SCSV) as detailled in RFC5746. */
254         ciphersuite = TLS_EMPTY_RENEGOTIATION_INFO_SCSV;
255         packet_buffer[length] = (UCHAR)((ciphersuite & 0xFF00) >> 8);
256         packet_buffer[length + 1] = (UCHAR)(ciphersuite & 0x00FF);
257         length += 2;
258         ciphersuites_length = (USHORT)(ciphersuites_length + 2);
259     }
260 #endif
261 
262     /* If we are falling back to an earlier TLS version, include the fallback notification SCSV. */
263     if(fallback_enabled)
264     {
265         ciphersuite = TLS_FALLBACK_NOTIFY_SCSV;
266         packet_buffer[length] = (UCHAR)((ciphersuite & 0xFF00) >> 8);
267         packet_buffer[length + 1] = (UCHAR)(ciphersuite & 0x00FF);
268         length += 2;
269         ciphersuites_length = (USHORT)(ciphersuites_length + 2);
270     }
271 
272     ciphersuites_length_ptr[0] = (UCHAR)((ciphersuites_length & 0xFF00) >> 8);
273     ciphersuites_length_ptr[1] = (UCHAR)(ciphersuites_length & 0x00FF);
274 
275     /* Compression methods length - one byte. For now we only have the NULL method, for a length of 1. */
276     packet_buffer[length] = 0x1;
277     length++;
278 
279     /* Compression methods - for now this is NULL. */
280     packet_buffer[length] = 0x0;
281     length++;
282 
283     /* ============ TLS ClientHello extensions. ============= */
284 
285     /* Save an offset to the beginning of the extensions so we can fill in the length
286        once all the extensions are added. */
287     extension_offset = length;
288     total_extensions_length = 0;
289 
290     /* The extensions length field is two bytes. */
291     length += 2;
292 
293     status = _nx_secure_tls_send_clienthello_extensions(tls_session, packet_buffer, &length, &extension_length,
294                                                         ((ULONG)send_packet -> nx_packet_data_end -
295                                                          (ULONG)packet_buffer));
296 
297     if (status)
298     {
299         return(status);
300     }
301     total_extensions_length += extension_length;
302 
303     /* !!! NOTE !!! The TLS 1.3 PSK extension MUST be the LAST extension in the ClientHello! (RFC 8446, Section 4.2.11) */
304 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
305     /* Send TLS 1.3 PSK extension, but only if there is a PSK to send. */
306     if(tls_session->nx_secure_tls_1_3 && tls_session->nx_secure_tls_credentials.nx_secure_tls_psk_count > 0)
307     {
308         status = _nx_secure_tls_send_clienthello_psk_extension(tls_session, packet_buffer, &length,
309                                                                extension_offset, total_extensions_length,
310                                                                &extension_length,
311                                                                ((ULONG)send_packet -> nx_packet_data_end - (ULONG)packet_buffer));
312         if(status != NX_SUCCESS)
313         {
314             return(status);
315         }
316         total_extensions_length += extension_length;
317     }
318 #endif
319 
320     /* Put the extensions length into the packet at our original offset and add
321        the total to our packet length. */
322     packet_buffer[extension_offset] = (UCHAR)((total_extensions_length & 0xFF00) >> 8);
323     packet_buffer[extension_offset + 1] = (UCHAR)(total_extensions_length & 0x00FF);
324 
325 
326     /* Finally, we have a complete length and can put it into the buffer. Before that,
327        save off and return the number of bytes we wrote and need to send. */
328     send_packet -> nx_packet_append_ptr = send_packet -> nx_packet_append_ptr + length;
329     send_packet -> nx_packet_length = send_packet -> nx_packet_length + length;
330 
331     return(status);
332 }
333 #endif /* NX_SECURE_TLS_CLIENT_DISABLED */
334