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