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