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 #define NX_SECURE_SOURCE_CODE
22
23 #include "nx_secure_tls.h"
24 #ifdef NX_SECURE_ENABLE_DTLS
25 #include "nx_secure_dtls.h"
26 #endif /* NX_SECURE_ENABLE_DTLS */
27
28 static UCHAR handshake_hash[16 + 20]; /* We concatenate MD5 and SHA-1 hashes into this buffer. */
29
30 /**************************************************************************/
31 /* */
32 /* FUNCTION RELEASE */
33 /* */
34 /* _nx_secure_tls_finished_hash_generate PORTABLE C */
35 /* 6.1.8 */
36 /* AUTHOR */
37 /* */
38 /* Timothy Stapko, Microsoft Corporation */
39 /* */
40 /* DESCRIPTION */
41 /* */
42 /* This function generates the Finished message hash using the hash */
43 /* data collected in the TLS session control block during the */
44 /* handshake. */
45 /* */
46 /* INPUT */
47 /* */
48 /* tls_session TLS control block */
49 /* finished_label Label used to generate hash */
50 /* finished_hash Pointer to hash output buffer */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* status Completion status */
55 /* */
56 /* CALLS */
57 /* */
58 /* [nx_crypto_init] Initialize crypto */
59 /* [nx_crypto_operation] Crypto operation */
60 /* */
61 /* CALLED BY */
62 /* */
63 /* _nx_secure_tls_send_finished Send Finished message */
64 /* _nx_secure_tls_process_finished Process Finished message */
65 /* */
66 /* RELEASE HISTORY */
67 /* */
68 /* DATE NAME DESCRIPTION */
69 /* */
70 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
71 /* 09-30-2020 Timothy Stapko Modified comment(s), */
72 /* verified memcpy use cases, */
73 /* resulting in version 6.1 */
74 /* 08-02-2021 Timothy Stapko Modified comment(s), added */
75 /* hash clone and cleanup, */
76 /* resulting in version 6.1.8 */
77 /* */
78 /**************************************************************************/
_nx_secure_tls_finished_hash_generate(NX_SECURE_TLS_SESSION * tls_session,UCHAR * finished_label,UCHAR * finished_hash)79 UINT _nx_secure_tls_finished_hash_generate(NX_SECURE_TLS_SESSION *tls_session,
80 UCHAR *finished_label, UCHAR *finished_hash)
81 {
82 UINT status;
83 UCHAR *master_sec;
84 const NX_CRYPTO_METHOD *method_ptr = NX_NULL;
85 VOID *handler = NX_NULL;
86 #if (NX_SECURE_TLS_TLS_1_0_ENABLED || NX_SECURE_TLS_TLS_1_1_ENABLED)
87 VOID *metadata;
88 UINT metadata_size;
89 #endif /* (NX_SECURE_TLS_TLS_1_0_ENABLED || NX_SECURE_TLS_TLS_1_1_ENABLED) */
90 UINT hash_size = 0;
91
92 /* We need to extract the Finished hash and verify that the handshake to this point
93 has not been corrupted or tampered with. */
94
95 /* From the RFC (TLS 1.1). TLS 1.2 uses the same strategy but uses only SHA-256.
96 struct {
97 opaque verify_data[12];
98 } Finished;
99
100 verify_data
101 PRF(master_secret, finished_label, MD5(handshake_messages) +
102 SHA-1(handshake_messages)) [0..11];
103
104 finished_label
105 For Finished messages sent by the client, the string "client
106 finished". For Finished messages sent by the server, the
107 string "server finished".
108
109 handshake_messages
110 All of the data from all messages in this handshake (not
111 including any HelloRequest messages) up to but not including
112 this message. This is only data visible at the handshake
113 layer and does not include record layer headers. This is the
114 concatenation of all the Handshake structures, as defined in
115 7.4, exchanged thus far.
116 */
117
118 if (tls_session -> nx_secure_tls_session_ciphersuite == NX_NULL)
119 {
120 return(NX_SECURE_TLS_UNKNOWN_CIPHERSUITE);
121 }
122
123
124 /* Get our master secret that was generated when we generated our key material. */
125 master_sec = tls_session -> nx_secure_tls_key_material.nx_secure_tls_master_secret;
126
127 /* Finally, generate the verification data required by TLS - 12 bytes using the PRF and the data
128 we have collected. Place the result directly into the packet buffer. */
129 #if (NX_SECURE_TLS_TLS_1_2_ENABLED)
130 #ifdef NX_SECURE_ENABLE_DTLS
131 if (tls_session -> nx_secure_tls_protocol_version == NX_SECURE_TLS_VERSION_TLS_1_2 ||
132 tls_session -> nx_secure_tls_protocol_version == NX_SECURE_DTLS_VERSION_1_2)
133 #else
134 if (tls_session -> nx_secure_tls_protocol_version == NX_SECURE_TLS_VERSION_TLS_1_2)
135 #endif /* NX_SECURE_ENABLE_DTLS */
136 {
137 /* Copy over the handshake hash state into scratch space to do the intermediate calculation. */
138 NX_SECURE_HASH_METADATA_CLONE(tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_scratch, /* lgtm[cpp/banned-api-usage-required-any] */
139 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_metadata,
140 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_metadata_size); /* Use case of memcpy is verified. */
141
142 /* Finalize the handshake message hash that we started at the beginning of the handshake. */
143 method_ptr = tls_session -> nx_secure_tls_crypto_table -> nx_secure_tls_handshake_hash_sha256_method;
144 handler = tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_handler;
145
146 if (method_ptr -> nx_crypto_operation != NX_NULL)
147 {
148 status = method_ptr -> nx_crypto_operation(NX_CRYPTO_HASH_CALCULATE,
149 handler,
150 (NX_CRYPTO_METHOD*)method_ptr,
151 NX_NULL,
152 0,
153 NX_NULL,
154 0,
155 NX_NULL,
156 &handshake_hash[0],
157 sizeof(handshake_hash),
158 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_scratch,
159 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_metadata_size,
160 NX_NULL,
161 NX_NULL);
162
163 }
164 else
165 {
166 status = NX_SECURE_TLS_MISSING_CRYPTO_ROUTINE;
167 }
168
169 NX_SECURE_HASH_CLONE_CLEANUP(tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_scratch,
170 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_metadata_size);
171
172 if (status != NX_CRYPTO_SUCCESS)
173 {
174 return(status);
175 }
176
177 /* For TLS 1.2, the PRF is defined by the ciphersuite. However, if we are using an older ciphersuite,
178 * default to the TLS 1.2 default PRF, which uses SHA-256-HMAC. */
179 method_ptr = tls_session -> nx_secure_tls_session_ciphersuite -> nx_secure_tls_prf;
180 hash_size = 32; /* Size of SHA-256 output. */
181 }
182
183 #endif
184
185 #if (NX_SECURE_TLS_TLS_1_0_ENABLED || NX_SECURE_TLS_TLS_1_1_ENABLED)
186 #ifdef NX_SECURE_ENABLE_DTLS
187 if (tls_session -> nx_secure_tls_protocol_version == NX_SECURE_TLS_VERSION_TLS_1_0 ||
188 tls_session -> nx_secure_tls_protocol_version == NX_SECURE_TLS_VERSION_TLS_1_1 ||
189 tls_session -> nx_secure_tls_protocol_version == NX_SECURE_DTLS_VERSION_1_0)
190 #else
191 if (tls_session -> nx_secure_tls_protocol_version == NX_SECURE_TLS_VERSION_TLS_1_0 ||
192 tls_session -> nx_secure_tls_protocol_version == NX_SECURE_TLS_VERSION_TLS_1_1)
193 #endif /* NX_SECURE_ENABLE_DTLS */
194 {
195 /* Copy over the handshake hash metadata into scratch metadata area to do the intermediate calculation. */
196 NX_SECURE_HASH_METADATA_CLONE(tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_scratch +
197 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha1_metadata_size,
198 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_md5_metadata,
199 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_md5_metadata_size); /* Use case of memcpy is verified. */
200
201 /* Finalize the handshake message hashes that we started at the beginning of the handshake. */
202 method_ptr = tls_session -> nx_secure_tls_crypto_table -> nx_secure_tls_handshake_hash_md5_method;
203 handler = tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_md5_handler;
204 metadata = tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_scratch +
205 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha1_metadata_size;
206 metadata_size = tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_md5_metadata_size;
207 if (method_ptr -> nx_crypto_operation != NX_NULL)
208 {
209 status = method_ptr -> nx_crypto_operation(NX_CRYPTO_HASH_CALCULATE,
210 handler,
211 (NX_CRYPTO_METHOD*)method_ptr,
212 NX_NULL,
213 0,
214 NX_NULL,
215 0,
216 NX_NULL,
217 &handshake_hash[0],
218 16,
219 metadata,
220 metadata_size,
221 NX_NULL,
222 NX_NULL);
223 }
224 else
225 {
226 status = NX_SECURE_TLS_MISSING_CRYPTO_ROUTINE;
227 }
228
229 NX_SECURE_HASH_CLONE_CLEANUP(metadata, metadata_size);
230
231 if (status != NX_CRYPTO_SUCCESS)
232 {
233 return(status);
234 }
235
236 NX_SECURE_HASH_METADATA_CLONE(tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_scratch,
237 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha1_metadata,
238 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha1_metadata_size); /* Use case of memcpy is verified. */
239
240 method_ptr = tls_session -> nx_secure_tls_crypto_table -> nx_secure_tls_handshake_hash_sha1_method;
241 handler = tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha1_handler;
242 metadata = tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_scratch;
243 metadata_size = tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha1_metadata_size;
244
245 if (method_ptr -> nx_crypto_operation != NX_NULL)
246 {
247 status = method_ptr -> nx_crypto_operation(NX_CRYPTO_HASH_CALCULATE,
248 handler,
249 (NX_CRYPTO_METHOD*)method_ptr,
250 NX_NULL,
251 0,
252 NX_NULL,
253 0,
254 NX_NULL,
255 &handshake_hash[16],
256 sizeof(handshake_hash) - 16,
257 metadata,
258 metadata_size,
259 NX_NULL,
260 NX_NULL);
261
262
263 }
264 else
265 {
266 status = NX_SECURE_TLS_MISSING_CRYPTO_ROUTINE;
267 }
268
269 NX_SECURE_HASH_CLONE_CLEANUP(metadata, metadata_size);
270
271 if (status != NX_CRYPTO_SUCCESS)
272 {
273 return(status);
274 }
275
276 /* TLS 1.0 and TLS 1.1 use the same PRF. */
277 method_ptr = tls_session -> nx_secure_tls_crypto_table -> nx_secure_tls_prf_1_method;
278 hash_size = 36;
279 }
280 #endif
281
282 /* Make sure we found a supported version (essentially an assertion check). */
283 if (method_ptr == NX_NULL)
284 {
285 return(NX_SECURE_TLS_UNSUPPORTED_TLS_VERSION);
286 }
287
288 /* Do the final PRF encoding of the finished hash. */
289 if (method_ptr -> nx_crypto_init != NX_NULL)
290 {
291 status = method_ptr -> nx_crypto_init((NX_CRYPTO_METHOD*)method_ptr,
292 master_sec, 48,
293 &handler,
294 tls_session -> nx_secure_tls_prf_metadata_area,
295 tls_session -> nx_secure_tls_prf_metadata_size);
296
297 if(status != NX_CRYPTO_SUCCESS)
298 {
299 return(status);
300 }
301 }
302 else
303 {
304 return(NX_SECURE_TLS_MISSING_CRYPTO_ROUTINE);
305 }
306
307 if (method_ptr -> nx_crypto_operation != NX_NULL)
308 {
309 status = method_ptr -> nx_crypto_operation(NX_CRYPTO_PRF,
310 handler,
311 (NX_CRYPTO_METHOD*)method_ptr,
312 finished_label,
313 15,
314 handshake_hash,
315 hash_size,
316 NX_NULL,
317 &finished_hash[0],
318 NX_SECURE_TLS_FINISHED_HASH_SIZE,
319 tls_session -> nx_secure_tls_prf_metadata_area,
320 tls_session -> nx_secure_tls_prf_metadata_size,
321 NX_NULL,
322 NX_NULL);
323
324 if(status != NX_CRYPTO_SUCCESS)
325 {
326 return(status);
327 }
328 }
329 else
330 {
331 return(NX_SECURE_TLS_MISSING_CRYPTO_ROUTINE);
332 }
333
334 if (method_ptr -> nx_crypto_cleanup != NX_NULL)
335 {
336 status = method_ptr -> nx_crypto_cleanup(tls_session -> nx_secure_tls_prf_metadata_area);
337
338 if(status != NX_CRYPTO_SUCCESS)
339 {
340 return(status);
341 }
342 }
343 #ifdef NX_SECURE_KEY_CLEAR
344 NX_SECURE_MEMSET(handshake_hash, 0, hash_size);
345 #endif /* NX_SECURE_KEY_CLEAR */
346
347 return(NX_SUCCESS);
348 }
349
350