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