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
28 /**************************************************************************/
29 /* */
30 /* FUNCTION RELEASE */
31 /* */
32 /* _nx_secure_dtls_send_serverhello PORTABLE C */
33 /* 6.1 */
34 /* AUTHOR */
35 /* */
36 /* Timothy Stapko, Microsoft Corporation */
37 /* */
38 /* DESCRIPTION */
39 /* */
40 /* This function generates a ServerHello message, which is used to */
41 /* respond to an incoming ClientHello message and provide the remote */
42 /* TLS Client with the chosen ciphersuite and key generation data. */
43 /* */
44 /* INPUT */
45 /* */
46 /* dtls_session DTLS control block */
47 /* send_packet Packet used to send message */
48 /* */
49 /* OUTPUT */
50 /* */
51 /* status Completion status */
52 /* */
53 /* CALLS */
54 /* */
55 /* [nx_crypto_operation] Crypto operation */
56 /* [nx_secure_tls_session_time_function] Get the current time for the */
57 /* DTLS timestamp */
58 /* */
59 /* CALLED BY */
60 /* */
61 /* _nx_secure_dtls_server_handshake DTLS server state machine */
62 /* */
63 /* RELEASE HISTORY */
64 /* */
65 /* DATE NAME DESCRIPTION */
66 /* */
67 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
68 /* 09-30-2020 Timothy Stapko Modified comment(s), */
69 /* verified memcpy use cases, */
70 /* resulting in version 6.1 */
71 /* */
72 /**************************************************************************/
_nx_secure_dtls_send_serverhello(NX_SECURE_DTLS_SESSION * dtls_session,NX_PACKET * send_packet)73 UINT _nx_secure_dtls_send_serverhello(NX_SECURE_DTLS_SESSION *dtls_session, NX_PACKET *send_packet)
74 {
75 UINT length;
76 UINT gmt_time;
77 UINT random_value;
78 UINT i;
79 USHORT ciphersuite;
80
81 #ifdef NX_SECURE_ENABLE_ECJPAKE_CIPHERSUITE
82 UINT status;
83 UCHAR *extension_total_length_ptr;
84 USHORT extension_total_length;
85 USHORT extension_length;
86 USHORT extension_type;
87 NX_CRYPTO_METHOD *crypto_method;
88 NX_CRYPTO_EXTENDED_OUTPUT extended_output;
89 #endif
90 UCHAR *packet_buffer;
91 NX_SECURE_TLS_SESSION *tls_session;
92 USHORT protocol_version;
93
94
95 /* Build up the ServerHello message.
96 * Structure:
97 * | 2 | 4 + 28 | 1 | <SID len> | 2 | 1 | 2 | <Ext. Len> |
98 * | TLS version | Random (time + random) | SID length | Session ID | Ciphersuite | Compression | Ext. Len | Extensions |
99 */
100
101 tls_session = &dtls_session -> nx_secure_dtls_tls_session;
102
103 if ((6u + sizeof(tls_session -> nx_secure_tls_key_material.nx_secure_tls_server_random) +
104 tls_session -> nx_secure_tls_session_id_length) >
105 ((ULONG)(send_packet -> nx_packet_data_end) - (ULONG)(send_packet -> nx_packet_prepend_ptr)))
106 {
107
108 /* Packet buffer is too small. */
109 return(NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL);
110 }
111
112 packet_buffer = send_packet -> nx_packet_prepend_ptr;
113
114 /* Use our length as an index into the buffer. */
115 length = 0;
116
117 /* First two bytes of the hello following the header are the TLS major and minor version numbers. */
118 /* DTLS version. */
119 protocol_version = tls_session -> nx_secure_tls_protocol_version;
120
121 packet_buffer[length] = (UCHAR)((protocol_version & 0xFF00) >> 8);
122 packet_buffer[length + 1] = (UCHAR)(protocol_version & 0x00FF);
123 length += 2;
124
125 /* Set the Server random data, used in key generation. First 4 bytes is GMT time. */
126 gmt_time = 0;
127 if (tls_session -> nx_secure_tls_session_time_function != NX_NULL)
128 {
129 gmt_time = tls_session -> nx_secure_tls_session_time_function();
130 }
131 NX_CHANGE_ULONG_ENDIAN(gmt_time);
132
133 NX_SECURE_MEMCPY(tls_session -> nx_secure_tls_key_material.nx_secure_tls_server_random, (UCHAR *)&gmt_time, sizeof(gmt_time)); /* Use case of memcpy is verified. */
134
135 /* Next 28 bytes is random data. */
136 for (i = 0; i < 28; i += (UINT)sizeof(random_value))
137 {
138 random_value = (UINT)NX_RAND();
139 *(tls_session -> nx_secure_tls_key_material.nx_secure_tls_server_random + (i + 4)) = (UCHAR)(random_value);
140 *(tls_session -> nx_secure_tls_key_material.nx_secure_tls_server_random + (i + 5)) = (UCHAR)(random_value >> 8);
141 *(tls_session -> nx_secure_tls_key_material.nx_secure_tls_server_random + (i + 6)) = (UCHAR)(random_value >> 16);
142 *(tls_session -> nx_secure_tls_key_material.nx_secure_tls_server_random + (i + 7)) = (UCHAR)(random_value >> 24);
143 }
144
145 /* Copy the random data into the packet. */
146 NX_SECURE_MEMCPY(&packet_buffer[length], tls_session -> nx_secure_tls_key_material.nx_secure_tls_server_random,
147 sizeof(tls_session -> nx_secure_tls_key_material.nx_secure_tls_server_random)); /* Use case of memcpy is verified. */
148 length += sizeof(tls_session -> nx_secure_tls_key_material.nx_secure_tls_server_random);
149
150 /* Session ID length is one byte. */
151 packet_buffer[length] = tls_session -> nx_secure_tls_session_id_length;
152 length++;
153
154 /* Session ID follows. */
155 if (tls_session -> nx_secure_tls_session_id_length > 0)
156 {
157 NX_SECURE_MEMCPY(&packet_buffer[length], tls_session -> nx_secure_tls_session_id, tls_session -> nx_secure_tls_session_id_length); /* Use case of memcpy is verified. */
158 length += tls_session -> nx_secure_tls_session_id_length;
159 }
160
161 /* Finally, our chosen ciphersuite - this is selected when we receive the Client Hello. */
162 ciphersuite = tls_session -> nx_secure_tls_session_ciphersuite -> nx_secure_tls_ciphersuite;
163 packet_buffer[length] = (UCHAR)(ciphersuite >> 8);
164 packet_buffer[length + 1] = (UCHAR)ciphersuite;
165
166 length += 2;
167
168 /* Compression method - for now this is NULL. */
169 packet_buffer[length] = 0x0;
170 length++;
171
172 /* TLS extensions will go here once supported. */
173
174 #ifdef NX_SECURE_ENABLE_ECJPAKE_CIPHERSUITE
175 if (tls_session -> nx_secure_tls_session_ciphersuite -> nx_secure_tls_public_auth -> nx_crypto_algorithm == NX_CRYPTO_KEY_EXCHANGE_ECJPAKE)
176 {
177 if (((ULONG)(send_packet -> nx_packet_data_end) - (ULONG)(send_packet -> nx_packet_prepend_ptr)) < 12u)
178 {
179
180 /* Packet buffer is too small. */
181 return(NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL);
182 }
183
184 crypto_method = (NX_CRYPTO_METHOD*)tls_session -> nx_secure_tls_session_ciphersuite -> nx_secure_tls_public_auth;
185
186 extension_total_length_ptr = &packet_buffer[length];
187 extension_total_length = 10;
188 length += 2;
189
190 /* ec_point_formats Extension. */
191 extension_type = NX_SECURE_TLS_EXTENSION_EC_POINT_FORMATS;
192 packet_buffer[length] = (UCHAR)((extension_type >> 8) & 0xFF);
193 packet_buffer[length + 1] = (UCHAR)(extension_type & 0xFF);
194 length += 2;
195
196 /* ec_point_formats Length: 2. */
197 extension_length = 2;
198 packet_buffer[length] = (UCHAR)((extension_length >> 8) & 0xFF);
199 packet_buffer[length + 1] = (UCHAR)(extension_length & 0xFF);
200 length += 2;
201
202 /* EC point formats Length: 1. */
203 packet_buffer[length] = 1;
204 length += 1;
205
206 /* EC point format: uncompressed(0). */
207 packet_buffer[length] = 0;
208 length += 1;
209
210 /* ecjpake_key_kp_pair Extension. */
211 extension_type = NX_SECURE_TLS_EXTENSION_ECJPAKE_KEY_KP_PAIR;
212 packet_buffer[length] = (UCHAR)((extension_type >> 8) & 0xFF);
213 packet_buffer[length + 1] = (UCHAR)(extension_type & 0xFF);
214 length += 2;
215
216 /* ecjpake_key_kp_pair Length. */
217 length += 2;
218
219 extended_output.nx_crypto_extended_output_data = &packet_buffer[length];
220 extended_output.nx_crypto_extended_output_length_in_byte =
221 (ULONG)send_packet -> nx_packet_data_end - (ULONG)&packet_buffer[length];
222 extended_output.nx_crypto_extended_output_actual_size = 0;
223 status = crypto_method -> nx_crypto_operation(NX_CRYPTO_ECJPAKE_SERVER_HELLO_GENERATE,
224 NX_NULL,
225 crypto_method,
226 NX_NULL, 0,
227 NX_NULL, 0, NX_NULL,
228 (UCHAR *)&extended_output,
229 sizeof(extended_output),
230 tls_session -> nx_secure_public_auth_metadata_area,
231 tls_session -> nx_secure_public_auth_metadata_size,
232 NX_NULL, NX_NULL);
233 if (status)
234 {
235 return(status);
236 }
237
238 /* Set length for ecjpake_key_kp_pair extension. */
239 extension_length = (USHORT)extended_output.nx_crypto_extended_output_actual_size;
240 packet_buffer[length - 2] = (UCHAR)((extension_length >> 8) & 0xFF);
241 packet_buffer[length - 1] = (UCHAR)(extension_length & 0xFF);
242
243 extension_total_length = (USHORT)(extension_total_length +
244 extended_output.nx_crypto_extended_output_actual_size);
245 length += extended_output.nx_crypto_extended_output_actual_size;
246
247 /* Set extension total length. */
248 extension_total_length_ptr[0] = (UCHAR)((extension_total_length >> 8) & 0xFF);
249 extension_total_length_ptr[1] = (UCHAR)(extension_total_length & 0xFF);
250 }
251 #endif
252
253 /* Finally, we have a complete length and can put it into the buffer. Before that,
254 save off and return the number of bytes we wrote and need to send. */
255 send_packet -> nx_packet_append_ptr = send_packet -> nx_packet_prepend_ptr + length;
256 send_packet -> nx_packet_length = send_packet -> nx_packet_length + length;
257
258 return(NX_SECURE_TLS_SUCCESS);
259 }
260 #endif /* NX_SECURE_ENABLE_DTLS */
261
262