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