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