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