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) */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define NX_SECURE_SOURCE_CODE
23
24 #include "nx_secure_tls.h"
25
26 /**************************************************************************/
27 /* */
28 /* FUNCTION RELEASE */
29 /* */
30 /* _nx_secure_tls_hash_record PORTABLE C */
31 /* 6.2.0 */
32 /* AUTHOR */
33 /* */
34 /* Timothy Stapko, Microsoft Corporation */
35 /* */
36 /* DESCRIPTION */
37 /* */
38 /* This function hashes an outgoing TLS record to generate the Message */
39 /* Authentication Code (MAC) value that is placed at the end of all */
40 /* encrypted TLS messages. */
41 /* */
42 /* INPUT */
43 /* */
44 /* tls_session TLS control block */
45 /* sequence_num Record sequence number */
46 /* header Record header */
47 /* header_length Length of record header */
48 /* packet_ptr TLS record packet */
49 /* offset Offset to TLS record in packet*/
50 /* length Length of payload data */
51 /* record_hash Pointer to output hash buffer */
52 /* hash_length Length of hash */
53 /* mac_secret Key used for MAC generation */
54 /* */
55 /* OUTPUT */
56 /* */
57 /* status Completion status */
58 /* */
59 /* CALLS */
60 /* */
61 /* [nx_crypto_operation] Crypto operation */
62 /* */
63 /* CALLED BY */
64 /* */
65 /* _nx_secure_tls_verify_mac Verify record MAC checksum */
66 /* */
67 /* RELEASE HISTORY */
68 /* */
69 /* DATE NAME DESCRIPTION */
70 /* */
71 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
72 /* 09-30-2020 Timothy Stapko Modified comment(s), */
73 /* supported chained packet, */
74 /* resulting in version 6.1 */
75 /* 06-02-2021 Timothy Stapko Modified comment(s), */
76 /* fixed compiler warning, */
77 /* resulting in version 6.1.7 */
78 /* 10-31-2022 Yanwu Cai Modified comment(s), */
79 /* adjusted parameters list, */
80 /* resulting in version 6.2.0 */
81 /* */
82 /**************************************************************************/
_nx_secure_tls_hash_record(const NX_SECURE_TLS_CIPHERSUITE_INFO * ciphersuite,ULONG sequence_num[NX_SECURE_TLS_SEQUENCE_NUMBER_SIZE],UCHAR * header,UINT header_length,NX_PACKET * packet_ptr,ULONG offset,UINT length,UCHAR * record_hash,UINT * hash_length,UCHAR * mac_secret,VOID * metadata,ULONG metadata_size)83 UINT _nx_secure_tls_hash_record(const NX_SECURE_TLS_CIPHERSUITE_INFO *ciphersuite,
84 ULONG sequence_num[NX_SECURE_TLS_SEQUENCE_NUMBER_SIZE],
85 UCHAR *header, UINT header_length, NX_PACKET *packet_ptr,
86 ULONG offset, UINT length, UCHAR *record_hash, UINT *hash_length,
87 UCHAR *mac_secret, VOID *metadata, ULONG metadata_size)
88 {
89 UINT hash_size;
90 UINT status = NX_SECURE_TLS_MISSING_CRYPTO_ROUTINE;
91 const NX_CRYPTO_METHOD *authentication_method;
92 UCHAR adjusted_sequence_num[8];
93 VOID *handler = NX_NULL;
94 ULONG current_length;
95
96 NX_PARAMETER_NOT_USED(header_length);
97
98 /* We need to generate a Message Authentication Code (MAC) for each record during an "active" TLS session
99 (following a ChangeCipherSpec message). The hash algorithm is determined by the ciphersuite, and HMAC
100 is used with that hash algorithm to protect the TLS record contents from tampering.
101
102 The MAC is generated as:
103
104 HMAC_hash(MAC_write_secret, seq_num + type + version + length + data);
105
106 */
107
108 /* Get our authentication method from the ciphersuite. */
109 authentication_method = ciphersuite -> nx_secure_tls_hash;
110
111 /* Get the hash size and MAC secret for our current session. */
112 hash_size = ciphersuite -> nx_secure_tls_hash_size;
113
114 /* Correct the endianness of our sequence number before hashing. */
115 adjusted_sequence_num[0] = (UCHAR)(sequence_num[1] >> 24);
116 adjusted_sequence_num[1] = (UCHAR)(sequence_num[1] >> 16);
117 adjusted_sequence_num[2] = (UCHAR)(sequence_num[1] >> 8);
118 adjusted_sequence_num[3] = (UCHAR)(sequence_num[1]);
119 adjusted_sequence_num[4] = (UCHAR)(sequence_num[0] >> 24);
120 adjusted_sequence_num[5] = (UCHAR)(sequence_num[0] >> 16);
121 adjusted_sequence_num[6] = (UCHAR)(sequence_num[0] >> 8);
122 adjusted_sequence_num[7] = (UCHAR)(sequence_num[0]);
123
124 if (authentication_method -> nx_crypto_init)
125 {
126 status = authentication_method -> nx_crypto_init((NX_CRYPTO_METHOD*)authentication_method,
127 mac_secret,
128 (NX_CRYPTO_KEY_SIZE)(hash_size << 3),
129 &handler,
130 metadata,
131 metadata_size);
132
133 if(status != NX_CRYPTO_SUCCESS)
134 {
135 return(status);
136 }
137 }
138
139 /* TLS header type, version, and length are in the proper order. */
140 if (authentication_method -> nx_crypto_operation != NX_NULL)
141 {
142 status = authentication_method -> nx_crypto_operation(NX_CRYPTO_HASH_INITIALIZE,
143 handler,
144 (NX_CRYPTO_METHOD*)authentication_method,
145 mac_secret,
146 (NX_CRYPTO_KEY_SIZE)(hash_size << 3),
147 NX_NULL,
148 0,
149 NX_NULL,
150 NX_NULL,
151 0,
152 metadata,
153 metadata_size,
154 NX_NULL,
155 NX_NULL);
156
157 if(status != NX_CRYPTO_SUCCESS)
158 {
159 return(status);
160 }
161
162 status = authentication_method -> nx_crypto_operation(NX_CRYPTO_HASH_UPDATE,
163 handler,
164 (NX_CRYPTO_METHOD*)authentication_method,
165 NX_NULL,
166 0,
167 adjusted_sequence_num,
168 8,
169 NX_NULL,
170 NX_NULL,
171 0,
172 metadata,
173 metadata_size,
174 NX_NULL,
175 NX_NULL);
176
177 if(status != NX_CRYPTO_SUCCESS)
178 {
179 return(status);
180 }
181
182 status = authentication_method -> nx_crypto_operation(NX_CRYPTO_HASH_UPDATE,
183 handler,
184 (NX_CRYPTO_METHOD*)authentication_method,
185 NX_NULL,
186 0,
187 header,
188 5,
189 NX_NULL,
190 NX_NULL,
191 0,
192 metadata,
193 metadata_size,
194 NX_NULL,
195 NX_NULL);
196
197 if(status != NX_CRYPTO_SUCCESS)
198 {
199 return(status);
200 }
201
202 /* Locate to start packet of TLS record payload. */
203 while (packet_ptr)
204 {
205 current_length = (ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr);
206 if (offset >= current_length)
207 {
208
209 /* Move to next packet. */
210 offset -= current_length;
211 packet_ptr = packet_ptr -> nx_packet_next;
212 }
213 else
214 {
215
216 /* Found offset in current packet. */
217 break;
218 }
219 }
220
221 /* Hash TLS record payload. */
222 while ((length > 0) && packet_ptr)
223 {
224 current_length = (ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr);
225 current_length -= offset;
226 offset = 0;
227 if (current_length > length)
228 {
229 current_length = length;
230 }
231 status = authentication_method -> nx_crypto_operation(NX_CRYPTO_HASH_UPDATE,
232 handler,
233 (NX_CRYPTO_METHOD*)authentication_method,
234 NX_NULL,
235 0,
236 &packet_ptr -> nx_packet_prepend_ptr[offset],
237 current_length,
238 NX_NULL,
239 NX_NULL,
240 0,
241 metadata,
242 metadata_size,
243 NX_NULL,
244 NX_NULL);
245
246 if(status != NX_CRYPTO_SUCCESS)
247 {
248 return(status);
249 }
250
251 length -= current_length;
252 packet_ptr = packet_ptr -> nx_packet_next;
253 }
254
255 if (length > 0)
256 {
257
258 /* Not all TLS record payload is hashed. */
259 return(NX_SECURE_TLS_INVALID_PACKET);
260 }
261
262 status = authentication_method -> nx_crypto_operation(NX_CRYPTO_HASH_CALCULATE,
263 handler,
264 (NX_CRYPTO_METHOD*)authentication_method,
265 NX_NULL,
266 0,
267 NX_NULL,
268 0,
269 NX_NULL,
270 record_hash,
271 NX_SECURE_TLS_MAX_HASH_SIZE,
272 metadata,
273 metadata_size,
274 NX_NULL,
275 NX_NULL);
276
277 if(status != NX_CRYPTO_SUCCESS)
278 {
279 return(status);
280 }
281 #ifdef NX_SECURE_KEY_CLEAR
282 NX_SECURE_MEMSET(adjusted_sequence_num, 0, 8);
283 #endif /* NX_SECURE_KEY_CLEAR */
284 }
285
286 if (authentication_method -> nx_crypto_cleanup)
287 {
288 status = authentication_method -> nx_crypto_cleanup(metadata);
289
290 if(status != NX_CRYPTO_SUCCESS)
291 {
292 return(status);
293 }
294 }
295
296 /* Return how many bytes our hash is since the caller doesn't necessarily know. */
297 *hash_length = hash_size;
298
299 return(status);
300 }
301
302