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