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