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 #include "pq-crypto/s2n_pq.h"
18 #include "tls/s2n_cipher_preferences.h"
19 #include "tls/s2n_cipher_suites.h"
20 #include "tls/s2n_client_key_exchange.h"
21 #include "tls/s2n_kem.h"
22 #include "tls/s2n_security_policies.h"
23 #include "tls/s2n_server_key_exchange.h"
24 #include "tls/s2n_tls.h"
25 #include "utils/s2n_safety.h"
26
s2n_check_rsa_key(const struct s2n_cipher_suite * cipher_suite,struct s2n_connection * conn,bool * is_supported)27 static S2N_RESULT s2n_check_rsa_key(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported)
28 {
29 RESULT_ENSURE_REF(cipher_suite);
30 RESULT_ENSURE_REF(conn);
31 RESULT_ENSURE_REF(is_supported);
32
33 *is_supported = s2n_get_compatible_cert_chain_and_key(conn, S2N_PKEY_TYPE_RSA) != NULL;
34
35 return S2N_RESULT_OK;
36 }
37
s2n_check_dhe(const struct s2n_cipher_suite * cipher_suite,struct s2n_connection * conn,bool * is_supported)38 static S2N_RESULT s2n_check_dhe(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported)
39 {
40 RESULT_ENSURE_REF(cipher_suite);
41 RESULT_ENSURE_REF(conn);
42 RESULT_ENSURE_REF(conn->config);
43 RESULT_ENSURE_REF(is_supported);
44
45 *is_supported = conn->config->dhparams != NULL;
46
47 return S2N_RESULT_OK;
48 }
49
s2n_check_ecdhe(const struct s2n_cipher_suite * cipher_suite,struct s2n_connection * conn,bool * is_supported)50 static S2N_RESULT s2n_check_ecdhe(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported)
51 {
52 RESULT_ENSURE_REF(cipher_suite);
53 RESULT_ENSURE_REF(conn);
54 RESULT_ENSURE_REF(is_supported);
55
56 *is_supported = conn->kex_params.server_ecc_evp_params.negotiated_curve != NULL;
57
58 return S2N_RESULT_OK;
59 }
60
s2n_check_kem(const struct s2n_cipher_suite * cipher_suite,struct s2n_connection * conn,bool * is_supported)61 static S2N_RESULT s2n_check_kem(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported)
62 {
63 RESULT_ENSURE_REF(cipher_suite);
64 RESULT_ENSURE_REF(conn);
65 RESULT_ENSURE_REF(is_supported);
66
67 /* If any of the necessary conditions are not met, we will return early and indicate KEM is not supported. */
68 *is_supported = false;
69
70 const struct s2n_kem_preferences *kem_preferences = NULL;
71 RESULT_GUARD_POSIX(s2n_connection_get_kem_preferences(conn, &kem_preferences));
72 RESULT_ENSURE_REF(kem_preferences);
73
74 if (!s2n_pq_is_enabled() || kem_preferences->kem_count == 0) {
75 return S2N_RESULT_OK;
76 }
77
78 const struct s2n_iana_to_kem *supported_params = NULL;
79 if (s2n_cipher_suite_to_kem(cipher_suite->iana_value, &supported_params) != S2N_SUCCESS) {
80 return S2N_RESULT_OK;
81 }
82
83 RESULT_ENSURE_REF(supported_params);
84 if (supported_params->kem_count == 0) {
85 return S2N_RESULT_OK;
86 }
87
88 struct s2n_blob *client_kem_pref_list = &(conn->kex_params.client_pq_kem_extension);
89 const struct s2n_kem *chosen_kem = NULL;
90 if (client_kem_pref_list == NULL || client_kem_pref_list->data == NULL) {
91 /* If the client did not send a PQ KEM extension, then the server can pick its preferred parameter */
92 if (s2n_choose_kem_without_peer_pref_list(cipher_suite->iana_value, kem_preferences->kems,
93 kem_preferences->kem_count, &chosen_kem) != S2N_SUCCESS) {
94 return S2N_RESULT_OK;
95 }
96 } else {
97 /* If the client did send a PQ KEM extension, then the server must find a mutually supported parameter. */
98 if (s2n_choose_kem_with_peer_pref_list(cipher_suite->iana_value, client_kem_pref_list, kem_preferences->kems,
99 kem_preferences->kem_count, &chosen_kem) != S2N_SUCCESS) {
100 return S2N_RESULT_OK;
101 }
102 }
103
104 *is_supported = chosen_kem != NULL;
105 return S2N_RESULT_OK;
106 }
107
s2n_configure_kem(const struct s2n_cipher_suite * cipher_suite,struct s2n_connection * conn)108 static S2N_RESULT s2n_configure_kem(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn)
109 {
110 RESULT_ENSURE_REF(cipher_suite);
111 RESULT_ENSURE_REF(conn);
112
113 RESULT_ENSURE(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED);
114
115 const struct s2n_kem_preferences *kem_preferences = NULL;
116 RESULT_GUARD_POSIX(s2n_connection_get_kem_preferences(conn, &kem_preferences));
117 RESULT_ENSURE_REF(kem_preferences);
118
119 struct s2n_blob *proposed_kems = &(conn->kex_params.client_pq_kem_extension);
120 const struct s2n_kem *chosen_kem = NULL;
121 if (proposed_kems == NULL || proposed_kems->data == NULL) {
122 /* If the client did not send a PQ KEM extension, then the server can pick its preferred parameter */
123 RESULT_GUARD_POSIX(s2n_choose_kem_without_peer_pref_list(cipher_suite->iana_value, kem_preferences->kems,
124 kem_preferences->kem_count, &chosen_kem));
125 } else {
126 /* If the client did send a PQ KEM extension, then the server must find a mutually supported parameter. */
127 RESULT_GUARD_POSIX(s2n_choose_kem_with_peer_pref_list(cipher_suite->iana_value, proposed_kems, kem_preferences->kems,
128 kem_preferences->kem_count, &chosen_kem));
129 }
130
131 conn->kex_params.kem_params.kem = chosen_kem;
132 return S2N_RESULT_OK;
133 }
134
s2n_no_op_configure(const struct s2n_cipher_suite * cipher_suite,struct s2n_connection * conn)135 static S2N_RESULT s2n_no_op_configure(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn)
136 {
137 return S2N_RESULT_OK;
138 }
139
s2n_check_hybrid_ecdhe_kem(const struct s2n_cipher_suite * cipher_suite,struct s2n_connection * conn,bool * is_supported)140 static S2N_RESULT s2n_check_hybrid_ecdhe_kem(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported)
141 {
142 RESULT_ENSURE_REF(cipher_suite);
143 RESULT_ENSURE_REF(conn);
144 RESULT_ENSURE_REF(is_supported);
145
146 bool ecdhe_supported = false;
147 bool kem_supported = false;
148 RESULT_GUARD(s2n_check_ecdhe(cipher_suite, conn, &ecdhe_supported));
149 RESULT_GUARD(s2n_check_kem(cipher_suite, conn, &kem_supported));
150
151 *is_supported = ecdhe_supported && kem_supported;
152
153 return S2N_RESULT_OK;
154 }
155
156 const struct s2n_kex s2n_kem = {
157 .is_ephemeral = true,
158 .connection_supported = &s2n_check_kem,
159 .configure_connection = &s2n_configure_kem,
160 .server_key_recv_read_data = &s2n_kem_server_key_recv_read_data,
161 .server_key_recv_parse_data = &s2n_kem_server_key_recv_parse_data,
162 .server_key_send = &s2n_kem_server_key_send,
163 .client_key_recv = &s2n_kem_client_key_recv,
164 .client_key_send = &s2n_kem_client_key_send,
165 };
166
167 const struct s2n_kex s2n_rsa = {
168 .is_ephemeral = false,
169 .connection_supported = &s2n_check_rsa_key,
170 .configure_connection = &s2n_no_op_configure,
171 .server_key_recv_read_data = NULL,
172 .server_key_recv_parse_data = NULL,
173 .server_key_send = NULL,
174 .client_key_recv = &s2n_rsa_client_key_recv,
175 .client_key_send = &s2n_rsa_client_key_send,
176 .prf = &s2n_prf_calculate_master_secret,
177 };
178
179 const struct s2n_kex s2n_dhe = {
180 .is_ephemeral = true,
181 .connection_supported = &s2n_check_dhe,
182 .configure_connection = &s2n_no_op_configure,
183 .server_key_recv_read_data = &s2n_dhe_server_key_recv_read_data,
184 .server_key_recv_parse_data = &s2n_dhe_server_key_recv_parse_data,
185 .server_key_send = &s2n_dhe_server_key_send,
186 .client_key_recv = &s2n_dhe_client_key_recv,
187 .client_key_send = &s2n_dhe_client_key_send,
188 .prf = &s2n_prf_calculate_master_secret,
189 };
190
191 const struct s2n_kex s2n_ecdhe = {
192 .is_ephemeral = true,
193 .connection_supported = &s2n_check_ecdhe,
194 .configure_connection = &s2n_no_op_configure,
195 .server_key_recv_read_data = &s2n_ecdhe_server_key_recv_read_data,
196 .server_key_recv_parse_data = &s2n_ecdhe_server_key_recv_parse_data,
197 .server_key_send = &s2n_ecdhe_server_key_send,
198 .client_key_recv = &s2n_ecdhe_client_key_recv,
199 .client_key_send = &s2n_ecdhe_client_key_send,
200 .prf = &s2n_prf_calculate_master_secret,
201 };
202
203 const struct s2n_kex s2n_hybrid_ecdhe_kem = {
204 .is_ephemeral = true,
205 .hybrid = { &s2n_ecdhe, &s2n_kem },
206 .connection_supported = &s2n_check_hybrid_ecdhe_kem,
207 .configure_connection = &s2n_configure_kem,
208 .server_key_recv_read_data = &s2n_hybrid_server_key_recv_read_data,
209 .server_key_recv_parse_data = &s2n_hybrid_server_key_recv_parse_data,
210 .server_key_send = &s2n_hybrid_server_key_send,
211 .client_key_recv = &s2n_hybrid_client_key_recv,
212 .client_key_send = &s2n_hybrid_client_key_send,
213 .prf = &s2n_hybrid_prf_master_secret,
214 };
215
s2n_kex_supported(const struct s2n_cipher_suite * cipher_suite,struct s2n_connection * conn,bool * is_supported)216 S2N_RESULT s2n_kex_supported(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported)
217 {
218 RESULT_ENSURE_REF(cipher_suite);
219 RESULT_ENSURE_REF(cipher_suite->key_exchange_alg);
220 RESULT_ENSURE_REF(cipher_suite->key_exchange_alg->connection_supported);
221 RESULT_ENSURE_REF(conn);
222 RESULT_ENSURE_REF(is_supported);
223
224 RESULT_GUARD(cipher_suite->key_exchange_alg->connection_supported(cipher_suite, conn, is_supported));
225
226 return S2N_RESULT_OK;
227 }
228
s2n_configure_kex(const struct s2n_cipher_suite * cipher_suite,struct s2n_connection * conn)229 S2N_RESULT s2n_configure_kex(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn)
230 {
231 RESULT_ENSURE_REF(cipher_suite);
232 RESULT_ENSURE_REF(cipher_suite->key_exchange_alg);
233 RESULT_ENSURE_REF(cipher_suite->key_exchange_alg->configure_connection);
234 RESULT_ENSURE_REF(conn);
235
236 RESULT_GUARD(cipher_suite->key_exchange_alg->configure_connection(cipher_suite, conn));
237
238 return S2N_RESULT_OK;
239 }
240
s2n_kex_is_ephemeral(const struct s2n_kex * kex,bool * is_ephemeral)241 S2N_RESULT s2n_kex_is_ephemeral(const struct s2n_kex *kex, bool *is_ephemeral)
242 {
243 RESULT_ENSURE_REF(kex);
244 RESULT_ENSURE_REF(is_ephemeral);
245
246 *is_ephemeral = kex->is_ephemeral;
247
248 return S2N_RESULT_OK;
249 }
250
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)251 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)
252 {
253 RESULT_ENSURE_REF(kex);
254 RESULT_ENSURE_REF(kex->server_key_recv_parse_data);
255 RESULT_ENSURE_REF(conn);
256 RESULT_ENSURE_REF(raw_server_data);
257
258 RESULT_GUARD_POSIX(kex->server_key_recv_parse_data(conn, raw_server_data));
259
260 return S2N_RESULT_OK;
261 }
262
s2n_kex_server_key_recv_read_data(const struct s2n_kex * kex,struct s2n_connection * conn,struct s2n_blob * data_to_verify,struct s2n_kex_raw_server_data * raw_server_data)263 S2N_RESULT s2n_kex_server_key_recv_read_data(const struct s2n_kex *kex, struct s2n_connection *conn, struct s2n_blob *data_to_verify,
264 struct s2n_kex_raw_server_data *raw_server_data)
265 {
266 RESULT_ENSURE_REF(kex);
267 RESULT_ENSURE_REF(kex->server_key_recv_read_data);
268 RESULT_ENSURE_REF(conn);
269 RESULT_ENSURE_REF(data_to_verify);
270
271 RESULT_GUARD_POSIX(kex->server_key_recv_read_data(conn, data_to_verify, raw_server_data));
272
273 return S2N_RESULT_OK;
274 }
275
s2n_kex_server_key_send(const struct s2n_kex * kex,struct s2n_connection * conn,struct s2n_blob * data_to_sign)276 S2N_RESULT s2n_kex_server_key_send(const struct s2n_kex *kex, struct s2n_connection *conn, struct s2n_blob *data_to_sign)
277 {
278 RESULT_ENSURE_REF(kex);
279 RESULT_ENSURE_REF(kex->server_key_send);
280 RESULT_ENSURE_REF(conn);
281 RESULT_ENSURE_REF(data_to_sign);
282
283 RESULT_GUARD_POSIX(kex->server_key_send(conn, data_to_sign));
284
285 return S2N_RESULT_OK;
286 }
287
s2n_kex_client_key_recv(const struct s2n_kex * kex,struct s2n_connection * conn,struct s2n_blob * shared_key)288 S2N_RESULT s2n_kex_client_key_recv(const struct s2n_kex *kex, struct s2n_connection *conn, struct s2n_blob *shared_key)
289 {
290 RESULT_ENSURE_REF(kex);
291 RESULT_ENSURE_REF(kex->client_key_recv);
292 RESULT_ENSURE_REF(conn);
293 RESULT_ENSURE_REF(shared_key);
294
295 RESULT_GUARD_POSIX(kex->client_key_recv(conn, shared_key));
296
297 return S2N_RESULT_OK;
298 }
299
s2n_kex_client_key_send(const struct s2n_kex * kex,struct s2n_connection * conn,struct s2n_blob * shared_key)300 S2N_RESULT s2n_kex_client_key_send(const struct s2n_kex *kex, struct s2n_connection *conn, struct s2n_blob *shared_key)
301 {
302 RESULT_ENSURE_REF(kex);
303 RESULT_ENSURE_REF(kex->client_key_send);
304 RESULT_ENSURE_REF(conn);
305 RESULT_ENSURE_REF(shared_key);
306
307 RESULT_GUARD_POSIX(kex->client_key_send(conn, shared_key));
308
309 return S2N_RESULT_OK;
310 }
311
s2n_kex_tls_prf(const struct s2n_kex * kex,struct s2n_connection * conn,struct s2n_blob * premaster_secret)312 S2N_RESULT s2n_kex_tls_prf(const struct s2n_kex *kex, struct s2n_connection *conn, struct s2n_blob *premaster_secret)
313 {
314 RESULT_ENSURE_REF(kex);
315 RESULT_ENSURE_REF(kex->prf);
316 RESULT_ENSURE_REF(conn);
317 RESULT_ENSURE_REF(premaster_secret);
318
319 RESULT_GUARD_POSIX(kex->prf(conn, premaster_secret));
320
321 return S2N_RESULT_OK;
322 }
323
s2n_kex_includes(const struct s2n_kex * kex,const struct s2n_kex * query)324 bool s2n_kex_includes(const struct s2n_kex *kex, const struct s2n_kex *query)
325 {
326 if (kex == query) {
327 return true;
328 }
329
330 if (kex == NULL || query == NULL) {
331 return false;
332 }
333
334 return query == kex->hybrid[0] || query == kex->hybrid[1];
335 }
336