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 hybrid 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-kwiatkowski-tls-ecdhe-mlkem/
118 : : */
119 : : const struct s2n_kem_group s2n_secp256r1_mlkem_768 = {
120 : : .name = "SecP256r1MLKEM768",
121 : : .iana_id = TLS_PQ_KEM_GROUP_ID_SECP256R1_MLKEM_768,
122 : : .curve = &s2n_ecc_curve_secp256r1,
123 : : .kem = &s2n_mlkem_768,
124 : : .send_kem_first = 0,
125 : : };
126 : :
127 : : const struct s2n_kem_group s2n_x25519_mlkem_768 = {
128 : : .name = "X25519MLKEM768",
129 : : .iana_id = TLS_PQ_KEM_GROUP_ID_X25519_MLKEM_768,
130 : : .curve = &s2n_ecc_curve_x25519,
131 : : .kem = &s2n_mlkem_768,
132 : : /* ML-KEM KeyShare should always be sent first for X25519MLKEM768.
133 : : * https://datatracker.ietf.org/doc/html/draft-kwiatkowski-tls-ecdhe-mlkem-02#name-negotiated-groups */
134 : : .send_kem_first = 1,
135 : : };
136 : :
137 : : const struct s2n_kem_group s2n_secp384r1_mlkem_1024 = {
138 : : .name = "SecP384r1MLKEM1024",
139 : : .iana_id = TLS_PQ_KEM_GROUP_ID_SECP384R1_MLKEM_1024,
140 : : .curve = &s2n_ecc_curve_secp384r1,
141 : : .kem = &s2n_mlkem_1024,
142 : : .send_kem_first = 0,
143 : : };
144 : :
145 : : const struct s2n_kem_group s2n_secp256r1_kyber_512_r3 = {
146 : : .name = "secp256r1_kyber-512-r3",
147 : : .iana_id = TLS_PQ_KEM_GROUP_ID_SECP256R1_KYBER_512_R3,
148 : : .curve = &s2n_ecc_curve_secp256r1,
149 : : .kem = &s2n_kyber_512_r3,
150 : : .send_kem_first = 0,
151 : : };
152 : :
153 : : const struct s2n_kem_group s2n_secp256r1_kyber_768_r3 = {
154 : : .name = "SecP256r1Kyber768Draft00",
155 : : .iana_id = TLS_PQ_KEM_GROUP_ID_SECP256R1_KYBER_768_R3,
156 : : .curve = &s2n_ecc_curve_secp256r1,
157 : : .kem = &s2n_kyber_768_r3,
158 : : .send_kem_first = 0,
159 : : };
160 : :
161 : : const struct s2n_kem_group s2n_secp384r1_kyber_768_r3 = {
162 : : .name = "secp384r1_kyber-768-r3",
163 : : .iana_id = TLS_PQ_KEM_GROUP_ID_SECP384R1_KYBER_768_R3,
164 : : .curve = &s2n_ecc_curve_secp384r1,
165 : : .kem = &s2n_kyber_768_r3,
166 : : .send_kem_first = 0,
167 : : };
168 : :
169 : : const struct s2n_kem_group s2n_secp521r1_kyber_1024_r3 = {
170 : : .name = "secp521r1_kyber-1024-r3",
171 : : .iana_id = TLS_PQ_KEM_GROUP_ID_SECP521R1_KYBER_1024_R3,
172 : : .curve = &s2n_ecc_curve_secp521r1,
173 : : .kem = &s2n_kyber_1024_r3,
174 : : .send_kem_first = 0,
175 : : };
176 : :
177 : : const struct s2n_kem_group s2n_x25519_kyber_512_r3 = {
178 : : .name = "x25519_kyber-512-r3",
179 : : .iana_id = TLS_PQ_KEM_GROUP_ID_X25519_KYBER_512_R3,
180 : : .curve = &s2n_ecc_curve_x25519,
181 : : .kem = &s2n_kyber_512_r3,
182 : : .send_kem_first = 0,
183 : : };
184 : :
185 : : const struct s2n_kem_group s2n_x25519_kyber_768_r3 = {
186 : : .name = "X25519Kyber768Draft00",
187 : : .iana_id = TLS_PQ_KEM_GROUP_ID_X25519_KYBER_768_R3,
188 : : .curve = &s2n_ecc_curve_x25519,
189 : : .kem = &s2n_kyber_768_r3,
190 : : .send_kem_first = 0,
191 : : };
192 : :
193 : : const struct s2n_kem_group *ALL_SUPPORTED_KEM_GROUPS[] = {
194 : : &s2n_x25519_mlkem_768,
195 : : &s2n_secp256r1_mlkem_768,
196 : : &s2n_secp384r1_mlkem_1024,
197 : : &s2n_secp256r1_kyber_768_r3,
198 : : &s2n_x25519_kyber_768_r3,
199 : : &s2n_secp384r1_kyber_768_r3,
200 : : &s2n_secp521r1_kyber_1024_r3,
201 : : &s2n_secp256r1_kyber_512_r3,
202 : : &s2n_x25519_kyber_512_r3,
203 : : };
204 : :
205 : : /* Helper safety macro to call the NIST PQ KEM functions. The NIST
206 : : * functions may return any non-zero value to indicate failure. */
207 : 12 : #define GUARD_PQ_AS_RESULT(x) RESULT_ENSURE((x) == 0, S2N_ERR_PQ_CRYPTO)
208 : :
209 : : S2N_RESULT s2n_kem_generate_keypair(struct s2n_kem_params *kem_params)
210 : 4 : {
211 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params);
212 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params->kem);
213 : 4 : const struct s2n_kem *kem = kem_params->kem;
214 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem->generate_keypair);
215 : :
216 [ # # ][ - + ]: 4 : RESULT_ENSURE_REF(kem_params->public_key.data);
217 [ - + ][ # # ]: 4 : RESULT_ENSURE(kem_params->public_key.size == kem->public_key_length, S2N_ERR_SAFETY);
218 : :
219 : : /* Need to save the private key for decapsulation */
220 [ - + ]: 4 : RESULT_GUARD_POSIX(s2n_realloc(&kem_params->private_key, kem->private_key_length));
221 : :
222 [ - + ][ # # ]: 4 : GUARD_PQ_AS_RESULT(kem->generate_keypair(kem, kem_params->public_key.data, kem_params->private_key.data));
223 : 4 : return S2N_RESULT_OK;
224 : 4 : }
225 : :
226 : : S2N_RESULT s2n_kem_encapsulate(struct s2n_kem_params *kem_params, struct s2n_blob *ciphertext)
227 : 4 : {
228 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params);
229 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params->kem);
230 : 4 : const struct s2n_kem *kem = kem_params->kem;
231 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem->encapsulate);
232 : :
233 [ - + ][ # # ]: 4 : RESULT_ENSURE(kem_params->public_key.size == kem->public_key_length, S2N_ERR_SAFETY);
234 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params->public_key.data);
235 : :
236 [ # # ][ - + ]: 4 : RESULT_ENSURE_REF(ciphertext);
237 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(ciphertext->data);
238 [ - + ][ # # ]: 4 : RESULT_ENSURE(ciphertext->size == kem->ciphertext_length, S2N_ERR_SAFETY);
239 : :
240 : : /* Need to save the shared secret for key derivation */
241 [ - + ]: 4 : RESULT_GUARD_POSIX(s2n_alloc(&(kem_params->shared_secret), kem->shared_secret_key_length));
242 : :
243 [ - + ][ # # ]: 4 : GUARD_PQ_AS_RESULT(kem->encapsulate(kem, ciphertext->data, kem_params->shared_secret.data, kem_params->public_key.data));
244 : 4 : return S2N_RESULT_OK;
245 : 4 : }
246 : :
247 : : S2N_RESULT s2n_kem_decapsulate(struct s2n_kem_params *kem_params, const struct s2n_blob *ciphertext)
248 : 4 : {
249 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params);
250 [ # # ][ - + ]: 4 : RESULT_ENSURE_REF(kem_params->kem);
251 : 4 : const struct s2n_kem *kem = kem_params->kem;
252 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem->decapsulate);
253 : :
254 [ - + ][ # # ]: 4 : RESULT_ENSURE(kem_params->private_key.size == kem->private_key_length, S2N_ERR_SAFETY);
255 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(kem_params->private_key.data);
256 : :
257 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(ciphertext);
258 [ - + ][ # # ]: 4 : RESULT_ENSURE_REF(ciphertext->data);
259 [ - + ][ # # ]: 4 : RESULT_ENSURE(ciphertext->size == kem->ciphertext_length, S2N_ERR_SAFETY);
260 : :
261 : : /* Need to save the shared secret for key derivation */
262 [ - + ]: 4 : RESULT_GUARD_POSIX(s2n_alloc(&(kem_params->shared_secret), kem->shared_secret_key_length));
263 : :
264 [ - + ][ # # ]: 4 : GUARD_PQ_AS_RESULT(kem->decapsulate(kem, kem_params->shared_secret.data, ciphertext->data, kem_params->private_key.data));
265 : 4 : return S2N_RESULT_OK;
266 : 4 : }
267 : :
268 : : static int s2n_kem_check_kem_compatibility(const uint8_t iana_value[S2N_TLS_CIPHER_SUITE_LEN], const struct s2n_kem *candidate_kem,
269 : : uint8_t *kem_is_compatible)
270 : 0 : {
271 : 0 : const struct s2n_iana_to_kem *compatible_kems = NULL;
272 [ # # ]: 0 : POSIX_GUARD(s2n_cipher_suite_to_kem(iana_value, &compatible_kems));
273 : :
274 [ # # ]: 0 : for (uint8_t i = 0; i < compatible_kems->kem_count; i++) {
275 [ # # ]: 0 : if (candidate_kem->kem_extension_id == compatible_kems->kems[i]->kem_extension_id) {
276 : 0 : *kem_is_compatible = 1;
277 : 0 : return S2N_SUCCESS;
278 : 0 : }
279 : 0 : }
280 : :
281 : 0 : *kem_is_compatible = 0;
282 : 0 : return S2N_SUCCESS;
283 : 0 : }
284 : :
285 : : int s2n_choose_kem_with_peer_pref_list(const uint8_t iana_value[S2N_TLS_CIPHER_SUITE_LEN], struct s2n_blob *client_kem_ids,
286 : : const struct s2n_kem *server_kem_pref_list[], const uint8_t num_server_supported_kems, const struct s2n_kem **chosen_kem)
287 : 0 : {
288 : 0 : struct s2n_stuffer client_kem_ids_stuffer = { 0 };
289 [ # # ]: 0 : POSIX_GUARD(s2n_stuffer_init(&client_kem_ids_stuffer, client_kem_ids));
290 [ # # ]: 0 : POSIX_GUARD(s2n_stuffer_write(&client_kem_ids_stuffer, client_kem_ids));
291 : :
292 : : /* Each KEM ID is 2 bytes */
293 : 0 : uint8_t num_client_candidate_kems = client_kem_ids->size / 2;
294 : :
295 [ # # ]: 0 : for (uint8_t i = 0; i < num_server_supported_kems; i++) {
296 : 0 : const struct s2n_kem *candidate_server_kem = (server_kem_pref_list[i]);
297 : :
298 : 0 : uint8_t server_kem_is_compatible = 0;
299 [ # # ]: 0 : POSIX_GUARD(s2n_kem_check_kem_compatibility(iana_value, candidate_server_kem, &server_kem_is_compatible));
300 : :
301 [ # # ]: 0 : if (!server_kem_is_compatible) {
302 : 0 : continue;
303 : 0 : }
304 : :
305 [ # # ]: 0 : for (uint8_t j = 0; j < num_client_candidate_kems; j++) {
306 : 0 : kem_extension_size candidate_client_kem_id = 0;
307 [ # # ]: 0 : POSIX_GUARD(s2n_stuffer_read_uint16(&client_kem_ids_stuffer, &candidate_client_kem_id));
308 : :
309 [ # # ]: 0 : if (candidate_server_kem->kem_extension_id == candidate_client_kem_id) {
310 : 0 : *chosen_kem = candidate_server_kem;
311 : 0 : return S2N_SUCCESS;
312 : 0 : }
313 : 0 : }
314 [ # # ]: 0 : POSIX_GUARD(s2n_stuffer_reread(&client_kem_ids_stuffer));
315 : 0 : }
316 : :
317 : : /* Client and server did not propose any mutually supported KEMs compatible with the ciphersuite */
318 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_KEM_UNSUPPORTED_PARAMS);
319 : 0 : }
320 : :
321 : : 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[],
322 : : const uint8_t num_server_supported_kems, const struct s2n_kem **chosen_kem)
323 : 0 : {
324 [ # # ]: 0 : for (uint8_t i = 0; i < num_server_supported_kems; i++) {
325 : 0 : uint8_t kem_is_compatible = 0;
326 [ # # ]: 0 : POSIX_GUARD(s2n_kem_check_kem_compatibility(iana_value, server_kem_pref_list[i], &kem_is_compatible));
327 [ # # ]: 0 : if (kem_is_compatible) {
328 : 0 : *chosen_kem = server_kem_pref_list[i];
329 : 0 : return S2N_SUCCESS;
330 : 0 : }
331 : 0 : }
332 : :
333 : : /* The server preference list did not contain any KEM extensions compatible with the ciphersuite */
334 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_KEM_UNSUPPORTED_PARAMS);
335 : 0 : }
336 : :
337 : : int s2n_kem_free(struct s2n_kem_params *kem_params)
338 : 10655272 : {
339 [ + + ]: 10655272 : if (kem_params != NULL) {
340 [ - + ]: 10655271 : POSIX_GUARD(s2n_free_or_wipe(&kem_params->private_key));
341 [ - + ]: 10655271 : POSIX_GUARD(s2n_free_or_wipe(&kem_params->public_key));
342 [ - + ]: 10655271 : POSIX_GUARD(s2n_free_or_wipe(&kem_params->shared_secret));
343 : 10655271 : }
344 : 10655272 : return S2N_SUCCESS;
345 : 10655272 : }
346 : :
347 : : int s2n_kem_group_free(struct s2n_kem_group_params *kem_group_params)
348 : 7109439 : {
349 [ + + ]: 7109439 : if (kem_group_params != NULL) {
350 [ - + ]: 7109438 : POSIX_GUARD(s2n_kem_free(&kem_group_params->kem_params));
351 [ - + ]: 7109438 : POSIX_GUARD(s2n_ecc_evp_params_free(&kem_group_params->ecc_params));
352 : 7109438 : }
353 : 7109439 : return S2N_SUCCESS;
354 : 7109439 : }
355 : :
356 : : int s2n_cipher_suite_to_kem(const uint8_t iana_value[S2N_TLS_CIPHER_SUITE_LEN], const struct s2n_iana_to_kem **compatible_params)
357 : 2 : {
358 [ + + ]: 3 : for (size_t i = 0; i < s2n_array_len(kem_mapping); i++) {
359 : 2 : const struct s2n_iana_to_kem *candidate = &kem_mapping[i];
360 [ + + ]: 2 : if (s2n_constant_time_equals(iana_value, candidate->iana_value, S2N_TLS_CIPHER_SUITE_LEN)) {
361 : 1 : *compatible_params = candidate;
362 : 1 : return S2N_SUCCESS;
363 : 1 : }
364 : 2 : }
365 [ + - ]: 1 : POSIX_BAIL(S2N_ERR_KEM_UNSUPPORTED_PARAMS);
366 : 1 : }
367 : :
368 : : int s2n_get_kem_from_extension_id(kem_extension_size kem_id, const struct s2n_kem **kem)
369 : 2 : {
370 [ + + ]: 3 : for (size_t i = 0; i < s2n_array_len(kem_mapping); i++) {
371 : 2 : const struct s2n_iana_to_kem *iana_to_kem = &kem_mapping[i];
372 : :
373 [ + + ]: 3 : for (int j = 0; j < iana_to_kem->kem_count; j++) {
374 : 2 : const struct s2n_kem *candidate_kem = iana_to_kem->kems[j];
375 [ + + ]: 2 : if (candidate_kem->kem_extension_id == kem_id) {
376 : 1 : *kem = candidate_kem;
377 : 1 : return S2N_SUCCESS;
378 : 1 : }
379 : 2 : }
380 : 2 : }
381 : :
382 [ + - ]: 1 : POSIX_BAIL(S2N_ERR_KEM_UNSUPPORTED_PARAMS);
383 : 1 : }
384 : :
385 : : int s2n_kem_send_public_key(struct s2n_stuffer *out, struct s2n_kem_params *kem_params)
386 : 8 : {
387 [ + - ][ + + ]: 8 : POSIX_ENSURE_REF(out);
388 [ + + ][ + - ]: 6 : POSIX_ENSURE_REF(kem_params);
389 [ + + ][ + - ]: 4 : POSIX_ENSURE_REF(kem_params->kem);
390 : :
391 : 2 : const struct s2n_kem *kem = kem_params->kem;
392 : :
393 [ + + ]: 2 : if (kem_params->len_prefixed) {
394 [ - + ]: 1 : POSIX_GUARD(s2n_stuffer_write_uint16(out, kem->public_key_length));
395 : 1 : }
396 : :
397 : : /* We don't need to store the public key after sending it.
398 : : * We write it directly to *out. */
399 : 2 : kem_params->public_key.data = s2n_stuffer_raw_write(out, kem->public_key_length);
400 [ # # ][ - + ]: 2 : POSIX_ENSURE_REF(kem_params->public_key.data);
401 : 2 : kem_params->public_key.size = kem->public_key_length;
402 : :
403 : : /* Saves the private key in kem_params */
404 [ - + ]: 2 : POSIX_GUARD_RESULT(s2n_kem_generate_keypair(kem_params));
405 : :
406 : : /* After using s2n_stuffer_raw_write() above to write the public
407 : : * key to the stuffer, we want to ensure that kem_params->public_key.data
408 : : * does not continue to point at *out, else we may unexpectedly
409 : : * overwrite part of the stuffer when s2n_kem_free() is called. */
410 : 2 : kem_params->public_key.data = NULL;
411 : 2 : kem_params->public_key.size = 0;
412 : :
413 : 2 : return S2N_SUCCESS;
414 : 2 : }
415 : :
416 : : int s2n_kem_recv_public_key(struct s2n_stuffer *in, struct s2n_kem_params *kem_params)
417 : 9 : {
418 [ + + ][ + - ]: 9 : POSIX_ENSURE_REF(in);
419 [ + + ][ + - ]: 7 : POSIX_ENSURE_REF(kem_params);
420 [ + + ][ + - ]: 5 : POSIX_ENSURE_REF(kem_params->kem);
421 : :
422 : 3 : const struct s2n_kem *kem = kem_params->kem;
423 : :
424 [ + + ]: 3 : if (kem_params->len_prefixed) {
425 : 2 : kem_public_key_size public_key_length = 0;
426 [ - + ]: 2 : POSIX_GUARD(s2n_stuffer_read_uint16(in, &public_key_length));
427 [ + + ][ + - ]: 2 : POSIX_ENSURE(public_key_length == kem->public_key_length, S2N_ERR_BAD_MESSAGE);
428 : 2 : }
429 : :
430 : : /* Alloc memory for the public key; the peer receiving it will need it
431 : : * later during the handshake to encapsulate the shared secret. */
432 [ - + ]: 2 : POSIX_GUARD(s2n_alloc(&(kem_params->public_key), kem->public_key_length));
433 [ - + ]: 2 : POSIX_GUARD(s2n_stuffer_read_bytes(in, kem_params->public_key.data, kem->public_key_length));
434 : :
435 : 2 : return S2N_SUCCESS;
436 : 2 : }
437 : :
438 : : int s2n_kem_send_ciphertext(struct s2n_stuffer *out, struct s2n_kem_params *kem_params)
439 : 10 : {
440 [ + + ][ + - ]: 10 : POSIX_ENSURE_REF(out);
441 [ + + ][ + - ]: 8 : POSIX_ENSURE_REF(kem_params);
442 [ + + ][ + - ]: 6 : POSIX_ENSURE_REF(kem_params->kem);
443 [ + + ][ + - ]: 4 : POSIX_ENSURE_REF(kem_params->public_key.data);
444 : :
445 : 2 : const struct s2n_kem *kem = kem_params->kem;
446 : :
447 [ + + ]: 2 : if (kem_params->len_prefixed) {
448 [ - + ]: 1 : POSIX_GUARD(s2n_stuffer_write_uint16(out, kem->ciphertext_length));
449 : 1 : }
450 : :
451 : : /* Ciphertext will get written to *out */
452 : 2 : struct s2n_blob ciphertext = { 0 };
453 [ - + ]: 2 : POSIX_GUARD(s2n_blob_init(&ciphertext, s2n_stuffer_raw_write(out, kem->ciphertext_length), kem->ciphertext_length));
454 [ # # ][ - + ]: 2 : POSIX_ENSURE_REF(ciphertext.data);
455 : :
456 : : /* Saves the shared secret in kem_params */
457 [ - + ]: 2 : POSIX_GUARD_RESULT(s2n_kem_encapsulate(kem_params, &ciphertext));
458 : :
459 : 2 : return S2N_SUCCESS;
460 : 2 : }
461 : :
462 : : int s2n_kem_recv_ciphertext(struct s2n_stuffer *in, struct s2n_kem_params *kem_params)
463 : 11 : {
464 [ + - ][ + + ]: 11 : POSIX_ENSURE_REF(in);
465 [ + + ][ + - ]: 9 : POSIX_ENSURE_REF(kem_params);
466 [ + - ][ + + ]: 7 : POSIX_ENSURE_REF(kem_params->kem);
467 [ + + ][ + - ]: 5 : POSIX_ENSURE_REF(kem_params->private_key.data);
468 : :
469 : 3 : const struct s2n_kem *kem = kem_params->kem;
470 : :
471 [ + + ]: 3 : if (kem_params->len_prefixed) {
472 : 2 : kem_ciphertext_key_size ciphertext_length = 0;
473 [ - + ]: 2 : POSIX_GUARD(s2n_stuffer_read_uint16(in, &ciphertext_length));
474 [ + + ][ + - ]: 2 : POSIX_ENSURE(ciphertext_length == kem->ciphertext_length, S2N_ERR_BAD_MESSAGE);
475 : 2 : }
476 : :
477 : 2 : const struct s2n_blob ciphertext = { .data = s2n_stuffer_raw_read(in, kem->ciphertext_length), .size = kem->ciphertext_length };
478 [ - + ][ # # ]: 2 : POSIX_ENSURE_REF(ciphertext.data);
479 : :
480 : : /* Saves the shared secret in kem_params */
481 [ - + ]: 2 : POSIX_GUARD_RESULT(s2n_kem_decapsulate(kem_params, &ciphertext));
482 : :
483 : 2 : return S2N_SUCCESS;
484 : 2 : }
485 : :
486 : : bool s2n_kem_is_available(const struct s2n_kem *kem)
487 : 426 : {
488 [ - + ][ + - ]: 426 : if (kem == NULL || kem->kem_nid == NID_undef) {
489 : 426 : return false;
490 : 426 : }
491 : :
492 : 0 : return s2n_libcrypto_supports_evp_kem();
493 : 426 : }
494 : :
495 : : bool s2n_kem_group_is_available(const struct s2n_kem_group *kem_group)
496 : 427 : {
497 : : /* Check for values that might be undefined when compiling for older libcrypto's */
498 [ + + ][ - + ]: 427 : if (kem_group == NULL || kem_group->curve == NULL || kem_group->kem == NULL) {
[ - + ]
499 : 6 : return false;
500 : 6 : }
501 : :
502 : 421 : bool available = s2n_kem_is_available(kem_group->kem);
503 : :
504 : : /* x25519 based tls13_kem_groups require EVP_APIS_SUPPORTED */
505 [ + + ]: 421 : if (kem_group->curve == &s2n_ecc_curve_x25519) {
506 : 152 : available &= s2n_is_evp_apis_supported();
507 : 152 : }
508 : :
509 : 421 : return available;
510 : 427 : }
|