1 /*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License").
5 * You may not use this file except in compliance with the License.
6 * A copy of the License is located at
7 *
8 * http://aws.amazon.com/apache2.0
9 *
10 * or in the "license" file accompanying this file. This file is distributed
11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 * express or implied. See the License for the specific language governing
13 * permissions and limitations under the License.
14 */
15
16 #include "tls/extensions/s2n_client_key_share.h"
17 #include "tls/extensions/s2n_key_share.h"
18 #include "tls/s2n_security_policies.h"
19 #include "tls/s2n_kem_preferences.h"
20
21 #include "error/s2n_errno.h"
22 #include "stuffer/s2n_stuffer.h"
23 #include "utils/s2n_safety.h"
24 #include "tls/s2n_tls13.h"
25 #include "pq-crypto/s2n_pq.h"
26
27 /**
28 * Specified in https://tools.ietf.org/html/rfc8446#section-4.2.8
29 * "The "key_share" extension contains the endpoint's cryptographic parameters."
30 *
31 * Structure:
32 * Extension type (2 bytes)
33 * Extension data size (2 bytes)
34 * Client shares size (2 bytes)
35 * Client shares:
36 * Named group (2 bytes)
37 * Key share size (2 bytes)
38 * Key share (variable size)
39 *
40 * This extension only modifies the connection's client ecc_evp_params. It does
41 * not make any decisions about which set of params to use.
42 *
43 * The server will NOT alert when processing a client extension that violates the RFC.
44 * So the server will accept:
45 * - Multiple key shares for the same named group. The server will accept the first
46 * key share for the group and ignore any duplicates.
47 * - Key shares for named groups not in the client's supported_groups extension.
48 **/
49
50 static int s2n_client_key_share_send(struct s2n_connection *conn, struct s2n_stuffer *out);
51 static int s2n_client_key_share_recv(struct s2n_connection *conn, struct s2n_stuffer *extension);
52
53 const s2n_extension_type s2n_client_key_share_extension = {
54 .iana_value = TLS_EXTENSION_KEY_SHARE,
55 .minimum_version = S2N_TLS13,
56 .is_response = false,
57 .send = s2n_client_key_share_send,
58 .recv = s2n_client_key_share_recv,
59 .should_send = s2n_extension_always_send,
60 .if_missing = s2n_extension_noop_if_missing,
61 };
62
s2n_generate_default_ecc_key_share(struct s2n_connection * conn,struct s2n_stuffer * out)63 static int s2n_generate_default_ecc_key_share(struct s2n_connection *conn, struct s2n_stuffer *out)
64 {
65 POSIX_ENSURE_REF(conn);
66 const struct s2n_ecc_preferences *ecc_pref = NULL;
67 POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref));
68 POSIX_ENSURE_REF(ecc_pref);
69
70 /* We only ever send a single EC key share: either the share requested by the server
71 * during a retry, or the most preferred share according to local preferences.
72 */
73 struct s2n_ecc_evp_params *client_params = &conn->kex_params.client_ecc_evp_params;
74 if (s2n_is_hello_retry_handshake(conn)) {
75 const struct s2n_ecc_named_curve *server_curve = conn->kex_params.server_ecc_evp_params.negotiated_curve;
76
77 /* If the server did not request a specific ECC keyshare, don't send one */
78 if (!server_curve) {
79 return S2N_SUCCESS;
80 }
81
82 /* If the server requested a new ECC keyshare, free the old one */
83 if (server_curve != client_params->negotiated_curve) {
84 POSIX_GUARD(s2n_ecc_evp_params_free(client_params));
85 }
86
87 client_params->negotiated_curve = server_curve;
88 } else {
89 client_params->negotiated_curve = ecc_pref->ecc_curves[0];
90 }
91 POSIX_GUARD(s2n_ecdhe_parameters_send(client_params, out));
92
93 return S2N_SUCCESS;
94 }
95
s2n_generate_pq_hybrid_key_share(struct s2n_stuffer * out,struct s2n_kem_group_params * kem_group_params)96 static int s2n_generate_pq_hybrid_key_share(struct s2n_stuffer *out, struct s2n_kem_group_params *kem_group_params)
97 {
98 POSIX_ENSURE_REF(out);
99 POSIX_ENSURE_REF(kem_group_params);
100
101 /* This function should never be called when PQ is disabled */
102 POSIX_ENSURE(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED);
103
104 const struct s2n_kem_group *kem_group = kem_group_params->kem_group;
105 POSIX_ENSURE_REF(kem_group);
106
107 /* The structure of the PQ share is:
108 * IANA ID (2 bytes)
109 * || total share size (2 bytes)
110 * || size of ECC key share (2 bytes)
111 * || ECC key share (variable bytes)
112 * || size of PQ key share (2 bytes)
113 * || PQ key share (variable bytes) */
114 POSIX_GUARD(s2n_stuffer_write_uint16(out, kem_group->iana_id));
115
116 struct s2n_stuffer_reservation total_share_size = {0};
117 POSIX_GUARD(s2n_stuffer_reserve_uint16(out, &total_share_size));
118
119 struct s2n_ecc_evp_params *ecc_params = &kem_group_params->ecc_params;
120 ecc_params->negotiated_curve = kem_group->curve;
121 POSIX_GUARD_RESULT(s2n_ecdhe_send_public_key(ecc_params, out));
122
123 struct s2n_kem_params *kem_params = &kem_group_params->kem_params;
124 kem_params->kem = kem_group->kem;
125 POSIX_GUARD(s2n_kem_send_public_key(out, kem_params));
126
127 POSIX_GUARD(s2n_stuffer_write_vector_size(&total_share_size));
128
129 return S2N_SUCCESS;
130 }
131
s2n_generate_default_pq_hybrid_key_share(struct s2n_connection * conn,struct s2n_stuffer * out)132 static int s2n_generate_default_pq_hybrid_key_share(struct s2n_connection *conn, struct s2n_stuffer *out)
133 {
134 POSIX_ENSURE_REF(conn);
135 POSIX_ENSURE_REF(out);
136
137 /* Client should skip sending PQ groups/key shares if PQ is disabled */
138 if (!s2n_pq_is_enabled()) {
139 return S2N_SUCCESS;
140 }
141
142 const struct s2n_kem_preferences *kem_pref = NULL;
143 POSIX_GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref));
144 POSIX_ENSURE_REF(kem_pref);
145
146 if (kem_pref->tls13_kem_group_count == 0) {
147 return S2N_SUCCESS;
148 }
149
150 /* We only ever send a single PQ key share: either the share requested by the server
151 * during a retry, or the most preferred share according to local preferences.
152 */
153 struct s2n_kem_group_params *client_params = &conn->kex_params.client_kem_group_params;
154 if (s2n_is_hello_retry_handshake(conn)) {
155 const struct s2n_kem_group *server_group = conn->kex_params.server_kem_group_params.kem_group;
156
157 /* If the server did not request a specific PQ keyshare, don't send one */
158 if (!server_group) {
159 return S2N_SUCCESS;
160 }
161
162 /* If the server requested a new PQ keyshare, free the old one */
163 if (client_params->kem_group != server_group) {
164 POSIX_GUARD(s2n_kem_group_free(client_params));
165 }
166
167 client_params->kem_group = server_group;
168 } else {
169 client_params->kem_group = kem_pref->tls13_kem_groups[0];
170 }
171 POSIX_GUARD(s2n_generate_pq_hybrid_key_share(out, client_params));
172
173 return S2N_SUCCESS;
174 }
175
s2n_client_key_share_send(struct s2n_connection * conn,struct s2n_stuffer * out)176 static int s2n_client_key_share_send(struct s2n_connection *conn, struct s2n_stuffer *out)
177 {
178 struct s2n_stuffer_reservation shares_size = {0};
179 POSIX_GUARD(s2n_stuffer_reserve_uint16(out, &shares_size));
180 POSIX_GUARD(s2n_generate_default_pq_hybrid_key_share(conn, out));
181 POSIX_GUARD(s2n_generate_default_ecc_key_share(conn, out));
182 POSIX_GUARD(s2n_stuffer_write_vector_size(&shares_size));
183
184 /* We must have written at least one share */
185 POSIX_ENSURE(s2n_stuffer_data_available(out) > shares_size.length, S2N_ERR_BAD_KEY_SHARE);
186
187 return S2N_SUCCESS;
188 }
189
s2n_client_key_share_parse_ecc(struct s2n_stuffer * key_share,const struct s2n_ecc_named_curve * curve,struct s2n_ecc_evp_params * ecc_params)190 static int s2n_client_key_share_parse_ecc(struct s2n_stuffer *key_share, const struct s2n_ecc_named_curve *curve,
191 struct s2n_ecc_evp_params *ecc_params)
192 {
193 POSIX_ENSURE_REF(key_share);
194 POSIX_ENSURE_REF(curve);
195 POSIX_ENSURE_REF(ecc_params);
196
197 struct s2n_blob point_blob = { 0 };
198 POSIX_GUARD(s2n_ecc_evp_read_params_point(key_share, curve->share_size, &point_blob));
199
200 /* Ignore curves with points we can't parse */
201 ecc_params->negotiated_curve = curve;
202 if (s2n_ecc_evp_parse_params_point(&point_blob, ecc_params) != S2N_SUCCESS) {
203 ecc_params->negotiated_curve = NULL;
204 POSIX_GUARD(s2n_ecc_evp_params_free(ecc_params));
205 }
206
207 return S2N_SUCCESS;
208 }
209
s2n_client_key_share_recv_ecc(struct s2n_connection * conn,struct s2n_stuffer * key_share,uint16_t curve_iana_id)210 static int s2n_client_key_share_recv_ecc(struct s2n_connection *conn, struct s2n_stuffer *key_share, uint16_t curve_iana_id)
211 {
212 POSIX_ENSURE_REF(conn);
213 POSIX_ENSURE_REF(key_share);
214
215 const struct s2n_ecc_preferences *ecc_pref = NULL;
216 POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref));
217 POSIX_ENSURE_REF(ecc_pref);
218
219 struct s2n_ecc_evp_params *client_params = &conn->kex_params.client_ecc_evp_params;
220
221 const struct s2n_ecc_named_curve *curve = NULL;
222 for (size_t i = 0; i < ecc_pref->count; i++) {
223 const struct s2n_ecc_named_curve *supported_curve = ecc_pref->ecc_curves[i];
224 POSIX_ENSURE_REF(supported_curve);
225
226 /* Stop if we reach the current highest priority share.
227 * Any share of lower priority is discarded.
228 */
229 if (client_params->negotiated_curve == supported_curve) {
230 break;
231 }
232
233 /* Skip if not supported by the client.
234 * The client must not send shares it doesn't support, but the server
235 * is not required to error if they are encountered.
236 */
237 if (!conn->kex_params.mutually_supported_curves[i]) {
238 continue;
239 }
240
241 /* Stop if we find a match */
242 if (curve_iana_id == supported_curve->iana_id) {
243 curve = supported_curve;
244 break;
245 }
246 }
247
248 /* Ignore unsupported curves */
249 if (!curve) {
250 return S2N_SUCCESS;
251 }
252
253 /* Ignore curves with unexpected share sizes */
254 if (key_share->blob.size != curve->share_size) {
255 return S2N_SUCCESS;
256 }
257
258 DEFER_CLEANUP(struct s2n_ecc_evp_params new_client_params = { 0 }, s2n_ecc_evp_params_free);
259
260 POSIX_GUARD(s2n_client_key_share_parse_ecc(key_share, curve, &new_client_params));
261 /* negotiated_curve will be NULL if the key share was not parsed successfully */
262 if (!new_client_params.negotiated_curve) {
263 return S2N_SUCCESS;
264 }
265
266 POSIX_GUARD(s2n_ecc_evp_params_free(client_params));
267 *client_params = new_client_params;
268
269 ZERO_TO_DISABLE_DEFER_CLEANUP(new_client_params);
270 return S2N_SUCCESS;
271 }
272
s2n_client_key_share_recv_pq_hybrid(struct s2n_connection * conn,struct s2n_stuffer * key_share,uint16_t kem_group_iana_id)273 static int s2n_client_key_share_recv_pq_hybrid(struct s2n_connection *conn, struct s2n_stuffer *key_share, uint16_t kem_group_iana_id)
274 {
275 POSIX_ENSURE_REF(conn);
276 POSIX_ENSURE_REF(key_share);
277
278 const struct s2n_kem_preferences *kem_pref = NULL;
279 POSIX_GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref));
280 POSIX_ENSURE_REF(kem_pref);
281
282 /* Ignore key share if PQ is not enabled */
283 if (!s2n_pq_is_enabled()) {
284 return S2N_SUCCESS;
285 }
286
287 struct s2n_kem_group_params *client_params = &conn->kex_params.client_kem_group_params;
288
289 const struct s2n_kem_group *kem_group = NULL;
290 for (size_t i = 0; i < kem_pref->tls13_kem_group_count; i++) {
291 const struct s2n_kem_group *supported_group = kem_pref->tls13_kem_groups[i];
292 POSIX_ENSURE_REF(supported_group);
293
294 /* Stop if we reach the current highest priority share.
295 * Any share of lower priority is discarded.
296 */
297 if (client_params->kem_group == supported_group) {
298 break;
299 }
300
301 /* Skip if not supported by the client.
302 * The client must not send shares it doesn't support, but the server
303 * is not required to error if they are encountered.
304 */
305 if (!conn->kex_params.mutually_supported_kem_groups[i]) {
306 continue;
307 }
308
309 /* Stop if we find a match */
310 if (kem_group_iana_id == supported_group->iana_id) {
311 kem_group = supported_group;
312 break;
313 }
314 }
315
316 /* Ignore unsupported KEM groups */
317 if (!kem_group) {
318 return S2N_SUCCESS;
319 }
320
321 /* Ignore KEM groups with unexpected overall total share sizes */
322 if (key_share->blob.size != kem_group->client_share_size) {
323 return S2N_SUCCESS;
324 }
325
326 /* Ignore KEM groups with unexpected ECC share sizes */
327 uint16_t ec_share_size = 0;
328 POSIX_GUARD(s2n_stuffer_read_uint16(key_share, &ec_share_size));
329 if (ec_share_size != kem_group->curve->share_size) {
330 return S2N_SUCCESS;
331 }
332
333 DEFER_CLEANUP(struct s2n_kem_group_params new_client_params = { 0 }, s2n_kem_group_free);
334 new_client_params.kem_group = kem_group;
335
336 POSIX_GUARD(s2n_client_key_share_parse_ecc(key_share, kem_group->curve, &new_client_params.ecc_params));
337 /* If we were unable to parse the EC portion of the share, negotiated_curve
338 * will be NULL, and we should ignore the entire key share. */
339 if (!new_client_params.ecc_params.negotiated_curve) {
340 return S2N_SUCCESS;
341 }
342
343 /* Note: the PQ share size is validated in s2n_kem_recv_public_key() */
344 /* Ignore groups with PQ public keys we can't parse */
345 new_client_params.kem_params.kem = kem_group->kem;
346 if (s2n_kem_recv_public_key(key_share, &new_client_params.kem_params) != S2N_SUCCESS) {
347 return S2N_SUCCESS;
348 }
349
350 POSIX_GUARD(s2n_kem_group_free(client_params));
351 *client_params = new_client_params;
352
353 ZERO_TO_DISABLE_DEFER_CLEANUP(new_client_params);
354 return S2N_SUCCESS;
355 }
356
357 /*
358 * We chose our most preferred group of the mutually supported groups while processing the
359 * supported_groups extension. However, our true most preferred group is always the
360 * group that we already have a key share for, since retries are expensive.
361 *
362 * This method modifies our group selection based on what keyshares are available.
363 * It then stores the client keyshare for the selected group, or initiates a retry
364 * if no valid keyshares are available.
365 */
s2n_client_key_share_recv(struct s2n_connection * conn,struct s2n_stuffer * extension)366 static int s2n_client_key_share_recv(struct s2n_connection *conn, struct s2n_stuffer *extension)
367 {
368 POSIX_ENSURE_REF(conn);
369 POSIX_ENSURE_REF(extension);
370
371 uint16_t key_shares_size;
372 POSIX_GUARD(s2n_stuffer_read_uint16(extension, &key_shares_size));
373 POSIX_ENSURE(s2n_stuffer_data_available(extension) == key_shares_size, S2N_ERR_BAD_MESSAGE);
374
375 uint16_t named_group = 0, share_size = 0;
376 struct s2n_blob key_share_blob = { 0 };
377 struct s2n_stuffer key_share = { 0 };
378
379 uint16_t keyshare_count = 0;
380 while(s2n_stuffer_data_available(extension) > 0) {
381 POSIX_GUARD(s2n_stuffer_read_uint16(extension, &named_group));
382 POSIX_GUARD(s2n_stuffer_read_uint16(extension, &share_size));
383 POSIX_ENSURE(s2n_stuffer_data_available(extension) >= share_size, S2N_ERR_BAD_MESSAGE);
384
385 POSIX_GUARD(s2n_blob_init(&key_share_blob,
386 s2n_stuffer_raw_read(extension, share_size), share_size));
387 POSIX_GUARD(s2n_stuffer_init(&key_share, &key_share_blob));
388 POSIX_GUARD(s2n_stuffer_skip_write(&key_share, share_size));
389 keyshare_count++;
390
391 /* Try to parse the share as ECC, then as PQ/hybrid; will ignore
392 * shares for unrecognized groups. */
393 POSIX_GUARD(s2n_client_key_share_recv_ecc(conn, &key_share, named_group));
394 POSIX_GUARD(s2n_client_key_share_recv_pq_hybrid(conn, &key_share, named_group));
395 }
396
397 /* During a retry, the client should only have sent one keyshare */
398 POSIX_ENSURE(!s2n_is_hello_retry_handshake(conn) || keyshare_count == 1, S2N_ERR_BAD_MESSAGE);
399
400 /* If there were no matching key shares, then we received an empty key share extension
401 * or we didn't match a key share with a supported group. We should send a retry. */
402 struct s2n_ecc_evp_params *client_ecc_params = &conn->kex_params.client_ecc_evp_params;
403 struct s2n_kem_group_params *client_pq_params = &conn->kex_params.client_kem_group_params;
404 if (!client_pq_params->kem_group && !client_ecc_params->negotiated_curve) {
405 POSIX_GUARD(s2n_set_hello_retry_required(conn));
406 }
407
408 return S2N_SUCCESS;
409 }
410
411 /* Old-style extension functions -- remove after extensions refactor is complete */
412
s2n_extensions_client_key_share_size(struct s2n_connection * conn)413 uint32_t s2n_extensions_client_key_share_size(struct s2n_connection *conn)
414 {
415 POSIX_ENSURE_REF(conn);
416
417 const struct s2n_ecc_preferences *ecc_pref = NULL;
418 POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref));
419 POSIX_ENSURE_REF(ecc_pref);
420
421 uint32_t s2n_client_key_share_extension_size = S2N_SIZE_OF_EXTENSION_TYPE
422 + S2N_SIZE_OF_EXTENSION_DATA_SIZE
423 + S2N_SIZE_OF_CLIENT_SHARES_SIZE;
424
425 s2n_client_key_share_extension_size += S2N_SIZE_OF_KEY_SHARE_SIZE + S2N_SIZE_OF_NAMED_GROUP;
426 s2n_client_key_share_extension_size += ecc_pref->ecc_curves[0]->share_size;
427
428 return s2n_client_key_share_extension_size;
429 }
430
s2n_extensions_client_key_share_send(struct s2n_connection * conn,struct s2n_stuffer * out)431 int s2n_extensions_client_key_share_send(struct s2n_connection *conn, struct s2n_stuffer *out)
432 {
433 return s2n_extension_send(&s2n_client_key_share_extension, conn, out);
434 }
435
s2n_extensions_client_key_share_recv(struct s2n_connection * conn,struct s2n_stuffer * extension)436 int s2n_extensions_client_key_share_recv(struct s2n_connection *conn, struct s2n_stuffer *extension)
437 {
438 return s2n_extension_recv(&s2n_client_key_share_extension, conn, extension);
439 }
440