Branch data Line data Source code
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/s2n_kex.h"
17 : :
18 : : #include "crypto/s2n_pq.h"
19 : : #include "tls/s2n_cipher_preferences.h"
20 : : #include "tls/s2n_cipher_suites.h"
21 : : #include "tls/s2n_client_key_exchange.h"
22 : : #include "tls/s2n_kem.h"
23 : : #include "tls/s2n_security_policies.h"
24 : : #include "tls/s2n_server_key_exchange.h"
25 : : #include "tls/s2n_tls.h"
26 : : #include "utils/s2n_safety.h"
27 : :
28 : : static S2N_RESULT s2n_check_tls13(const struct s2n_cipher_suite *cipher_suite,
29 : : struct s2n_connection *conn, bool *is_supported)
30 : 4950 : {
31 [ # # ][ - + ]: 4950 : RESULT_ENSURE_REF(is_supported);
32 : 4950 : *is_supported = (s2n_connection_get_protocol_version(conn) >= S2N_TLS13);
33 : 4950 : return S2N_RESULT_OK;
34 : 4950 : }
35 : :
36 : : static S2N_RESULT s2n_check_rsa_key(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported)
37 : 1552 : {
38 [ - + ][ # # ]: 1552 : RESULT_ENSURE_REF(cipher_suite);
39 [ - + ][ # # ]: 1552 : RESULT_ENSURE_REF(conn);
40 [ - + ][ # # ]: 1552 : RESULT_ENSURE_REF(is_supported);
41 : :
42 : 1552 : *is_supported = s2n_get_compatible_cert_chain_and_key(conn, S2N_PKEY_TYPE_RSA) != NULL;
43 : :
44 : 1552 : return S2N_RESULT_OK;
45 : 1552 : }
46 : :
47 : : static S2N_RESULT s2n_check_dhe(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported)
48 : 36 : {
49 [ # # ][ - + ]: 36 : RESULT_ENSURE_REF(cipher_suite);
50 [ - + ][ # # ]: 36 : RESULT_ENSURE_REF(conn);
51 [ - + ][ # # ]: 36 : RESULT_ENSURE_REF(conn->config);
52 [ - + ][ # # ]: 36 : RESULT_ENSURE_REF(is_supported);
53 : :
54 : 36 : *is_supported = conn->config->dhparams != NULL;
55 : :
56 : 36 : return S2N_RESULT_OK;
57 : 36 : }
58 : :
59 : : static S2N_RESULT s2n_check_ecdhe(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported)
60 : 903 : {
61 [ - + ][ # # ]: 903 : RESULT_ENSURE_REF(cipher_suite);
62 [ - + ][ # # ]: 903 : RESULT_ENSURE_REF(conn);
63 [ - + ][ # # ]: 903 : RESULT_ENSURE_REF(is_supported);
64 : :
65 : 903 : *is_supported = conn->kex_params.server_ecc_evp_params.negotiated_curve != NULL;
66 : :
67 : 903 : return S2N_RESULT_OK;
68 : 903 : }
69 : :
70 : : static S2N_RESULT s2n_check_kem(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported)
71 : 0 : {
72 [ # # ][ # # ]: 0 : RESULT_ENSURE_REF(cipher_suite);
73 [ # # ][ # # ]: 0 : RESULT_ENSURE_REF(conn);
74 [ # # ][ # # ]: 0 : RESULT_ENSURE_REF(is_supported);
75 : :
76 : : /* If any of the necessary conditions are not met, we will return early and indicate KEM is not supported. */
77 : 0 : *is_supported = false;
78 : :
79 : 0 : const struct s2n_kem_preferences *kem_preferences = NULL;
80 [ # # ]: 0 : RESULT_GUARD_POSIX(s2n_connection_get_kem_preferences(conn, &kem_preferences));
81 [ # # ][ # # ]: 0 : RESULT_ENSURE_REF(kem_preferences);
82 : :
83 [ # # ][ # # ]: 0 : if (!s2n_pq_is_enabled() || kem_preferences->kem_count == 0) {
84 : 0 : return S2N_RESULT_OK;
85 : 0 : }
86 : :
87 : 0 : const struct s2n_iana_to_kem *supported_params = NULL;
88 [ # # ]: 0 : if (s2n_cipher_suite_to_kem(cipher_suite->iana_value, &supported_params) != S2N_SUCCESS) {
89 : 0 : return S2N_RESULT_OK;
90 : 0 : }
91 : :
92 [ # # ][ # # ]: 0 : RESULT_ENSURE_REF(supported_params);
93 [ # # ]: 0 : if (supported_params->kem_count == 0) {
94 : 0 : return S2N_RESULT_OK;
95 : 0 : }
96 : :
97 : 0 : struct s2n_blob *client_kem_pref_list = &(conn->kex_params.client_pq_kem_extension);
98 : 0 : const struct s2n_kem *chosen_kem = NULL;
99 [ # # ][ # # ]: 0 : if (client_kem_pref_list == NULL || client_kem_pref_list->data == NULL) {
100 : : /* If the client did not send a PQ KEM extension, then the server can pick its preferred parameter */
101 [ # # ]: 0 : if (s2n_choose_kem_without_peer_pref_list(
102 : 0 : cipher_suite->iana_value, kem_preferences->kems, kem_preferences->kem_count, &chosen_kem)
103 : 0 : != S2N_SUCCESS) {
104 : 0 : return S2N_RESULT_OK;
105 : 0 : }
106 : 0 : } else {
107 : : /* If the client did send a PQ KEM extension, then the server must find a mutually supported parameter. */
108 [ # # ]: 0 : if (s2n_choose_kem_with_peer_pref_list(
109 : 0 : cipher_suite->iana_value, client_kem_pref_list, kem_preferences->kems, kem_preferences->kem_count, &chosen_kem)
110 : 0 : != S2N_SUCCESS) {
111 : 0 : return S2N_RESULT_OK;
112 : 0 : }
113 : 0 : }
114 : :
115 : 0 : *is_supported = chosen_kem != NULL;
116 : 0 : return S2N_RESULT_OK;
117 : 0 : }
118 : :
119 : : static S2N_RESULT s2n_configure_kem(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn)
120 : 0 : {
121 [ # # ][ # # ]: 0 : RESULT_ENSURE_REF(cipher_suite);
122 [ # # ][ # # ]: 0 : RESULT_ENSURE_REF(conn);
123 : :
124 [ # # ][ # # ]: 0 : RESULT_ENSURE(s2n_pq_is_enabled(), S2N_ERR_UNIMPLEMENTED);
125 : :
126 : 0 : const struct s2n_kem_preferences *kem_preferences = NULL;
127 [ # # ]: 0 : RESULT_GUARD_POSIX(s2n_connection_get_kem_preferences(conn, &kem_preferences));
128 [ # # ][ # # ]: 0 : RESULT_ENSURE_REF(kem_preferences);
129 : :
130 : 0 : struct s2n_blob *proposed_kems = &(conn->kex_params.client_pq_kem_extension);
131 : 0 : const struct s2n_kem *chosen_kem = NULL;
132 [ # # ][ # # ]: 0 : if (proposed_kems == NULL || proposed_kems->data == NULL) {
133 : : /* If the client did not send a PQ KEM extension, then the server can pick its preferred parameter */
134 [ # # ]: 0 : RESULT_GUARD_POSIX(s2n_choose_kem_without_peer_pref_list(cipher_suite->iana_value, kem_preferences->kems,
135 : 0 : kem_preferences->kem_count, &chosen_kem));
136 : 0 : } else {
137 : : /* If the client did send a PQ KEM extension, then the server must find a mutually supported parameter. */
138 [ # # ]: 0 : RESULT_GUARD_POSIX(s2n_choose_kem_with_peer_pref_list(cipher_suite->iana_value, proposed_kems, kem_preferences->kems,
139 : 0 : kem_preferences->kem_count, &chosen_kem));
140 : 0 : }
141 : :
142 : 0 : conn->kex_params.kem_params.kem = chosen_kem;
143 : 0 : return S2N_RESULT_OK;
144 : 0 : }
145 : :
146 : : static S2N_RESULT s2n_check_hybrid_ecdhe_kem(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported)
147 : 0 : {
148 [ # # ][ # # ]: 0 : RESULT_ENSURE_REF(cipher_suite);
149 [ # # ][ # # ]: 0 : RESULT_ENSURE_REF(conn);
150 [ # # ][ # # ]: 0 : RESULT_ENSURE_REF(is_supported);
151 : :
152 : 0 : bool ecdhe_supported = false;
153 : 0 : bool kem_supported = false;
154 [ # # ]: 0 : RESULT_GUARD(s2n_check_ecdhe(cipher_suite, conn, &ecdhe_supported));
155 [ # # ]: 0 : RESULT_GUARD(s2n_check_kem(cipher_suite, conn, &kem_supported));
156 : :
157 [ # # ][ # # ]: 0 : *is_supported = ecdhe_supported && kem_supported;
158 : :
159 : 0 : return S2N_RESULT_OK;
160 : 0 : }
161 : :
162 : : static S2N_RESULT s2n_kex_configure_noop(const struct s2n_cipher_suite *cipher_suite,
163 : : struct s2n_connection *conn)
164 : 7421 : {
165 : 7421 : return S2N_RESULT_OK;
166 : 7421 : }
167 : :
168 : : static int s2n_kex_server_key_recv_read_data_unimplemented(struct s2n_connection *conn,
169 : : struct s2n_blob *data_to_verify, struct s2n_kex_raw_server_data *kex_data)
170 : 0 : {
171 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_UNIMPLEMENTED);
172 : 0 : }
173 : :
174 : : static int s2n_kex_server_key_recv_parse_data_unimplemented(struct s2n_connection *conn,
175 : : struct s2n_kex_raw_server_data *kex_data)
176 : 0 : {
177 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_UNIMPLEMENTED);
178 : 0 : }
179 : :
180 : : static int s2n_kex_io_unimplemented(struct s2n_connection *conn, struct s2n_blob *data_to_sign)
181 : 0 : {
182 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_UNIMPLEMENTED);
183 : 0 : }
184 : :
185 : : static int s2n_kex_prf_unimplemented(struct s2n_connection *conn, struct s2n_blob *premaster_secret)
186 : 0 : {
187 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_UNIMPLEMENTED);
188 : 0 : }
189 : :
190 : : const struct s2n_kex s2n_kem = {
191 : : .is_ephemeral = true,
192 : : .connection_supported = &s2n_check_kem,
193 : : .configure_connection = &s2n_configure_kem,
194 : : .server_key_recv_read_data = &s2n_kem_server_key_recv_read_data,
195 : : .server_key_recv_parse_data = &s2n_kem_server_key_recv_parse_data,
196 : : .server_key_send = &s2n_kem_server_key_send,
197 : : .client_key_recv = &s2n_kem_client_key_recv,
198 : : .client_key_send = &s2n_kem_client_key_send,
199 : : .prf = &s2n_kex_prf_unimplemented,
200 : : };
201 : :
202 : : const struct s2n_kex s2n_rsa = {
203 : : .is_ephemeral = false,
204 : : .connection_supported = &s2n_check_rsa_key,
205 : : .configure_connection = &s2n_kex_configure_noop,
206 : : .server_key_recv_read_data = &s2n_kex_server_key_recv_read_data_unimplemented,
207 : : .server_key_recv_parse_data = &s2n_kex_server_key_recv_parse_data_unimplemented,
208 : : .server_key_send = &s2n_kex_io_unimplemented,
209 : : .client_key_recv = &s2n_rsa_client_key_recv,
210 : : .client_key_send = &s2n_rsa_client_key_send,
211 : : .prf = &s2n_prf_calculate_master_secret,
212 : : };
213 : :
214 : : const struct s2n_kex s2n_dhe = {
215 : : .is_ephemeral = true,
216 : : .connection_supported = &s2n_check_dhe,
217 : : .configure_connection = &s2n_kex_configure_noop,
218 : : .server_key_recv_read_data = &s2n_dhe_server_key_recv_read_data,
219 : : .server_key_recv_parse_data = &s2n_dhe_server_key_recv_parse_data,
220 : : .server_key_send = &s2n_dhe_server_key_send,
221 : : .client_key_recv = &s2n_dhe_client_key_recv,
222 : : .client_key_send = &s2n_dhe_client_key_send,
223 : : .prf = &s2n_prf_calculate_master_secret,
224 : : };
225 : :
226 : : const struct s2n_kex s2n_ecdhe = {
227 : : .is_ephemeral = true,
228 : : .connection_supported = &s2n_check_ecdhe,
229 : : .configure_connection = &s2n_kex_configure_noop,
230 : : .server_key_recv_read_data = &s2n_ecdhe_server_key_recv_read_data,
231 : : .server_key_recv_parse_data = &s2n_ecdhe_server_key_recv_parse_data,
232 : : .server_key_send = &s2n_ecdhe_server_key_send,
233 : : .client_key_recv = &s2n_ecdhe_client_key_recv,
234 : : .client_key_send = &s2n_ecdhe_client_key_send,
235 : : .prf = &s2n_prf_calculate_master_secret,
236 : : };
237 : :
238 : : const struct s2n_kex s2n_hybrid_ecdhe_kem = {
239 : : .is_ephemeral = true,
240 : : .hybrid = { &s2n_ecdhe, &s2n_kem },
241 : : .connection_supported = &s2n_check_hybrid_ecdhe_kem,
242 : : .configure_connection = &s2n_configure_kem,
243 : : .server_key_recv_read_data = &s2n_hybrid_server_key_recv_read_data,
244 : : .server_key_recv_parse_data = &s2n_hybrid_server_key_recv_parse_data,
245 : : .server_key_send = &s2n_hybrid_server_key_send,
246 : : .client_key_recv = &s2n_hybrid_client_key_recv,
247 : : .client_key_send = &s2n_hybrid_client_key_send,
248 : : .prf = &s2n_prf_hybrid_master_secret,
249 : : };
250 : :
251 : : /* TLS1.3 key exchange is implemented differently from previous versions and does
252 : : * not currently require most of the functionality offered by s2n_kex.
253 : : * This structure primarily acts as a placeholder, so its methods are either
254 : : * noops or unimplemented.
255 : : */
256 : : const struct s2n_kex s2n_tls13_kex = {
257 : : .is_ephemeral = true,
258 : : .connection_supported = &s2n_check_tls13,
259 : : .configure_connection = &s2n_kex_configure_noop,
260 : : .server_key_recv_read_data = &s2n_kex_server_key_recv_read_data_unimplemented,
261 : : .server_key_recv_parse_data = &s2n_kex_server_key_recv_parse_data_unimplemented,
262 : : .server_key_send = &s2n_kex_io_unimplemented,
263 : : .client_key_recv = &s2n_kex_io_unimplemented,
264 : : .client_key_send = &s2n_kex_io_unimplemented,
265 : : .prf = &s2n_kex_prf_unimplemented,
266 : : };
267 : :
268 : : S2N_RESULT s2n_kex_supported(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported)
269 : 7441 : {
270 [ # # ][ - + ]: 7441 : RESULT_ENSURE_REF(cipher_suite);
271 [ - + ][ # # ]: 7441 : RESULT_ENSURE_REF(cipher_suite->key_exchange_alg);
272 [ # # ][ - + ]: 7441 : RESULT_ENSURE_REF(cipher_suite->key_exchange_alg->connection_supported);
273 [ - + ][ # # ]: 7441 : RESULT_ENSURE_REF(conn);
274 [ # # ][ - + ]: 7441 : RESULT_ENSURE_REF(is_supported);
275 : :
276 [ - + ]: 7441 : RESULT_GUARD(cipher_suite->key_exchange_alg->connection_supported(cipher_suite, conn, is_supported));
277 : :
278 : 7441 : return S2N_RESULT_OK;
279 : 7441 : }
280 : :
281 : : S2N_RESULT s2n_configure_kex(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn)
282 : 7423 : {
283 [ + + ][ + - ]: 7423 : RESULT_ENSURE_REF(cipher_suite);
284 [ + + ][ + - ]: 7422 : RESULT_ENSURE_REF(cipher_suite->key_exchange_alg);
285 [ - + ][ # # ]: 7421 : RESULT_ENSURE_REF(cipher_suite->key_exchange_alg->configure_connection);
286 [ # # ][ - + ]: 7421 : RESULT_ENSURE_REF(conn);
287 : :
288 [ - + ]: 7421 : RESULT_GUARD(cipher_suite->key_exchange_alg->configure_connection(cipher_suite, conn));
289 : :
290 : 7421 : return S2N_RESULT_OK;
291 : 7421 : }
292 : :
293 : : S2N_RESULT s2n_kex_is_ephemeral(const struct s2n_kex *kex, bool *is_ephemeral)
294 : 4664 : {
295 [ + - ][ + + ]: 4664 : RESULT_ENSURE_REF(kex);
296 [ + + ][ + - ]: 4663 : RESULT_ENSURE_REF(is_ephemeral);
297 : :
298 : 4662 : *is_ephemeral = kex->is_ephemeral;
299 : :
300 : 4662 : return S2N_RESULT_OK;
301 : 4663 : }
302 : :
303 : : S2N_RESULT s2n_kex_server_key_recv_parse_data(const struct s2n_kex *kex, struct s2n_connection *conn, struct s2n_kex_raw_server_data *raw_server_data)
304 : 775 : {
305 [ + - ][ + + ]: 775 : RESULT_ENSURE_REF(kex);
306 [ - + ][ # # ]: 774 : RESULT_ENSURE_REF(kex->server_key_recv_parse_data);
307 [ - + ][ # # ]: 774 : RESULT_ENSURE_REF(conn);
308 [ # # ][ - + ]: 774 : RESULT_ENSURE_REF(raw_server_data);
309 : :
310 [ - + ]: 774 : RESULT_GUARD_POSIX(kex->server_key_recv_parse_data(conn, raw_server_data));
311 : :
312 : 774 : return S2N_RESULT_OK;
313 : 774 : }
314 : :
315 : : S2N_RESULT s2n_kex_server_key_recv_read_data(const struct s2n_kex *kex, struct s2n_connection *conn, struct s2n_blob *data_to_verify,
316 : : struct s2n_kex_raw_server_data *raw_server_data)
317 : 779 : {
318 [ + - ][ + + ]: 779 : RESULT_ENSURE_REF(kex);
319 [ - + ][ # # ]: 778 : RESULT_ENSURE_REF(kex->server_key_recv_read_data);
320 [ - + ][ # # ]: 778 : RESULT_ENSURE_REF(conn);
321 [ - + ][ # # ]: 778 : RESULT_ENSURE_REF(data_to_verify);
322 : :
323 [ - + ]: 778 : RESULT_GUARD_POSIX(kex->server_key_recv_read_data(conn, data_to_verify, raw_server_data));
324 : :
325 : 778 : return S2N_RESULT_OK;
326 : 778 : }
327 : :
328 : : S2N_RESULT s2n_kex_server_key_send(const struct s2n_kex *kex, struct s2n_connection *conn, struct s2n_blob *data_to_sign)
329 : 851 : {
330 [ + + ][ + - ]: 851 : RESULT_ENSURE_REF(kex);
331 [ - + ][ # # ]: 850 : RESULT_ENSURE_REF(kex->server_key_send);
332 [ - + ][ # # ]: 850 : RESULT_ENSURE_REF(conn);
333 [ # # ][ - + ]: 850 : RESULT_ENSURE_REF(data_to_sign);
334 : :
335 [ - + ]: 850 : RESULT_GUARD_POSIX(kex->server_key_send(conn, data_to_sign));
336 : :
337 : 850 : return S2N_RESULT_OK;
338 : 850 : }
339 : :
340 : : S2N_RESULT s2n_kex_client_key_recv(const struct s2n_kex *kex, struct s2n_connection *conn, struct s2n_blob *shared_key)
341 : 2300 : {
342 [ + - ][ + + ]: 2300 : RESULT_ENSURE_REF(kex);
343 [ - + ][ # # ]: 2299 : RESULT_ENSURE_REF(kex->client_key_recv);
344 [ - + ][ # # ]: 2299 : RESULT_ENSURE_REF(conn);
345 [ # # ][ - + ]: 2299 : RESULT_ENSURE_REF(shared_key);
346 : :
347 [ + + ]: 2299 : RESULT_GUARD_POSIX(kex->client_key_recv(conn, shared_key));
348 : :
349 : 2236 : return S2N_RESULT_OK;
350 : 2299 : }
351 : :
352 : : S2N_RESULT s2n_kex_client_key_send(const struct s2n_kex *kex, struct s2n_connection *conn, struct s2n_blob *shared_key)
353 : 2205 : {
354 [ + - ][ + + ]: 2205 : RESULT_ENSURE_REF(kex);
355 [ - + ][ # # ]: 2204 : RESULT_ENSURE_REF(kex->client_key_send);
356 [ - + ][ # # ]: 2204 : RESULT_ENSURE_REF(conn);
357 [ # # ][ - + ]: 2204 : RESULT_ENSURE_REF(shared_key);
358 : :
359 [ - + ]: 2204 : RESULT_GUARD_POSIX(kex->client_key_send(conn, shared_key));
360 : :
361 : 2204 : return S2N_RESULT_OK;
362 : 2204 : }
363 : :
364 : : S2N_RESULT s2n_kex_tls_prf(const struct s2n_kex *kex, struct s2n_connection *conn, struct s2n_blob *premaster_secret)
365 : 4441 : {
366 [ + + ][ + - ]: 4441 : RESULT_ENSURE_REF(kex);
367 [ # # ][ - + ]: 4440 : RESULT_ENSURE_REF(kex->prf);
368 [ - + ][ # # ]: 4440 : RESULT_ENSURE_REF(conn);
369 [ - + ][ # # ]: 4440 : RESULT_ENSURE_REF(premaster_secret);
370 : :
371 [ - + ]: 4440 : RESULT_GUARD_POSIX(kex->prf(conn, premaster_secret));
372 : :
373 : 4440 : return S2N_RESULT_OK;
374 : 4440 : }
375 : :
376 : : bool s2n_kex_includes(const struct s2n_kex *kex, const struct s2n_kex *query)
377 : 2111359 : {
378 [ + + ]: 2111359 : if (kex == query) {
379 : 587016 : return true;
380 : 587016 : }
381 : :
382 [ + + ][ + + ]: 1524343 : if (kex == NULL || query == NULL) {
383 : 6 : return false;
384 : 6 : }
385 : :
386 [ + + ][ + + ]: 1524337 : return query == kex->hybrid[0] || query == kex->hybrid[1];
387 : 1524343 : }
|