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