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 
29 #if 0
30 // Utility function to print buffer
31 static void print_buffer(const char* buf_name, const UCHAR* buf, ULONG size)
32 {
33 UINT i;
34     printf("Buffer %s of size: %ld. Data:\n", buf_name, size);
35     if(buf)
36     {
37         for(i = 0; i < size; ++i)
38         {
39             printf("%02x ", (UINT)buf[i]);
40             if((i+1) % 8 == 0)
41             {
42                 printf("\n");
43             }
44         }
45     }
46     else
47     {
48         printf("NULL buffer passed as number\n");
49     }
50     printf("\n");
51 }
52 #endif
53 
54 /**************************************************************************/
55 /*                                                                        */
56 /*  FUNCTION                                               RELEASE        */
57 /*                                                                        */
58 /*    _nx_secure_tls_psk_binder_generate                  PORTABLE C      */
59 /*                                                           6.1          */
60 /*  AUTHOR                                                                */
61 /*                                                                        */
62 /*    Timothy Stapko, Microsoft Corporation                               */
63 /*                                                                        */
64 /*  DESCRIPTION                                                           */
65 /*                                                                        */
66 /*    This function generates the PSK binder, a hash that is used to      */
67 /*    associate a PSK with a specific session/handshake. The PSK binder   */
68 /*    concept was introduced in TLS 1.3.                                  */
69 /*                                                                        */
70 /*  INPUT                                                                 */
71 /*                                                                        */
72 /*    tls_session                           TLS control block             */
73 /*    psk_entry                             Pointer to PSK entry          */
74 /*                                                                        */
75 /*  OUTPUT                                                                */
76 /*                                                                        */
77 /*    status                                Completion status             */
78 /*                                                                        */
79 /*  CALLS                                                                 */
80 /*                                                                        */
81 /*    [nx_crypto_init]                      Initialize crypto             */
82 /*    [nx_crypto_operation]                 Crypto operation              */
83 /*                                                                        */
84 /*  CALLED BY                                                             */
85 /*                                                                        */
86 /*    _nx_secure_tls_send_clienthello_extensions                          */
87 /*                                          Send ClientHello extensions   */
88 /*                                                                        */
89 /*  RELEASE HISTORY                                                       */
90 /*                                                                        */
91 /*    DATE              NAME                      DESCRIPTION             */
92 /*                                                                        */
93 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
94 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
95 /*                                            resulting in version 6.1    */
96 /*                                                                        */
97 /**************************************************************************/
98 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
_nx_secure_tls_psk_binder_generate(NX_SECURE_TLS_SESSION * tls_session,NX_SECURE_TLS_PSK_STORE * psk_entry)99 UINT _nx_secure_tls_psk_binder_generate(NX_SECURE_TLS_SESSION *tls_session, NX_SECURE_TLS_PSK_STORE *psk_entry)
100 {
101 UINT                                  status = NX_SUCCESS;
102 const NX_CRYPTO_METHOD               *hmac_method = NX_NULL;
103 const NX_CRYPTO_METHOD               *hash_method = NX_NULL;
104 CHAR                                 *metadata = NX_NULL;
105 UINT                                  metadata_size;
106 VOID                                 *handler = NX_NULL;
107 UCHAR                                *binder_key = NX_NULL;
108 UINT                                  binder_key_len;
109 UINT                                  hash_size;
110 UCHAR                                *transcript_hash;
111 UCHAR                                *psk_binder;
112 
113     /* From RFC 8446 (TLS 1.3, section 4.2.11.2):
114        The PSK binder value forms a binding between a PSK and the current
115        handshake, as well as a binding between the handshake in which the
116        PSK was generated (if via a NewSessionTicket message) and the current
117        handshake.  Each entry in the binders list is computed as an HMAC
118        over a transcript hash (see Section 4.4.1) containing a partial
119        ClientHello up to and including the PreSharedKeyExtension.identities
120        field.  That is, it includes all of the ClientHello but not the
121        binders list itself.  The length fields for the message (including
122        the overall length, the length of the extensions block, and the
123        length of the "pre_shared_key" extension) are all set as if binders
124        of the correct lengths were present.
125 
126        The PskBinderEntry is computed in the same way as the Finished
127        message (Section 4.4.4) but with the BaseKey being the binder_key
128        derived via the key schedule from the corresponding PSK which is
129        being offered (see Section 7.1).
130 
131        If the handshake includes a HelloRetryRequest, the initial
132        ClientHello and HelloRetryRequest are included in the transcript
133        along with the new ClientHello.  For instance, if the client sends
134        ClientHello1, its binder will be computed over:
135 
136           Transcript-Hash(Truncate(ClientHello1))
137 
138        Where Truncate() removes the binders list from the ClientHello.
139 
140        If the server responds with a HelloRetryRequest and the client then
141        sends ClientHello2, its binder will be computed over:
142 
143           Transcript-Hash(ClientHello1,
144                           HelloRetryRequest,
145                           Truncate(ClientHello2))
146 
147        The full ClientHello1/ClientHello2 is included in all other handshake
148        hash computations.  Note that in the first flight,
149        Truncate(ClientHello1) is hashed directly, but in the second flight,
150        ClientHello1 is hashed and then reinjected as a "message_hash"
151        message, as described in Section 4.4.1.
152 
153      For reference, the Finished message calculation is as follows :
154 
155           verify_data =
156               HMAC(finished_key,
157                    Transcript-Hash(Handshake Context,
158                                    Certificate*, CertificateVerify*))
159     */
160 
161 
162 
163     /* Get our HMAC and hash methods. */
164 
165     /* If the PSK binder ciphersuite is not NULL, then we have a previously-associated hash method or ciphersuite.
166        This may be a session-resumption PSK or a user-defined hash routine/ciphersuite, but if it exists, use it. */
167     if(psk_entry->nx_secure_tls_psk_binder_ciphersuite != NX_NULL)
168     {
169         hash_method = psk_entry->nx_secure_tls_psk_binder_ciphersuite->nx_secure_tls_hash;
170         hash_size = psk_entry->nx_secure_tls_psk_binder_ciphersuite->nx_secure_tls_hash_size;
171     }
172     else
173     {
174         /* Default to SHA-256 if no ciphersuite is present. */
175         hash_method = tls_session->nx_secure_tls_crypto_table->nx_secure_tls_handshake_hash_sha256_method;
176         hash_size = (hash_method->nx_crypto_ICV_size_in_bits >> 3);
177     }
178     hmac_method = tls_session->nx_secure_tls_crypto_table->nx_secure_tls_hmac_method;
179 
180 
181     /* Generate our binder key using our hash method and PSK. */
182     status = _nx_secure_tls_1_3_generate_psk_secret(tls_session, psk_entry, hash_method);
183 
184     if(status != NX_SUCCESS)
185     {
186         return(status);
187     }
188 
189     binder_key = psk_entry->nx_secure_tls_psk_finished_key;
190     binder_key_len = psk_entry->nx_secure_tls_psk_finished_key_size;
191 
192 
193 //    printf("\n=====BINDER GENERATION=========\n");
194 //    print_buffer("Finished binder key", binder_key, binder_key_len);
195 //    printf("\n==============\n");
196 
197     /* Working pointer to PSK binder output. */
198     psk_binder = &psk_entry->nx_secure_tls_psk_binder[0];
199 
200     /* Use the Finished Hash metadata scratch space to calculate our binder hash. */
201     metadata = tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_scratch;
202     metadata_size = tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_scratch_size;
203 
204     /* Get the transcript hash context up to now - Server Finished received for Client, all messages before Finished sent for Server. */
205     transcript_hash = tls_session->nx_secure_tls_key_material.nx_secure_tls_transcript_hashes[NX_SECURE_TLS_TRANSCRIPT_IDX_CLIENTHELLO];
206 
207 //    print_buffer("transcript hash value", transcript_hash, hash_size);
208 //    printf("\n==============\n");
209 
210     /* Initialize HMAC. */
211     if (hash_method -> nx_crypto_init)
212     {
213         status = hmac_method -> nx_crypto_init((NX_CRYPTO_METHOD*)hmac_method,
214                                                 binder_key,
215                                                 (binder_key_len << 3),
216                                                 handler,
217                                                 metadata,
218                                                 metadata_size);
219 
220         if (status != NX_SUCCESS)
221         {
222             return(status);
223         }
224     }
225 
226     /* Initialize HMAC with our hash method. */
227     status = hmac_method->nx_crypto_operation(NX_CRYPTO_HMAC_SET_HASH, NX_NULL, (NX_CRYPTO_METHOD*)hash_method, NX_NULL, 0, NX_NULL, 0,
228                                               NX_NULL, NX_NULL, 0, metadata, metadata_size, NX_NULL, NX_NULL);
229 
230     if (status != NX_CRYPTO_SUCCESS)
231     {
232         return(status);
233     }
234 
235     if (hmac_method -> nx_crypto_operation != NX_NULL)
236     {
237         status = hmac_method -> nx_crypto_operation(NX_CRYPTO_HASH_INITIALIZE,
238                                                  handler,
239                                                  (NX_CRYPTO_METHOD*)hmac_method,
240                                                  binder_key,
241                                                  (NX_CRYPTO_KEY_SIZE)(binder_key_len << 3),
242                                                  NX_NULL,
243                                                  0,
244                                                  NX_NULL,
245                                                  NX_NULL,
246                                                  0,
247                                                  metadata,
248                                                  metadata_size,
249                                                  NX_NULL,
250                                                  NX_NULL);
251 
252         if (status != NX_CRYPTO_SUCCESS)
253         {
254             return(status);
255         }
256     }
257 
258     /* Update the HMAC with the transcript hash context. */
259     if (hmac_method -> nx_crypto_operation != NX_NULL)
260     {
261         status = hmac_method -> nx_crypto_operation(NX_CRYPTO_HASH_UPDATE,
262                                                     handler,
263                                                     (NX_CRYPTO_METHOD*)hmac_method,
264                                                     NX_NULL, /* Key. */
265                                                     0,
266                                                     transcript_hash, /* Input. */
267                                                     hash_size,
268                                                     NX_NULL,
269                                                     NX_NULL, /* output */
270                                                     0,
271                                                     metadata,
272                                                     metadata_size,
273                                                     NX_NULL,
274                                                     NX_NULL);
275 
276         if (status != NX_CRYPTO_SUCCESS)
277         {
278             return(status);
279         }
280     }
281 
282     /* Finally, calculate the PSK binder data. */
283     if (hmac_method -> nx_crypto_operation != NX_NULL)
284     {
285         status = hmac_method -> nx_crypto_operation(NX_CRYPTO_HASH_CALCULATE,
286                                                     handler,
287                                                     (NX_CRYPTO_METHOD*)hmac_method,
288                                                     NX_NULL,
289                                                     0,
290                                                     NX_NULL,
291                                                     0,
292                                                     NX_NULL,
293                                                     psk_binder,
294                                                     hash_size,
295                                                     metadata,
296                                                     metadata_size,
297                                                     NX_NULL,
298                                                     NX_NULL);
299 
300         if (status != NX_CRYPTO_SUCCESS)
301         {
302             return(status);
303         }
304     }
305     else
306     {
307         return(NX_SECURE_TLS_MISSING_CRYPTO_ROUTINE);
308     }
309 
310 
311 //    print_buffer("psk binder", psk_binder, hash_size);
312 //    printf("\n==============\n");
313 
314     /* Finally, set the size of the PSK binder. */
315     psk_entry->nx_secure_tls_psk_binder_size = hash_size;
316 
317     return(status);
318 }
319 #endif
320