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