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
26 #include "nx_secure_tls.h"
27
28 #ifndef NX_SECURE_DISABLE_X509
29 static UCHAR _nx_secure_client_padded_pre_master[600];
30 #endif
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _nx_secure_generate_client_key_exchange PORTABLE C */
37 /* 6.2.1 */
38 /* AUTHOR */
39 /* */
40 /* Yanwu Cai, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function encrypts the Pre-Master Secret (generated earlier) */
45 /* and populates the buffer with the complete ClientKeyExchange */
46 /* message (to be sent by the caller). It also will send ephemeral */
47 /* keys for ciphersuites that require them. */
48 /* */
49 /* INPUT */
50 /* */
51 /* ciphersuite Selected cipher suite */
52 /* tls_key_material TLS key material */
53 /* tls_credentials TLS credentials */
54 /* data_buffer Pointer to output buffer */
55 /* buffer_length Length of data buffer */
56 /* output_size Size of data written to buffer*/
57 /* public_cipher_metadata Metadata for public cipher */
58 /* public_cipher_metadata_size Size of public cipher metadata*/
59 /* public_auth_metadata Metadata for public auth */
60 /* public_auth_metadata_size Size of public auth metadata */
61 /* */
62 /* OUTPUT */
63 /* */
64 /* status Completion status */
65 /* */
66 /* CALLS */
67 /* */
68 /* _nx_secure_x509_remote_endpoint_certificate_get */
69 /* Get cert for remote host */
70 /* [nx_crypto_operation] Public-key ciphers */
71 /* [nx_crypto_init] Initialize Crypto Method */
72 /* */
73 /* CALLED BY */
74 /* */
75 /* _nx_secure_tls_send_client_key_exchange */
76 /* Send ClientKeyExchange */
77 /* */
78 /* RELEASE HISTORY */
79 /* */
80 /* DATE NAME DESCRIPTION */
81 /* */
82 /* 10-31-2022 Yanwu Cai Initial Version 6.2.0 */
83 /* 03-08-2023 Yanwu Cai Modified comment(s), */
84 /* fixed compiler errors when */
85 /* x509 is disabled, */
86 /* resulting in version 6.2.1 */
87 /* */
88 /**************************************************************************/
_nx_secure_generate_client_key_exchange(const NX_SECURE_TLS_CIPHERSUITE_INFO * ciphersuite,NX_SECURE_TLS_KEY_MATERIAL * tls_key_material,NX_SECURE_TLS_CREDENTIALS * tls_credentials,UCHAR * data_buffer,ULONG buffer_length,ULONG * output_size,VOID * public_cipher_metadata,ULONG public_cipher_metadata_size,VOID * public_auth_metadata,ULONG public_auth_metadata_size)89 UINT _nx_secure_generate_client_key_exchange(const NX_SECURE_TLS_CIPHERSUITE_INFO *ciphersuite,
90 NX_SECURE_TLS_KEY_MATERIAL *tls_key_material, NX_SECURE_TLS_CREDENTIALS *tls_credentials,
91 UCHAR *data_buffer, ULONG buffer_length, ULONG *output_size,
92 VOID *public_cipher_metadata, ULONG public_cipher_metadata_size,
93 VOID *public_auth_metadata, ULONG public_auth_metadata_size)
94 {
95 #if defined(NX_SECURE_ENABLE_ECJPAKE_CIPHERSUITE) || !defined(NX_SECURE_DISABLE_X509)
96 UINT status;
97 const NX_CRYPTO_METHOD *public_cipher_method;
98 VOID *handler = NX_NULL;
99 #endif
100 UINT data_size;
101 UCHAR *encrypted_data_ptr;
102 #ifndef NX_SECURE_DISABLE_X509
103 UCHAR rand_byte;
104 UINT i;
105 NX_SECURE_X509_CERT *remote_certificate;
106 #endif
107 #ifdef NX_SECURE_ENABLE_ECJPAKE_CIPHERSUITE
108 NX_CRYPTO_EXTENDED_OUTPUT extended_output;
109 #endif /* NX_SECURE_ENABLE_ECJPAKE_CIPHERSUITE */
110
111 /* Send a ClientKeyExchange message.
112 * Structure:
113 * | 2 | <Length> |
114 * | Length | Encrypted Pre-Master Secret |
115 *
116 * ECDHE ephemeral key structure:
117 * | 2 | <Length> |
118 * | Length | EC Diffie-Hellman Client Params |
119 */
120
121 #ifndef NX_SECURE_ENABLE_ECJPAKE_CIPHERSUITE
122 NX_PARAMETER_NOT_USED(public_auth_metadata);
123 NX_PARAMETER_NOT_USED(public_auth_metadata_size);
124 #endif
125 #ifdef NX_SECURE_DISABLE_X509
126 NX_PARAMETER_NOT_USED(tls_key_material);
127 NX_PARAMETER_NOT_USED(public_cipher_metadata);
128 NX_PARAMETER_NOT_USED(public_cipher_metadata_size);
129 #endif
130
131 #ifdef NX_SECURE_ENABLE_ECC_CIPHERSUITE
132 if (ciphersuite -> nx_secure_tls_public_cipher -> nx_crypto_algorithm == NX_CRYPTO_KEY_EXCHANGE_ECDH ||
133 ciphersuite -> nx_secure_tls_public_cipher -> nx_crypto_algorithm == NX_CRYPTO_KEY_EXCHANGE_ECDHE)
134 {
135 data_size = (UINT)(1 + tls_key_material -> nx_secure_tls_new_key_material_data[0]);
136
137 if ((data_size > sizeof(tls_key_material -> nx_secure_tls_new_key_material_data)) ||
138 (data_size > buffer_length))
139 {
140
141 /* Packet buffer too small. */
142 return(NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL);
143 }
144
145 NX_SECURE_MEMCPY(data_buffer, tls_key_material -> nx_secure_tls_new_key_material_data, data_size); /* Use case of memcpy is verified. */
146 }
147 else
148 #endif /* NX_SECURE_ENABLE_ECC_CIPHERSUITE */
149 {
150
151 /* Pointer to the output encrypted pre-master secret. */
152 encrypted_data_ptr = &data_buffer[2];
153
154 #ifdef NX_SECURE_ENABLE_PSK_CIPHERSUITES
155 /* Check for PSK ciphersuites. */
156 if (ciphersuite -> nx_secure_tls_public_auth -> nx_crypto_algorithm == NX_CRYPTO_KEY_EXCHANGE_PSK)
157 {
158 if ((tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id_hint_size >
159 sizeof(tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id_hint)) ||
160 (tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id_hint_size >
161 (buffer_length - 2)))
162 {
163
164 /* Packet buffer too small. */
165 return(NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL);
166 }
167
168 /* Send the PSK Identity string to the remote server along with its length. */
169 NX_SECURE_MEMCPY(encrypted_data_ptr, tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id,
170 tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id_size); /* Use case of memcpy is verified. */
171
172 /* Make sure our size is correct. */
173 data_size = tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id_size;
174
175 /* Put the length into our outgoing packet buffer. */
176 data_buffer[0] = (UCHAR)((data_size & 0xFF00) >> 8);
177 data_buffer[1] = (UCHAR)(data_size & 0x00FF);
178
179 data_size += 2;
180 }
181 else
182 #endif
183 #ifdef NX_SECURE_ENABLE_ECJPAKE_CIPHERSUITE
184 if (ciphersuite -> nx_secure_tls_public_auth -> nx_crypto_algorithm == NX_CRYPTO_KEY_EXCHANGE_ECJPAKE)
185 {
186 data_size = 0;
187 public_cipher_method = ciphersuite -> nx_secure_tls_public_auth;
188
189 extended_output.nx_crypto_extended_output_data = data_buffer;
190 extended_output.nx_crypto_extended_output_length_in_byte = buffer_length;
191 extended_output.nx_crypto_extended_output_actual_size = 0;
192 status = public_cipher_method -> nx_crypto_operation(NX_CRYPTO_ECJPAKE_CLIENT_KEY_EXCHANGE_GENERATE,
193 handler,
194 (NX_CRYPTO_METHOD*)public_cipher_method,
195 NX_NULL, 0,
196 NX_NULL, 0, NX_NULL,
197 (UCHAR *)&extended_output,
198 sizeof(extended_output),
199 public_auth_metadata,
200 public_auth_metadata_size,
201 NX_NULL, NX_NULL);
202 if (status)
203 {
204 return(status);
205 }
206
207 data_size += extended_output.nx_crypto_extended_output_actual_size;
208 }
209 else
210 #endif
211 {
212 #ifndef NX_SECURE_DISABLE_X509
213 /* Extract the data to be verified from the remote certificate processed earlier. */
214 status = _nx_secure_x509_remote_endpoint_certificate_get(&tls_credentials -> nx_secure_tls_certificate_store,
215 &remote_certificate);
216
217 if (status)
218 {
219
220 /* No certificate found, error! */
221 return(NX_SECURE_TLS_NO_CERT_SPACE_ALLOCATED);
222 }
223
224 /* Get the public cipher method from the ciphersuite. */
225 public_cipher_method = ciphersuite -> nx_secure_tls_public_cipher;
226
227 /* If using RSA, the length is equal to the key size. */
228 data_size = remote_certificate -> nx_secure_x509_public_key.rsa_public_key.nx_secure_rsa_public_modulus_length;
229
230 /* check data_size */
231 if ((data_size < NX_SECURE_TLS_RSA_PREMASTER_SIZE + 1) ||
232 (buffer_length < (2u + data_size)))
233 {
234
235 /* Invalid certificate modulus length. */
236 return(NX_SECURE_TLS_INVALID_CERTIFICATE);
237 }
238
239 /* PKCS#1 v1.5 padding. The scheme is to start with the block type (0x00, 0x02 for PKCS#1)
240 then pad with non-zero bytes (random is cryptographically more secure), followed with
241 a single 0 byte right before the payload, which comes at the end of the RSA block. */
242 NX_SECURE_MEMSET(_nx_secure_client_padded_pre_master, 0x0, sizeof(_nx_secure_client_padded_pre_master));
243 _nx_secure_client_padded_pre_master[1] = 0x2; /* Block type is 0x00, 0x02 */
244 for (i = 2; i < (data_size - NX_SECURE_TLS_RSA_PREMASTER_SIZE - 1); ++i)
245 {
246 /* PKCS#1 padding must be random, but CANNOT be 0. */
247 do
248 {
249 rand_byte = (UCHAR)NX_RAND();
250 } while (rand_byte == 0);
251 _nx_secure_client_padded_pre_master[i] = rand_byte;
252 }
253
254 /* Now put the pre-master data into the padded buffer - must be at the end. */
255 NX_SECURE_MEMCPY(&_nx_secure_client_padded_pre_master[data_size - NX_SECURE_TLS_RSA_PREMASTER_SIZE],
256 tls_key_material -> nx_secure_tls_pre_master_secret, NX_SECURE_TLS_RSA_PREMASTER_SIZE); /* Use case of memcpy is verified. */
257
258 if (public_cipher_method -> nx_crypto_init != NX_NULL)
259 {
260 /* Initialize the crypto method with public key. */
261 status = public_cipher_method -> nx_crypto_init((NX_CRYPTO_METHOD*)public_cipher_method,
262 (UCHAR *)remote_certificate -> nx_secure_x509_public_key.rsa_public_key.nx_secure_rsa_public_modulus,
263 (NX_CRYPTO_KEY_SIZE)(remote_certificate -> nx_secure_x509_public_key.rsa_public_key.nx_secure_rsa_public_modulus_length << 3),
264 &handler,
265 public_cipher_metadata,
266 public_cipher_metadata_size);
267
268 if(status != NX_CRYPTO_SUCCESS)
269 {
270 #ifdef NX_SECURE_KEY_CLEAR
271 NX_SECURE_MEMSET(_nx_secure_client_padded_pre_master, 0, sizeof(_nx_secure_client_padded_pre_master));
272 #endif /* NX_SECURE_KEY_CLEAR */
273
274 return(status);
275 }
276 }
277
278 if (public_cipher_method -> nx_crypto_operation != NX_NULL)
279 {
280 /* Now encrypt the pre-master secret using the public key provided by the remote host
281 and place the result in the outgoing packet buffer. */
282 status = public_cipher_method -> nx_crypto_operation(NX_CRYPTO_DECRYPT,
283 handler,
284 (NX_CRYPTO_METHOD*)public_cipher_method,
285 (UCHAR *)remote_certificate -> nx_secure_x509_public_key.rsa_public_key.nx_secure_rsa_public_exponent,
286 (NX_CRYPTO_KEY_SIZE)(remote_certificate -> nx_secure_x509_public_key.rsa_public_key.nx_secure_rsa_public_exponent_length << 3),
287 _nx_secure_client_padded_pre_master,
288 data_size,
289 NX_NULL,
290 encrypted_data_ptr,
291 data_size,
292 public_cipher_metadata,
293 public_cipher_metadata_size,
294 NX_NULL, NX_NULL);
295
296 if(status != NX_CRYPTO_SUCCESS)
297 {
298 #ifdef NX_SECURE_KEY_CLEAR
299 NX_SECURE_MEMSET(_nx_secure_client_padded_pre_master, 0, sizeof(_nx_secure_client_padded_pre_master));
300 #endif /* NX_SECURE_KEY_CLEAR */
301
302 return(status);
303 }
304 }
305
306 if (public_cipher_method -> nx_crypto_cleanup)
307 {
308 status = public_cipher_method -> nx_crypto_cleanup(public_cipher_metadata);
309
310 if(status != NX_CRYPTO_SUCCESS)
311 {
312 #ifdef NX_SECURE_KEY_CLEAR
313 NX_SECURE_MEMSET(_nx_secure_client_padded_pre_master, 0, sizeof(_nx_secure_client_padded_pre_master));
314 #endif /* NX_SECURE_KEY_CLEAR */
315
316 return(status);
317 }
318 }
319
320 /* Put the length into our outgoing packet buffer. */
321 data_buffer[0] = (UCHAR)((data_size & 0xFF00) >> 8);
322 data_buffer[1] = (UCHAR)(data_size & 0x00FF);
323
324 data_size += 2;
325 #else
326 return(NX_NOT_SUPPORTED);
327 #endif /* NX_SECURE_DISABLE_X509 */
328 }
329 }
330
331 /* Let the caller know how many bytes we wrote. +2 for the length we just added. */
332 *output_size = data_size;
333
334 #if defined(NX_SECURE_KEY_CLEAR) && !defined(NX_SECURE_DISABLE_X509)
335 NX_SECURE_MEMSET(_nx_secure_client_padded_pre_master, 0, sizeof(_nx_secure_client_padded_pre_master));
336 #endif /* NX_SECURE_KEY_CLEAR && !NX_SECURE_DISABLE_X509 */
337
338 return(NX_SECURE_TLS_SUCCESS);
339 }
340
341