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) - Generate Session Keys */
18 /** */
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 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
30
31 /* Some secret generation requires a string of zeroes with a length
32 equivalent to the key/hash size. This array is used for that with a memset. */
33 static UCHAR _nx_secure_tls_zeroes[NX_SECURE_TLS_MAX_KEY_SIZE];
34
35 static UINT _nx_secure_tls_1_3_generate_handshake_secrets(NX_SECURE_TLS_SESSION *tls_session);
36
37 static UINT _nx_secure_tls_1_3_generate_session_secrets(NX_SECURE_TLS_SESSION *tls_session);
38
39
40 static UINT _nx_secure_tls_hkdf_expand_label(NX_SECURE_TLS_SESSION *tls_session, UCHAR *secret, UINT secret_len,
41 UCHAR *label, UINT label_len, UCHAR *context, UINT context_len, UINT length,
42 UCHAR *output, UINT output_length, const NX_CRYPTO_METHOD *hash_method);
43
44 static UINT _nx_secure_tls_derive_secret(NX_SECURE_TLS_SESSION *tls_session, UCHAR *secret, UINT secret_len,
45 UCHAR *label, UINT label_len,
46 UCHAR *message_hash, UINT message_hash_len,
47 UCHAR *output, UINT output_length, const NX_CRYPTO_METHOD *hash_method);
48
49 static UINT _nx_secure_tls_hkdf_extract(NX_SECURE_TLS_SESSION *tls_session, UCHAR *salt, UINT salt_len,
50 UCHAR *ikm, UINT ikm_len, UCHAR *output, UINT output_length, const NX_CRYPTO_METHOD *hash_method);
51 #endif
52
53
54
55 /**************************************************************************/
56 /* */
57 /* FUNCTION RELEASE */
58 /* */
59 /* _nx_secure_tls_1_3_generate_psk_secrets PORTABLE C */
60 /* 6.1 */
61 /* AUTHOR */
62 /* */
63 /* Timothy Stapko, Microsoft Corporation */
64 /* */
65 /* DESCRIPTION */
66 /* */
67 /* This function is used by TLS 1.3 to generate the secrets and keys */
68 /* needed for PSK binder generation. Since each "external" PSK needs */
69 /* a binder generated from the early secret (which is generated using */
70 /* that PSK), each PSK gets a separate "early secret" and "binder key".*/
71 /* Therefore, this function will be called for *every* PSK provided by */
72 /* the application, each time with a different PSK and hash method. */
73 /* */
74 /* INPUT */
75 /* */
76 /* tls_session TLS control block */
77 /* */
78 /* OUTPUT */
79 /* */
80 /* status Completion status */
81 /* */
82 /* CALLS */
83 /* */
84 /* */
85 /* CALLED BY */
86 /* */
87 /* */
88 /* RELEASE HISTORY */
89 /* */
90 /* DATE NAME DESCRIPTION */
91 /* */
92 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
93 /* 09-30-2020 Timothy Stapko Modified comment(s), */
94 /* resulting in version 6.1 */
95 /* */
96 /**************************************************************************/
97 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
98
_nx_secure_tls_1_3_generate_psk_secret(NX_SECURE_TLS_SESSION * tls_session,NX_SECURE_TLS_PSK_STORE * psk_entry,const NX_CRYPTO_METHOD * hash_method)99 UINT _nx_secure_tls_1_3_generate_psk_secret(NX_SECURE_TLS_SESSION *tls_session, NX_SECURE_TLS_PSK_STORE *psk_entry, const NX_CRYPTO_METHOD *hash_method)
100 {
101 UINT status;
102 UINT hash_length;
103 UCHAR *psk_secret;
104 UINT psk_secret_length;
105 UCHAR *label;
106 UINT label_length;
107 UINT is_resumption_psk = NX_FALSE;
108
109
110 /* Get the hash length so we know how much data we are generating. */
111 hash_length = (hash_method->nx_crypto_ICV_size_in_bits >> 3);
112
113 /* The PSK is the input to the early secret. */
114 psk_secret = (UCHAR *)psk_entry->nx_secure_tls_psk_data;
115 psk_secret_length = psk_entry->nx_secure_tls_psk_data_size;
116
117 NX_SECURE_MEMSET(_nx_secure_tls_zeroes, 0, sizeof(_nx_secure_tls_zeroes));
118
119 /* Perform an HKDF-Extract to get the "early secret". */
120 /* Salt: 0 string, IKM: PSK secret. */
121
122
123 status = _nx_secure_tls_hkdf_extract(tls_session, _nx_secure_tls_zeroes, hash_length, psk_secret, psk_secret_length,
124 psk_entry->nx_secure_tls_psk_early_secret, hash_length, hash_method);
125
126 if(status != NX_SUCCESS)
127 {
128 return(status);
129 }
130
131 psk_entry->nx_secure_tls_psk_early_secret_size = hash_length;
132
133 /*----- Binder key value. -----*/
134
135 /* Get the appropriate label for our secret derivation. */
136 label = (UCHAR *)((is_resumption_psk)? "res binder" : "ext binder" );
137 label_length = 10;
138
139 /* Ext/Res binder key has an empty messages context. */
140 status = _nx_secure_tls_derive_secret(tls_session, psk_entry->nx_secure_tls_psk_early_secret, psk_entry->nx_secure_tls_psk_early_secret_size,
141 label, label_length,
142 (UCHAR *)"", 0,
143 psk_entry->nx_secure_tls_psk_binder_key, hash_length, hash_method);
144
145 if(status != NX_SUCCESS)
146 {
147 return(status);
148 }
149
150 psk_entry->nx_secure_tls_psk_binder_key_size = hash_length;
151
152 /* Generate Finished Key. According to RFC 8446 Section 4.2.11.2, we generate the PSK binder in the same
153 * fashion as the Finished message, but using the binder key as input to the HKDF expansion. Thus, generate a "finished"
154 * key for this specific PSK entry to use in the binder generation. */
155 status = _nx_secure_tls_hkdf_expand_label(tls_session, psk_entry->nx_secure_tls_psk_binder_key, psk_entry->nx_secure_tls_psk_binder_key_size,
156 (UCHAR *)"finished", 8, (UCHAR *)"", 0, hash_length,
157 psk_entry->nx_secure_tls_psk_finished_key, hash_length, hash_method);
158
159 psk_entry->nx_secure_tls_psk_finished_key_size = hash_length;
160
161 return(status);
162 }
163 #endif
164
165
166 /**************************************************************************/
167 /* */
168 /* FUNCTION RELEASE */
169 /* */
170 /* _nx_secure_tls_1_3_generate_handshake_keys PORTABLE C */
171 /* 6.1.8 */
172 /* AUTHOR */
173 /* */
174 /* Timothy Stapko, Microsoft Corporation */
175 /* */
176 /* DESCRIPTION */
177 /* */
178 /* This function is used by TLS 1.3 to generate the symmetric */
179 /* encryption keys used to protect TLS handshake messages. */
180 /* */
181 /* INPUT */
182 /* */
183 /* tls_session TLS control block */
184 /* */
185 /* OUTPUT */
186 /* */
187 /* status Completion status */
188 /* */
189 /* CALLS */
190 /* */
191 /* */
192 /* CALLED BY */
193 /* */
194 /* */
195 /* RELEASE HISTORY */
196 /* */
197 /* DATE NAME DESCRIPTION */
198 /* */
199 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
200 /* 09-30-2020 Timothy Stapko Modified comment(s), */
201 /* resulting in version 6.1 */
202 /* 08-02-2021 Timothy Stapko Modified comment(s), added */
203 /* cleanup for session cipher, */
204 /* resulting in version 6.1.8 */
205 /* */
206 /**************************************************************************/
207 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
208
_nx_secure_tls_1_3_generate_handshake_keys(NX_SECURE_TLS_SESSION * tls_session)209 UINT _nx_secure_tls_1_3_generate_handshake_keys(NX_SECURE_TLS_SESSION *tls_session)
210 {
211 UINT status;
212 UCHAR *key_block;
213 ULONG key_block_size;
214 NX_SECURE_TLS_KEY_SECRETS *secrets;
215 const NX_CRYPTO_METHOD *session_cipher_method = NX_NULL;
216 const NX_CRYPTO_METHOD *hash_method = NX_NULL;
217 UINT key_size;
218 UINT iv_size;
219 UINT key_offset;
220 UINT hash_size;
221
222 /* From RFC 8446, Section 7.3:
223 The traffic keying material is generated from an input traffic secret
224 value using:
225
226 [sender]_write_key = HKDF-Expand-Label(Secret, "key", "", key_length)
227 [sender]_write_iv = HKDF-Expand-Label(Secret, "iv", "", iv_length)
228
229 [sender] denotes the sending side. The value of Secret for each
230 record type is shown in the table below.
231
232 +-------------------+---------------------------------------+
233 | Record Type | Secret |
234 +-------------------+---------------------------------------+
235 | 0-RTT Application | client_early_traffic_secret |
236 | | |
237 | Handshake | [sender]_handshake_traffic_secret |
238 | | |
239 | Application Data | [sender]_application_traffic_secret_N |
240 +-------------------+---------------------------------------+
241 */
242
243 /* Generate handshake secrets. */
244 status = _nx_secure_tls_1_3_generate_handshake_secrets(tls_session);
245
246 /* Get our generated secrets. */
247 secrets = &tls_session->nx_secure_tls_key_material.nx_secure_tls_key_secrets;
248
249 if(status != NX_SUCCESS)
250 {
251 return(status);
252 }
253
254 if (tls_session -> nx_secure_tls_session_ciphersuite == NX_NULL)
255 {
256 /* Likely internal error since at this point ciphersuite negotiation was theoretically completed. */
257 return(NX_SECURE_TLS_UNKNOWN_CIPHERSUITE);
258 }
259
260 /* Get our session cipher method so we can get key sizes. */
261 session_cipher_method = tls_session -> nx_secure_tls_session_ciphersuite -> nx_secure_tls_session_cipher;
262
263 hash_method = tls_session -> nx_secure_tls_session_ciphersuite -> nx_secure_tls_hash;
264
265 /* Lookup ciphersuite data for key size. We need 2 keys for each session. */
266 key_size = session_cipher_method -> nx_crypto_key_size_in_bits >> 3;
267
268 /* Lookup initialization vector size. */
269 /* IV size for AES-128-GCM is 12 bytes! */
270 iv_size = 12; // session_cipher_method -> nx_crypto_IV_size_in_bits >> 3;
271
272 /* Working pointers into our key material blocks - we need a place to store generated keys. */
273 key_block = tls_session -> nx_secure_tls_key_material.nx_secure_tls_key_material_data;
274 key_block_size = sizeof(tls_session -> nx_secure_tls_key_material.nx_secure_tls_key_material_data);
275
276
277 /* Assign MAC secrets to TLS Session. */
278 tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_write_mac_secret = secrets->tls_client_handshake_traffic_secret;
279 tls_session -> nx_secure_tls_key_material.nx_secure_tls_server_write_mac_secret = secrets->tls_server_handshake_traffic_secret;
280
281 /* To generate handshake keys, we need the [sender]_handshake_traffic_secret. */
282
283 /* Generate client traffic key. */
284 key_offset = 0;
285 status = _nx_secure_tls_hkdf_expand_label(tls_session, secrets->tls_client_handshake_traffic_secret, secrets->tls_client_handshake_traffic_secret_len,
286 (UCHAR *)"key", 3, (UCHAR *)"", 0, key_size,
287 &key_block[key_offset], (key_block_size - key_offset), hash_method);
288
289 if(status != NX_SUCCESS)
290 {
291 return(status);
292 }
293
294 tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_write_key = &key_block[key_offset];
295
296 key_offset += key_size;
297
298 /* Generate client traffic IV. */
299 status = _nx_secure_tls_hkdf_expand_label(tls_session, secrets->tls_client_handshake_traffic_secret, secrets->tls_client_handshake_traffic_secret_len,
300 (UCHAR *)"iv", 2, (UCHAR *)"", 0, iv_size,
301 &key_block[key_offset], (key_block_size - key_offset), hash_method);
302
303 if(status != NX_SUCCESS)
304 {
305 return(status);
306 }
307
308 tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_iv = &key_block[key_offset];
309
310 key_offset += iv_size;
311
312 /* Generate server-side key. */
313 status = _nx_secure_tls_hkdf_expand_label(tls_session, secrets->tls_server_handshake_traffic_secret, secrets->tls_server_handshake_traffic_secret_len,
314 (UCHAR *)"key", 3, (UCHAR *)"", 0, key_size,
315 &key_block[key_offset], (key_block_size - key_offset), hash_method);
316
317 if(status != NX_SUCCESS)
318 {
319 return(status);
320 }
321
322 tls_session -> nx_secure_tls_key_material.nx_secure_tls_server_write_key = &key_block[key_offset];
323
324 key_offset += key_size;
325
326 /* Generate server-side IV. */
327 status = _nx_secure_tls_hkdf_expand_label(tls_session, secrets->tls_server_handshake_traffic_secret, secrets->tls_server_handshake_traffic_secret_len,
328 (UCHAR *)"iv", 2, (UCHAR *)"", 0, iv_size,
329 &key_block[key_offset], (key_block_size - key_offset), hash_method);
330
331 if(status != NX_SUCCESS)
332 {
333 return(status);
334 }
335
336 tls_session -> nx_secure_tls_key_material.nx_secure_tls_server_iv = &key_block[key_offset];
337
338 key_offset += iv_size;
339
340 /* We now have the session keys so we can generate the Finished keys for both client and server. */
341 /* From RFC 8446 (TLS 1.3):
342 finished_key =
343 HKDF-Expand-Label(BaseKey, "finished", "", Hash.length)
344 */
345
346 /* Get hash size for this ciphersuite. */
347 hash_size = tls_session -> nx_secure_tls_session_ciphersuite -> nx_secure_tls_hash_size;
348
349 /* Generate server-side Finished Key. */
350 status = _nx_secure_tls_hkdf_expand_label(tls_session, secrets->tls_server_handshake_traffic_secret, secrets->tls_server_handshake_traffic_secret_len,
351 (UCHAR *)"finished", 8, (UCHAR *)"", 0, hash_size,
352 &secrets->tls_server_finished_key[0], (key_block_size - key_offset), hash_method);
353
354 if(status != NX_SUCCESS)
355 {
356 return(status);
357 }
358
359 secrets->tls_server_finished_key_len = hash_size;
360
361 /* Generate client-side Finished Key. */
362 status = _nx_secure_tls_hkdf_expand_label(tls_session, secrets->tls_client_handshake_traffic_secret, secrets->tls_client_handshake_traffic_secret_len,
363 (UCHAR *)"finished", 8, (UCHAR *)"", 0, hash_size,
364 &secrets->tls_client_finished_key[0], (key_block_size - key_offset), hash_method);
365
366 secrets->tls_client_finished_key_len = hash_size;
367
368 if(status != NX_SUCCESS)
369 {
370 return(status);
371 }
372
373
374 /* Now, we can initialize our crypto routines and turn on encryption. */
375 /* Initialize the crypto method used in the session cipher. */
376 if (session_cipher_method -> nx_crypto_init != NULL)
377 {
378 if (tls_session -> nx_secure_tls_session_cipher_client_initialized && session_cipher_method -> nx_crypto_cleanup)
379 {
380 status = session_cipher_method -> nx_crypto_cleanup(tls_session -> nx_secure_session_cipher_metadata_area_client);
381 if (status != NX_CRYPTO_SUCCESS)
382 {
383 return(status);
384 }
385
386 tls_session -> nx_secure_tls_session_cipher_client_initialized = 0;
387 }
388
389 /* Set client write key. */
390 status = session_cipher_method -> nx_crypto_init((NX_CRYPTO_METHOD*)session_cipher_method,
391 tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_write_key,
392 session_cipher_method -> nx_crypto_key_size_in_bits,
393 &tls_session -> nx_secure_session_cipher_handler_client,
394 tls_session -> nx_secure_session_cipher_metadata_area_client,
395 tls_session -> nx_secure_session_cipher_metadata_size);
396
397 if (status != NX_CRYPTO_SUCCESS)
398 {
399 return(status);
400 }
401
402 tls_session -> nx_secure_tls_session_cipher_client_initialized = 1;
403
404 if (tls_session -> nx_secure_tls_session_cipher_server_initialized && session_cipher_method -> nx_crypto_cleanup)
405 {
406 status = session_cipher_method -> nx_crypto_cleanup(tls_session -> nx_secure_session_cipher_metadata_area_server);
407 if (status != NX_CRYPTO_SUCCESS)
408 {
409 return(status);
410 }
411
412 tls_session -> nx_secure_tls_session_cipher_server_initialized = 0;
413 }
414
415 /* Set server write key. */
416 status = session_cipher_method -> nx_crypto_init((NX_CRYPTO_METHOD*)session_cipher_method,
417 tls_session -> nx_secure_tls_key_material.nx_secure_tls_server_write_key,
418 session_cipher_method -> nx_crypto_key_size_in_bits,
419 &tls_session -> nx_secure_session_cipher_handler_server,
420 tls_session -> nx_secure_session_cipher_metadata_area_server,
421 tls_session -> nx_secure_session_cipher_metadata_size);
422
423 if (status != NX_CRYPTO_SUCCESS)
424 {
425 return(status);
426 }
427
428 tls_session -> nx_secure_tls_session_cipher_server_initialized = 1;
429 }
430
431 return(NX_SUCCESS);
432 }
433
434 #endif
435
436 /**************************************************************************/
437 /* */
438 /* FUNCTION RELEASE */
439 /* */
440 /* _nx_secure_tls_1_3_generate_session_keys PORTABLE C */
441 /* 6.1 */
442 /* AUTHOR */
443 /* */
444 /* Timothy Stapko, Microsoft Corporation */
445 /* */
446 /* DESCRIPTION */
447 /* */
448 /* This function is used by TLS 1.3 to generate the symmetric */
449 /* encryption keys used to protect application data. */
450 /* */
451 /* INPUT */
452 /* */
453 /* tls_session TLS control block */
454 /* */
455 /* OUTPUT */
456 /* */
457 /* status Completion status */
458 /* */
459 /* CALLS */
460 /* */
461 /* */
462 /* CALLED BY */
463 /* */
464 /* */
465 /* RELEASE HISTORY */
466 /* */
467 /* DATE NAME DESCRIPTION */
468 /* */
469 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
470 /* 09-30-2020 Timothy Stapko Modified comment(s), */
471 /* resulting in version 6.1 */
472 /* */
473 /**************************************************************************/
474 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
475
_nx_secure_tls_1_3_generate_session_keys(NX_SECURE_TLS_SESSION * tls_session)476 UINT _nx_secure_tls_1_3_generate_session_keys(NX_SECURE_TLS_SESSION *tls_session)
477 {
478 UINT status;
479 UCHAR *key_block;
480 ULONG key_block_size;
481 NX_SECURE_TLS_KEY_SECRETS *secrets;
482 const NX_CRYPTO_METHOD *session_cipher_method = NX_NULL;
483 const NX_CRYPTO_METHOD *hash_method = NX_NULL;
484 UINT key_size;
485 UINT iv_size;
486 UINT key_offset;
487
488 /* From RFC 8446, Section 7.3:
489 The traffic keying material is generated from an input traffic secret
490 value using:
491
492 [sender]_write_key = HKDF-Expand-Label(Secret, "key", "", key_length)
493 [sender]_write_iv = HKDF-Expand-Label(Secret, "iv", "", iv_length)
494
495 [sender] denotes the sending side. The value of Secret for each
496 record type is shown in the table below.
497
498 +-------------------+---------------------------------------+
499 | Record Type | Secret |
500 +-------------------+---------------------------------------+
501 | 0-RTT Application | client_early_traffic_secret |
502 | | |
503 | Handshake | [sender]_handshake_traffic_secret |
504 | | |
505 | Application Data | [sender]_application_traffic_secret_N |
506 +-------------------+---------------------------------------+
507 */
508
509 /* Generate handshake secrets. */
510 status = _nx_secure_tls_1_3_generate_session_secrets(tls_session);
511
512 /* Get our generated secrets. */
513 secrets = &tls_session->nx_secure_tls_key_material.nx_secure_tls_key_secrets;
514
515 if(status != NX_SUCCESS)
516 {
517 return(status);
518 }
519
520 if (tls_session -> nx_secure_tls_session_ciphersuite == NX_NULL)
521 {
522 /* Likely internal error since at this point ciphersuite negotiation was theoretically completed. */
523 return(NX_SECURE_TLS_UNKNOWN_CIPHERSUITE);
524 }
525
526 /* Get our session cipher method so we can get key sizes. */
527 session_cipher_method = tls_session -> nx_secure_tls_session_ciphersuite -> nx_secure_tls_session_cipher;
528
529 hash_method = tls_session -> nx_secure_tls_session_ciphersuite -> nx_secure_tls_hash;
530
531 /* Lookup ciphersuite data for key size. We need 2 keys for each session. */
532 key_size = session_cipher_method -> nx_crypto_key_size_in_bits >> 3;
533
534 /* Lookup initialization vector size. */
535 // iv_size = session_cipher_method -> nx_crypto_IV_size_in_bits >> 3;
536
537 /* IV size for AES-128-GCM is 12 bytes. */
538 iv_size = 12; // session_cipher_method -> nx_crypto_IV_size_in_bits >> 3;
539
540 /* Working pointers into our key material blocks - we need a place to store generated keys.
541 * Whenever we generate session keys in TLS 1.3 we are coming from an existing encrypted
542 * context so save the keys to the "on-deck" space to be enabled later. */
543 key_block = tls_session -> nx_secure_tls_key_material.nx_secure_tls_new_key_material_data;
544 key_block_size = sizeof(tls_session -> nx_secure_tls_key_material.nx_secure_tls_key_material_data);
545
546
547 /* Assign MAC secrets to TLS Session. */
548 tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_write_mac_secret = secrets->tls_client_application_traffic_secret_0;
549 tls_session -> nx_secure_tls_key_material.nx_secure_tls_server_write_mac_secret = secrets->tls_server_application_traffic_secret_0;
550
551 /* To generate handshake keys, we need the [sender]_handshake_traffic_secret. */
552
553 /* Generate client traffic key. */
554 key_offset = 0;
555 status = _nx_secure_tls_hkdf_expand_label(tls_session, secrets->tls_client_application_traffic_secret_0, secrets->tls_client_application_traffic_secret_0_len,
556 (UCHAR *)"key", 3, (UCHAR *)"", 0, key_size,
557 &key_block[key_offset], (key_block_size - key_offset), hash_method);
558
559 if(status != NX_SUCCESS)
560 {
561 return(status);
562 }
563
564 /* Save the generated keys to the on-deck space (don't initialize yet). */
565 tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_next_write_key = &key_block[key_offset];
566
567 key_offset += key_size;
568
569 /* Generate client traffic IV. */
570 status = _nx_secure_tls_hkdf_expand_label(tls_session, secrets->tls_client_application_traffic_secret_0, secrets->tls_client_application_traffic_secret_0_len,
571 (UCHAR *)"iv", 2, (UCHAR *)"", 0, iv_size,
572 &key_block[key_offset], (key_block_size - key_offset), hash_method);
573
574 if(status != NX_SUCCESS)
575 {
576 return(status);
577 }
578
579 tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_next_iv = &key_block[key_offset];
580
581 key_offset += iv_size;
582
583 /* Generate server-side key. */
584 status = _nx_secure_tls_hkdf_expand_label(tls_session, secrets->tls_server_application_traffic_secret_0, secrets->tls_server_application_traffic_secret_0_len,
585 (UCHAR *)"key", 3, (UCHAR *)"", 0, key_size,
586 &key_block[key_offset], (key_block_size - key_offset), hash_method);
587
588 if(status != NX_SUCCESS)
589 {
590 return(status);
591 }
592
593 tls_session -> nx_secure_tls_key_material.nx_secure_tls_server_next_write_key = &key_block[key_offset];
594
595 key_offset += key_size;
596
597 /* Generate server-side IV. */
598 status = _nx_secure_tls_hkdf_expand_label(tls_session, secrets->tls_server_application_traffic_secret_0, secrets->tls_server_application_traffic_secret_0_len,
599 (UCHAR *)"iv", 2, (UCHAR *)"", 0, iv_size,
600 &key_block[key_offset], (key_block_size - key_offset), hash_method);
601
602 if(status != NX_SUCCESS)
603 {
604 return(status);
605 }
606
607 tls_session -> nx_secure_tls_key_material.nx_secure_tls_server_next_iv = &key_block[key_offset];
608
609 key_offset += iv_size;
610
611 if(status != NX_SUCCESS)
612 {
613 return(status);
614 }
615
616 return(NX_SUCCESS);
617
618 }
619
620 #endif
621
622 /**************************************************************************/
623 /* */
624 /* FUNCTION RELEASE */
625 /* */
626 /* _nx_secure_tls_generate_session_psk PORTABLE C */
627 /* 6.1 */
628 /* AUTHOR */
629 /* */
630 /* Timothy Stapko, Microsoft Corporation */
631 /* */
632 /* DESCRIPTION */
633 /* */
634 /* This function is used by TLS 1.3 to generate a PSK for use in */
635 /* session resumptions, using the nonce provided in the */
636 /* NewSessionTicket message. */
637 /* */
638 /* INPUT */
639 /* */
640 /* tls_session TLS control block */
641 /* ticket_psk PSK control block for output */
642 /* nonce Pointer to session nonce */
643 /* nonce_len Length of nonce */
644 /* */
645 /* OUTPUT */
646 /* */
647 /* status Completion status */
648 /* */
649 /* CALLS */
650 /* */
651 /* */
652 /* CALLED BY */
653 /* */
654 /* */
655 /* RELEASE HISTORY */
656 /* */
657 /* DATE NAME DESCRIPTION */
658 /* */
659 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
660 /* 09-30-2020 Timothy Stapko Modified comment(s), */
661 /* resulting in version 6.1 */
662 /* */
663 /**************************************************************************/
664 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
665
_nx_secure_tls_1_3_session_psk_generate(NX_SECURE_TLS_SESSION * tls_session,NX_SECURE_TLS_PSK_STORE * ticket_psk,UCHAR * nonce,UINT nonce_len)666 UINT _nx_secure_tls_1_3_session_psk_generate(NX_SECURE_TLS_SESSION *tls_session, NX_SECURE_TLS_PSK_STORE *ticket_psk, UCHAR *nonce, UINT nonce_len)
667 {
668 NX_SECURE_TLS_KEY_SECRETS *secrets;
669 UINT status;
670 UINT hash_length;
671 const NX_CRYPTO_METHOD *hash_method;
672
673 /* Session PSK is generated as follows (From RFC 8446):
674 * HKDF-Expand-Label(resumption_master_secret,
675 * "resumption", ticket_nonce, Hash.length)
676 *
677 */
678
679 /* Get a pointer to our key secrets for this session. */
680 secrets = &tls_session->nx_secure_tls_key_material.nx_secure_tls_key_secrets;
681
682 if (tls_session -> nx_secure_tls_session_ciphersuite == NX_NULL)
683 {
684 /* Likely internal error since at this point ciphersuite negotiation was theoretically completed. */
685 return(NX_SECURE_TLS_UNKNOWN_CIPHERSUITE);
686 }
687
688 /* Get the hash method so we know how much data we are generating. */
689 hash_method = tls_session -> nx_secure_tls_session_ciphersuite -> nx_secure_tls_hash;
690 hash_length = (hash_method->nx_crypto_ICV_size_in_bits >> 3);
691
692 /* Generate the PSK by running HKDF-Expand-Label with the resumption secret and the passed-in nonce. */
693 status = _nx_secure_tls_hkdf_expand_label(tls_session, secrets->tls_resumption_master_secret, secrets->tls_resumption_master_secret_len,
694 (UCHAR *)"resumption", 10, nonce, nonce_len, hash_length,
695 ticket_psk->nx_secure_tls_psk_data,
696 sizeof(ticket_psk->nx_secure_tls_psk_data), hash_method);
697
698 /* Set the length of our PSK. */
699 ticket_psk->nx_secure_tls_psk_data_size = hash_length;
700
701 return(status);
702 }
703 #endif
704
705 /**************************************************************************/
706 /* */
707 /* FUNCTION RELEASE */
708 /* */
709 /* _nx_secure_tls_1_3_generate_handshake_secrets PORTABLE C */
710 /* 6.1 */
711 /* AUTHOR */
712 /* */
713 /* Timothy Stapko, Microsoft Corporation */
714 /* */
715 /* DESCRIPTION */
716 /* */
717 /* This function is used by TLS 1.3 in generating key material. */
718 /* */
719 /* INPUT */
720 /* */
721 /* tls_session TLS control block */
722 /* */
723 /* OUTPUT */
724 /* */
725 /* status Completion status */
726 /* */
727 /* CALLS */
728 /* */
729 /* */
730 /* CALLED BY */
731 /* */
732 /* */
733 /* RELEASE HISTORY */
734 /* */
735 /* DATE NAME DESCRIPTION */
736 /* */
737 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
738 /* 09-30-2020 Timothy Stapko Modified comment(s), */
739 /* resulting in version 6.1 */
740 /* */
741 /**************************************************************************/
742 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
743
_nx_secure_tls_1_3_generate_handshake_secrets(NX_SECURE_TLS_SESSION * tls_session)744 static UINT _nx_secure_tls_1_3_generate_handshake_secrets(NX_SECURE_TLS_SESSION *tls_session)
745 {
746 UINT status;
747 NX_SECURE_TLS_KEY_SECRETS *secrets;
748 UINT hash_length;
749 const NX_CRYPTO_METHOD *hash_method;
750 UCHAR *psk_secret;
751 UINT psk_secret_length;
752 UCHAR *label;
753 UINT label_length;
754 UINT is_resumption_psk = NX_FALSE;
755
756 if (tls_session -> nx_secure_tls_session_ciphersuite == NX_NULL)
757 {
758 /* Likely internal error since at this point ciphersuite negotiation was theoretically completed. */
759 return(NX_SECURE_TLS_UNKNOWN_CIPHERSUITE);
760 }
761
762 /* Get the hash method so we know how much data we are generating. */
763 hash_method = tls_session -> nx_secure_tls_session_ciphersuite -> nx_secure_tls_hash;
764 hash_length = (hash_method->nx_crypto_ICV_size_in_bits >> 3);
765
766 /* Get a pointer to our key secrets for this session. */
767 secrets = &tls_session->nx_secure_tls_key_material.nx_secure_tls_key_secrets;
768
769 /* From RFC 8446, section 7.1:
770
771 Keys are derived from two input secrets using the HKDF-Extract and
772 Derive-Secret functions. The general pattern for adding a new secret
773 is to use HKDF-Extract with the Salt being the current secret state
774 and the Input Keying Material (IKM) being the new secret to be added.
775 In this version of TLS 1.3, the two input secrets are:
776
777 - PSK (a pre-shared key established externally or derived from the
778 resumption_master_secret value from a previous connection)
779
780 - (EC)DHE shared secret (Section 7.4)
781
782 This produces a full key derivation schedule shown in the diagram
783 below. In this diagram, the following formatting conventions apply:
784
785 - HKDF-Extract is drawn as taking the Salt argument from the top and
786 the IKM argument from the left, with its output to the bottom and
787 the name of the output on the right.
788
789 - Derive-Secret's Secret argument is indicated by the incoming
790 arrow. For instance, the Early Secret is the Secret for
791 generating the client_early_traffic_secret.
792
793 - "0" indicates a string of Hash.length bytes set to zero.
794
795 0
796 |
797 v
798 PSK -> HKDF-Extract = Early Secret
799 |
800 +-----> Derive-Secret(., "ext binder" | "res binder", "")
801 | = binder_key
802 |
803 +-----> Derive-Secret(., "c e traffic", ClientHello)
804 | = client_early_traffic_secret
805 |
806 +-----> Derive-Secret(., "e exp master", ClientHello)
807 | = early_exporter_master_secret
808 v
809 Derive-Secret(., "derived", "")
810 |
811 v
812 (EC)DHE -> HKDF-Extract = Handshake Secret
813 |
814 +-----> Derive-Secret(., "c hs traffic",
815 | ClientHello...ServerHello)
816 | = client_handshake_traffic_secret
817 |
818 +-----> Derive-Secret(., "s hs traffic",
819 | ClientHello...ServerHello)
820 | = server_handshake_traffic_secret
821 v
822 Derive-Secret(., "derived", "")
823 |
824 v
825 0 -> HKDF-Extract = Master Secret
826 |
827 +-----> Derive-Secret(., "c ap traffic",
828 | ClientHello...server Finished)
829 | = client_application_traffic_secret_0
830 |
831 +-----> Derive-Secret(., "s ap traffic",
832 | ClientHello...server Finished)
833 | = server_application_traffic_secret_0
834 |
835 +-----> Derive-Secret(., "exp master",
836 | ClientHello...server Finished)
837 | = exporter_master_secret
838 |
839 +-----> Derive-Secret(., "res master",
840 ClientHello...client Finished)
841 = resumption_master_secret
842
843 The general pattern here is that the secrets shown down the left side
844 of the diagram are just raw entropy without context, whereas the
845 secrets down the right side include Handshake Context and therefore
846 can be used to derive working keys without additional context. Note
847 that the different calls to Derive-Secret may take different Messages
848 arguments, even with the same secret. In a 0-RTT exchange,
849 Derive-Secret is called with four distinct transcripts; in a
850 1-RTT-only exchange, it is called with three distinct transcripts.
851
852 If a given secret is not available, then the 0-value consisting of a
853 string of Hash.length bytes set to zeros is used. Note that this
854 does not mean skipping rounds, so if PSK is not in use, Early Secret
855 will still be HKDF-Extract(0, 0). For the computation of the
856 binder_key, the label is "ext binder" for external PSKs (those
857 provisioned outside of TLS) and "res binder" for resumption PSKs
858 (those provisioned as the resumption master secret of a previous
859 handshake). The different labels prevent the substitution of one
860 type of PSK for the other.
861
862 There are multiple potential Early Secret values, depending on which
863 PSK the server ultimately selects. The client will need to compute
864 one for each potential PSK; if no PSK is selected, it will then need
865 to compute the Early Secret corresponding to the zero PSK.
866
867 Once all the values which are to be derived from a given secret have
868 been computed, that secret SHOULD be erased.
869
870
871 */
872
873 /* Go through all secrets, generate those that haven't been generated yet. */
874
875 /* If available, the chosen PSK is fed into the key generation process. */
876 /* If PSK is not in use, Early Secret will still be HKDF-Extract(0, 0). So set PSK as "0". */
877 psk_secret = _nx_secure_tls_zeroes;
878 psk_secret_length = hash_length;
879
880 if(tls_session->nx_secure_tls_credentials.nx_secure_tls_client_psk.nx_secure_tls_psk_data_size > 0)
881 {
882 psk_secret = tls_session->nx_secure_tls_credentials.nx_secure_tls_client_psk.nx_secure_tls_psk_data;
883 psk_secret_length = tls_session->nx_secure_tls_credentials.nx_secure_tls_client_psk.nx_secure_tls_psk_data_size;
884 }
885
886 NX_SECURE_MEMSET(_nx_secure_tls_zeroes, 0, sizeof(_nx_secure_tls_zeroes));
887
888 if(secrets->tls_early_secret_len == 0)
889 {
890 /* Perform an HKDF-Extract to get the "early secret". */
891 /* Salt: 0 string, IKM: PSK secret. */
892 status = _nx_secure_tls_hkdf_extract(tls_session, _nx_secure_tls_zeroes, hash_length, psk_secret, psk_secret_length,
893 secrets->tls_early_secret, hash_length, hash_method);
894
895 if(status != NX_SUCCESS)
896 {
897 return(status);
898 }
899 secrets->tls_early_secret_len = hash_length;
900 }
901
902 /* Generate keys and secrets based on the "early secret". */
903 if(secrets->tls_early_secret_len != 0)
904 {
905 /*----- Binder key value. -----*/
906
907 /* Get the appropriate label for our secret derivation. */
908 label = (UCHAR *)((is_resumption_psk)? "res binder" : "ext binder");
909 label_length = 10;
910
911 /* Ext/Res binder key has an empty messages context. */
912 status = _nx_secure_tls_derive_secret(tls_session, secrets->tls_early_secret, secrets->tls_early_secret_len, label, label_length,
913 (UCHAR *)"", 0,
914 secrets->tls_binder_key, hash_length, hash_method);
915
916 if(status != NX_SUCCESS)
917 {
918 return(status);
919 }
920 secrets->tls_binder_key_len = hash_length;
921
922 /*----- Early traffic secret. -----*/
923 label = (UCHAR *)"c e traffic";
924 label_length = 11;
925
926 /* Context is hash of ClientHello. */
927 status = _nx_secure_tls_derive_secret(tls_session, secrets->tls_early_secret, secrets->tls_early_secret_len, label, label_length,
928 (UCHAR *)"FIXME", 5,
929 secrets->tls_client_early_traffic_secret, hash_length, hash_method);
930
931 if(status != NX_SUCCESS)
932 {
933 return(status);
934 }
935 secrets->tls_client_early_traffic_secret_len = hash_length;
936
937 /*----- Early exporter master secret. -----*/
938 label = (UCHAR *)"e exp master";
939 label_length = 12;
940
941 /* Context is hash of ClientHello. */
942 status = _nx_secure_tls_derive_secret(tls_session, secrets->tls_early_secret, secrets->tls_early_secret_len, label, label_length,
943 (UCHAR *)"FIXME", 5,
944 secrets->tls_early_exporter_master_secret, hash_length, hash_method);
945
946 if(status != NX_SUCCESS)
947 {
948 return(status);
949 }
950 secrets->tls_early_exporter_master_secret_len = hash_length;
951 }
952
953 /* Handshake secret - special case! Needs a pre-master secret from the ECDHE exchange and the early secret from above. */
954 if(secrets->tls_handshake_secret_len == 0 && tls_session->nx_secure_tls_key_material.nx_secure_tls_pre_master_secret_size != 0)
955 {
956 /* Start by deriving the salt from the early secret. Context is empty! */
957 status = _nx_secure_tls_derive_secret(tls_session, secrets->tls_early_secret, secrets->tls_early_secret_len, (UCHAR *)"derived", 7,
958 (UCHAR *)"", 0,
959 secrets->tls_handshake_secret, hash_length, hash_method);
960
961 if(status != NX_SUCCESS)
962 {
963 return(status);
964 }
965
966 /* Now perform an HKDF-Extract to get the handshake secret.
967 Salt: derived secret from above, IKM: ECDHE pre-master secret */
968 status = _nx_secure_tls_hkdf_extract(tls_session, secrets->tls_handshake_secret, hash_length,
969 tls_session->nx_secure_tls_key_material.nx_secure_tls_pre_master_secret,
970 tls_session->nx_secure_tls_key_material.nx_secure_tls_pre_master_secret_size,
971 secrets->tls_handshake_secret, hash_length, hash_method);
972
973 if(status != NX_SUCCESS)
974 {
975 return(status);
976 }
977 secrets->tls_handshake_secret_len = hash_length;
978 }
979
980 /* Generate keys and secrets based on the "handshake secret". */
981 if(secrets->tls_handshake_secret_len != 0)
982 {
983 /*----- Client handshake traffic secret. -----*/
984 label = (UCHAR *)"c hs traffic";
985 label_length = 12;
986
987 status = _nx_secure_tls_derive_secret(tls_session, secrets->tls_handshake_secret, secrets->tls_handshake_secret_len, label, label_length,
988 tls_session->nx_secure_tls_key_material.nx_secure_tls_transcript_hashes[NX_SECURE_TLS_TRANSCRIPT_IDX_SERVERHELLO], hash_length,
989 secrets->tls_client_handshake_traffic_secret, hash_length, hash_method);
990
991 if(status != NX_SUCCESS)
992 {
993 return(status);
994 }
995 secrets->tls_client_handshake_traffic_secret_len = hash_length;
996
997 /*----- Server handshake traffic secret. -----*/
998 label = (UCHAR *)"s hs traffic";
999 label_length = 12;
1000
1001 status = _nx_secure_tls_derive_secret(tls_session, secrets->tls_handshake_secret, secrets->tls_handshake_secret_len, label, label_length,
1002 tls_session->nx_secure_tls_key_material.nx_secure_tls_transcript_hashes[NX_SECURE_TLS_TRANSCRIPT_IDX_SERVERHELLO], hash_length,
1003 secrets->tls_server_handshake_traffic_secret, hash_length, hash_method);
1004
1005 if(status != NX_SUCCESS)
1006 {
1007 return(status);
1008 }
1009 secrets->tls_server_handshake_traffic_secret_len = hash_length;
1010 }
1011
1012 return(NX_SUCCESS);
1013 }
1014 #endif
1015
1016 /**************************************************************************/
1017 /* */
1018 /* FUNCTION RELEASE */
1019 /* */
1020 /* _nx_secure_tls_1_3_generate_session_secrets PORTABLE C */
1021 /* 6.1 */
1022 /* AUTHOR */
1023 /* */
1024 /* Timothy Stapko, Microsoft Corporation */
1025 /* */
1026 /* DESCRIPTION */
1027 /* */
1028 /* This function is used by TLS 1.3 in generating key material. */
1029 /* */
1030 /* INPUT */
1031 /* */
1032 /* tls_session TLS control block */
1033 /* */
1034 /* OUTPUT */
1035 /* */
1036 /* status Completion status */
1037 /* */
1038 /* CALLS */
1039 /* */
1040 /* */
1041 /* CALLED BY */
1042 /* */
1043 /* */
1044 /* RELEASE HISTORY */
1045 /* */
1046 /* DATE NAME DESCRIPTION */
1047 /* */
1048 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
1049 /* 09-30-2020 Timothy Stapko Modified comment(s), */
1050 /* resulting in version 6.1 */
1051 /* */
1052 /**************************************************************************/
1053 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
1054
_nx_secure_tls_1_3_generate_session_secrets(NX_SECURE_TLS_SESSION * tls_session)1055 static UINT _nx_secure_tls_1_3_generate_session_secrets(NX_SECURE_TLS_SESSION *tls_session)
1056 {
1057 UINT status;
1058 NX_SECURE_TLS_KEY_SECRETS *secrets;
1059 UINT hash_length;
1060 const NX_CRYPTO_METHOD *hash_method;
1061 UCHAR *label;
1062 UINT label_length;
1063 UCHAR (*transcript_hashes)[NX_SECURE_TLS_MAX_HASH_SIZE] = tls_session->nx_secure_tls_key_material.nx_secure_tls_transcript_hashes;
1064
1065
1066
1067 if (tls_session -> nx_secure_tls_session_ciphersuite == NX_NULL)
1068 {
1069 /* Likely internal error since at this point ciphersuite negotiation was theoretically completed. */
1070 return(NX_SECURE_TLS_UNKNOWN_CIPHERSUITE);
1071 }
1072
1073 /* Get the hash method so we know how much data we are generating. */
1074 hash_method = tls_session -> nx_secure_tls_session_ciphersuite -> nx_secure_tls_hash;
1075 hash_length = (hash_method->nx_crypto_ICV_size_in_bits >> 3);
1076
1077 /* Get a pointer to our key secrets for this session. */
1078 secrets = &tls_session->nx_secure_tls_key_material.nx_secure_tls_key_secrets;
1079
1080 /* Make sure our zeroes string is initialized. */
1081 NX_SECURE_MEMSET(_nx_secure_tls_zeroes, 0, sizeof(_nx_secure_tls_zeroes));
1082
1083 /* Application Master secret - special case! Needs a secret derived from the previous secret. */
1084 if(secrets->tls_master_secret_len == 0 && secrets->tls_handshake_secret_len != 0)
1085 {
1086 /* Start by deriving the salt from the handshake secret. Context is empty! */
1087 status = _nx_secure_tls_derive_secret(tls_session, secrets->tls_handshake_secret, secrets->tls_handshake_secret_len, (UCHAR *)"derived", 7,
1088 (UCHAR *)"", 0,
1089 secrets->tls_master_secret, hash_length, hash_method);
1090
1091 if(status != NX_SUCCESS)
1092 {
1093 return(status);
1094 }
1095
1096 /* Now perform an HKDF-Extract to get the application master secret.
1097 Salt: derived secret from above, IKM: 0 string */
1098 status = _nx_secure_tls_hkdf_extract(tls_session, secrets->tls_master_secret, hash_length,
1099 _nx_secure_tls_zeroes, hash_length,
1100 secrets->tls_master_secret, hash_length, hash_method);
1101
1102 if(status != NX_SUCCESS)
1103 {
1104 return(status);
1105 }
1106 secrets->tls_master_secret_len = hash_length;
1107 }
1108
1109 /* Derive secrets based on the application master secret. */
1110 if(secrets->tls_master_secret_len != 0)
1111 {
1112 /*----- Client application traffic secret 0. -----*/
1113 label = (UCHAR *)"c ap traffic";
1114 label_length = 12;
1115
1116 status = _nx_secure_tls_derive_secret(tls_session, secrets->tls_master_secret, secrets->tls_master_secret_len, label, label_length,
1117 transcript_hashes[NX_SECURE_TLS_TRANSCRIPT_IDX_SERVER_FINISHED], hash_length,
1118 secrets->tls_client_application_traffic_secret_0, hash_length, hash_method);
1119
1120 if(status != NX_SUCCESS)
1121 {
1122 return(status);
1123 }
1124 secrets->tls_client_application_traffic_secret_0_len = hash_length;
1125
1126 /*----- Server application traffic secret 0. -----*/
1127 label = (UCHAR *)"s ap traffic";
1128 label_length = 12;
1129
1130 status = _nx_secure_tls_derive_secret(tls_session, secrets->tls_master_secret, secrets->tls_master_secret_len, label, label_length,
1131 transcript_hashes[NX_SECURE_TLS_TRANSCRIPT_IDX_SERVER_FINISHED], hash_length,
1132 secrets->tls_server_application_traffic_secret_0, hash_length, hash_method);
1133
1134 if(status != NX_SUCCESS)
1135 {
1136 return(status);
1137 }
1138 secrets->tls_server_application_traffic_secret_0_len = hash_length;
1139
1140 /*----- Exporter master secret. -----*/
1141 label = (UCHAR *)"exp master";
1142 label_length = 10;
1143
1144 status = _nx_secure_tls_derive_secret(tls_session, secrets->tls_master_secret, secrets->tls_master_secret_len, label, label_length,
1145 transcript_hashes[NX_SECURE_TLS_TRANSCRIPT_IDX_SERVER_FINISHED], hash_length,
1146 secrets->tls_exporter_master_secret, hash_length, hash_method);
1147
1148 if(status != NX_SUCCESS)
1149 {
1150 return(status);
1151 }
1152 secrets->tls_early_exporter_master_secret_len = hash_length;
1153
1154 /*----- Resumption master secret. -----*/
1155 label = (UCHAR *)"res master";
1156 label_length = 10;
1157
1158 status = _nx_secure_tls_derive_secret(tls_session, secrets->tls_master_secret, secrets->tls_master_secret_len, label, label_length,
1159 transcript_hashes[NX_SECURE_TLS_TRANSCRIPT_IDX_CLIENT_FINISHED], hash_length,
1160 secrets->tls_resumption_master_secret, hash_length, hash_method);
1161
1162 if(status != NX_SUCCESS)
1163 {
1164 return(status);
1165 }
1166 secrets->tls_resumption_master_secret_len = hash_length;
1167
1168
1169 }
1170
1171 return(NX_SUCCESS);
1172 }
1173 #endif
1174
1175 /**************************************************************************/
1176 /* */
1177 /* FUNCTION RELEASE */
1178 /* */
1179 /* _nx_secure_tls_derive_secret PORTABLE C */
1180 /* 6.1 */
1181 /* AUTHOR */
1182 /* */
1183 /* Timothy Stapko, Microsoft Corporation */
1184 /* */
1185 /* DESCRIPTION */
1186 /* */
1187 /* This function is used by TLS 1.3 in generating key material. */
1188 /* */
1189 /* INPUT */
1190 /* */
1191 /* tls_session TLS control block */
1192 /* */
1193 /* OUTPUT */
1194 /* */
1195 /* status Completion status */
1196 /* */
1197 /* CALLS */
1198 /* */
1199 /* */
1200 /* CALLED BY */
1201 /* */
1202 /* */
1203 /* RELEASE HISTORY */
1204 /* */
1205 /* DATE NAME DESCRIPTION */
1206 /* */
1207 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
1208 /* 09-30-2020 Timothy Stapko Modified comment(s), */
1209 /* resulting in version 6.1 */
1210 /* */
1211 /**************************************************************************/
1212 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
1213
1214 static UCHAR _nx_secure_tls_temp_hash[100];
1215
_nx_secure_tls_derive_secret(NX_SECURE_TLS_SESSION * tls_session,UCHAR * secret,UINT secret_len,UCHAR * label,UINT label_len,UCHAR * message_hash,UINT message_hash_len,UCHAR * output,UINT output_length,const NX_CRYPTO_METHOD * hash_method)1216 static UINT _nx_secure_tls_derive_secret(NX_SECURE_TLS_SESSION *tls_session, UCHAR *secret, UINT secret_len,
1217 UCHAR *label, UINT label_len,
1218 UCHAR *message_hash, UINT message_hash_len,
1219 UCHAR *output, UINT output_length, const NX_CRYPTO_METHOD *hash_method)
1220 {
1221 UINT status;
1222 UINT hash_length;
1223
1224 /* From RFC 8446, section 7.1:
1225 Derive-Secret(Secret, Label, Messages) =
1226 HKDF-Expand-Label(Secret, Label,
1227 Transcript-Hash(Messages), Hash.length)
1228 */
1229
1230
1231 /* Get session hash routine. */
1232 hash_length = (hash_method->nx_crypto_ICV_size_in_bits >> 3);
1233
1234
1235 /* Our "messages" parameter is actually the ongoing hash of handshake
1236 messages stored in the TLS session context. In some contexts, the message hash will be of 0 length! */
1237 if(message_hash_len == 0)
1238 {
1239 /* Point the message hash at our temporary buffer. */
1240 message_hash = &_nx_secure_tls_temp_hash[0];
1241 message_hash_len = hash_length;
1242
1243 /* Context has 0 length, so generate a hash on the empty string to feed into expand label call below.
1244 * Utilize the temporary "hash scratch" data buffer to initialize and calculate the hash. */
1245 if (hash_method -> nx_crypto_init)
1246 {
1247 status = hash_method -> nx_crypto_init((NX_CRYPTO_METHOD*)hash_method,
1248 NX_NULL,
1249 0,
1250 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_handler,
1251 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_scratch,
1252 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_metadata_size);
1253
1254 if (status != NX_CRYPTO_SUCCESS)
1255 {
1256 return(status);
1257 }
1258 }
1259
1260 if (hash_method -> nx_crypto_operation != NX_NULL)
1261 {
1262 status = hash_method -> nx_crypto_operation(NX_CRYPTO_HASH_INITIALIZE,
1263 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_handler,
1264 (NX_CRYPTO_METHOD*)hash_method,
1265 NX_NULL,
1266 0,
1267 NX_NULL,
1268 0,
1269 NX_NULL,
1270 NX_NULL,
1271 0,
1272 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_scratch,
1273 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_metadata_size,
1274 NX_NULL,
1275 NX_NULL);
1276
1277 if (status != NX_CRYPTO_SUCCESS)
1278 {
1279 return(status);
1280 }
1281 }
1282
1283 if (hash_method -> nx_crypto_operation != NX_NULL)
1284 {
1285 status = hash_method -> nx_crypto_operation(NX_CRYPTO_HASH_UPDATE,
1286 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_handler,
1287 (NX_CRYPTO_METHOD*)hash_method,
1288 NX_NULL,
1289 0,
1290 (UCHAR *)"",
1291 0,
1292 NX_NULL,
1293 NX_NULL,
1294 0,
1295 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_scratch,
1296 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_metadata_size,
1297 NX_NULL,
1298 NX_NULL);
1299
1300 if (status != NX_CRYPTO_SUCCESS)
1301 {
1302 return(status);
1303 }
1304 }
1305
1306
1307
1308 /* Generate a hash using our temporary copy of the hash metadata, place it into the TLS Session transcript hash array. */
1309 if (hash_method -> nx_crypto_operation != NX_NULL)
1310 {
1311 status = hash_method -> nx_crypto_operation(NX_CRYPTO_HASH_CALCULATE,
1312 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_handler,
1313 (NX_CRYPTO_METHOD*)hash_method,
1314 NX_NULL,
1315 0,
1316 NX_NULL,
1317 0,
1318 NX_NULL,
1319 message_hash,
1320 hash_length,
1321 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_scratch,
1322 tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_metadata_size,
1323 NX_NULL,
1324 NX_NULL);
1325
1326 if (status != NX_CRYPTO_SUCCESS)
1327 {
1328 return(status);
1329 }
1330
1331 }
1332 }
1333
1334 /* Now derive the output by calling HKDF-Expand-Label. */
1335 status = _nx_secure_tls_hkdf_expand_label(tls_session, secret, secret_len,
1336 label, label_len, message_hash, message_hash_len, hash_length,
1337 output, output_length, hash_method);
1338
1339 return(status);
1340 }
1341
1342 #endif
1343
1344 /**************************************************************************/
1345 /* */
1346 /* FUNCTION RELEASE */
1347 /* */
1348 /* _nx_secure_tls_hkdf_expand_label PORTABLE C */
1349 /* 6.1 */
1350 /* AUTHOR */
1351 /* */
1352 /* Timothy Stapko, Microsoft Corporation */
1353 /* */
1354 /* DESCRIPTION */
1355 /* */
1356 /* This function is used by TLS 1.3 in generating key material. */
1357 /* */
1358 /* INPUT */
1359 /* */
1360 /* tls_session TLS control block */
1361 /* */
1362 /* OUTPUT */
1363 /* */
1364 /* status Completion status */
1365 /* */
1366 /* CALLS */
1367 /* */
1368 /* */
1369 /* CALLED BY */
1370 /* */
1371 /* */
1372 /* RELEASE HISTORY */
1373 /* */
1374 /* DATE NAME DESCRIPTION */
1375 /* */
1376 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
1377 /* 09-30-2020 Timothy Stapko Modified comment(s), */
1378 /* verified memcpy use cases, */
1379 /* resulting in version 6.1 */
1380 /* */
1381 /**************************************************************************/
1382 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
1383
1384 /* Buffer for HKDF output. The HKDF temporary can technically be as big as
1385 514 bytes: 2 (length) + 1 (label length byte) + 255 (label) + 1 (context length byte) + 255 (context).
1386 However, 100 bytes is sufficient for the mandatory ciphersuite. */
1387 static UCHAR _nx_secure_tls_hkdf_temp_output[100];
_nx_secure_tls_hkdf_expand_label(NX_SECURE_TLS_SESSION * tls_session,UCHAR * secret,UINT secret_len,UCHAR * label,UINT label_len,UCHAR * context,UINT context_len,UINT length,UCHAR * output,UINT output_length,const NX_CRYPTO_METHOD * hash_method)1388 static UINT _nx_secure_tls_hkdf_expand_label(NX_SECURE_TLS_SESSION *tls_session, UCHAR *secret, UINT secret_len,
1389 UCHAR *label, UINT label_len, UCHAR *context, UINT context_len, UINT length,
1390 UCHAR *output, UINT output_length, const NX_CRYPTO_METHOD *hash_method)
1391 {
1392 UINT status;
1393 UINT data_len;
1394 const NX_CRYPTO_METHOD *session_hkdf_method = NX_NULL;
1395 const NX_CRYPTO_METHOD *session_hmac_method = NX_NULL;
1396
1397 /*VOID *handler = NX_NULL;*/
1398 /* From RFC 8446, section 7.1:
1399 HKDF-Expand-Label(Secret, Label, Context, Length) =
1400 HKDF-Expand(Secret, HkdfLabel, Length)
1401
1402 Where HkdfLabel is specified as:
1403
1404 struct {
1405 uint16 length = Length;
1406 opaque label<7..255> = "tls13 " + Label;
1407 opaque context<0..255> = Context;
1408 } HkdfLabel;
1409 */
1410
1411 if (sizeof(_nx_secure_tls_hkdf_temp_output) < (10u + label_len + context_len))
1412 {
1413
1414 /* Buffer too small. */
1415 return(NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL);
1416 }
1417
1418 /* Get our HKDF method and hash routine. */
1419 /*session_hash_method = ciphersuite->nx_secure_tls_hash;*/
1420 session_hkdf_method = tls_session->nx_secure_tls_crypto_table->nx_secure_tls_hkdf_method;
1421 session_hmac_method = tls_session->nx_secure_tls_crypto_table->nx_secure_tls_hmac_method;
1422
1423 /* Now build the HkdfLabel from our inputs. */
1424 _nx_secure_tls_hkdf_temp_output[0] = (UCHAR)((length & 0xFF00) >> 8);
1425 _nx_secure_tls_hkdf_temp_output[1] = (UCHAR)(length & 0x00FF);
1426 data_len = 2;
1427
1428 /* Add the length of the label (single octet). */
1429 _nx_secure_tls_hkdf_temp_output[data_len] = (UCHAR)(6 + label_len);
1430 data_len = data_len + 1;
1431
1432 /* Now copy in label with TLS 1.3 prefix. */
1433 NX_CRYPTO_MEMCPY(&_nx_secure_tls_hkdf_temp_output[data_len], "tls13 ", 6); /* Use case of memcpy is verified. */
1434 data_len += 6;
1435 NX_CRYPTO_MEMCPY(&_nx_secure_tls_hkdf_temp_output[data_len], label, label_len); /* Use case of memcpy is verified. */
1436 data_len += label_len;
1437
1438 /* Add the length of the context (single octet). */
1439 _nx_secure_tls_hkdf_temp_output[data_len] = (UCHAR)(context_len);
1440 data_len = data_len + 1;
1441
1442 /* Now copy in context. */
1443 NX_CRYPTO_MEMCPY(&_nx_secure_tls_hkdf_temp_output[data_len], context, context_len); /* Use case of memcpy is verified. */
1444 data_len += context_len;
1445
1446
1447 /* Initialize the HKDF context. */
1448 status = session_hkdf_method->nx_crypto_init((NX_CRYPTO_METHOD*)session_hkdf_method, NX_NULL, 0, NX_NULL,
1449 tls_session -> nx_secure_tls_prf_metadata_area,
1450 tls_session -> nx_secure_tls_prf_metadata_size);
1451
1452 if(status != NX_CRYPTO_SUCCESS)
1453 {
1454 return(status);
1455 }
1456
1457 /* Set the hash and HMAC routines for the HKDF. */
1458 status = session_hkdf_method->nx_crypto_operation(NX_CRYPTO_HKDF_SET_HMAC, NX_NULL, (NX_CRYPTO_METHOD*)session_hmac_method,
1459 NX_NULL, 0, NX_NULL, 0, NX_NULL, NX_NULL, 0,
1460 tls_session -> nx_secure_tls_prf_metadata_area,
1461 tls_session -> nx_secure_tls_prf_metadata_size,
1462 NX_NULL, NX_NULL);
1463
1464 if(status != NX_CRYPTO_SUCCESS)
1465 {
1466 return(status);
1467 }
1468
1469 status = session_hkdf_method->nx_crypto_operation(NX_CRYPTO_HKDF_SET_HASH, NX_NULL,
1470 (NX_CRYPTO_METHOD*)hash_method,
1471 NX_NULL, 0,NX_NULL, 0, NX_NULL, NX_NULL, 0,
1472 tls_session -> nx_secure_tls_prf_metadata_area,
1473 tls_session -> nx_secure_tls_prf_metadata_size,
1474 NX_NULL, NX_NULL);
1475
1476 if(status != NX_CRYPTO_SUCCESS)
1477 {
1478 return(status);
1479 }
1480
1481 /* Set the PRK for the HKDF-expand operation. */
1482 status = session_hkdf_method->nx_crypto_operation(NX_CRYPTO_HKDF_SET_PRK,
1483 NX_NULL,
1484 (NX_CRYPTO_METHOD*)session_hkdf_method,
1485 (UCHAR*)(secret), /* Input HKDF label. */
1486 (secret_len << 3),
1487 NX_NULL,
1488 0,
1489 NX_NULL,
1490 NX_NULL,
1491 0,
1492 tls_session -> nx_secure_tls_prf_metadata_area,
1493 tls_session -> nx_secure_tls_prf_metadata_size,
1494 NX_NULL, NX_NULL);
1495
1496 if(status != NX_CRYPTO_SUCCESS)
1497 {
1498 return(status);
1499 }
1500
1501 /* Now perform the HKDF operation. */
1502 status = session_hkdf_method->nx_crypto_operation(NX_CRYPTO_HKDF_EXPAND,
1503 NX_NULL,
1504 (NX_CRYPTO_METHOD*)session_hkdf_method,
1505 (UCHAR*)(_nx_secure_tls_hkdf_temp_output), /* Input HKDF label. */
1506 (data_len << 3),
1507 NX_NULL,
1508 0,
1509 NX_NULL,
1510 (UCHAR *)output,
1511 output_length,
1512 tls_session -> nx_secure_tls_prf_metadata_area,
1513 tls_session -> nx_secure_tls_prf_metadata_size,
1514 NX_NULL, NX_NULL);
1515
1516 return(status);
1517 }
1518 #endif
1519
1520
1521 /**************************************************************************/
1522 /* */
1523 /* FUNCTION RELEASE */
1524 /* */
1525 /* _nx_secure_tls_hkdf_extract PORTABLE C */
1526 /* 6.1 */
1527 /* AUTHOR */
1528 /* */
1529 /* Timothy Stapko, Microsoft Corporation */
1530 /* */
1531 /* DESCRIPTION */
1532 /* */
1533 /* This function is used by TLS 1.3 in generating key material. */
1534 /* */
1535 /* INPUT */
1536 /* */
1537 /* tls_session TLS control block */
1538 /* salt HKDF salt parameter */
1539 /* salt_len Length of salt */
1540 /* ikm HKDF input key material */
1541 /* ikm_len Length of IKM */
1542 /* output Output buffer */
1543 /* output_length Desired output length */
1544 /* hash_method Hash routine for HMAC */
1545 /* */
1546 /* OUTPUT */
1547 /* */
1548 /* status Completion status */
1549 /* */
1550 /* CALLS */
1551 /* */
1552 /* */
1553 /* CALLED BY */
1554 /* */
1555 /* */
1556 /* RELEASE HISTORY */
1557 /* */
1558 /* DATE NAME DESCRIPTION */
1559 /* */
1560 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
1561 /* 09-30-2020 Timothy Stapko Modified comment(s), */
1562 /* resulting in version 6.1 */
1563 /* */
1564 /**************************************************************************/
1565 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
1566
1567 /*static UCHAR _nx_secure_tls_hkdf_label[524];*/
1568
_nx_secure_tls_hkdf_extract(NX_SECURE_TLS_SESSION * tls_session,UCHAR * salt,UINT salt_len,UCHAR * ikm,UINT ikm_len,UCHAR * output,UINT output_length,const NX_CRYPTO_METHOD * hash_method)1569 static UINT _nx_secure_tls_hkdf_extract(NX_SECURE_TLS_SESSION *tls_session, UCHAR *salt, UINT salt_len,
1570 UCHAR *ikm, UINT ikm_len, UCHAR *output, UINT output_length, const NX_CRYPTO_METHOD *hash_method)
1571 {
1572 UINT status;
1573 const NX_CRYPTO_METHOD *session_hkdf_method = NX_NULL;
1574 const NX_CRYPTO_METHOD *session_hmac_method = NX_NULL;
1575
1576
1577 /* Get our HKDF method and hash routine. */
1578 session_hkdf_method = tls_session->nx_secure_tls_crypto_table->nx_secure_tls_hkdf_method;
1579 session_hmac_method = tls_session->nx_secure_tls_crypto_table->nx_secure_tls_hmac_method;
1580
1581 /* Initialize the HKDF context with our IKM. */
1582 status = session_hkdf_method->nx_crypto_init((NX_CRYPTO_METHOD*)session_hkdf_method, ikm, ikm_len << 3, NX_NULL,
1583 tls_session -> nx_secure_tls_prf_metadata_area,
1584 tls_session -> nx_secure_tls_prf_metadata_size);
1585
1586 if(status != NX_CRYPTO_SUCCESS)
1587 {
1588 return(status);
1589 }
1590
1591 /* Set the hash and HMAC routines for the HKDF. */
1592 status = session_hkdf_method->nx_crypto_operation(NX_CRYPTO_HKDF_SET_HMAC, NX_NULL, (NX_CRYPTO_METHOD*)session_hmac_method,
1593 NX_NULL, 0, NX_NULL, 0, NX_NULL, NX_NULL, 0,
1594 tls_session -> nx_secure_tls_prf_metadata_area,
1595 tls_session -> nx_secure_tls_prf_metadata_size,
1596 NX_NULL, NX_NULL);
1597
1598 if(status != NX_CRYPTO_SUCCESS)
1599 {
1600 return(status);
1601 }
1602
1603 status = session_hkdf_method->nx_crypto_operation(NX_CRYPTO_HKDF_SET_HASH, NX_NULL,
1604 (NX_CRYPTO_METHOD*)hash_method,
1605 NX_NULL, 0,NX_NULL, 0, NX_NULL, NX_NULL, 0,
1606 tls_session -> nx_secure_tls_prf_metadata_area,
1607 tls_session -> nx_secure_tls_prf_metadata_size,
1608 NX_NULL, NX_NULL);
1609
1610 if(status != NX_CRYPTO_SUCCESS)
1611 {
1612 return(status);
1613 }
1614
1615 /* Now perform the HKDF operation. */
1616 status = session_hkdf_method->nx_crypto_operation(NX_CRYPTO_HKDF_EXTRACT,
1617 NX_NULL,
1618 (NX_CRYPTO_METHOD*)session_hkdf_method,
1619 salt,
1620 salt_len << 3,
1621 ikm,
1622 ikm_len,
1623 NX_NULL,
1624 (UCHAR *)output,
1625 output_length,
1626 tls_session -> nx_secure_tls_prf_metadata_area,
1627 tls_session -> nx_secure_tls_prf_metadata_size,
1628 NX_NULL, NX_NULL);
1629
1630 return(status);
1631 }
1632 #endif
1633
1634
1635