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