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_pure_mlkem_1024,
212 : : &s2n_secp256r1_kyber_768_r3,
213 : : &s2n_x25519_kyber_768_r3,
214 : : &s2n_secp384r1_kyber_768_r3,
215 : : &s2n_secp521r1_kyber_1024_r3,
216 : : &s2n_secp256r1_kyber_512_r3,
217 : : &s2n_x25519_kyber_512_r3,
218 : : };
219 : :
220 : : /* Helper safety macro to call the NIST PQ KEM functions. The NIST
221 : : * functions may return any non-zero value to indicate failure. */
222 : 12 : #define GUARD_PQ_AS_RESULT(x) RESULT_ENSURE((x) == 0, S2N_ERR_PQ_CRYPTO)
223 : :
224 : : S2N_RESULT s2n_kem_generate_keypair(struct s2n_kem_params *kem_params)
225 : 4 : {
226 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params);
227 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params->kem);
228 : 4 : const struct s2n_kem *kem = kem_params->kem;
229 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem->generate_keypair);
230 : :
231 [ # # ][ - + ]: 4 : RESULT_ENSURE_REF(kem_params->public_key.data);
232 [ - + ][ # # ]: 4 : RESULT_ENSURE(kem_params->public_key.size == kem->public_key_length, S2N_ERR_SAFETY);
233 : :
234 : : /* Need to save the private key for decapsulation */
235 [ - + ]: 4 : RESULT_GUARD_POSIX(s2n_realloc(&kem_params->private_key, kem->private_key_length));
236 : :
237 [ - + ][ # # ]: 4 : GUARD_PQ_AS_RESULT(kem->generate_keypair(kem, kem_params->public_key.data, kem_params->private_key.data));
238 : 4 : return S2N_RESULT_OK;
239 : 4 : }
240 : :
241 : : S2N_RESULT s2n_kem_encapsulate(struct s2n_kem_params *kem_params, struct s2n_blob *ciphertext)
242 : 4 : {
243 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params);
244 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params->kem);
245 : 4 : const struct s2n_kem *kem = kem_params->kem;
246 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem->encapsulate);
247 : :
248 [ - + ][ # # ]: 4 : RESULT_ENSURE(kem_params->public_key.size == kem->public_key_length, S2N_ERR_SAFETY);
249 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params->public_key.data);
250 : :
251 [ # # ][ - + ]: 4 : RESULT_ENSURE_REF(ciphertext);
252 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(ciphertext->data);
253 [ - + ][ # # ]: 4 : RESULT_ENSURE(ciphertext->size == kem->ciphertext_length, S2N_ERR_SAFETY);
254 : :
255 : : /* Need to save the shared secret for key derivation */
256 [ - + ]: 4 : RESULT_GUARD_POSIX(s2n_alloc(&(kem_params->shared_secret), kem->shared_secret_key_length));
257 : :
258 [ - + ][ # # ]: 4 : GUARD_PQ_AS_RESULT(kem->encapsulate(kem, ciphertext->data, kem_params->shared_secret.data, kem_params->public_key.data));
259 : 4 : return S2N_RESULT_OK;
260 : 4 : }
261 : :
262 : : S2N_RESULT s2n_kem_decapsulate(struct s2n_kem_params *kem_params, const struct s2n_blob *ciphertext)
263 : 4 : {
264 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params);
265 [ # # ][ - + ]: 4 : RESULT_ENSURE_REF(kem_params->kem);
266 : 4 : const struct s2n_kem *kem = kem_params->kem;
267 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem->decapsulate);
268 : :
269 [ - + ][ # # ]: 4 : RESULT_ENSURE(kem_params->private_key.size == kem->private_key_length, S2N_ERR_SAFETY);
270 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params->private_key.data);
271 : :
272 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(ciphertext);
273 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(ciphertext->data);
274 [ - + ][ # # ]: 4 : RESULT_ENSURE(ciphertext->size == kem->ciphertext_length, S2N_ERR_SAFETY);
275 : :
276 : : /* Need to save the shared secret for key derivation */
277 [ - + ]: 4 : RESULT_GUARD_POSIX(s2n_alloc(&(kem_params->shared_secret), kem->shared_secret_key_length));
278 : :
279 [ - + ][ # # ]: 4 : GUARD_PQ_AS_RESULT(kem->decapsulate(kem, kem_params->shared_secret.data, ciphertext->data, kem_params->private_key.data));
280 : 4 : return S2N_RESULT_OK;
281 : 4 : }
282 : :
283 : : static int s2n_kem_check_kem_compatibility(const uint8_t iana_value[S2N_TLS_CIPHER_SUITE_LEN], const struct s2n_kem *candidate_kem,
284 : : uint8_t *kem_is_compatible)
285 : 0 : {
286 : 0 : const struct s2n_iana_to_kem *compatible_kems = NULL;
287 [ # # ]: 0 : POSIX_GUARD(s2n_cipher_suite_to_kem(iana_value, &compatible_kems));
288 : :
289 [ # # ]: 0 : for (uint8_t i = 0; i < compatible_kems->kem_count; i++) {
290 [ # # ]: 0 : if (candidate_kem->kem_extension_id == compatible_kems->kems[i]->kem_extension_id) {
291 : 0 : *kem_is_compatible = 1;
292 : 0 : return S2N_SUCCESS;
293 : 0 : }
294 : 0 : }
295 : :
296 : 0 : *kem_is_compatible = 0;
297 : 0 : return S2N_SUCCESS;
298 : 0 : }
299 : :
300 : : int s2n_choose_kem_with_peer_pref_list(const uint8_t iana_value[S2N_TLS_CIPHER_SUITE_LEN], struct s2n_blob *client_kem_ids,
301 : : const struct s2n_kem *server_kem_pref_list[], const uint8_t num_server_supported_kems, const struct s2n_kem **chosen_kem)
302 : 0 : {
303 : 0 : struct s2n_stuffer client_kem_ids_stuffer = { 0 };
304 [ # # ]: 0 : POSIX_GUARD(s2n_stuffer_init(&client_kem_ids_stuffer, client_kem_ids));
305 [ # # ]: 0 : POSIX_GUARD(s2n_stuffer_write(&client_kem_ids_stuffer, client_kem_ids));
306 : :
307 : : /* Each KEM ID is 2 bytes */
308 : 0 : uint8_t num_client_candidate_kems = client_kem_ids->size / 2;
309 : :
310 [ # # ]: 0 : for (uint8_t i = 0; i < num_server_supported_kems; i++) {
311 : 0 : const struct s2n_kem *candidate_server_kem = (server_kem_pref_list[i]);
312 : :
313 : 0 : uint8_t server_kem_is_compatible = 0;
314 [ # # ]: 0 : POSIX_GUARD(s2n_kem_check_kem_compatibility(iana_value, candidate_server_kem, &server_kem_is_compatible));
315 : :
316 [ # # ]: 0 : if (!server_kem_is_compatible) {
317 : 0 : continue;
318 : 0 : }
319 : :
320 [ # # ]: 0 : for (uint8_t j = 0; j < num_client_candidate_kems; j++) {
321 : 0 : kem_extension_size candidate_client_kem_id = 0;
322 [ # # ]: 0 : POSIX_GUARD(s2n_stuffer_read_uint16(&client_kem_ids_stuffer, &candidate_client_kem_id));
323 : :
324 [ # # ]: 0 : if (candidate_server_kem->kem_extension_id == candidate_client_kem_id) {
325 : 0 : *chosen_kem = candidate_server_kem;
326 : 0 : return S2N_SUCCESS;
327 : 0 : }
328 : 0 : }
329 [ # # ]: 0 : POSIX_GUARD(s2n_stuffer_reread(&client_kem_ids_stuffer));
330 : 0 : }
331 : :
332 : : /* Client and server did not propose any mutually supported KEMs compatible with the ciphersuite */
333 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_KEM_UNSUPPORTED_PARAMS);
334 : 0 : }
335 : :
336 : : 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[],
337 : : const uint8_t num_server_supported_kems, const struct s2n_kem **chosen_kem)
338 : 0 : {
339 [ # # ]: 0 : for (uint8_t i = 0; i < num_server_supported_kems; i++) {
340 : 0 : uint8_t kem_is_compatible = 0;
341 [ # # ]: 0 : POSIX_GUARD(s2n_kem_check_kem_compatibility(iana_value, server_kem_pref_list[i], &kem_is_compatible));
342 [ # # ]: 0 : if (kem_is_compatible) {
343 : 0 : *chosen_kem = server_kem_pref_list[i];
344 : 0 : return S2N_SUCCESS;
345 : 0 : }
346 : 0 : }
347 : :
348 : : /* The server preference list did not contain any KEM extensions compatible with the ciphersuite */
349 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_KEM_UNSUPPORTED_PARAMS);
350 : 0 : }
351 : :
352 : : int s2n_kem_free(struct s2n_kem_params *kem_params)
353 : 10664326 : {
354 [ + + ]: 10664326 : if (kem_params != NULL) {
355 [ - + ]: 10664325 : POSIX_GUARD(s2n_free_or_wipe(&kem_params->private_key));
356 [ - + ]: 10664325 : POSIX_GUARD(s2n_free_or_wipe(&kem_params->public_key));
357 [ - + ]: 10664325 : POSIX_GUARD(s2n_free_or_wipe(&kem_params->shared_secret));
358 : 10664325 : }
359 : 10664326 : return S2N_SUCCESS;
360 : 10664326 : }
361 : :
362 : : int s2n_kem_group_free(struct s2n_kem_group_params *kem_group_params)
363 : 7115807 : {
364 [ + + ]: 7115807 : if (kem_group_params != NULL) {
365 [ - + ]: 7115806 : POSIX_GUARD(s2n_kem_free(&kem_group_params->kem_params));
366 [ - + ]: 7115806 : POSIX_GUARD(s2n_ecc_evp_params_free(&kem_group_params->ecc_params));
367 : 7115806 : }
368 : 7115807 : return S2N_SUCCESS;
369 : 7115807 : }
370 : :
371 : : int s2n_cipher_suite_to_kem(const uint8_t iana_value[S2N_TLS_CIPHER_SUITE_LEN], const struct s2n_iana_to_kem **compatible_params)
372 : 2 : {
373 [ + + ]: 3 : for (size_t i = 0; i < s2n_array_len(kem_mapping); i++) {
374 : 2 : const struct s2n_iana_to_kem *candidate = &kem_mapping[i];
375 [ + + ]: 2 : if (s2n_constant_time_equals(iana_value, candidate->iana_value, S2N_TLS_CIPHER_SUITE_LEN)) {
376 : 1 : *compatible_params = candidate;
377 : 1 : return S2N_SUCCESS;
378 : 1 : }
379 : 2 : }
380 [ + - ]: 1 : POSIX_BAIL(S2N_ERR_KEM_UNSUPPORTED_PARAMS);
381 : 1 : }
382 : :
383 : : int s2n_get_kem_from_extension_id(kem_extension_size kem_id, const struct s2n_kem **kem)
384 : 2 : {
385 [ + + ]: 3 : for (size_t i = 0; i < s2n_array_len(kem_mapping); i++) {
386 : 2 : const struct s2n_iana_to_kem *iana_to_kem = &kem_mapping[i];
387 : :
388 [ + + ]: 3 : for (int j = 0; j < iana_to_kem->kem_count; j++) {
389 : 2 : const struct s2n_kem *candidate_kem = iana_to_kem->kems[j];
390 [ + + ]: 2 : if (candidate_kem->kem_extension_id == kem_id) {
391 : 1 : *kem = candidate_kem;
392 : 1 : return S2N_SUCCESS;
393 : 1 : }
394 : 2 : }
395 : 2 : }
396 : :
397 [ + - ]: 1 : POSIX_BAIL(S2N_ERR_KEM_UNSUPPORTED_PARAMS);
398 : 1 : }
399 : :
400 : : int s2n_kem_send_public_key(struct s2n_stuffer *out, struct s2n_kem_params *kem_params)
401 : 8 : {
402 [ + - ][ + + ]: 8 : POSIX_ENSURE_REF(out);
403 [ + + ][ + - ]: 6 : POSIX_ENSURE_REF(kem_params);
404 [ + + ][ + - ]: 4 : POSIX_ENSURE_REF(kem_params->kem);
405 : :
406 : 2 : const struct s2n_kem *kem = kem_params->kem;
407 : :
408 [ + + ]: 2 : if (kem_params->len_prefixed) {
409 [ - + ]: 1 : POSIX_GUARD(s2n_stuffer_write_uint16(out, kem->public_key_length));
410 : 1 : }
411 : :
412 : : /* We don't need to store the public key after sending it.
413 : : * We write it directly to *out. */
414 : 2 : kem_params->public_key.data = s2n_stuffer_raw_write(out, kem->public_key_length);
415 [ # # ][ - + ]: 2 : POSIX_ENSURE_REF(kem_params->public_key.data);
416 : 2 : kem_params->public_key.size = kem->public_key_length;
417 : :
418 : : /* Saves the private key in kem_params */
419 [ - + ]: 2 : POSIX_GUARD_RESULT(s2n_kem_generate_keypair(kem_params));
420 : :
421 : : /* After using s2n_stuffer_raw_write() above to write the public
422 : : * key to the stuffer, we want to ensure that kem_params->public_key.data
423 : : * does not continue to point at *out, else we may unexpectedly
424 : : * overwrite part of the stuffer when s2n_kem_free() is called. */
425 : 2 : kem_params->public_key.data = NULL;
426 : 2 : kem_params->public_key.size = 0;
427 : :
428 : 2 : return S2N_SUCCESS;
429 : 2 : }
430 : :
431 : : int s2n_kem_recv_public_key(struct s2n_stuffer *in, struct s2n_kem_params *kem_params)
432 : 9 : {
433 [ + + ][ + - ]: 9 : POSIX_ENSURE_REF(in);
434 [ + + ][ + - ]: 7 : POSIX_ENSURE_REF(kem_params);
435 [ + + ][ + - ]: 5 : POSIX_ENSURE_REF(kem_params->kem);
436 : :
437 : 3 : const struct s2n_kem *kem = kem_params->kem;
438 : :
439 [ + + ]: 3 : if (kem_params->len_prefixed) {
440 : 2 : kem_public_key_size public_key_length = 0;
441 [ - + ]: 2 : POSIX_GUARD(s2n_stuffer_read_uint16(in, &public_key_length));
442 [ + + ][ + - ]: 2 : POSIX_ENSURE(public_key_length == kem->public_key_length, S2N_ERR_BAD_MESSAGE);
443 : 2 : }
444 : :
445 : : /* Alloc memory for the public key; the peer receiving it will need it
446 : : * later during the handshake to encapsulate the shared secret. */
447 [ - + ]: 2 : POSIX_GUARD(s2n_alloc(&(kem_params->public_key), kem->public_key_length));
448 [ - + ]: 2 : POSIX_GUARD(s2n_stuffer_read_bytes(in, kem_params->public_key.data, kem->public_key_length));
449 : :
450 : 2 : return S2N_SUCCESS;
451 : 2 : }
452 : :
453 : : int s2n_kem_send_ciphertext(struct s2n_stuffer *out, struct s2n_kem_params *kem_params)
454 : 10 : {
455 [ + + ][ + - ]: 10 : POSIX_ENSURE_REF(out);
456 [ + + ][ + - ]: 8 : POSIX_ENSURE_REF(kem_params);
457 [ + + ][ + - ]: 6 : POSIX_ENSURE_REF(kem_params->kem);
458 [ + + ][ + - ]: 4 : POSIX_ENSURE_REF(kem_params->public_key.data);
459 : :
460 : 2 : const struct s2n_kem *kem = kem_params->kem;
461 : :
462 [ + + ]: 2 : if (kem_params->len_prefixed) {
463 [ - + ]: 1 : POSIX_GUARD(s2n_stuffer_write_uint16(out, kem->ciphertext_length));
464 : 1 : }
465 : :
466 : : /* Ciphertext will get written to *out */
467 : 2 : struct s2n_blob ciphertext = { 0 };
468 [ - + ]: 2 : POSIX_GUARD(s2n_blob_init(&ciphertext, s2n_stuffer_raw_write(out, kem->ciphertext_length), kem->ciphertext_length));
469 [ # # ][ - + ]: 2 : POSIX_ENSURE_REF(ciphertext.data);
470 : :
471 : : /* Saves the shared secret in kem_params */
472 [ - + ]: 2 : POSIX_GUARD_RESULT(s2n_kem_encapsulate(kem_params, &ciphertext));
473 : :
474 : 2 : return S2N_SUCCESS;
475 : 2 : }
476 : :
477 : : int s2n_kem_recv_ciphertext(struct s2n_stuffer *in, struct s2n_kem_params *kem_params)
478 : 11 : {
479 [ + - ][ + + ]: 11 : POSIX_ENSURE_REF(in);
480 [ + + ][ + - ]: 9 : POSIX_ENSURE_REF(kem_params);
481 [ + - ][ + + ]: 7 : POSIX_ENSURE_REF(kem_params->kem);
482 [ + + ][ + - ]: 5 : POSIX_ENSURE_REF(kem_params->private_key.data);
483 : :
484 : 3 : const struct s2n_kem *kem = kem_params->kem;
485 : :
486 [ + + ]: 3 : if (kem_params->len_prefixed) {
487 : 2 : kem_ciphertext_key_size ciphertext_length = 0;
488 [ - + ]: 2 : POSIX_GUARD(s2n_stuffer_read_uint16(in, &ciphertext_length));
489 [ + + ][ + - ]: 2 : POSIX_ENSURE(ciphertext_length == kem->ciphertext_length, S2N_ERR_BAD_MESSAGE);
490 : 2 : }
491 : :
492 : 2 : const struct s2n_blob ciphertext = { .data = s2n_stuffer_raw_read(in, kem->ciphertext_length), .size = kem->ciphertext_length };
493 [ - + ][ # # ]: 2 : POSIX_ENSURE_REF(ciphertext.data);
494 : :
495 : : /* Saves the shared secret in kem_params */
496 [ - + ]: 2 : POSIX_GUARD_RESULT(s2n_kem_decapsulate(kem_params, &ciphertext));
497 : :
498 : 2 : return S2N_SUCCESS;
499 : 2 : }
500 : :
501 : : bool s2n_kem_is_available(const struct s2n_kem *kem)
502 : 15055 : {
503 [ - + ][ + - ]: 15055 : if (kem == NULL || kem->kem_nid == NID_undef) {
504 : 15055 : return false;
505 : 15055 : }
506 : :
507 : 0 : return s2n_libcrypto_supports_evp_kem();
508 : 15055 : }
509 : :
510 : : bool s2n_kem_group_is_available(const struct s2n_kem_group *kem_group)
511 : 15058 : {
512 : : /* Check for values that might be undefined when compiling for older libcrypto's */
513 [ + + ][ - + ]: 15058 : if (kem_group == NULL || kem_group->curve == NULL || kem_group->kem == NULL) {
[ - + ]
514 : 8 : return false;
515 : 8 : }
516 : :
517 : 15050 : bool available = s2n_kem_is_available(kem_group->kem);
518 : :
519 : : /* x25519 based tls13_kem_groups require EVP_APIS_SUPPORTED */
520 [ + + ]: 15050 : if (kem_group->curve == &s2n_ecc_curve_x25519) {
521 : 5023 : available &= s2n_is_evp_apis_supported();
522 : 5023 : }
523 : :
524 : 15050 : return available;
525 : 15058 : }
|