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 static UCHAR _generated_hash[NX_SECURE_TLS_MAX_HASH_SIZE];
28 static UCHAR _received_hash[NX_SECURE_TLS_MAX_HASH_SIZE];
29
30 /**************************************************************************/
31 /* */
32 /* FUNCTION RELEASE */
33 /* */
34 /* _nx_secure_verify_mac PORTABLE C */
35 /* 6.2.0 */
36 /* AUTHOR */
37 /* */
38 /* Yanwu Cai, Microsoft Corporation */
39 /* */
40 /* DESCRIPTION */
41 /* */
42 /* This function verifies the Message Authentication Code (MAC) that */
43 /* is included in encrypted TLS records. It hashes the incoming */
44 /* message data and then compares it to the MAC in the received */
45 /* record. If there is a mismatch, then the record has been corrupted */
46 /* in transit and represents a possible security breach. */
47 /* */
48 /* INPUT */
49 /* */
50 /* ciphersuite Selected cipher suite */
51 /* mac_secret Key used for MAC generation */
52 /* sequence_num Record sequence number */
53 /* header_data TLS record header data */
54 /* header_length Length of header data */
55 /* packet_ptr TLS record packet */
56 /* offset Offset to TLS record in packet*/
57 /* length Length of payload data */
58 /* hash_mac_metadata Metadata for hash mac crypto */
59 /* hash_mac_metadata_size Size of hash mac metadata */
60 /* */
61 /* OUTPUT */
62 /* */
63 /* status Completion status */
64 /* */
65 /* CALLS */
66 /* */
67 /* _nx_secure_tls_hash_record Generate payload data hash */
68 /* */
69 /* CALLED BY */
70 /* */
71 /* _nx_secure_tls_verify_mac Verify record MAC checksum */
72 /* */
73 /* RELEASE HISTORY */
74 /* */
75 /* DATE NAME DESCRIPTION */
76 /* */
77 /* 10-31-2022 Yanwu Cai Initial Version 6.2.0 */
78 /* */
79 /**************************************************************************/
_nx_secure_verify_mac(const NX_SECURE_TLS_CIPHERSUITE_INFO * ciphersuite,UCHAR * mac_secret,ULONG sequence_num[NX_SECURE_TLS_SEQUENCE_NUMBER_SIZE],UCHAR * header_data,USHORT header_length,NX_PACKET * packet_ptr,ULONG offset,UINT * length,VOID * hash_mac_metadata,ULONG hash_mac_metadata_size)80 UINT _nx_secure_verify_mac(const NX_SECURE_TLS_CIPHERSUITE_INFO *ciphersuite, UCHAR *mac_secret, ULONG sequence_num[NX_SECURE_TLS_SEQUENCE_NUMBER_SIZE],
81 UCHAR *header_data, USHORT header_length, NX_PACKET *packet_ptr, ULONG offset, UINT *length,
82 VOID *hash_mac_metadata, ULONG hash_mac_metadata_size)
83 {
84
85 USHORT hash_size;
86 INT compare_result;
87 USHORT data_length;
88 UINT hash_length;
89 UCHAR header[6];
90 ULONG bytes_copied;
91
92
93
94 /* Get the hash size and MAC secret for our current session. */
95 hash_size = ciphersuite -> nx_secure_tls_hash_size;
96
97 /* Check for 0-length records. With nothing to hash, don't continue to hash generation. */
98 if (hash_size >= *length)
99 {
100
101 if (header_data[0] == (UCHAR)(NX_SECURE_TLS_APPLICATION_DATA) &&
102 *length == hash_size)
103 {
104 /* BEAST attack mitigation. In TLS 1.0 and SSLv3, the implicit IV enables the BEAST
105 attack. Some implementations counter the attack by sending an empty record which
106 has the effect of resetting the IVs. We normally don't allow empty records since there
107 is no data to hash, but in this case we want to allow it. */
108 *length = 0;
109
110 /* Increment the sequence number. */
111 if ((sequence_num[0] + 1) == 0)
112 {
113 /* Check for overflow of the 32-bit unsigned number. */
114 sequence_num[1]++;
115
116 if (sequence_num[1] == 0)
117 {
118
119 /* Check for overflow of the 64-bit unsigned number. As it should not reach here
120 in practical, we return a general error to prevent overflow theoretically. */
121 return(NX_NOT_SUCCESSFUL);
122 }
123
124 }
125 sequence_num[0]++;
126
127 return(NX_SUCCESS);
128 }
129
130 /* The record data was smaller than the selected hash... Error. */
131 return(NX_SECURE_TLS_HASH_MAC_VERIFY_FAILURE);
132 }
133
134 /* Adjust our length so we only hash the record data, not the hash as well. */
135 data_length = (USHORT)(*length - hash_size);
136
137 /* Copy the header data into our local buffer so we can change it if we need to. */
138 if (header_length > sizeof(header))
139 {
140 return(NX_SECURE_TLS_HASH_MAC_VERIFY_FAILURE);
141 }
142 NX_SECURE_MEMCPY(header, header_data, header_length); /* Use case of memcpy is verified. */
143
144 /* Adjust the length in the header to match the length of the data before the hash was added. */
145 header[3] = (UCHAR)((data_length >> 8) & 0x00FF);
146 header[4] = (UCHAR)(data_length & 0x00FF);
147
148 /* Generate the hash on the plaintext data. */
149 _nx_secure_tls_hash_record(ciphersuite, sequence_num, header, header_length,
150 packet_ptr, offset, data_length, _generated_hash, &hash_length, mac_secret,
151 hash_mac_metadata, hash_mac_metadata_size);
152
153 /* Increment the sequence number. */
154 if ((sequence_num[0] + 1) == 0)
155 {
156 /* Check for overflow of the 32-bit unsigned number. */
157 sequence_num[1]++;
158
159 if (sequence_num[1] == 0)
160 {
161
162 /* Check for overflow of the 64-bit unsigned number. As it should not reach here
163 in practical, we return a general error to prevent overflow theoretically. */
164 return(NX_NOT_SUCCESSFUL);
165 }
166
167 }
168 sequence_num[0]++;
169
170 if (hash_size == 0)
171 {
172
173 /* For ciphersuite without explict hash, just return success. */
174 return(NX_SECURE_TLS_SUCCESS);
175 }
176
177 /* Now, compare the hash we generated to the one we received. */
178 if (nx_packet_data_extract_offset(packet_ptr,
179 offset + data_length,
180 _received_hash, hash_size, &bytes_copied))
181
182 {
183
184 /* The record data was smaller than the selected hash... Error. */
185 return(NX_SECURE_TLS_PADDING_CHECK_FAILED);
186 }
187
188 if (bytes_copied != hash_size)
189 {
190
191 /* The record data was smaller than the selected hash... Error. */
192 return(NX_SECURE_TLS_PADDING_CHECK_FAILED);
193 }
194
195 compare_result = NX_SECURE_MEMCMP(_received_hash, _generated_hash, hash_size);
196
197 #ifdef NX_SECURE_KEY_CLEAR
198 NX_SECURE_MEMSET(_generated_hash, 0, sizeof(_generated_hash));
199 #endif /* NX_SECURE_KEY_CLEAR */
200
201 /* Before we return, adjust our data size so the caller will only see data, not the hash. */
202 *length = data_length;
203
204 /* If the hashes match, we are all good. Otherwise we have a problem. */
205 if (compare_result == 0)
206 {
207 return(NX_SECURE_TLS_SUCCESS);
208 }
209 else
210 {
211 return(NX_SECURE_TLS_HASH_MAC_VERIFY_FAILURE);
212 }
213 }
214
215