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 static UCHAR generated_hash[NX_SECURE_TLS_MAX_HASH_SIZE];
27
28 /**************************************************************************/
29 /* */
30 /* FUNCTION RELEASE */
31 /* */
32 /* _nx_secure_tls_process_finished PORTABLE C */
33 /* 6.2.1 */
34 /* AUTHOR */
35 /* */
36 /* Timothy Stapko, Microsoft Corporation */
37 /* */
38 /* DESCRIPTION */
39 /* */
40 /* This function processes an incoming Finished message by generating */
41 /* a hash of the received handshake messages (up to this point) and */
42 /* comparing the result to the hash received from the remote host. */
43 /* If the generated hash and the received hash do not match, it */
44 /* indicates that the handshake messages were corrupted in some way. */
45 /* */
46 /* INPUT */
47 /* */
48 /* tls_session TLS control block */
49 /* packet_buffer Pointer to received data */
50 /* message_length Length of received data */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* status Result of hash comparison */
55 /* */
56 /* CALLS */
57 /* */
58 /* _nx_secure_tls_finished_hash_generate Generate Finished hash */
59 /* */
60 /* CALLED BY */
61 /* */
62 /* _nx_secure_dtls_client_handshake DTLS client state machine */
63 /* _nx_secure_dtls_server_handshake DTLS server state machine */
64 /* _nx_secure_tls_client_handshake TLS client state machine */
65 /* _nx_secure_tls_server_handshake TLS server state machine */
66 /* */
67 /* RELEASE HISTORY */
68 /* */
69 /* DATE NAME DESCRIPTION */
70 /* */
71 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
72 /* 09-30-2020 Timothy Stapko Modified comment(s), */
73 /* verified memcpy use cases, */
74 /* fixed renegotiation bug, */
75 /* resulting in version 6.1 */
76 /* 03-08-2023 Yanwu Cai Modified comment(s), */
77 /* fixed compiler errors when */
78 /* x509 is disabled, */
79 /* corrected hash cleanup, */
80 /* resulting in version 6.2.1 */
81 /* */
82 /**************************************************************************/
_nx_secure_tls_process_finished(NX_SECURE_TLS_SESSION * tls_session,UCHAR * packet_buffer,UINT message_length)83 UINT _nx_secure_tls_process_finished(NX_SECURE_TLS_SESSION *tls_session, UCHAR *packet_buffer,
84 UINT message_length)
85 {
86 UCHAR *finished_label;
87 UINT compare_result, status;
88 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
89 UINT hash_size = 0;
90 UINT is_server;
91 #endif
92
93 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
94 /* Make sure the length is what we expect. */
95 if(tls_session -> nx_secure_tls_1_3)
96 {
97 /* TLS 1.3 Finished messages are different from earlier versions
98 and require specific processing. */
99 /* Check if the Finished is from server. */
100 is_server = (tls_session -> nx_secure_tls_socket_type == NX_SECURE_TLS_SESSION_TYPE_CLIENT);
101
102 /* Verify Finished hash. */
103 status = _nx_secure_tls_1_3_finished_hash_generate(tls_session, is_server, &hash_size, generated_hash, sizeof(generated_hash));
104
105 if ((hash_size > message_length) || (hash_size > sizeof(generated_hash)))
106 {
107
108 /* Size error. */
109 compare_result = 1;
110 }
111 else
112 {
113
114 /* Compare to see if the Finished hash matches the received hash. */
115 compare_result = (UINT)NX_SECURE_MEMCMP(generated_hash, packet_buffer, hash_size);
116 }
117
118 #ifdef NX_SECURE_KEY_CLEAR
119 NX_SECURE_MEMSET(generated_hash, 0, sizeof(generated_hash));
120 #endif /* NX_SECURE_KEY_CLEAR */
121 }
122 else
123 #endif
124 {
125 /* TLS 1.2 and earlier use the same Finished hash construction. */
126 if (message_length != NX_SECURE_TLS_FINISHED_HASH_SIZE)
127 {
128 return(NX_SECURE_TLS_INCORRECT_MESSAGE_LENGTH);
129 }
130
131
132 /* If we received a Finished message but the session is not active, error! */
133 if (!tls_session -> nx_secure_tls_remote_session_active)
134 {
135 return(NX_SECURE_TLS_UNEXPECTED_MESSAGE);
136 }
137
138 /* If we have not received credentials from the remote host, we
139 cannot validate the handshake under any circumstances. */
140 if (!tls_session -> nx_secure_tls_received_remote_credentials)
141 {
142 return(NX_SECURE_TLS_HANDSHAKE_FAILURE);
143 }
144
145 /* Select our label for generating the finished hash expansion - we are comparing against
146 the remote hosts hash, so use the opposite label. */
147 if (tls_session -> nx_secure_tls_socket_type == NX_SECURE_TLS_SESSION_TYPE_SERVER)
148 {
149 finished_label = (UCHAR *)"client finished";
150 }
151 else
152 {
153 finished_label = (UCHAR *)"server finished";
154 }
155
156 /* Finally, generate the verification data required by TLS - 12 bytes using the PRF and the data
157 we have collected. */
158 status = _nx_secure_tls_finished_hash_generate(tls_session, finished_label, generated_hash);
159
160 if(status != NX_SUCCESS)
161 {
162 return(status);
163 }
164
165 #ifndef NX_SECURE_TLS_DISABLE_SECURE_RENEGOTIATION
166 /* If we are doing secure renegotiation as per RFC 5746, we need to save off the generated
167 verify data now. For TLS 1.0-1.2 this is 12 bytes. If SSLv3 is ever used, it will be 36 bytes. */
168 NX_SECURE_MEMCPY(tls_session -> nx_secure_tls_remote_verify_data, generated_hash, NX_SECURE_TLS_FINISHED_HASH_SIZE); /* Use case of memcpy is verified. lgtm[cpp/banned-api-usage-required-any] */
169 #endif /* NX_SECURE_TLS_DISABLE_SECURE_RENEGOTIATION */
170
171 /* The finished verify data is always 12 bytes (*except for SSLv3) - compare to see if the Finished hash matches the received hash. */
172 compare_result = (UINT)NX_SECURE_MEMCMP(generated_hash, packet_buffer, NX_SECURE_TLS_FINISHED_HASH_SIZE);
173 }
174
175 if (compare_result != 0)
176 {
177 return(NX_SECURE_TLS_FINISHED_HASH_FAILURE);
178 }
179
180 /* If the comparison was OK, set the state appropriately. */
181 #ifndef NX_SECURE_TLS_CLIENT_DISABLED
182 if (tls_session -> nx_secure_tls_socket_type == NX_SECURE_TLS_SESSION_TYPE_CLIENT)
183 {
184 tls_session -> nx_secure_tls_client_state = NX_SECURE_TLS_CLIENT_STATE_HANDSHAKE_FINISHED;
185 }
186 #endif
187
188 #ifndef NX_SECURE_DISABLE_X509
189
190 /* Now that we are done with the handshake, free all remote certificates - we don't need them anymore. */
191 status = _nx_secure_tls_remote_certificate_free_all(tls_session);
192
193 if (status != NX_SUCCESS)
194 {
195 return(status);
196 }
197 #endif
198
199 return(NX_SECURE_TLS_SUCCESS);
200 }
201
202