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 #include "nx_secure_tls.h"
25 
26 /**************************************************************************/
27 /*                                                                        */
28 /*  FUNCTION                                               RELEASE        */
29 /*                                                                        */
30 /*    _nx_secure_tls_send_certificate                     PORTABLE C      */
31 /*                                                           6.3.0        */
32 /*  AUTHOR                                                                */
33 /*                                                                        */
34 /*    Timothy Stapko, Microsoft Corporation                               */
35 /*                                                                        */
36 /*  DESCRIPTION                                                           */
37 /*                                                                        */
38 /*    This function populates an NX_PACKET with the TLS Certificate       */
39 /*    message, which contains the identity certificate for this device.   */
40 /*                                                                        */
41 /*  INPUT                                                                 */
42 /*                                                                        */
43 /*    tls_session                           TLS control block             */
44 /*    send_packet                           Packet to be filled           */
45 /*    wait_option                           Controls timeout actions      */
46 /*                                                                        */
47 /*  OUTPUT                                                                */
48 /*                                                                        */
49 /*    status                                Completion status             */
50 /*                                                                        */
51 /*  CALLS                                                                 */
52 /*                                                                        */
53 /*    _nx_secure_x509_distinguished_name_compare                          */
54 /*                                          Compare distinguished name    */
55 /*    _nx_secure_x509_local_device_certificate_get                        */
56 /*                                          Get local certificate to send */
57 /*    nx_packet_data_append                 Append data to packet         */
58 /*    tx_mutex_get                          Get protection mutex          */
59 /*    tx_mutex_put                          Put protection mutex          */
60 /*                                                                        */
61 /*  CALLED BY                                                             */
62 /*                                                                        */
63 /*    _nx_secure_dtls_client_handshake      DTLS client state machine     */
64 /*    _nx_secure_dtls_server_handshake      DTLS server state machine     */
65 /*    _nx_secure_tls_client_handshake       TLS client state machine      */
66 /*    _nx_secure_tls_server_handshake       TLS server state machine      */
67 /*                                                                        */
68 /*  RELEASE HISTORY                                                       */
69 /*                                                                        */
70 /*    DATE              NAME                      DESCRIPTION             */
71 /*                                                                        */
72 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
73 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
74 /*                                            resulting in version 6.1    */
75 /*  04-02-2021     Timothy Stapko           Modified comment(s),          */
76 /*                                            updated X.509 return value, */
77 /*                                            resulting in version 6.1.6  */
78 /*  04-25-2022     Zhen Kong                Modified comment(s), removed  */
79 /*                                            unreachable error code,     */
80 /*                                            resulting in version 6.1.11 */
81 /*  03-08-2023     Yanwu Cai                Modified comment(s),          */
82 /*                                            fixed compiler errors when  */
83 /*                                            x509 is disabled,           */
84 /*                                            resulting in version 6.2.1  */
85 /*  10-31-2023     Yanwu Cai                Modified comment(s),          */
86 /*                                            fixed packet buffer overrun,*/
87 /*                                            resulting in version 6.3.0  */
88 /*                                                                        */
89 /**************************************************************************/
_nx_secure_tls_send_certificate(NX_SECURE_TLS_SESSION * tls_session,NX_PACKET * send_packet,ULONG wait_option)90 UINT _nx_secure_tls_send_certificate(NX_SECURE_TLS_SESSION *tls_session, NX_PACKET *send_packet,
91                                      ULONG wait_option)
92 {
93 #ifndef NX_SECURE_DISABLE_X509
94 UINT                 length;
95 UINT                 total_length;
96 UCHAR                length_buffer[3];
97 UINT                 status = NX_SECURE_TLS_SUCCESS;
98 NX_SECURE_X509_CERT *cert;
99 INT                  compare_result = 0;
100 UCHAR               *record_start;
101 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
102 USHORT               extensions_length;
103 #endif
104 
105 
106     /* Structure:
107      * |      3       |                     <Total Length>                      |
108      * | Total length |       3        |   <Cert[0] Length> | 3 + <Cert[x] Len> |
109      * |              | Cert[0] Length |   Certificate[0]   |    More certs...  |
110      */
111 
112     /* TLS 1.3 Structure:
113      * |    1    | <Ctx Len> |      3       |                     <Total Length>                         |
114      * | Ctx Len | Context   | Total length |       3        |   <Cert[x] Length> |   2    |   <ExtLen>  |
115      * |                                    | Cert[x] Length |   Certificate[x]   | ExtLen |  Extensions |
116      */
117 
118     /* See if the local certificate has been overridden. If so, use that instead. */
119     if (tls_session -> nx_secure_tls_credentials.nx_secure_tls_active_certificate != NX_NULL)
120     {
121         cert = tls_session -> nx_secure_tls_credentials.nx_secure_tls_active_certificate;
122     }
123     else
124     {
125         /* Get reference to local device certificate. NX_NULL is passed for name to get default entry. */
126         status = _nx_secure_x509_local_device_certificate_get(&tls_session -> nx_secure_tls_credentials.nx_secure_tls_certificate_store,
127                                                               NX_NULL, &cert);
128     }
129 
130 #ifndef NX_SECURE_TLS_CLIENT_DISABLED
131     /* See if this is a TLS client sending a certificate in response to a certificate request from
132        the remote server. */
133     if (tls_session -> nx_secure_tls_socket_type == NX_SECURE_TLS_SESSION_TYPE_CLIENT &&
134         (status == NX_SECURE_X509_CERTIFICATE_NOT_FOUND))
135     {
136         /* If this is a TLS client, as per the RFC we can have no certificate assigned in which
137            case our response to the server that has requested our certificate will contain
138            an empty certificate field. */
139         cert = NX_NULL;
140 
141         /* Clear the requested flag so no further certificate-specific messages are sent. */
142         tls_session -> nx_secure_tls_client_certificate_requested = NX_FALSE;
143     }
144     else
145 #endif
146     {
147         if (status)
148         {
149 
150             /* _nx_secure_x509_local_device_certificate_get can only return
151                 NX_SECURE_X509_CERTIFICATE_NOT_FOUND in this case. */
152             return(NX_SECURE_TLS_CERTIFICATE_NOT_FOUND);
153         }
154     }
155 
156     if (((ULONG)(send_packet -> nx_packet_data_end) - (ULONG)(send_packet -> nx_packet_append_ptr)) < 3u)
157     {
158 
159         /* Packet buffer is too small to hold random and ID. */
160         return(NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL);
161     }
162 
163 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
164     /* In TLS 1.3, the context length is the first field, followed by the context itself (if necessary). */
165     if(tls_session->nx_secure_tls_1_3)
166     {
167         send_packet -> nx_packet_append_ptr[0] = 0;
168         send_packet -> nx_packet_append_ptr = send_packet -> nx_packet_append_ptr + 1;
169         send_packet -> nx_packet_length = send_packet -> nx_packet_length + (USHORT)(1);
170     }
171 #endif
172 
173     /* Save a reference to the start of our record. */
174     record_start = send_packet -> nx_packet_append_ptr;
175 
176     /* Pointer to where we are going to place the next certificate. */
177     /* The first 3 bytes hold the total length field.  Therefore
178        certificate data starts from offset 3.*/
179     send_packet -> nx_packet_append_ptr = send_packet -> nx_packet_append_ptr + 3;
180     send_packet -> nx_packet_length = send_packet -> nx_packet_length + (USHORT)(3);
181 
182     /* Total length is the length of all certificates and is the first 3 bytes of the message. */
183     total_length = 0;
184 
185     while (status == NX_SUCCESS)
186     {
187         /* Place certificate data into the packet buffer with the appropriate length.
188            NOTE: We need to use the RAW data of the certificate when sending, not the parsed certificate! */
189         length = cert -> nx_secure_x509_certificate_raw_data_length;
190 
191         /* Total length is increased by the length of the certificate plus the 3 bytes for
192            the certificate length parameter. */
193         total_length += (length + 3);
194 
195         /* Put the length of this certificate into the buffer. */
196         length_buffer[0] = (UCHAR)((length & 0xFF0000) >> 16);
197         length_buffer[1] = (UCHAR)((length & 0xFF00) >> 8);
198         length_buffer[2] = (UCHAR)(length & 0xFF);
199 
200         /* Release the protection before suspending on nx_packet_data_append. */
201         tx_mutex_put(&_nx_secure_tls_protection);
202 
203         /* Put the length into the buffer. */
204         status = nx_packet_data_append(send_packet, length_buffer, 3,
205                                        tls_session -> nx_secure_tls_packet_pool, wait_option);
206 
207         /* Get the protection after nx_packet_data_append. */
208         tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER);
209 
210         if (status != NX_SUCCESS)
211         {
212             return(status);
213         }
214 
215         /* Release the protection before suspending on nx_packet_data_append. */
216         tx_mutex_put(&_nx_secure_tls_protection);
217 
218         /* Put the certificate data into the buffer. */
219         status = nx_packet_data_append(send_packet, cert -> nx_secure_x509_certificate_raw_data, length,
220                                        tls_session -> nx_secure_tls_packet_pool, wait_option);
221 
222         /* Get the protection after nx_packet_data_append. */
223         tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER);
224 
225 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
226         /* Check for TLS 1.3 extensions following each certificate. */
227         if (tls_session -> nx_secure_tls_1_3)
228         {
229             extensions_length = 0;
230             NX_CHANGE_USHORT_ENDIAN(extensions_length);
231 
232             /* Add extension length to packet. */
233             status = nx_packet_data_append(send_packet, &extensions_length,
234                                            sizeof(extensions_length),
235                                            tls_session -> nx_secure_tls_packet_pool,
236                                            wait_option);
237             if (status != NX_SUCCESS)
238             {
239                 return(status);
240             }
241 
242             total_length += 2;
243         }
244 #endif
245 
246 
247         if (status != NX_SUCCESS)
248         {
249             return(status);
250         }
251 
252         /* Get certificate issuer - if it exists in the store, send it, otherwise we are done. */
253         status = _nx_secure_x509_local_device_certificate_get(&tls_session -> nx_secure_tls_credentials.nx_secure_tls_certificate_store,
254                                                               &cert -> nx_secure_x509_issuer, &cert);
255 
256         /* If certificate was not found, don't try to dereference. */
257         if (status == NX_SUCCESS)
258         {
259             /* Prevent infinite loop if certificate is self-signed. */
260             compare_result = _nx_secure_x509_distinguished_name_compare(&cert -> nx_secure_x509_distinguished_name,
261                                                                         &cert -> nx_secure_x509_issuer, NX_SECURE_X509_NAME_ALL_FIELDS);
262             if (compare_result == 0)
263             {
264                 break;
265             }
266         }
267 
268         /* If an issuer certificate was not found, that is OK - this should actually be the common case
269          * as any certificate that is not self-signed should not have its root CA certificate on the
270          * same device.
271          */
272     }
273 
274     /* Put the total length of all certificates into the buffer. */
275     record_start[0] = (UCHAR)((total_length & 0xFF0000) >> 16);
276     record_start[1] = (UCHAR)((total_length & 0xFF00) >> 8);
277     record_start[2] = (UCHAR)(total_length & 0xFF);
278 
279     return(NX_SUCCESS);
280 #else
281     NX_PARAMETER_NOT_USED(tls_session);
282     NX_PARAMETER_NOT_USED(send_packet);
283     NX_PARAMETER_NOT_USED(wait_option);
284 
285     return(NX_NOT_SUPPORTED);
286 #endif
287 }
288