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_kem.h"
17 : :
18 : : #include "crypto/s2n_evp_kem.h"
19 : : #include "crypto/s2n_pq.h"
20 : : #include "stuffer/s2n_stuffer.h"
21 : : #include "tls/extensions/s2n_key_share.h"
22 : : #include "tls/s2n_tls_parameters.h"
23 : : #include "utils/s2n_mem.h"
24 : : #include "utils/s2n_safety.h"
25 : :
26 : : const struct s2n_kem s2n_mlkem_768 = {
27 : : .name = "mlkem768",
28 : : .kem_nid = S2N_NID_MLKEM768,
29 : : .kem_extension_id = 0, /* This is not used in TLS 1.2's KEM extension */
30 : : .public_key_length = S2N_MLKEM_768_PUBLIC_KEY_BYTES,
31 : : .private_key_length = S2N_MLKEM_768_SECRET_KEY_BYTES,
32 : : .shared_secret_key_length = S2N_MLKEM_768_SHARED_SECRET_BYTES,
33 : : .ciphertext_length = S2N_MLKEM_768_CIPHERTEXT_BYTES,
34 : : .generate_keypair = &s2n_evp_kem_generate_keypair,
35 : : .encapsulate = &s2n_evp_kem_encapsulate,
36 : : .decapsulate = &s2n_evp_kem_decapsulate,
37 : : };
38 : :
39 : : const struct s2n_kem s2n_mlkem_1024 = {
40 : : .name = "mlkem1024",
41 : : .kem_nid = S2N_NID_MLKEM1024,
42 : : .kem_extension_id = 0, /* This is not used in TLS 1.2's KEM extension */
43 : : .public_key_length = S2N_MLKEM_1024_PUBLIC_KEY_BYTES,
44 : : .private_key_length = S2N_MLKEM_1024_SECRET_KEY_BYTES,
45 : : .shared_secret_key_length = S2N_MLKEM_1024_SHARED_SECRET_BYTES,
46 : : .ciphertext_length = S2N_MLKEM_1024_CIPHERTEXT_BYTES,
47 : : .generate_keypair = &s2n_evp_kem_generate_keypair,
48 : : .encapsulate = &s2n_evp_kem_encapsulate,
49 : : .decapsulate = &s2n_evp_kem_decapsulate,
50 : : };
51 : :
52 : : const struct s2n_kem s2n_kyber_512_r3 = {
53 : : .name = "kyber512r3",
54 : : .kem_nid = S2N_NID_KYBER512,
55 : : .kem_extension_id = TLS_PQ_KEM_EXTENSION_ID_KYBER_512_R3,
56 : : .public_key_length = S2N_KYBER_512_R3_PUBLIC_KEY_BYTES,
57 : : .private_key_length = S2N_KYBER_512_R3_SECRET_KEY_BYTES,
58 : : .shared_secret_key_length = S2N_KYBER_512_R3_SHARED_SECRET_BYTES,
59 : : .ciphertext_length = S2N_KYBER_512_R3_CIPHERTEXT_BYTES,
60 : : .generate_keypair = &s2n_evp_kem_generate_keypair,
61 : : .encapsulate = &s2n_evp_kem_encapsulate,
62 : : .decapsulate = &s2n_evp_kem_decapsulate,
63 : : };
64 : :
65 : : const struct s2n_kem s2n_kyber_768_r3 = {
66 : : .name = "kyber768r3",
67 : : .kem_nid = S2N_NID_KYBER768,
68 : : .kem_extension_id = 0, /* This is not used in TLS 1.2's KEM extension */
69 : : .public_key_length = S2N_KYBER_768_R3_PUBLIC_KEY_BYTES,
70 : : .private_key_length = S2N_KYBER_768_R3_SECRET_KEY_BYTES,
71 : : .shared_secret_key_length = S2N_KYBER_768_R3_SHARED_SECRET_BYTES,
72 : : .ciphertext_length = S2N_KYBER_768_R3_CIPHERTEXT_BYTES,
73 : : .generate_keypair = &s2n_evp_kem_generate_keypair,
74 : : .encapsulate = &s2n_evp_kem_encapsulate,
75 : : .decapsulate = &s2n_evp_kem_decapsulate,
76 : : };
77 : :
78 : : const struct s2n_kem s2n_kyber_1024_r3 = {
79 : : .name = "kyber1024r3",
80 : : .kem_nid = S2N_NID_KYBER1024,
81 : : .kem_extension_id = 0, /* This is not used in TLS 1.2's KEM extension */
82 : : .public_key_length = S2N_KYBER_1024_R3_PUBLIC_KEY_BYTES,
83 : : .private_key_length = S2N_KYBER_1024_R3_SECRET_KEY_BYTES,
84 : : .shared_secret_key_length = S2N_KYBER_1024_R3_SHARED_SECRET_BYTES,
85 : : .ciphertext_length = S2N_KYBER_1024_R3_CIPHERTEXT_BYTES,
86 : : .generate_keypair = &s2n_evp_kem_generate_keypair,
87 : : .encapsulate = &s2n_evp_kem_encapsulate,
88 : : .decapsulate = &s2n_evp_kem_decapsulate,
89 : : };
90 : :
91 : : const struct s2n_kem *tls12_kyber_kems[] = {
92 : : &s2n_kyber_512_r3,
93 : : };
94 : :
95 : : const struct s2n_iana_to_kem kem_mapping[1] = {
96 : : {
97 : : .iana_value = { TLS_ECDHE_KYBER_RSA_WITH_AES_256_GCM_SHA384 },
98 : : .kems = tls12_kyber_kems,
99 : : .kem_count = s2n_array_len(tls12_kyber_kems),
100 : : },
101 : : };
102 : :
103 : : /* Specific assignments of KEM group IDs and names have not yet been
104 : : * published in an RFC (or draft). There is consensus in the
105 : : * community to use values in the proposed reserved range defined in
106 : : * https://tools.ietf.org/html/draft-stebila-tls-hybrid-design.
107 : : * Values for interoperability are defined in
108 : : * https://github.com/open-quantum-safe/oqs-provider/blob/main/oqs-template/oqs-kem-info.md
109 : : * and
110 : : * https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml
111 : : */
112 : :
113 : : /*
114 : : * ML-KEM based pure PQ KEMs as specified by IETF and registered in IANA.
115 : : *
116 : : * https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
117 : : * https://datatracker.ietf.org/doc/draft-connolly-tls-mlkem-key-agreement/05/
118 : : */
119 : : const struct s2n_kem_group s2n_pure_mlkem_1024 = {
120 : : .name = "MLKEM1024",
121 : : .iana_id = TLS_PQ_KEM_GROUP_ID_MLKEM_1024,
122 : : .curve = &s2n_ecc_curve_none,
123 : : .kem = &s2n_mlkem_1024,
124 : : .send_kem_first = 0,
125 : : };
126 : :
127 : : /*
128 : : * ML-KEM based hybrid KEMs as specified by IETF and registered in IANA.
129 : : *
130 : : * https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
131 : : * https://datatracker.ietf.org/doc/draft-kwiatkowski-tls-ecdhe-mlkem/
132 : : */
133 : : const struct s2n_kem_group s2n_secp256r1_mlkem_768 = {
134 : : .name = "SecP256r1MLKEM768",
135 : : .iana_id = TLS_PQ_KEM_GROUP_ID_SECP256R1_MLKEM_768,
136 : : .curve = &s2n_ecc_curve_secp256r1,
137 : : .kem = &s2n_mlkem_768,
138 : : .send_kem_first = 0,
139 : : };
140 : :
141 : : const struct s2n_kem_group s2n_x25519_mlkem_768 = {
142 : : .name = "X25519MLKEM768",
143 : : .iana_id = TLS_PQ_KEM_GROUP_ID_X25519_MLKEM_768,
144 : : .curve = &s2n_ecc_curve_x25519,
145 : : .kem = &s2n_mlkem_768,
146 : : /* ML-KEM KeyShare should always be sent first for X25519MLKEM768.
147 : : * https://datatracker.ietf.org/doc/html/draft-kwiatkowski-tls-ecdhe-mlkem-02#name-negotiated-groups */
148 : : .send_kem_first = 1,
149 : : };
150 : :
151 : : const struct s2n_kem_group s2n_secp384r1_mlkem_1024 = {
152 : : .name = "SecP384r1MLKEM1024",
153 : : .iana_id = TLS_PQ_KEM_GROUP_ID_SECP384R1_MLKEM_1024,
154 : : .curve = &s2n_ecc_curve_secp384r1,
155 : : .kem = &s2n_mlkem_1024,
156 : : .send_kem_first = 0,
157 : : };
158 : :
159 : : const struct s2n_kem_group s2n_secp256r1_kyber_512_r3 = {
160 : : .name = "secp256r1_kyber-512-r3",
161 : : .iana_id = TLS_PQ_KEM_GROUP_ID_SECP256R1_KYBER_512_R3,
162 : : .curve = &s2n_ecc_curve_secp256r1,
163 : : .kem = &s2n_kyber_512_r3,
164 : : .send_kem_first = 0,
165 : : };
166 : :
167 : : const struct s2n_kem_group s2n_secp256r1_kyber_768_r3 = {
168 : : .name = "SecP256r1Kyber768Draft00",
169 : : .iana_id = TLS_PQ_KEM_GROUP_ID_SECP256R1_KYBER_768_R3,
170 : : .curve = &s2n_ecc_curve_secp256r1,
171 : : .kem = &s2n_kyber_768_r3,
172 : : .send_kem_first = 0,
173 : : };
174 : :
175 : : const struct s2n_kem_group s2n_secp384r1_kyber_768_r3 = {
176 : : .name = "secp384r1_kyber-768-r3",
177 : : .iana_id = TLS_PQ_KEM_GROUP_ID_SECP384R1_KYBER_768_R3,
178 : : .curve = &s2n_ecc_curve_secp384r1,
179 : : .kem = &s2n_kyber_768_r3,
180 : : .send_kem_first = 0,
181 : : };
182 : :
183 : : const struct s2n_kem_group s2n_secp521r1_kyber_1024_r3 = {
184 : : .name = "secp521r1_kyber-1024-r3",
185 : : .iana_id = TLS_PQ_KEM_GROUP_ID_SECP521R1_KYBER_1024_R3,
186 : : .curve = &s2n_ecc_curve_secp521r1,
187 : : .kem = &s2n_kyber_1024_r3,
188 : : .send_kem_first = 0,
189 : : };
190 : :
191 : : const struct s2n_kem_group s2n_x25519_kyber_512_r3 = {
192 : : .name = "x25519_kyber-512-r3",
193 : : .iana_id = TLS_PQ_KEM_GROUP_ID_X25519_KYBER_512_R3,
194 : : .curve = &s2n_ecc_curve_x25519,
195 : : .kem = &s2n_kyber_512_r3,
196 : : .send_kem_first = 0,
197 : : };
198 : :
199 : : const struct s2n_kem_group s2n_x25519_kyber_768_r3 = {
200 : : .name = "X25519Kyber768Draft00",
201 : : .iana_id = TLS_PQ_KEM_GROUP_ID_X25519_KYBER_768_R3,
202 : : .curve = &s2n_ecc_curve_x25519,
203 : : .kem = &s2n_kyber_768_r3,
204 : : .send_kem_first = 0,
205 : : };
206 : :
207 : : const struct s2n_kem_group *ALL_SUPPORTED_KEM_GROUPS[] = {
208 : : &s2n_x25519_mlkem_768,
209 : : &s2n_secp256r1_mlkem_768,
210 : : &s2n_secp384r1_mlkem_1024,
211 : : &s2n_secp256r1_kyber_768_r3,
212 : : &s2n_x25519_kyber_768_r3,
213 : : &s2n_secp384r1_kyber_768_r3,
214 : : &s2n_secp521r1_kyber_1024_r3,
215 : : &s2n_secp256r1_kyber_512_r3,
216 : : &s2n_x25519_kyber_512_r3,
217 : : };
218 : :
219 : : /* Helper safety macro to call the NIST PQ KEM functions. The NIST
220 : : * functions may return any non-zero value to indicate failure. */
221 : 12 : #define GUARD_PQ_AS_RESULT(x) RESULT_ENSURE((x) == 0, S2N_ERR_PQ_CRYPTO)
222 : :
223 : : S2N_RESULT s2n_kem_generate_keypair(struct s2n_kem_params *kem_params)
224 : 4 : {
225 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params);
226 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params->kem);
227 : 4 : const struct s2n_kem *kem = kem_params->kem;
228 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem->generate_keypair);
229 : :
230 [ # # ][ - + ]: 4 : RESULT_ENSURE_REF(kem_params->public_key.data);
231 [ - + ][ # # ]: 4 : RESULT_ENSURE(kem_params->public_key.size == kem->public_key_length, S2N_ERR_SAFETY);
232 : :
233 : : /* Need to save the private key for decapsulation */
234 [ - + ]: 4 : RESULT_GUARD_POSIX(s2n_realloc(&kem_params->private_key, kem->private_key_length));
235 : :
236 [ - + ][ # # ]: 4 : GUARD_PQ_AS_RESULT(kem->generate_keypair(kem, kem_params->public_key.data, kem_params->private_key.data));
237 : 4 : return S2N_RESULT_OK;
238 : 4 : }
239 : :
240 : : S2N_RESULT s2n_kem_encapsulate(struct s2n_kem_params *kem_params, struct s2n_blob *ciphertext)
241 : 4 : {
242 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params);
243 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params->kem);
244 : 4 : const struct s2n_kem *kem = kem_params->kem;
245 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem->encapsulate);
246 : :
247 [ - + ][ # # ]: 4 : RESULT_ENSURE(kem_params->public_key.size == kem->public_key_length, S2N_ERR_SAFETY);
248 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params->public_key.data);
249 : :
250 [ # # ][ - + ]: 4 : RESULT_ENSURE_REF(ciphertext);
251 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(ciphertext->data);
252 [ - + ][ # # ]: 4 : RESULT_ENSURE(ciphertext->size == kem->ciphertext_length, S2N_ERR_SAFETY);
253 : :
254 : : /* Need to save the shared secret for key derivation */
255 [ - + ]: 4 : RESULT_GUARD_POSIX(s2n_alloc(&(kem_params->shared_secret), kem->shared_secret_key_length));
256 : :
257 [ - + ][ # # ]: 4 : GUARD_PQ_AS_RESULT(kem->encapsulate(kem, ciphertext->data, kem_params->shared_secret.data, kem_params->public_key.data));
258 : 4 : return S2N_RESULT_OK;
259 : 4 : }
260 : :
261 : : S2N_RESULT s2n_kem_decapsulate(struct s2n_kem_params *kem_params, const struct s2n_blob *ciphertext)
262 : 4 : {
263 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params);
264 [ # # ][ - + ]: 4 : RESULT_ENSURE_REF(kem_params->kem);
265 : 4 : const struct s2n_kem *kem = kem_params->kem;
266 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem->decapsulate);
267 : :
268 [ - + ][ # # ]: 4 : RESULT_ENSURE(kem_params->private_key.size == kem->private_key_length, S2N_ERR_SAFETY);
269 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params->private_key.data);
270 : :
271 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(ciphertext);
272 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(ciphertext->data);
273 [ - + ][ # # ]: 4 : RESULT_ENSURE(ciphertext->size == kem->ciphertext_length, S2N_ERR_SAFETY);
274 : :
275 : : /* Need to save the shared secret for key derivation */
276 [ - + ]: 4 : RESULT_GUARD_POSIX(s2n_alloc(&(kem_params->shared_secret), kem->shared_secret_key_length));
277 : :
278 [ - + ][ # # ]: 4 : GUARD_PQ_AS_RESULT(kem->decapsulate(kem, kem_params->shared_secret.data, ciphertext->data, kem_params->private_key.data));
279 : 4 : return S2N_RESULT_OK;
280 : 4 : }
281 : :
282 : : static int s2n_kem_check_kem_compatibility(const uint8_t iana_value[S2N_TLS_CIPHER_SUITE_LEN], const struct s2n_kem *candidate_kem,
283 : : uint8_t *kem_is_compatible)
284 : 0 : {
285 : 0 : const struct s2n_iana_to_kem *compatible_kems = NULL;
286 [ # # ]: 0 : POSIX_GUARD(s2n_cipher_suite_to_kem(iana_value, &compatible_kems));
287 : :
288 [ # # ]: 0 : for (uint8_t i = 0; i < compatible_kems->kem_count; i++) {
289 [ # # ]: 0 : if (candidate_kem->kem_extension_id == compatible_kems->kems[i]->kem_extension_id) {
290 : 0 : *kem_is_compatible = 1;
291 : 0 : return S2N_SUCCESS;
292 : 0 : }
293 : 0 : }
294 : :
295 : 0 : *kem_is_compatible = 0;
296 : 0 : return S2N_SUCCESS;
297 : 0 : }
298 : :
299 : : int s2n_choose_kem_with_peer_pref_list(const uint8_t iana_value[S2N_TLS_CIPHER_SUITE_LEN], struct s2n_blob *client_kem_ids,
300 : : const struct s2n_kem *server_kem_pref_list[], const uint8_t num_server_supported_kems, const struct s2n_kem **chosen_kem)
301 : 0 : {
302 : 0 : struct s2n_stuffer client_kem_ids_stuffer = { 0 };
303 [ # # ]: 0 : POSIX_GUARD(s2n_stuffer_init(&client_kem_ids_stuffer, client_kem_ids));
304 [ # # ]: 0 : POSIX_GUARD(s2n_stuffer_write(&client_kem_ids_stuffer, client_kem_ids));
305 : :
306 : : /* Each KEM ID is 2 bytes */
307 : 0 : uint8_t num_client_candidate_kems = client_kem_ids->size / 2;
308 : :
309 [ # # ]: 0 : for (uint8_t i = 0; i < num_server_supported_kems; i++) {
310 : 0 : const struct s2n_kem *candidate_server_kem = (server_kem_pref_list[i]);
311 : :
312 : 0 : uint8_t server_kem_is_compatible = 0;
313 [ # # ]: 0 : POSIX_GUARD(s2n_kem_check_kem_compatibility(iana_value, candidate_server_kem, &server_kem_is_compatible));
314 : :
315 [ # # ]: 0 : if (!server_kem_is_compatible) {
316 : 0 : continue;
317 : 0 : }
318 : :
319 [ # # ]: 0 : for (uint8_t j = 0; j < num_client_candidate_kems; j++) {
320 : 0 : kem_extension_size candidate_client_kem_id = 0;
321 [ # # ]: 0 : POSIX_GUARD(s2n_stuffer_read_uint16(&client_kem_ids_stuffer, &candidate_client_kem_id));
322 : :
323 [ # # ]: 0 : if (candidate_server_kem->kem_extension_id == candidate_client_kem_id) {
324 : 0 : *chosen_kem = candidate_server_kem;
325 : 0 : return S2N_SUCCESS;
326 : 0 : }
327 : 0 : }
328 [ # # ]: 0 : POSIX_GUARD(s2n_stuffer_reread(&client_kem_ids_stuffer));
329 : 0 : }
330 : :
331 : : /* Client and server did not propose any mutually supported KEMs compatible with the ciphersuite */
332 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_KEM_UNSUPPORTED_PARAMS);
333 : 0 : }
334 : :
335 : : int s2n_choose_kem_without_peer_pref_list(const uint8_t iana_value[S2N_TLS_CIPHER_SUITE_LEN], const struct s2n_kem *server_kem_pref_list[],
336 : : const uint8_t num_server_supported_kems, const struct s2n_kem **chosen_kem)
337 : 0 : {
338 [ # # ]: 0 : for (uint8_t i = 0; i < num_server_supported_kems; i++) {
339 : 0 : uint8_t kem_is_compatible = 0;
340 [ # # ]: 0 : POSIX_GUARD(s2n_kem_check_kem_compatibility(iana_value, server_kem_pref_list[i], &kem_is_compatible));
341 [ # # ]: 0 : if (kem_is_compatible) {
342 : 0 : *chosen_kem = server_kem_pref_list[i];
343 : 0 : return S2N_SUCCESS;
344 : 0 : }
345 : 0 : }
346 : :
347 : : /* The server preference list did not contain any KEM extensions compatible with the ciphersuite */
348 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_KEM_UNSUPPORTED_PARAMS);
349 : 0 : }
350 : :
351 : : int s2n_kem_free(struct s2n_kem_params *kem_params)
352 : 10663696 : {
353 [ + + ]: 10663696 : if (kem_params != NULL) {
354 [ - + ]: 10663695 : POSIX_GUARD(s2n_free_or_wipe(&kem_params->private_key));
355 [ - + ]: 10663695 : POSIX_GUARD(s2n_free_or_wipe(&kem_params->public_key));
356 [ - + ]: 10663695 : POSIX_GUARD(s2n_free_or_wipe(&kem_params->shared_secret));
357 : 10663695 : }
358 : 10663696 : return S2N_SUCCESS;
359 : 10663696 : }
360 : :
361 : : int s2n_kem_group_free(struct s2n_kem_group_params *kem_group_params)
362 : 7115335 : {
363 [ + + ]: 7115335 : if (kem_group_params != NULL) {
364 [ - + ]: 7115334 : POSIX_GUARD(s2n_kem_free(&kem_group_params->kem_params));
365 [ - + ]: 7115334 : POSIX_GUARD(s2n_ecc_evp_params_free(&kem_group_params->ecc_params));
366 : 7115334 : }
367 : 7115335 : return S2N_SUCCESS;
368 : 7115335 : }
369 : :
370 : : int s2n_cipher_suite_to_kem(const uint8_t iana_value[S2N_TLS_CIPHER_SUITE_LEN], const struct s2n_iana_to_kem **compatible_params)
371 : 2 : {
372 [ + + ]: 3 : for (size_t i = 0; i < s2n_array_len(kem_mapping); i++) {
373 : 2 : const struct s2n_iana_to_kem *candidate = &kem_mapping[i];
374 [ + + ]: 2 : if (s2n_constant_time_equals(iana_value, candidate->iana_value, S2N_TLS_CIPHER_SUITE_LEN)) {
375 : 1 : *compatible_params = candidate;
376 : 1 : return S2N_SUCCESS;
377 : 1 : }
378 : 2 : }
379 [ + - ]: 1 : POSIX_BAIL(S2N_ERR_KEM_UNSUPPORTED_PARAMS);
380 : 1 : }
381 : :
382 : : int s2n_get_kem_from_extension_id(kem_extension_size kem_id, const struct s2n_kem **kem)
383 : 2 : {
384 [ + + ]: 3 : for (size_t i = 0; i < s2n_array_len(kem_mapping); i++) {
385 : 2 : const struct s2n_iana_to_kem *iana_to_kem = &kem_mapping[i];
386 : :
387 [ + + ]: 3 : for (int j = 0; j < iana_to_kem->kem_count; j++) {
388 : 2 : const struct s2n_kem *candidate_kem = iana_to_kem->kems[j];
389 [ + + ]: 2 : if (candidate_kem->kem_extension_id == kem_id) {
390 : 1 : *kem = candidate_kem;
391 : 1 : return S2N_SUCCESS;
392 : 1 : }
393 : 2 : }
394 : 2 : }
395 : :
396 [ + - ]: 1 : POSIX_BAIL(S2N_ERR_KEM_UNSUPPORTED_PARAMS);
397 : 1 : }
398 : :
399 : : int s2n_kem_send_public_key(struct s2n_stuffer *out, struct s2n_kem_params *kem_params)
400 : 8 : {
401 [ + - ][ + + ]: 8 : POSIX_ENSURE_REF(out);
402 [ + + ][ + - ]: 6 : POSIX_ENSURE_REF(kem_params);
403 [ + + ][ + - ]: 4 : POSIX_ENSURE_REF(kem_params->kem);
404 : :
405 : 2 : const struct s2n_kem *kem = kem_params->kem;
406 : :
407 [ + + ]: 2 : if (kem_params->len_prefixed) {
408 [ - + ]: 1 : POSIX_GUARD(s2n_stuffer_write_uint16(out, kem->public_key_length));
409 : 1 : }
410 : :
411 : : /* We don't need to store the public key after sending it.
412 : : * We write it directly to *out. */
413 : 2 : kem_params->public_key.data = s2n_stuffer_raw_write(out, kem->public_key_length);
414 [ # # ][ - + ]: 2 : POSIX_ENSURE_REF(kem_params->public_key.data);
415 : 2 : kem_params->public_key.size = kem->public_key_length;
416 : :
417 : : /* Saves the private key in kem_params */
418 [ - + ]: 2 : POSIX_GUARD_RESULT(s2n_kem_generate_keypair(kem_params));
419 : :
420 : : /* After using s2n_stuffer_raw_write() above to write the public
421 : : * key to the stuffer, we want to ensure that kem_params->public_key.data
422 : : * does not continue to point at *out, else we may unexpectedly
423 : : * overwrite part of the stuffer when s2n_kem_free() is called. */
424 : 2 : kem_params->public_key.data = NULL;
425 : 2 : kem_params->public_key.size = 0;
426 : :
427 : 2 : return S2N_SUCCESS;
428 : 2 : }
429 : :
430 : : int s2n_kem_recv_public_key(struct s2n_stuffer *in, struct s2n_kem_params *kem_params)
431 : 9 : {
432 [ + + ][ + - ]: 9 : POSIX_ENSURE_REF(in);
433 [ + + ][ + - ]: 7 : POSIX_ENSURE_REF(kem_params);
434 [ + + ][ + - ]: 5 : POSIX_ENSURE_REF(kem_params->kem);
435 : :
436 : 3 : const struct s2n_kem *kem = kem_params->kem;
437 : :
438 [ + + ]: 3 : if (kem_params->len_prefixed) {
439 : 2 : kem_public_key_size public_key_length = 0;
440 [ - + ]: 2 : POSIX_GUARD(s2n_stuffer_read_uint16(in, &public_key_length));
441 [ + + ][ + - ]: 2 : POSIX_ENSURE(public_key_length == kem->public_key_length, S2N_ERR_BAD_MESSAGE);
442 : 2 : }
443 : :
444 : : /* Alloc memory for the public key; the peer receiving it will need it
445 : : * later during the handshake to encapsulate the shared secret. */
446 [ - + ]: 2 : POSIX_GUARD(s2n_alloc(&(kem_params->public_key), kem->public_key_length));
447 [ - + ]: 2 : POSIX_GUARD(s2n_stuffer_read_bytes(in, kem_params->public_key.data, kem->public_key_length));
448 : :
449 : 2 : return S2N_SUCCESS;
450 : 2 : }
451 : :
452 : : int s2n_kem_send_ciphertext(struct s2n_stuffer *out, struct s2n_kem_params *kem_params)
453 : 10 : {
454 [ + + ][ + - ]: 10 : POSIX_ENSURE_REF(out);
455 [ + + ][ + - ]: 8 : POSIX_ENSURE_REF(kem_params);
456 [ + + ][ + - ]: 6 : POSIX_ENSURE_REF(kem_params->kem);
457 [ + + ][ + - ]: 4 : POSIX_ENSURE_REF(kem_params->public_key.data);
458 : :
459 : 2 : const struct s2n_kem *kem = kem_params->kem;
460 : :
461 [ + + ]: 2 : if (kem_params->len_prefixed) {
462 [ - + ]: 1 : POSIX_GUARD(s2n_stuffer_write_uint16(out, kem->ciphertext_length));
463 : 1 : }
464 : :
465 : : /* Ciphertext will get written to *out */
466 : 2 : struct s2n_blob ciphertext = { 0 };
467 [ - + ]: 2 : POSIX_GUARD(s2n_blob_init(&ciphertext, s2n_stuffer_raw_write(out, kem->ciphertext_length), kem->ciphertext_length));
468 [ # # ][ - + ]: 2 : POSIX_ENSURE_REF(ciphertext.data);
469 : :
470 : : /* Saves the shared secret in kem_params */
471 [ - + ]: 2 : POSIX_GUARD_RESULT(s2n_kem_encapsulate(kem_params, &ciphertext));
472 : :
473 : 2 : return S2N_SUCCESS;
474 : 2 : }
475 : :
476 : : int s2n_kem_recv_ciphertext(struct s2n_stuffer *in, struct s2n_kem_params *kem_params)
477 : 11 : {
478 [ + - ][ + + ]: 11 : POSIX_ENSURE_REF(in);
479 [ + + ][ + - ]: 9 : POSIX_ENSURE_REF(kem_params);
480 [ + - ][ + + ]: 7 : POSIX_ENSURE_REF(kem_params->kem);
481 [ + + ][ + - ]: 5 : POSIX_ENSURE_REF(kem_params->private_key.data);
482 : :
483 : 3 : const struct s2n_kem *kem = kem_params->kem;
484 : :
485 [ + + ]: 3 : if (kem_params->len_prefixed) {
486 : 2 : kem_ciphertext_key_size ciphertext_length = 0;
487 [ - + ]: 2 : POSIX_GUARD(s2n_stuffer_read_uint16(in, &ciphertext_length));
488 [ + + ][ + - ]: 2 : POSIX_ENSURE(ciphertext_length == kem->ciphertext_length, S2N_ERR_BAD_MESSAGE);
489 : 2 : }
490 : :
491 : 2 : const struct s2n_blob ciphertext = { .data = s2n_stuffer_raw_read(in, kem->ciphertext_length), .size = kem->ciphertext_length };
492 [ - + ][ # # ]: 2 : POSIX_ENSURE_REF(ciphertext.data);
493 : :
494 : : /* Saves the shared secret in kem_params */
495 [ - + ]: 2 : POSIX_GUARD_RESULT(s2n_kem_decapsulate(kem_params, &ciphertext));
496 : :
497 : 2 : return S2N_SUCCESS;
498 : 2 : }
499 : :
500 : : bool s2n_kem_is_available(const struct s2n_kem *kem)
501 : 457 : {
502 [ - + ][ + - ]: 457 : if (kem == NULL || kem->kem_nid == NID_undef) {
503 : 457 : return false;
504 : 457 : }
505 : :
506 : 0 : return s2n_libcrypto_supports_evp_kem();
507 : 457 : }
508 : :
509 : : bool s2n_kem_group_is_available(const struct s2n_kem_group *kem_group)
510 : 458 : {
511 : : /* Check for values that might be undefined when compiling for older libcrypto's */
512 [ + + ][ - + ]: 458 : if (kem_group == NULL || kem_group->curve == NULL || kem_group->kem == NULL) {
[ - + ]
513 : 6 : return false;
514 : 6 : }
515 : :
516 : 452 : bool available = s2n_kem_is_available(kem_group->kem);
517 : :
518 : : /* x25519 based tls13_kem_groups require EVP_APIS_SUPPORTED */
519 [ + + ]: 452 : if (kem_group->curve == &s2n_ecc_curve_x25519) {
520 : 162 : available &= s2n_is_evp_apis_supported();
521 : 162 : }
522 : :
523 : 452 : return available;
524 : 458 : }
|