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