1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** NetX Secure Component */
16 /** */
17 /** Datagram Transport Layer Security (DTLS) */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define NX_SECURE_SOURCE_CODE
23
24 #include "nx_secure_dtls.h"
25
26 #ifdef NX_SECURE_ENABLE_DTLS
27 static UCHAR adjusted_sequence_num[8];
28 static UCHAR adjusted_header[5];
29
30 /**************************************************************************/
31 /* */
32 /* FUNCTION RELEASE */
33 /* */
34 /* _nx_secure_dtls_hash_record PORTABLE C */
35 /* 6.1 */
36 /* AUTHOR */
37 /* */
38 /* Timothy Stapko, Microsoft Corporation */
39 /* */
40 /* DESCRIPTION */
41 /* */
42 /* This function hashes an outgoing DTLS record to generate the Message*/
43 /* Authentication Code (MAC) value that is placed at the end of all */
44 /* encrypted DTLS messages. */
45 /* */
46 /* INPUT */
47 /* */
48 /* dtls_session DTLS control block */
49 /* sequence_num Record sequence number */
50 /* header Record header */
51 /* header_length Length of record header */
52 /* data Record payload */
53 /* length Length of record payload */
54 /* record_hash Pointer to output hash buffer */
55 /* hash_length Length of hash */
56 /* mac_secret Key used for MAC generation */
57 /* */
58 /* OUTPUT */
59 /* */
60 /* status Completion status */
61 /* */
62 /* CALLS */
63 /* */
64 /* [nx_crypto_operation] Hash functions */
65 /* */
66 /* CALLED BY */
67 /* */
68 /* _nx_secure_dtls_send_record Send DTLS records */
69 /* _nx_secure_dtls_verify_mac Verify record MAC checksum */
70 /* */
71 /* RELEASE HISTORY */
72 /* */
73 /* DATE NAME DESCRIPTION */
74 /* */
75 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
76 /* 09-30-2020 Timothy Stapko Modified comment(s), */
77 /* verified memcpy use cases, */
78 /* resulting in version 6.1 */
79 /* */
80 /**************************************************************************/
_nx_secure_dtls_hash_record(NX_SECURE_DTLS_SESSION * dtls_session,ULONG sequence_num[NX_SECURE_TLS_SEQUENCE_NUMBER_SIZE],UCHAR * header,UINT header_length,UCHAR * data,UINT length,UCHAR * record_hash,UINT * hash_length,UCHAR * mac_secret)81 UINT _nx_secure_dtls_hash_record(NX_SECURE_DTLS_SESSION *dtls_session,
82 ULONG sequence_num[NX_SECURE_TLS_SEQUENCE_NUMBER_SIZE],
83 UCHAR *header, UINT header_length, UCHAR *data, UINT length,
84 UCHAR *record_hash, UINT *hash_length, UCHAR *mac_secret)
85 {
86 UINT hash_size;
87 UINT status = NX_SECURE_TLS_SUCCESS;
88 const NX_CRYPTO_METHOD *authentication_method;
89 NX_SECURE_TLS_SESSION *tls_session;
90
91 NX_PARAMETER_NOT_USED(sequence_num);
92 NX_PARAMETER_NOT_USED(header_length);
93
94 /* We need to generate a Message Authentication Code (MAC) for each record during an "active" TLS session
95 (following a ChangeCipherSpec message). The hash algorithm is determined by the ciphersuite, and HMAC
96 is used with that hash algorithm to protect the TLS record contents from tampering.
97
98 The MAC is generated as:
99
100 HMAC_hash(MAC_write_secret, seq_num + type + version + length + data);
101
102 */
103
104 /* Get a reference to the internal TLS session. */
105 tls_session = &dtls_session -> nx_secure_dtls_tls_session;
106
107 if (tls_session -> nx_secure_tls_session_ciphersuite == NX_NULL)
108 {
109
110 /* Likely internal error since at this point ciphersuite negotiation was theoretically completed. */
111 return(NX_SECURE_TLS_UNKNOWN_CIPHERSUITE);
112 }
113
114 /* Get our authentication method from the ciphersuite. */
115 authentication_method = tls_session -> nx_secure_tls_session_ciphersuite -> nx_secure_tls_hash;
116
117 /* Get the hash size and MAC secret for our current session. */
118 hash_size = tls_session -> nx_secure_tls_session_ciphersuite -> nx_secure_tls_hash_size;
119
120 /* In DTLS, use the sequence number + epoch from the header. */
121 NX_SECURE_MEMCPY(adjusted_sequence_num, &header[3], 8); /* Use case of memcpy is verified. */
122
123 /* We need to extract the type, version, and length from the DTLS header. */
124 adjusted_header[0] = header[0]; /* Type. */
125 adjusted_header[1] = header[1]; /* Version. */
126 adjusted_header[2] = header[2];
127 adjusted_header[3] = header[11]; /* Length. */
128 adjusted_header[4] = header[12];
129
130 if (authentication_method -> nx_crypto_operation != NX_NULL)
131 {
132 status = authentication_method -> nx_crypto_operation(NX_CRYPTO_HASH_INITIALIZE,
133 NX_NULL,
134 (NX_CRYPTO_METHOD*)authentication_method,
135 mac_secret,
136 (NX_CRYPTO_KEY_SIZE)(hash_size << 3),
137 NX_NULL,
138 0,
139 NX_NULL,
140 NX_NULL,
141 0,
142 tls_session -> nx_secure_hash_mac_metadata_area,
143 tls_session -> nx_secure_hash_mac_metadata_size,
144 NX_NULL,
145 NX_NULL);
146
147 if(status != NX_CRYPTO_SUCCESS)
148 {
149 return(status);
150 }
151
152 status = authentication_method -> nx_crypto_operation(NX_CRYPTO_HASH_UPDATE,
153 NX_NULL,
154 (NX_CRYPTO_METHOD*)authentication_method,
155 NX_NULL,
156 0,
157 adjusted_sequence_num,
158 8,
159 NX_NULL,
160 NX_NULL,
161 0,
162 tls_session -> nx_secure_hash_mac_metadata_area,
163 tls_session -> nx_secure_hash_mac_metadata_size,
164 NX_NULL,
165 NX_NULL);
166
167 if(status != NX_CRYPTO_SUCCESS)
168 {
169 return(status);
170 }
171
172 status = authentication_method -> nx_crypto_operation(NX_CRYPTO_HASH_UPDATE,
173 NX_NULL,
174 (NX_CRYPTO_METHOD*)authentication_method,
175 NX_NULL,
176 0,
177 adjusted_header,
178 5,
179 NX_NULL,
180 NX_NULL,
181 0,
182 tls_session -> nx_secure_hash_mac_metadata_area,
183 tls_session -> nx_secure_hash_mac_metadata_size,
184 NX_NULL,
185 NX_NULL);
186
187 if(status != NX_CRYPTO_SUCCESS)
188 {
189 return(status);
190 }
191
192 status = authentication_method -> nx_crypto_operation(NX_CRYPTO_HASH_UPDATE,
193 NX_NULL,
194 (NX_CRYPTO_METHOD*)authentication_method,
195 NX_NULL,
196 0,
197 data,
198 length,
199 NX_NULL,
200 NX_NULL,
201 0,
202 tls_session -> nx_secure_hash_mac_metadata_area,
203 tls_session -> nx_secure_hash_mac_metadata_size,
204 NX_NULL,
205 NX_NULL);
206
207 if(status != NX_CRYPTO_SUCCESS)
208 {
209 return(status);
210 }
211
212 status = authentication_method -> nx_crypto_operation(NX_CRYPTO_HASH_CALCULATE,
213 NX_NULL,
214 (NX_CRYPTO_METHOD*)authentication_method,
215 NX_NULL,
216 0,
217 NX_NULL,
218 0,
219 NX_NULL,
220 record_hash,
221 NX_SECURE_TLS_MAX_HASH_SIZE,
222 tls_session -> nx_secure_hash_mac_metadata_area,
223 tls_session -> nx_secure_hash_mac_metadata_size,
224 NX_NULL,
225 NX_NULL);
226
227 if(status != NX_CRYPTO_SUCCESS)
228 {
229 return(status);
230 }
231
232 }
233
234 /* Return how many bytes our hash is since the caller doesn't necessarily know. */
235 *hash_length = hash_size;
236
237 return(status);
238 }
239 #endif /* NX_SECURE_ENABLE_DTLS */
240
241