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