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 
25 #include "nx_secure_tls.h"
26 
27 /**************************************************************************/
28 /*                                                                        */
29 /*  FUNCTION                                               RELEASE        */
30 /*                                                                        */
31 /*    _nx_secure_session_keys_set                         PORTABLE C      */
32 /*                                                           6.2.0        */
33 /*  AUTHOR                                                                */
34 /*                                                                        */
35 /*    Yanwu Cai, Microsoft Corporation                                    */
36 /*                                                                        */
37 /*  DESCRIPTION                                                           */
38 /*                                                                        */
39 /*    This function sets the session keys for a TLS session following the */
40 /*    sending or receiving of a ChangeCipherSpec message. In              */
41 /*    renegotiation handshakes, two separate set of session keys will be  */
42 /*    in use simultaneously so we need this to be able to separate which  */
43 /*    keys are actually in use.                                           */
44 /*                                                                        */
45 /*    Once the keys are set, this function initializes the appropriate    */
46 /*    session cipher with the new key set.                                */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    ciphersuite                           Selected cipher suite         */
51 /*    tls_key_material                      TLS key material              */
52 /*    key_material_data_size                Length of key material        */
53 /*    is_client                             Indicate keys for client      */
54 /*    session_cipher_initialized            Whether cipher is initialized */
55 /*    session_cipher_metadata               Metadata for session cipher   */
56 /*    session_cipher_handler                Session cipher handler        */
57 /*    session_cipher_metadata_size          Size of session metadata      */
58 /*                                                                        */
59 /*  OUTPUT                                                                */
60 /*                                                                        */
61 /*    status                                Completion status             */
62 /*                                                                        */
63 /*  CALLS                                                                 */
64 /*                                                                        */
65 /*    [nx_crypto_init]                      Initialize crypto             */
66 /*                                                                        */
67 /*  CALLED BY                                                             */
68 /*                                                                        */
69 /*    _nx_secure_tls_session_keys_set       Set session keys              */
70 /*                                                                        */
71 /*  RELEASE HISTORY                                                       */
72 /*                                                                        */
73 /*    DATE              NAME                      DESCRIPTION             */
74 /*                                                                        */
75 /*  10-31-2022     Yanwu Cai                Initial Version 6.2.0         */
76 /*                                                                        */
77 /**************************************************************************/
_nx_secure_session_keys_set(const NX_SECURE_TLS_CIPHERSUITE_INFO * ciphersuite,NX_SECURE_TLS_KEY_MATERIAL * tls_key_material,UINT key_material_data_size,UINT is_client,UCHAR * session_cipher_initialized,VOID * session_cipher_metadata,VOID ** session_cipher_handler,ULONG session_cipher_metadata_size)78 UINT _nx_secure_session_keys_set(const NX_SECURE_TLS_CIPHERSUITE_INFO *ciphersuite, NX_SECURE_TLS_KEY_MATERIAL *tls_key_material,
79                                  UINT key_material_data_size, UINT is_client, UCHAR *session_cipher_initialized,
80                                  VOID *session_cipher_metadata, VOID **session_cipher_handler, ULONG session_cipher_metadata_size)
81 {
82 UINT                    status;
83 UCHAR                  *key_block;     /* Maximum ciphersuite key size - AES_256_CBC_SHA, 2x32 byte keys + 2x20 byte MAC secrets + 2x16 IVs. */
84 UINT                    key_size;
85 UINT                    hash_size;
86 UINT                    iv_size;
87 UINT                    key_offset;
88 UCHAR                  *write_key;
89 const NX_CRYPTO_METHOD *session_cipher_method = NX_NULL;
90 
91     /* The key material should have already been generated by nx_secure_tls_generate_keys once all
92      * key generation data was available. This simply switches the appropriate key data over to the active
93      * key block */
94 
95     /* Working pointers into our key material blocks. */
96     key_block = tls_key_material -> nx_secure_tls_key_material_data;
97 
98     /* Get our session cipher method so we can get key sizes. */
99     session_cipher_method = ciphersuite -> nx_secure_tls_session_cipher;
100 
101     /* Lookup ciphersuite data for key size. We need 2 keys for each session. */
102     key_size = session_cipher_method -> nx_crypto_key_size_in_bits >> 3;
103 
104     /* Lookup ciphersuite data for hash size - used for the MAC secret. */
105     hash_size = ciphersuite -> nx_secure_tls_hash_size;
106 
107     /* Lookup initialization vector size.  */
108     iv_size = session_cipher_method -> nx_crypto_IV_size_in_bits >> 3;
109 
110     /* Partition the key block into our keys and secrets following the TLS spec.*/
111     key_offset = 0;
112 
113     if (((hash_size + key_size + iv_size) << 1) > key_material_data_size)
114     {
115 
116         /* No space for key material data. */
117         return(NX_SECURE_TLS_CRYPTO_KEYS_TOO_LARGE);
118     }
119 
120     /* First, the mac secrets. Check for non-zero in the (unlikely) event we are using a NULL hash. */
121     if (hash_size > 0)
122     {
123 
124         /* Copy new client mac secret over if setting client keys. */
125         if (is_client)
126         {
127             NX_SECURE_MEMCPY(&tls_key_material -> nx_secure_tls_key_material_data[key_offset],
128                              &tls_key_material -> nx_secure_tls_new_key_material_data[key_offset], hash_size); /* Use case of memcpy is verified. */
129         }
130         tls_key_material -> nx_secure_tls_client_write_mac_secret = key_block + key_offset;
131         key_offset += hash_size;
132 
133         /* Copy new server mac secret if setting server keys. */
134         if (!is_client)
135         {
136             NX_SECURE_MEMCPY(&tls_key_material -> nx_secure_tls_key_material_data[key_offset],
137                              &tls_key_material -> nx_secure_tls_new_key_material_data[key_offset], hash_size); /* Use case of memcpy is verified. */
138         }
139         tls_key_material -> nx_secure_tls_server_write_mac_secret = key_block + key_offset;
140         key_offset += hash_size;
141     }
142 
143     /* Now the keys. Check for non-zero size in the event we are using a NULL cipher (usually for debugging). */
144     if (key_size > 0)
145     {
146         /* Copy new client session key if setting client keys. */
147         if (is_client)
148         {
149             NX_SECURE_MEMCPY(&tls_key_material -> nx_secure_tls_key_material_data[key_offset],
150                              &tls_key_material -> nx_secure_tls_new_key_material_data[key_offset], key_size); /* Use case of memcpy is verified. */
151         }
152         tls_key_material -> nx_secure_tls_client_write_key = key_block + key_offset;
153         key_offset += key_size;
154 
155         /* Copy new server session key if setting server keys. */
156         if (!is_client)
157         {
158             NX_SECURE_MEMCPY(&tls_key_material -> nx_secure_tls_key_material_data[key_offset],
159                              &tls_key_material -> nx_secure_tls_new_key_material_data[key_offset], key_size); /* Use case of memcpy is verified. */
160         }
161         tls_key_material -> nx_secure_tls_server_write_key = key_block + key_offset;
162         key_offset += key_size;
163     }
164 
165     /* Finally, the IVs. Many ciphers don't use IV's so the iv_size is often zero. */
166     if (iv_size > 0)
167     {
168         /* Copy new client IV if setting client keys. */
169         if (is_client)
170         {
171             NX_SECURE_MEMCPY(&tls_key_material -> nx_secure_tls_key_material_data[key_offset],
172                              &tls_key_material -> nx_secure_tls_new_key_material_data[key_offset], iv_size); /* Use case of memcpy is verified. */
173         }
174         tls_key_material -> nx_secure_tls_client_iv = key_block + key_offset;
175         key_offset += iv_size;
176 
177         /* Copy new server IV if setting server keys. */
178         if (!is_client)
179         {
180             NX_SECURE_MEMCPY(&tls_key_material -> nx_secure_tls_key_material_data[key_offset],
181                              &tls_key_material -> nx_secure_tls_new_key_material_data[key_offset], iv_size); /* Use case of memcpy is verified. */
182         }
183         tls_key_material -> nx_secure_tls_server_iv = key_block + key_offset;
184     }
185 
186     /* Initialize the crypto method used in the session cipher. */
187     if (session_cipher_method -> nx_crypto_init != NULL)
188     {
189         /* Set client write key. */
190         if (*session_cipher_initialized && session_cipher_method -> nx_crypto_cleanup)
191         {
192             status = session_cipher_method -> nx_crypto_cleanup(session_cipher_metadata);
193             if (status != NX_CRYPTO_SUCCESS)
194             {
195                 return(status);
196             }
197 
198             *session_cipher_initialized = 0;
199         }
200 
201         if (is_client)
202         {
203             write_key = tls_key_material -> nx_secure_tls_client_write_key;
204         }
205         else
206         {
207             write_key = tls_key_material -> nx_secure_tls_server_write_key;
208         }
209 
210         status = session_cipher_method -> nx_crypto_init((NX_CRYPTO_METHOD*)session_cipher_method,
211                                                          write_key,
212                                                          session_cipher_method -> nx_crypto_key_size_in_bits,
213                                                          session_cipher_handler,
214                                                          session_cipher_metadata,
215                                                          session_cipher_metadata_size);
216 
217         *session_cipher_initialized = 1;
218 
219         if(status != NX_CRYPTO_SUCCESS)
220         {
221             return(status);
222         }
223     }
224 
225     return(NX_SECURE_TLS_SUCCESS);
226 }
227 
228