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 /**    Datagram Transport Layer Security (DTLS)                           */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 #define NX_SECURE_SOURCE_CODE
24 
25 #include "nx_secure_dtls.h"
26 
27 #ifdef NX_SECURE_ENABLE_DTLS
28 static UCHAR _generated_hash[NX_SECURE_TLS_MAX_HASH_SIZE];
29 
30 /**************************************************************************/
31 /*                                                                        */
32 /*  FUNCTION                                               RELEASE        */
33 /*                                                                        */
34 /*    _nx_secure_dtls_verify_mac                          PORTABLE C      */
35 /*                                                           6.1          */
36 /*  AUTHOR                                                                */
37 /*                                                                        */
38 /*    Timothy Stapko, Microsoft Corporation                               */
39 /*                                                                        */
40 /*  DESCRIPTION                                                           */
41 /*                                                                        */
42 /*    This function verifies the Message Authentication Code (MAC) that   */
43 /*    is included in encrypted DTLS 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 /*    dtls_session                          DTLS control block            */
51 /*    header_data                           DTLS record header data       */
52 /*    header_length                         Length of header data         */
53 /*    data                                  DTLS record payload data      */
54 /*    length                                Length of payload data        */
55 /*                                                                        */
56 /*  OUTPUT                                                                */
57 /*                                                                        */
58 /*    status                                Completion status             */
59 /*                                                                        */
60 /*  CALLS                                                                 */
61 /*                                                                        */
62 /*    _nx_secure_dtls_hash_record           Generate payload data hash    */
63 /*                                                                        */
64 /*  CALLED BY                                                             */
65 /*                                                                        */
66 /*    _nx_secure_dtls_process_record        Process DTLS record data      */
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 /*                                            verified memcpy use cases,  */
75 /*                                            resulting in version 6.1    */
76 /*                                                                        */
77 /**************************************************************************/
_nx_secure_dtls_verify_mac(NX_SECURE_DTLS_SESSION * dtls_session,UCHAR * header_data,USHORT header_length,UCHAR * data,UINT * length)78 UINT _nx_secure_dtls_verify_mac(NX_SECURE_DTLS_SESSION *dtls_session, UCHAR *header_data,
79                                 USHORT header_length, UCHAR *data, UINT *length)
80 {
81 UCHAR                                *mac_secret;
82 USHORT                                hash_size;
83 UINT                                  status;
84 INT                                   compare_result;
85 USHORT                                data_length;
86 UCHAR                                *received_hash;
87 UINT                                  hash_length;
88 UCHAR                                 header[20];
89 NX_SECURE_TLS_SESSION                *tls_session;
90 
91     tls_session = &dtls_session -> nx_secure_dtls_tls_session;
92 
93     if (tls_session -> nx_secure_tls_session_ciphersuite == NX_NULL)
94     {
95 
96         /* Likely internal error since at this point ciphersuite negotiation was theoretically completed. */
97         return(NX_SECURE_TLS_UNKNOWN_CIPHERSUITE);
98     }
99 
100     /* Get the hash size and MAC secret for our current session. */
101     hash_size = tls_session -> nx_secure_tls_session_ciphersuite -> nx_secure_tls_hash_size;
102 
103     /* Select our proper MAC secret for hashing. */
104     if (tls_session -> nx_secure_tls_socket_type == NX_SECURE_TLS_SESSION_TYPE_SERVER)
105     {
106         /* If we are a server, we need to use the client's MAC secret. */
107         mac_secret = tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_write_mac_secret;
108     }
109     else
110     {
111         /* We are a client, so use the server's MAC secret. */
112         mac_secret = tls_session -> nx_secure_tls_key_material.nx_secure_tls_server_write_mac_secret;
113     }
114 
115     if (hash_size >= *length)
116     {
117         /* The record data was smaller than the selected hash... Error. */
118         return(NX_SECURE_TLS_HASH_MAC_VERIFY_FAILURE);
119     }
120 
121     /* Adjust our length so we only hash the record data, not the hash as well. */
122     data_length = (USHORT)(*length - hash_size);
123 
124     /* Copy the header data into our local buffer so we can change it if we need to. */
125     if (header_length > sizeof(header))
126     {
127         return(NX_SECURE_TLS_HASH_MAC_VERIFY_FAILURE);
128     }
129     NX_SECURE_MEMCPY(header, header_data, header_length); /* Use case of memcpy is verified. */
130 
131     /* Adjust the length in the header to match data without hash. */
132 
133     /* In DTLS, the length is at offset 11. */
134     header[11] = (UCHAR)((data_length >> 8) & 0x00FF);
135     header[12] = (UCHAR)(data_length & 0x00FF);
136 
137     /* Generate the hash on the plaintext data. */
138     status = _nx_secure_dtls_hash_record(dtls_session, tls_session -> nx_secure_tls_remote_sequence_number, header, header_length,
139                                          data, (USHORT)(data_length), _generated_hash, &hash_length, mac_secret);
140 
141     if (status != NX_SUCCESS)
142     {
143         /* The hash operation failed for some reason. */
144         return(NX_SECURE_TLS_HASH_MAC_VERIFY_FAILURE);
145     }
146 
147     /* In DTLS, the sequence number is explicit in the record. In TLS the sequence number would be incremented here. */
148 
149     /* Now, compare the hash we generated to the one we received. */
150     received_hash = &data[data_length];
151     compare_result = NX_SECURE_MEMCMP(received_hash, _generated_hash, hash_size);
152 
153     /* Before we return, adjust our data size so the caller will only see data, not the hash. */
154     *length = data_length;
155 
156     /* If the hashes match, we are all good. Otherwise we have a problem. */
157     if (compare_result == 0)
158     {
159         return(NX_SECURE_TLS_SUCCESS);
160     }
161     else
162     {
163         return(NX_SECURE_TLS_HASH_MAC_VERIFY_FAILURE);
164     }
165 }
166 #endif /* NX_SECURE_ENABLE_DTLS */
167 
168