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 /** Transport Layer Security (TLS) */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define NX_SECURE_SOURCE_CODE
23
24 #include "nx_secure_tls.h"
25
26 /**************************************************************************/
27 /* */
28 /* FUNCTION RELEASE */
29 /* */
30 /* _nx_secure_generate_server_key_exchange PORTABLE C */
31 /* 6.2.0 */
32 /* AUTHOR */
33 /* */
34 /* Yanwu Cai, Microsoft Corporation */
35 /* */
36 /* DESCRIPTION */
37 /* */
38 /* This function generates a ServerKeyExchange message, which is used */
39 /* when the chosen ciphersuite requires additional information for key */
40 /* generation, such as when using Diffie-Hellman ciphers. */
41 /* */
42 /* INPUT */
43 /* */
44 /* ciphersuite Selected cipher suite */
45 /* protocol_version Selected TLS version */
46 /* tls_1_3 Whether TLS 1.3 is chosen */
47 /* tls_crypto_table TLS crypto methods */
48 /* tls_handshake_hash Metadata for handshake hash */
49 /* tls_key_material TLS key material */
50 /* tls_credentials TLS credentials */
51 /* data_buffer Pointer to output buffer */
52 /* buffer_length Length of data buffer */
53 /* output_size Size of data written to buffer*/
54 /* public_cipher_metadata Metadata for public cipher */
55 /* public_cipher_metadata_size Size of public cipher metadata*/
56 /* public_auth_metadata Metadata for public auth */
57 /* public_auth_metadata_size Size of public auth metadata */
58 /* tls_ecc_curves ECC curves */
59 /* */
60 /* OUTPUT */
61 /* */
62 /* status Completion status */
63 /* */
64 /* CALLS */
65 /* */
66 /* _nx_secure_tls_ecc_generate_keys Generate keys for ECC exchange*/
67 /* [nx_crypto_init] Initialize Crypto Method */
68 /* [nx_crypto_operation] Crypto operation */
69 /* */
70 /* CALLED BY */
71 /* */
72 /* _nx_secure_tls_send_server_key_exchange */
73 /* Send ServerKeyExchange */
74 /* */
75 /* RELEASE HISTORY */
76 /* */
77 /* DATE NAME DESCRIPTION */
78 /* */
79 /* 10-31-2022 Yanwu Cai Initial Version 6.2.0 */
80 /* */
81 /**************************************************************************/
_nx_secure_generate_server_key_exchange(const NX_SECURE_TLS_CIPHERSUITE_INFO * ciphersuite,USHORT protocol_version,UCHAR tls_1_3,NX_SECURE_TLS_CRYPTO * tls_crypto_table,NX_SECURE_TLS_HANDSHAKE_HASH * tls_handshake_hash,NX_SECURE_TLS_KEY_MATERIAL * tls_key_material,NX_SECURE_TLS_CREDENTIALS * tls_credentials,UCHAR * data_buffer,ULONG buffer_length,ULONG * output_size,VOID * public_cipher_metadata,ULONG public_cipher_metadata_size,VOID * public_auth_metadata,ULONG public_auth_metadata_size,VOID * tls_ecc_curves)82 UINT _nx_secure_generate_server_key_exchange(const NX_SECURE_TLS_CIPHERSUITE_INFO *ciphersuite, USHORT protocol_version, UCHAR tls_1_3,
83 NX_SECURE_TLS_CRYPTO *tls_crypto_table, NX_SECURE_TLS_HANDSHAKE_HASH *tls_handshake_hash,
84 NX_SECURE_TLS_KEY_MATERIAL *tls_key_material, NX_SECURE_TLS_CREDENTIALS *tls_credentials,
85 UCHAR *data_buffer, ULONG buffer_length, ULONG *output_size,
86 VOID *public_cipher_metadata, ULONG public_cipher_metadata_size,
87 VOID *public_auth_metadata, ULONG public_auth_metadata_size, VOID *tls_ecc_curves)
88 {
89 UINT length;
90
91 #if defined(NX_SECURE_ENABLE_ECJPAKE_CIPHERSUITE) || defined(NX_SECURE_ENABLE_ECC_CIPHERSUITE)
92 UINT status;
93 #endif /* defined(NX_SECURE_ENABLE_ECJPAKE_CIPHERSUITE) || defined(NX_SECURE_ENABLE_ECC_CIPHERSUITE) */
94
95 #ifdef NX_SECURE_ENABLE_PSK_CIPHERSUITES
96 USHORT identity_length;
97 UCHAR *identity;
98 #endif
99
100 #if defined(NX_SECURE_ENABLE_ECJPAKE_CIPHERSUITE)
101 VOID *handler = NX_NULL;
102 USHORT named_curve;
103 NX_CRYPTO_METHOD *crypto_method;
104 NX_CRYPTO_EXTENDED_OUTPUT extended_output;
105 #endif /* defined(NX_SECURE_ENABLE_ECJPAKE_CIPHERSUITE) */
106
107 #ifdef NX_SECURE_ENABLE_ECC_CIPHERSUITE
108 NX_SECURE_TLS_ECDHE_HANDSHAKE_DATA *ecdhe_data;
109 #endif
110
111
112 /* Build up the server key exchange message. Structure:
113 * | 2 | <key data length> |
114 * | Key data length | Key data (opaque) |
115 */
116
117 #ifndef NX_SECURE_ENABLE_ECC_CIPHERSUITE
118 NX_PARAMETER_NOT_USED(ciphersuite);
119 NX_PARAMETER_NOT_USED(protocol_version);
120 NX_PARAMETER_NOT_USED(tls_1_3);
121 NX_PARAMETER_NOT_USED(tls_crypto_table);
122 NX_PARAMETER_NOT_USED(tls_handshake_hash);
123 NX_PARAMETER_NOT_USED(tls_key_material);
124 NX_PARAMETER_NOT_USED(tls_credentials);
125 NX_PARAMETER_NOT_USED(data_buffer);
126 NX_PARAMETER_NOT_USED(buffer_length);
127 NX_PARAMETER_NOT_USED(public_cipher_metadata);
128 NX_PARAMETER_NOT_USED(public_cipher_metadata_size);
129 NX_PARAMETER_NOT_USED(public_auth_metadata);
130 NX_PARAMETER_NOT_USED(public_auth_metadata_size);
131 NX_PARAMETER_NOT_USED(tls_ecc_curves);
132 #endif
133
134 length = 0;
135
136 /* In the future, any Diffie-Hellman-based ciphersuites will populate this message with key
137 data. RSA ciphersuites do not use this message. */
138
139 #ifdef NX_SECURE_ENABLE_PSK_CIPHERSUITES
140
141 /* Check for PSK ciphersuites. */
142 if (ciphersuite -> nx_secure_tls_public_auth -> nx_crypto_algorithm == NX_CRYPTO_KEY_EXCHANGE_PSK)
143 {
144 /* If PSK is being used, the server sends an identity value to the client so
145 the client can respond with the appropriate PSK. */
146
147 /* Get identity hint and length. */
148 identity = tls_credentials -> nx_secure_tls_psk_store[0].nx_secure_tls_psk_id_hint;
149 identity_length = (USHORT)tls_credentials -> nx_secure_tls_psk_store[0].nx_secure_tls_psk_id_hint_size;
150
151 if ((identity_length + 2u) > buffer_length)
152 {
153
154 /* Packet buffer too small. */
155 return(NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL);
156 }
157
158 /* Use identity hint length for key data length. */
159 data_buffer[length] = (UCHAR)((identity_length & 0xFF00) >> 8);
160 data_buffer[length + 1] = (UCHAR)(identity_length & 0x00FF);
161 length = (USHORT)(length + 2);
162
163 /* Extract the identity hint and put it into the packet buffer. */
164 NX_SECURE_MEMCPY(&data_buffer[length], identity, identity_length); /* Use case of memcpy is verified. */
165
166 /* Advance our total length. */
167 length = (USHORT)(length + identity_length);
168 }
169 #endif
170
171 #ifdef NX_SECURE_ENABLE_ECJPAKE_CIPHERSUITE
172
173 /* Check for ECJ-PAKE ciphersuites. */
174 if (ciphersuite -> nx_secure_tls_public_auth -> nx_crypto_algorithm == NX_CRYPTO_KEY_EXCHANGE_ECJPAKE)
175 {
176
177 if (buffer_length < 3)
178 {
179
180 /* Packet buffer too small. */
181 return(NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL);
182 }
183
184 /* ECCurveType: named_curve (3). */
185 data_buffer[length] = NX_CRYPTO_EC_CURVE_TYPE_NAMED_CURVE;
186 length += 1;
187
188 /* NamedCurve: secp256r1 (23) */
189 named_curve = (USHORT)NX_CRYPTO_EC_SECP256R1;
190 data_buffer[length] = (UCHAR)((named_curve >> 8) & 0xFF);
191 data_buffer[length + 1] = (UCHAR)(named_curve & 0xFF);
192 length += 2;
193
194 extended_output.nx_crypto_extended_output_data = &data_buffer[length];
195 extended_output.nx_crypto_extended_output_length_in_byte = buffer_length - length;
196 extended_output.nx_crypto_extended_output_actual_size = 0;
197
198 crypto_method = (NX_CRYPTO_METHOD*)ciphersuite -> nx_secure_tls_public_auth;
199 status = crypto_method -> nx_crypto_operation(NX_CRYPTO_ECJPAKE_SERVER_KEY_EXCHANGE_GENERATE,
200 handler,
201 crypto_method,
202 NX_NULL, 0,
203 NX_NULL, 0, NX_NULL,
204 (UCHAR *)&extended_output,
205 sizeof(extended_output),
206 public_auth_metadata,
207 public_auth_metadata_size,
208 NX_NULL, NX_NULL);
209 if (status)
210 {
211 return(status);
212 }
213 length += extended_output.nx_crypto_extended_output_actual_size;
214 }
215 #endif
216
217 #ifdef NX_SECURE_ENABLE_ECC_CIPHERSUITE
218 /* Check for ECDHE ciphersuites. */
219 if (ciphersuite -> nx_secure_tls_public_cipher -> nx_crypto_algorithm == NX_CRYPTO_KEY_EXCHANGE_ECDHE)
220 {
221 ecdhe_data = (NX_SECURE_TLS_ECDHE_HANDSHAKE_DATA *)tls_key_material -> nx_secure_tls_new_key_material_data;
222
223 length = buffer_length;
224
225 status = _nx_secure_tls_ecc_generate_keys(ciphersuite, protocol_version, tls_1_3,
226 tls_crypto_table, tls_handshake_hash, (NX_SECURE_TLS_ECC *)tls_ecc_curves,
227 tls_key_material, tls_credentials, ecdhe_data -> nx_secure_tls_ecdhe_named_curve, NX_TRUE,
228 data_buffer, &length, ecdhe_data, public_cipher_metadata, public_cipher_metadata_size,
229 public_auth_metadata, public_auth_metadata_size);
230
231 if (status != NX_SUCCESS)
232 {
233 return(status);
234 }
235 }
236 #endif /* NX_SECURE_ENABLE_ECC_CIPHERSUITE */
237
238
239 /* Finally, we let the caller know the length . */
240 *output_size = length;
241
242 return(NX_SECURE_TLS_SUCCESS);
243 }
244
245