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