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 Crypto Component */
16 /** */
17 /** Transport Layer Security (TLS) */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22
23 #include "nx_crypto_tls_prf_1.h"
24
25 /**************************************************************************/
26 /* */
27 /* FUNCTION RELEASE */
28 /* */
29 /* _nx_crypto_method_prf_1_init PORTABLE C */
30 /* 6.3.0 */
31 /* AUTHOR */
32 /* */
33 /* Timothy Stapko, Microsoft Corporation */
34 /* */
35 /* DESCRIPTION */
36 /* */
37 /* This function initializes the PRF crypto module with SHA-1. */
38 /* */
39 /* INPUT */
40 /* */
41 /* method Crypto Method Object */
42 /* key Key */
43 /* key_size_in_bits Size of the key, in bits */
44 /* handle Handle, specified by user */
45 /* crypto_metadata Metadata area */
46 /* crypto_metadata_size Size of the metadata area */
47 /* */
48 /* OUTPUT */
49 /* */
50 /* status Completion status */
51 /* */
52 /* CALLS */
53 /* */
54 /* None */
55 /* */
56 /* CALLED BY */
57 /* */
58 /* Application Code */
59 /* */
60 /* RELEASE HISTORY */
61 /* */
62 /* DATE NAME DESCRIPTION */
63 /* */
64 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
65 /* 09-30-2020 Timothy Stapko Modified comment(s), */
66 /* resulting in version 6.1 */
67 /* 10-31-2023 Yanwu Cai Modified comment(s), */
68 /* resulting in version 6.3.0 */
69 /* */
70 /**************************************************************************/
_nx_crypto_method_prf_1_init(struct NX_CRYPTO_METHOD_STRUCT * method,UCHAR * key,NX_CRYPTO_KEY_SIZE key_size_in_bits,VOID ** handle,VOID * crypto_metadata,ULONG crypto_metadata_size)71 NX_CRYPTO_KEEP UINT _nx_crypto_method_prf_1_init(struct NX_CRYPTO_METHOD_STRUCT *method,
72 UCHAR *key, NX_CRYPTO_KEY_SIZE key_size_in_bits,
73 VOID **handle,
74 VOID *crypto_metadata,
75 ULONG crypto_metadata_size)
76 {
77 NX_CRYPTO_TLS_PRF_1 *prf;
78 NX_CRYPTO_PHASH *phash;
79
80 NX_CRYPTO_PARAMETER_NOT_USED(handle);
81
82 NX_CRYPTO_STATE_CHECK
83
84 if ((method == NX_CRYPTO_NULL) || (key == NX_CRYPTO_NULL) || (crypto_metadata == NX_CRYPTO_NULL))
85 {
86 return(NX_CRYPTO_PTR_ERROR);
87 }
88
89 /* Verify the metadata address is 4-byte aligned. */
90 if((((ULONG)crypto_metadata) & 0x3) != 0)
91 {
92 return(NX_CRYPTO_PTR_ERROR);
93 }
94
95 if(crypto_metadata_size < sizeof(NX_CRYPTO_TLS_PRF_1))
96 {
97 return(NX_CRYPTO_PTR_ERROR);
98 }
99
100 /* Get our control block. */
101 prf = (NX_CRYPTO_TLS_PRF_1 *)crypto_metadata;
102 phash = &(prf -> nx_secure_tls_prf_phash_info);
103
104 /* Set the secret using the key value. */
105 phash -> nx_crypto_phash_secret = key;
106 /* This is the length of secret in bytes actually */
107 phash -> nx_crypto_phash_secret_length = key_size_in_bits;
108
109 return(NX_CRYPTO_SUCCESS);
110 }
111
112
113 /**************************************************************************/
114 /* */
115 /* FUNCTION RELEASE */
116 /* */
117 /* _nx_crypto_method_prf_1_cleanup PORTABLE C */
118 /* 6.1 */
119 /* AUTHOR */
120 /* */
121 /* Timothy Stapko, Microsoft Corporation */
122 /* */
123 /* DESCRIPTION */
124 /* */
125 /* This function cleans up the crypto metadata. */
126 /* */
127 /* INPUT */
128 /* */
129 /* crypto_metadata Crypto metadata */
130 /* */
131 /* OUTPUT */
132 /* */
133 /* status Completion status */
134 /* */
135 /* CALLS */
136 /* */
137 /* NX_CRYPTO_MEMSET Set the memory */
138 /* */
139 /* CALLED BY */
140 /* */
141 /* Application Code */
142 /* */
143 /* RELEASE HISTORY */
144 /* */
145 /* DATE NAME DESCRIPTION */
146 /* */
147 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
148 /* 09-30-2020 Timothy Stapko Modified comment(s), */
149 /* resulting in version 6.1 */
150 /* */
151 /**************************************************************************/
_nx_crypto_method_prf_1_cleanup(VOID * crypto_metadata)152 NX_CRYPTO_KEEP UINT _nx_crypto_method_prf_1_cleanup(VOID *crypto_metadata)
153 {
154
155 NX_CRYPTO_STATE_CHECK
156
157 #ifdef NX_SECURE_KEY_CLEAR
158 if (!crypto_metadata)
159 return (NX_CRYPTO_SUCCESS);
160
161 /* Clean up the crypto metadata. */
162 NX_CRYPTO_MEMSET(crypto_metadata, 0, sizeof(NX_CRYPTO_TLS_PRF_1));
163 #else
164 NX_CRYPTO_PARAMETER_NOT_USED(crypto_metadata);
165 #endif/* NX_SECURE_KEY_CLEAR */
166
167 return(NX_CRYPTO_SUCCESS);
168 }
169
170
171 /**************************************************************************/
172 /* */
173 /* FUNCTION RELEASE */
174 /* */
175 /* _nx_crypto_method_prf_1_operation PORTABLE C */
176 /* 6.3.0 */
177 /* AUTHOR */
178 /* */
179 /* Timothy Stapko, Microsoft Corporation */
180 /* */
181 /* DESCRIPTION */
182 /* */
183 /* This function encrypts and decrypts a message using */
184 /* the PRF SHA-1 algorithm. */
185 /* */
186 /* INPUT */
187 /* */
188 /* op PRF operation */
189 /* handle Crypto handle */
190 /* method Cryption Method Object */
191 /* key Encryption Key */
192 /* key_size_in_bits Key size in bits */
193 /* input Input data */
194 /* input_length_in_byte Input data size */
195 /* iv_ptr Initial vector */
196 /* output Output buffer */
197 /* output_length_in_byte Output buffer size */
198 /* crypto_metadata Metadata area */
199 /* crypto_metadata_size Metadata area size */
200 /* packet_ptr Pointer to packet */
201 /* nx_crypto_hw_process_callback Callback function pointer */
202 /* */
203 /* OUTPUT */
204 /* */
205 /* status Completion status */
206 /* */
207 /* CALLS */
208 /* */
209 /* _nx_crypto_tls_prf_1 Implement the TLS PRF */
210 /* using SHA-1 */
211 /* */
212 /* CALLED BY */
213 /* */
214 /* Application Code */
215 /* */
216 /* RELEASE HISTORY */
217 /* */
218 /* DATE NAME DESCRIPTION */
219 /* */
220 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
221 /* 09-30-2020 Timothy Stapko Modified comment(s), improved */
222 /* buffer length verification, */
223 /* verified memcpy use cases, */
224 /* resulting in version 6.1 */
225 /* 10-31-2023 Yanwu Cai Modified comment(s), */
226 /* resulting in version 6.3.0 */
227 /* */
228 /**************************************************************************/
_nx_crypto_method_prf_1_operation(UINT op,VOID * handle,struct NX_CRYPTO_METHOD_STRUCT * method,UCHAR * key,NX_CRYPTO_KEY_SIZE key_size_in_bits,UCHAR * input,ULONG input_length_in_byte,UCHAR * iv_ptr,UCHAR * output,ULONG output_length_in_byte,VOID * crypto_metadata,ULONG crypto_metadata_size,VOID * packet_ptr,VOID (* nx_crypto_hw_process_callback)(VOID * packet_ptr,UINT status))229 NX_CRYPTO_KEEP UINT _nx_crypto_method_prf_1_operation(UINT op, /* Encrypt, Decrypt, Authenticate */
230 VOID *handle, /* Crypto handler */
231 struct NX_CRYPTO_METHOD_STRUCT *method,
232 UCHAR *key,
233 NX_CRYPTO_KEY_SIZE key_size_in_bits,
234 UCHAR *input,
235 ULONG input_length_in_byte,
236 UCHAR *iv_ptr,
237 UCHAR *output,
238 ULONG output_length_in_byte,
239 VOID *crypto_metadata,
240 ULONG crypto_metadata_size,
241 VOID *packet_ptr,
242 VOID (*nx_crypto_hw_process_callback)(VOID *packet_ptr, UINT status))
243 {
244 UINT status, secret_len;
245 UCHAR *secret_half_point;
246 NX_CRYPTO_TLS_PRF_1 *prf;
247 NX_CRYPTO_PHASH *phash;
248
249 NX_CRYPTO_PARAMETER_NOT_USED(handle);
250 NX_CRYPTO_PARAMETER_NOT_USED(iv_ptr);
251 NX_CRYPTO_PARAMETER_NOT_USED(packet_ptr);
252 NX_CRYPTO_PARAMETER_NOT_USED(nx_crypto_hw_process_callback);
253
254 NX_CRYPTO_STATE_CHECK
255
256 /* Verify the metadata address is 4-byte aligned. */
257 if((method == NX_CRYPTO_NULL) || (key == NX_CRYPTO_NULL) || (crypto_metadata == NX_CRYPTO_NULL) || ((((ULONG)crypto_metadata) & 0x3) != 0))
258 {
259 return(NX_CRYPTO_PTR_ERROR);
260 }
261
262 if(crypto_metadata_size < sizeof(NX_CRYPTO_TLS_PRF_1))
263 {
264 return(NX_CRYPTO_PTR_ERROR);
265 }
266
267 /* This must be a PRF operation. */
268 if (op != NX_CRYPTO_PRF)
269 {
270 return(NX_CRYPTO_NOT_SUCCESSFUL);
271 }
272
273 /* Get our control block. */
274 prf = (NX_CRYPTO_TLS_PRF_1 *)crypto_metadata;
275 phash = &(prf -> nx_secure_tls_prf_phash_info);
276
277 /* Install the label_seed_buffer to the phash structure as the buffer of phash seed. */
278 phash -> nx_crypto_phash_seed = prf -> nx_secure_tls_prf_label_seed_buffer;
279 if ((key_size_in_bits + input_length_in_byte) > sizeof(prf -> nx_secure_tls_prf_label_seed_buffer))
280 {
281 return(NX_CRYPTO_SIZE_ERROR);
282 }
283
284 /* Concatenate label and seed. */
285 NX_CRYPTO_MEMCPY(phash -> nx_crypto_phash_seed, key, key_size_in_bits); /* Use case of memcpy is verified. */
286 NX_CRYPTO_MEMCPY(&phash -> nx_crypto_phash_seed[key_size_in_bits], input, input_length_in_byte); /* Use case of memcpy is verified. */
287 phash -> nx_crypto_phash_seed_length = key_size_in_bits + input_length_in_byte;
288
289 /* Install the temp_A_buffer to the phash structure. */
290 phash -> nx_crypto_phash_temp_A = prf -> nx_secure_tls_prf_temp_A_buffer;
291 phash -> nx_crypto_phash_temp_A_size = sizeof(prf -> nx_secure_tls_prf_temp_A_buffer);
292
293 /* Install metadata buffer for the hmac method. */
294 phash -> nx_crypto_hmac_metadata = prf -> nx_secure_tls_prf_hmac_metadata_area;
295 phash -> nx_crypto_hmac_metadata_size = sizeof(prf -> nx_secure_tls_prf_hmac_metadata_area);
296
297 /* Install the buffer for hmac output. */
298 phash -> nx_crypto_hmac_output = prf -> nx_secure_tls_prf_temp_hmac_output_buffer;
299 phash -> nx_crypto_hmac_output_size = sizeof(prf -> nx_secure_tls_prf_temp_hmac_output_buffer);
300
301 /* SHA1 first. */
302 /* Clear the output buffer for the generic phash routine will show the output by XOR. */
303 NX_CRYPTO_MEMSET(output, 0, output_length_in_byte);
304
305 /* Install the hmac method to the phash structure. */
306 phash -> nx_crypto_hmac_method = &crypto_method_hmac_md5;
307
308 /* Calculate secret half-length. */
309 secret_len = (phash -> nx_crypto_phash_secret_length + 1) / 2;
310
311 /* Find the offset of the half-way point. If the size of the secret is not even, overlap
312 the last byte of the first half and first byte of the second half. */
313 if (phash -> nx_crypto_phash_secret_length % 2)
314 {
315 /* Length is odd - overlap a byte. */
316 secret_half_point = &(phash -> nx_crypto_phash_secret[secret_len - 1]);
317 }
318 else
319 {
320 /* Evenly divisible, offset is just after the half-length. */
321 secret_half_point = &(phash -> nx_crypto_phash_secret[secret_len]);
322 }
323
324 /* Update secret length. */
325 phash -> nx_crypto_phash_secret_length = secret_len;
326
327 status = _nx_crypto_phash(phash, output, output_length_in_byte);
328
329 if (status)
330 {
331 return status;
332 }
333
334 /* Install the hmac method to the phash structure. */
335 phash -> nx_crypto_hmac_method = &crypto_method_hmac_sha1;
336
337 /* Take use of the second half of the secret. */
338 phash -> nx_crypto_phash_secret = secret_half_point;
339
340 /* Do not clear the output buffer this time. */
341 status = _nx_crypto_phash(phash, output, output_length_in_byte);
342
343 return status;
344 }
345
346