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