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