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