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