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 #include "nx_secure_x509.h"
27 
28 /**************************************************************************/
29 /*                                                                        */
30 /*  FUNCTION                                               RELEASE        */
31 /*                                                                        */
32 /*    _nx_secure_tls_process_remote_certificate           PORTABLE C      */
33 /*                                                           6.2.1        */
34 /*  AUTHOR                                                                */
35 /*                                                                        */
36 /*    Timothy Stapko, Microsoft Corporation                               */
37 /*                                                                        */
38 /*  DESCRIPTION                                                           */
39 /*                                                                        */
40 /*    This function processes an incoming TLS server certificate message, */
41 /*    extracting the RSA or DH public key and verifying the validity of   */
42 /*    the certificate. It parses the X509 certificate and fills in the    */
43 /*    relevant information if the caller has allocated space for it using */
44 /*    nx_secure_remote_certificate_allocate.                              */
45 /*                                                                        */
46 /*  INPUT                                                                 */
47 /*                                                                        */
48 /*    tls_session                           TLS control block             */
49 /*    packet_buffer                         Pointer to message data       */
50 /*    message_length                        Length of message data (bytes)*/
51 /*    data_length                           Length of packet buffer       */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    status                                Completion status             */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    _nx_secure_tls_remote_certificate_verify                            */
60 /*                                          Verify the server certificate */
61 /*    _nx_secure_x509_certificate_list_add  Add incoming cert to store    */
62 /*    _nx_secure_x509_certificate_parse     Extract public key data       */
63 /*    _nx_secure_x509_free_certificate_get  Get free cert for storage     */
64 /*    tx_mutex_get                          Get protection mutex          */
65 /*    tx_mutex_put                          Put protection mutex          */
66 /*                                                                        */
67 /*  CALLED BY                                                             */
68 /*                                                                        */
69 /*    _nx_secure_dtls_client_handshake      DTLS client state machine     */
70 /*    _nx_secure_tls_client_handshake       TLS client state machine      */
71 /*    _nx_secure_tls_server_handshake       TLS server state machine      */
72 /*                                                                        */
73 /*  RELEASE HISTORY                                                       */
74 /*                                                                        */
75 /*    DATE              NAME                      DESCRIPTION             */
76 /*                                                                        */
77 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
78 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
79 /*                                            verified memcpy use cases,  */
80 /*                                            fixed certificate buffer    */
81 /*                                            allocation,                 */
82 /*                                            resulting in version 6.1    */
83 /*  04-02-2021     Timothy Stapko           Modified comment(s),          */
84 /*                                            updated X.509 return value, */
85 /*                                            resulting in version 6.1.6  */
86 /*  04-25-2022     Timothy Stapko           Modified comment(s),          */
87 /*                                            removed unnecessary code,   */
88 /*                                            resulting in version 6.1.11 */
89 /*  03-08-2023     Yanwu Cai                Modified comment(s),          */
90 /*                                            fixed compiler errors when  */
91 /*                                            x509 is disabled,           */
92 /*                                            initialized metadata for    */
93 /*                                            remote certificate,         */
94 /*                                            resulting in version 6.2.1  */
95 /*                                                                        */
96 /**************************************************************************/
_nx_secure_tls_process_remote_certificate(NX_SECURE_TLS_SESSION * tls_session,UCHAR * packet_buffer,UINT message_length,UINT data_length)97 UINT _nx_secure_tls_process_remote_certificate(NX_SECURE_TLS_SESSION *tls_session,
98                                                UCHAR *packet_buffer, UINT message_length,
99                                                UINT data_length)
100 {
101 #ifndef NX_SECURE_DISABLE_X509
102 UINT                 length;
103 UINT                 total_length;
104 UINT                 cert_length = 0;
105 UINT                 status;
106 NX_SECURE_X509_CERT *certificate;
107 UCHAR               *endpoint_raw_ptr;
108 UINT                 endpoint_length;
109 UINT                 bytes_processed;
110 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
111 UINT                 extensions_length;
112 #endif
113 UCHAR               *cert_buffer;
114 ULONG                cert_buf_size;
115 
116 
117     /* Structure:
118      * |      3       |                     <Total Length>                      |
119      * | Total length |       3        |   <Cert[0] Length> | 3 + <Cert[x] Len> |
120      * |              | Cert[0] Length |   Certificate[0]   |    More certs...  |
121      */
122 
123     /* TLS 1.3 Structure:
124      * |    1    | <Ctx Len> |      3       |                     <Total Length>                         |
125      * | Ctx Len | Context   | Total length |       3        |   <Cert[x] Length> |   2    |   <ExtLen>  |
126      * |                                    | Cert[x] Length |   Certificate[x]   | ExtLen |  Extensions |
127      */
128 
129 
130 
131     /* At this point, the packet buffer is filled with a TLS record. We can use the remainder of
132         the buffer to hold certificate structures for parsing. The remote certificates will
133         remain in the packet buffer and only the X.509 parsing structure (NX_SECURE_X509_CERT)
134         will be allocated. See _nx_secure_tls_process_remote_certificate for more info. */
135     /* Typical layout of packet buffer and certificate buffer. Cert buffer allocates top-down, X.509 parsing structures
136         are allocated and used only until the certificate chain verification step. After that, the remote certs are cleared
137         and then the endpoint certificate is copied into the cert buffer (only the endpoint) for later use. The packet buffer
138         following this function (on success) should have the following layout (assuming no user-allocated certs):
139         |                      Packet buffer                     |    Certificate buffer    |
140         |<-----------data------------------>|-->  free space  <--| Endpoint Cert 1 | X.509  |
141     */
142 
143     if (data_length > tls_session -> nx_secure_tls_packet_buffer_size)
144     {
145         return(NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL);
146     }
147 
148     /* Certificate buffer is at the end of the record in the record assembly buffer. */
149     cert_buffer = &tls_session->nx_secure_tls_packet_buffer[data_length];
150 
151     /* The size of the buffer is the remaining space in the record assembly buffer. */
152     cert_buf_size = tls_session -> nx_secure_tls_packet_buffer_size - data_length;
153 
154     /* Use our length as an index into the buffer. */
155     length = 0;
156 
157 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
158     if(tls_session->nx_secure_tls_1_3)
159     {
160         /* The certificate chain in TLS 1.3 contains a "context" at
161            the beginning of the handshake record. If the first byte is non-zero
162            it means the following bytes (length given as the value of that byte)
163            should be the context. */
164         packet_buffer++;
165         message_length--;
166 
167     }
168 #endif
169 
170 
171     /* Extract the certificate(s) from the incoming data, starting with. */
172     total_length = (UINT)((packet_buffer[0] << 16) + (packet_buffer[1] << 8) + packet_buffer[2]);
173     length = length + 3;
174 
175     /* Make sure what we extracted makes sense. */
176     if (total_length > message_length)
177     {
178         return(NX_SECURE_TLS_INCORRECT_MESSAGE_LENGTH);
179     }
180 
181     /* See if remote host sent an empty certificate message. */
182     if (total_length == 0)
183     {
184         /*  No certificate received! */
185         return(NX_SECURE_TLS_EMPTY_REMOTE_CERTIFICATE_RECEIVED);
186     }
187 
188     /* Keep subtracting from the total length until no more certificates left. */
189     while (total_length > 0)
190     {
191         /* Extract the next certificate's length. */
192         cert_length = (UINT)((packet_buffer[length] << 16) + (packet_buffer[length + 1] << 8) + packet_buffer[length + 2]);
193         length = length + 3;
194 
195         /* Make sure the individual cert length makes sense. */
196         if ((cert_length + 3) > total_length)
197         {
198             return(NX_SECURE_TLS_INCORRECT_MESSAGE_LENGTH);
199         }
200 
201         /* Get a reference to the remote endpoint certificate that was allocated earlier. */
202         status = _nx_secure_x509_free_certificate_get(&tls_session -> nx_secure_tls_credentials.nx_secure_tls_certificate_store,
203                                                       &certificate);
204 
205         /* If there are no free certificates, attempt to allocate from the packet reassembly buffer
206            (the certificate buffer is carved from the packet buffer in nx_secure_tls_process_record). */
207         if (status != NX_SUCCESS)
208         {
209             /* No remote certificates added. Instead try extracting space from packet buffer. */
210             if(cert_buf_size < sizeof(NX_SECURE_X509_CERT))
211             {
212                 /* Not enough space to allocate the X.509 structure. */
213                 return(NX_SECURE_TLS_INSUFFICIENT_CERT_SPACE);
214             }
215 
216             /* Get space for the parsing structure. */
217             cert_buf_size -= sizeof(NX_SECURE_X509_CERT);
218             certificate = (NX_SECURE_X509_CERT*)(&cert_buffer[cert_buf_size]);
219             NX_SECURE_MEMSET(certificate, 0, sizeof(NX_SECURE_X509_CERT));
220 
221             /* Point structure to certificate being parsed. Note that the certificate
222                structure points directly into the packet buffer where the certificate
223                is located - this certificate structure must NOT be used outside this function. */
224             certificate -> nx_secure_x509_certificate_raw_data_length = cert_length;
225             certificate -> nx_secure_x509_certificate_raw_data = &packet_buffer[length];
226             certificate -> nx_secure_x509_certificate_raw_buffer_size = cert_length;
227             certificate -> nx_secure_x509_user_allocated_cert = NX_FALSE;
228         }
229         else
230         {
231             /* Make sure we have enough space to save our certificate. */
232             if (certificate -> nx_secure_x509_certificate_raw_buffer_size < cert_length)
233             {
234                 return(NX_SECURE_TLS_INSUFFICIENT_CERT_SPACE);
235             }
236 
237             /* Copy the certificate from the packet buffer into our allocated certificate space. */
238             certificate -> nx_secure_x509_certificate_raw_data_length = cert_length;
239             NX_SECURE_MEMCPY(certificate -> nx_secure_x509_certificate_raw_data, &packet_buffer[length], cert_length); /* Use case of memcpy is verified.  lgtm[cpp/banned-api-usage-required-any] */
240         }
241         length += cert_length;
242 
243         /* Release the protection. */
244         tx_mutex_put(&_nx_secure_tls_protection);
245 
246         /* Parse the DER-encoded X509 certificate to extract the public key data. */
247         status = _nx_secure_x509_certificate_parse(certificate -> nx_secure_x509_certificate_raw_data, cert_length, &bytes_processed, certificate);
248 
249         /* Get the protection. */
250         tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER);
251 
252         /* Make sure we parsed a valid certificate. */
253         if (status != NX_SUCCESS)
254         {
255 
256             /* Translate some X.509 return values into TLS return values. */
257             if (status == NX_SECURE_X509_UNSUPPORTED_PUBLIC_CIPHER)
258             {
259                 return(NX_SECURE_TLS_UNSUPPORTED_PUBLIC_CIPHER);
260             }
261 
262             return(status);
263         }
264 
265 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
266         /* Check for TLS 1.3 extensions following each certificate. */
267         if(tls_session->nx_secure_tls_1_3)
268         {
269             extensions_length = (UINT)((packet_buffer[length] << 8) + packet_buffer[length + 1]);
270 
271             /* Add extensions length bytes. */
272             length += 2;
273 
274             /* Add extensions length to offset. */
275             length += extensions_length;
276 
277             /* Adjust the total length with our extension data. */
278             total_length -= (2 + extensions_length);
279         }
280 #endif
281 
282         /* Advance the variable of total_length. */
283         total_length -= (3 + cert_length);
284 
285         /* Assign the TLS Session metadata areas to the certificate for later use. */
286         certificate -> nx_secure_x509_public_cipher_metadata_area = tls_session -> nx_secure_public_cipher_metadata_area;
287         certificate -> nx_secure_x509_public_cipher_metadata_size = tls_session -> nx_secure_public_cipher_metadata_size;
288 
289         certificate -> nx_secure_x509_hash_metadata_area = tls_session -> nx_secure_hash_mac_metadata_area;
290         certificate -> nx_secure_x509_hash_metadata_size = tls_session -> nx_secure_hash_mac_metadata_size;
291 
292         /* Add the certificate to the remote store. */
293         /* Parse and initialize the remote certificate for use in subsequent operations. */
294         status = _nx_secure_x509_certificate_list_add(&tls_session -> nx_secure_tls_credentials.nx_secure_tls_certificate_store.nx_secure_x509_remote_certificates,
295                                                       certificate, NX_TRUE);
296 
297         /* Make sure we parsed a valid certificate. */
298         if (status != NX_SUCCESS)
299         {
300 
301             /* Translate some X.509 return values into TLS return values. */
302             if (status == NX_SECURE_X509_CERT_ID_DUPLICATE)
303             {
304                 return(NX_SECURE_TLS_CERT_ID_DUPLICATE);
305             }
306 
307             return(status);
308         }
309 
310         /* Make sure the certificate has it's cipher table initialized. */
311         certificate -> nx_secure_x509_cipher_table = tls_session -> nx_secure_tls_crypto_table -> nx_secure_tls_x509_cipher_table;
312         certificate -> nx_secure_x509_cipher_table_size = tls_session -> nx_secure_tls_crypto_table -> nx_secure_tls_x509_cipher_table_size;
313     }
314 
315     /* =============================== CERTIFICATE CHAIN VERIFICATION ======================================== */
316     /* Verify the certificates we received are valid against the trusted store. */
317     status = _nx_secure_tls_remote_certificate_verify(tls_session);
318 
319     if(status != NX_SUCCESS)
320     {
321         return(status);
322     }
323 
324     /* ======================== Save off the endpoint certificate for later use. =============================*/
325     /* Get the endpoint from the certificates we just parsed. */
326     status = _nx_secure_x509_remote_endpoint_certificate_get(&tls_session -> nx_secure_tls_credentials.nx_secure_tls_certificate_store,
327                                                              &certificate);
328     NX_ASSERT(status == NX_SUCCESS);
329 
330     /* If the endpoint certificate was NOT allocated by the user application, we need to
331         make a copy and save it for later use. */
332     if(!certificate -> nx_secure_x509_user_allocated_cert)
333     {
334         /* Free all certificates that we added to the packet buffer. Do this before the
335            call to nx_secure_x509_free_certificate_get so that if there are user-allocated
336            certificates the endpoint is put into one of them. */
337         status = _nx_secure_tls_remote_certificate_free_all(tls_session);
338 
339         if(status != NX_SUCCESS)
340         {
341             return(status);
342         }
343 
344         /* Save the raw pointer to endpoint so we can clear remote certificate state. */
345         endpoint_raw_ptr = certificate->nx_secure_x509_certificate_raw_data;
346         endpoint_length = certificate->nx_secure_x509_certificate_raw_data_length;
347 
348         /* Now allocate a new certificate for the endpoint. */
349         status = _nx_secure_x509_free_certificate_get(&tls_session -> nx_secure_tls_credentials.nx_secure_tls_certificate_store,
350                                                     &certificate);
351 
352         /* If there are no free certificates, attempt to allocate from the packet reassembly buffer
353             (the certificate buffer is carved from the packet buffer in nx_secure_tls_process_record). */
354         if (status != NX_SUCCESS)
355         {
356             /* No remote certificates added. Instead try extracting space from packet buffer. */
357             cert_buffer = &tls_session -> nx_secure_tls_packet_buffer[data_length];
358             cert_buf_size = tls_session -> nx_secure_tls_packet_buffer_size - data_length;
359 
360             /* Get space for the parsing structure. */
361             cert_buf_size -= sizeof(NX_SECURE_X509_CERT);
362             certificate = (NX_SECURE_X509_CERT*)(&cert_buffer[cert_buf_size]);
363             NX_SECURE_MEMSET(certificate, 0, sizeof(NX_SECURE_X509_CERT));
364 
365             if(cert_buf_size < endpoint_length)
366             {
367 
368                 /* Not enough space to allocate the raw certificate data. */
369                 return(NX_SECURE_TLS_INSUFFICIENT_CERT_SPACE);
370             }
371 
372             /* Allocate space for the endpoint certificate. */
373             cert_buf_size -= endpoint_length;
374 
375             /* Point structure to certificate being parsed. */
376             certificate -> nx_secure_x509_certificate_raw_data = &cert_buffer[cert_buf_size];
377             certificate -> nx_secure_x509_certificate_raw_buffer_size = endpoint_length;
378 
379             /* Update total remaining size. */
380             tls_session -> nx_secure_tls_packet_buffer_size -= (sizeof(NX_SECURE_X509_CERT) + endpoint_length);
381         }
382 
383         /* Copy the certificate data to the end of the certificate buffer or use an allocated certificate. */
384         certificate -> nx_secure_x509_certificate_raw_data_length = endpoint_length;
385         NX_SECURE_MEMCPY(certificate->nx_secure_x509_certificate_raw_data, endpoint_raw_ptr, endpoint_length); /* Use case of memcpy is verified.  lgtm[cpp/banned-api-usage-required-any] */
386 
387         /* Assign the TLS Session metadata areas to the certificate for later use. */
388         certificate -> nx_secure_x509_public_cipher_metadata_area = tls_session -> nx_secure_public_cipher_metadata_area;
389         certificate -> nx_secure_x509_public_cipher_metadata_size = tls_session -> nx_secure_public_cipher_metadata_size;
390 
391         certificate -> nx_secure_x509_hash_metadata_area = tls_session -> nx_secure_hash_mac_metadata_area;
392         certificate -> nx_secure_x509_hash_metadata_size = tls_session -> nx_secure_hash_mac_metadata_size;
393 
394         /* Assign the cipher table from the parent TLS session. */
395         certificate -> nx_secure_x509_cipher_table = tls_session -> nx_secure_tls_crypto_table -> nx_secure_tls_x509_cipher_table;
396         certificate -> nx_secure_x509_cipher_table_size = tls_session -> nx_secure_tls_crypto_table -> nx_secure_tls_x509_cipher_table_size;
397 
398         /* Release the protection. */
399         tx_mutex_put(&_nx_secure_tls_protection);
400 
401         /* Re-parse the certificate using the original data. */
402         status = _nx_secure_x509_certificate_parse(certificate -> nx_secure_x509_certificate_raw_data, endpoint_length, &bytes_processed, certificate);
403         NX_ASSERT(status == NX_SUCCESS);
404 
405         /* Get the protection. */
406         tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER);
407 
408         /* Re-add the remote endpoint certificate for later use. */
409         status = _nx_secure_x509_certificate_list_add(&tls_session -> nx_secure_tls_credentials.nx_secure_tls_certificate_store.nx_secure_x509_remote_certificates,
410                                                       certificate, NX_TRUE);
411         NX_ASSERT(status == NX_SUCCESS);
412 
413         /* Make sure the certificate has it's cipher table initialized. */
414         certificate -> nx_secure_x509_cipher_table = tls_session -> nx_secure_tls_crypto_table -> nx_secure_tls_x509_cipher_table;
415         certificate -> nx_secure_x509_cipher_table_size = tls_session -> nx_secure_tls_crypto_table -> nx_secure_tls_x509_cipher_table_size;
416     }
417 #ifdef NX_SECURE_TLS_CLIENT_DISABLED
418     /* If TLS Client is disabled and we have processed a ServerCertificate message, something is wrong... */
419     tls_session -> nx_secure_tls_server_state = NX_SECURE_TLS_SERVER_STATE_ERROR;
420 
421     return(NX_SECURE_TLS_INVALID_STATE);
422 #else
423     /* Set our state to indicate we successfully parsed the Certificate message. */
424     tls_session -> nx_secure_tls_client_state = NX_SECURE_TLS_CLIENT_STATE_SERVER_CERTIFICATE;
425 
426     return(status);
427 #endif
428 #else
429     NX_PARAMETER_NOT_USED(tls_session);
430     NX_PARAMETER_NOT_USED(packet_buffer);
431     NX_PARAMETER_NOT_USED(message_length);
432     NX_PARAMETER_NOT_USED(data_length);
433 
434     return(NX_NOT_SUPPORTED);
435 #endif
436 }
437 
438