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 "crypto/s2n_ecc_evp.h"
17 : :
18 : : #include <openssl/ecdh.h>
19 : : #include <openssl/evp.h>
20 : : #if defined(OPENSSL_IS_AWSLC)
21 : : #include <openssl/mem.h>
22 : : #endif
23 : :
24 : : #include <stdint.h>
25 : :
26 : : #include "crypto/s2n_fips.h"
27 : : #include "crypto/s2n_libcrypto.h"
28 : : #include "tls/s2n_connection.h"
29 : : #include "tls/s2n_ecc_preferences.h"
30 : : #include "tls/s2n_tls_parameters.h"
31 : : #include "utils/s2n_mem.h"
32 : : #include "utils/s2n_safety.h"
33 : :
34 : : #define TLS_EC_CURVE_TYPE_NAMED 3
35 : :
36 : : DEFINE_POINTER_CLEANUP_FUNC(EVP_PKEY *, EVP_PKEY_free);
37 : : DEFINE_POINTER_CLEANUP_FUNC(EVP_PKEY_CTX *, EVP_PKEY_CTX_free);
38 : : DEFINE_POINTER_CLEANUP_FUNC(EC_KEY *, EC_KEY_free);
39 : :
40 : : #if EVP_APIS_SUPPORTED
41 : 12283 : DEFINE_POINTER_CLEANUP_FUNC(uint8_t *, OPENSSL_free);
42 : : #endif
43 : :
44 : : #if !EVP_APIS_SUPPORTED
45 : : DEFINE_POINTER_CLEANUP_FUNC(EC_POINT *, EC_POINT_free);
46 : : #endif
47 : :
48 : : #if EVP_APIS_SUPPORTED
49 : : static int s2n_ecc_evp_generate_key_x25519(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey);
50 : : #else
51 : : static int s2n_ecc_evp_write_point_data_snug(const EC_POINT *point, const EC_GROUP *group, struct s2n_blob *out);
52 : : static int s2n_ecc_evp_calculate_point_length(const EC_POINT *point, const EC_GROUP *group, uint8_t *length);
53 : : static EC_POINT *s2n_ecc_evp_blob_to_point(struct s2n_blob *blob, const EC_KEY *ec_key);
54 : : #endif
55 : : static int s2n_ecc_evp_generate_key_nist_curves(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey);
56 : : static int s2n_ecc_evp_generate_own_key(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey);
57 : : static int s2n_ecc_evp_compute_shared_secret(EVP_PKEY *own_key, EVP_PKEY *peer_public, uint16_t iana_id, struct s2n_blob *shared_secret);
58 : : static int s2n_ecc_evp_generate_key_noop(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey);
59 : :
60 : : /* IANA values can be found here: https://tools.ietf.org/html/rfc8446#appendix-B.3.1.4 */
61 : :
62 : : const struct s2n_ecc_named_curve s2n_ecc_curve_secp256r1 = {
63 : : .iana_id = TLS_EC_CURVE_SECP_256_R1,
64 : : .libcrypto_nid = NID_X9_62_prime256v1,
65 : : .name = "secp256r1",
66 : : .share_size = SECP256R1_SHARE_SIZE,
67 : : .generate_key = s2n_ecc_evp_generate_key_nist_curves,
68 : : };
69 : :
70 : : const struct s2n_ecc_named_curve s2n_ecc_curve_secp384r1 = {
71 : : .iana_id = TLS_EC_CURVE_SECP_384_R1,
72 : : .libcrypto_nid = NID_secp384r1,
73 : : .name = "secp384r1",
74 : : .share_size = SECP384R1_SHARE_SIZE,
75 : : .generate_key = s2n_ecc_evp_generate_key_nist_curves,
76 : : };
77 : :
78 : : const struct s2n_ecc_named_curve s2n_ecc_curve_secp521r1 = {
79 : : .iana_id = TLS_EC_CURVE_SECP_521_R1,
80 : : .libcrypto_nid = NID_secp521r1,
81 : : .name = "secp521r1",
82 : : .share_size = SECP521R1_SHARE_SIZE,
83 : : .generate_key = s2n_ecc_evp_generate_key_nist_curves,
84 : : };
85 : :
86 : : #if EVP_APIS_SUPPORTED
87 : : const struct s2n_ecc_named_curve s2n_ecc_curve_x25519 = {
88 : : .iana_id = TLS_EC_CURVE_ECDH_X25519,
89 : : .libcrypto_nid = NID_X25519,
90 : : .name = "x25519",
91 : : .share_size = X25519_SHARE_SIZE,
92 : : .generate_key = s2n_ecc_evp_generate_key_x25519,
93 : : };
94 : : #else
95 : : const struct s2n_ecc_named_curve s2n_ecc_curve_x25519 = { 0 };
96 : : #endif
97 : :
98 : : /* A fake / unsupported curve for use in triggering retries
99 : : * during testing.
100 : : */
101 : : const struct s2n_ecc_named_curve s2n_unsupported_curve = {
102 : : .iana_id = 0,
103 : : .name = "unsupported",
104 : : .libcrypto_nid = NID_X9_62_prime256v1,
105 : : .share_size = SECP256R1_SHARE_SIZE,
106 : : .generate_key = s2n_ecc_evp_generate_key_nist_curves,
107 : : };
108 : :
109 : : const struct s2n_ecc_named_curve s2n_ecc_curve_none = {
110 : : .iana_id = 0,
111 : : .name = "none",
112 : : .libcrypto_nid = 0,
113 : : .share_size = 0,
114 : : .generate_key = s2n_ecc_evp_generate_key_noop,
115 : : };
116 : :
117 : : /* All curves that s2n supports. New curves MUST be added here.
118 : : * This list is a super set of all the curves present in s2n_ecc_preferences list.
119 : : */
120 : : const struct s2n_ecc_named_curve *const s2n_all_supported_curves_list[] = {
121 : : &s2n_ecc_curve_secp256r1,
122 : : &s2n_ecc_curve_secp384r1,
123 : : #if EVP_APIS_SUPPORTED
124 : : &s2n_ecc_curve_x25519,
125 : : #endif
126 : : &s2n_ecc_curve_secp521r1,
127 : : };
128 : :
129 : : const size_t s2n_all_supported_curves_list_len = s2n_array_len(s2n_all_supported_curves_list);
130 : :
131 : : int s2n_is_evp_apis_supported()
132 : 3687 : {
133 : 3687 : return EVP_APIS_SUPPORTED;
134 : 3687 : }
135 : :
136 : : bool s2n_ecc_evp_supports_fips_check()
137 : 0 : {
138 : : #ifdef S2N_LIBCRYPTO_SUPPORTS_EC_KEY_CHECK_FIPS
139 : : return true;
140 : : #else
141 : 0 : return false;
142 : 0 : #endif
143 : 0 : }
144 : :
145 : : int s2n_find_ecc_curve_from_iana_id(uint16_t iana_id, const struct s2n_ecc_named_curve **out, bool *found)
146 : 4 : {
147 [ # # ][ - + ]: 4 : POSIX_ENSURE_REF(out);
148 [ # # ][ - + ]: 4 : POSIX_ENSURE_REF(found);
149 : 4 : *found = false;
150 : :
151 [ + - ]: 8 : for (size_t i = 0; i < s2n_all_supported_curves_list_len; i++) {
152 : 8 : const struct s2n_ecc_named_curve *curve = s2n_all_supported_curves_list[i];
153 [ - + ][ # # ]: 8 : POSIX_ENSURE_REF(curve);
154 [ + + ]: 8 : if (curve->iana_id == iana_id) {
155 : 4 : *out = curve;
156 : 4 : *found = true;
157 : 4 : return S2N_SUCCESS;
158 : 4 : }
159 : 8 : }
160 : 0 : return S2N_SUCCESS;
161 : 4 : }
162 : :
163 : : #if EVP_APIS_SUPPORTED
164 : : static int s2n_ecc_evp_generate_key_x25519(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey)
165 : 1960 : {
166 : 1960 : DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(named_curve->libcrypto_nid, NULL),
167 : 1960 : EVP_PKEY_CTX_free_pointer);
168 [ - + ][ # # ]: 1960 : S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_GEN_KEY);
169 : :
170 [ - + ][ # # ]: 1960 : POSIX_GUARD_OSSL(EVP_PKEY_keygen_init(pctx), S2N_ERR_ECDHE_GEN_KEY);
171 [ - + ][ # # ]: 1960 : POSIX_GUARD_OSSL(EVP_PKEY_keygen(pctx, evp_pkey), S2N_ERR_ECDHE_GEN_KEY);
172 [ - + ][ # # ]: 1960 : S2N_ERROR_IF(evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY);
173 : :
174 : 1960 : return 0;
175 : 1960 : }
176 : : #endif
177 : :
178 : : static int s2n_ecc_evp_generate_key_nist_curves(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey)
179 : 12126 : {
180 : 12126 : DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL), EVP_PKEY_CTX_free_pointer);
181 [ - + ][ # # ]: 12126 : S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_GEN_KEY);
182 : :
183 [ - + ][ # # ]: 12126 : POSIX_GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_GEN_KEY);
184 [ - + ][ # # ]: 12126 : POSIX_GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, named_curve->libcrypto_nid), S2N_ERR_ECDHE_GEN_KEY);
185 : :
186 : 12126 : DEFER_CLEANUP(EVP_PKEY *params = NULL, EVP_PKEY_free_pointer);
187 [ # # ][ - + ]: 12126 : POSIX_GUARD_OSSL(EVP_PKEY_paramgen(pctx, ¶ms), S2N_ERR_ECDHE_GEN_KEY);
188 [ - + ][ # # ]: 12126 : S2N_ERROR_IF(params == NULL, S2N_ERR_ECDHE_GEN_KEY);
189 : :
190 : 12126 : DEFER_CLEANUP(EVP_PKEY_CTX *kctx = EVP_PKEY_CTX_new(params, NULL), EVP_PKEY_CTX_free_pointer);
191 [ - + ][ # # ]: 12126 : S2N_ERROR_IF(kctx == NULL, S2N_ERR_ECDHE_GEN_KEY);
192 : :
193 [ # # ][ - + ]: 12126 : POSIX_GUARD_OSSL(EVP_PKEY_keygen_init(kctx), S2N_ERR_ECDHE_GEN_KEY);
194 [ - + ][ # # ]: 12126 : POSIX_GUARD_OSSL(EVP_PKEY_keygen(kctx, evp_pkey), S2N_ERR_ECDHE_GEN_KEY);
195 [ - + ][ # # ]: 12126 : S2N_ERROR_IF(evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY);
196 : :
197 : 12126 : return 0;
198 : 12126 : }
199 : :
200 : : static int s2n_ecc_evp_generate_key_noop(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey)
201 : 0 : {
202 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_UNIMPLEMENTED);
203 : 0 : }
204 : :
205 : : static int s2n_ecc_evp_generate_own_key(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey)
206 : 14087 : {
207 [ - + ][ # # ]: 14087 : POSIX_ENSURE_REF(named_curve);
208 [ + + ][ + - ]: 14087 : S2N_ERROR_IF(named_curve->generate_key == NULL, S2N_ERR_ECDHE_GEN_KEY);
209 : :
210 : 14086 : return named_curve->generate_key(named_curve, evp_pkey);
211 : 14087 : }
212 : :
213 : : static S2N_RESULT s2n_ecc_check_key(EC_KEY *ec_key)
214 : 10185 : {
215 [ # # ][ - + ]: 10185 : RESULT_ENSURE_REF(ec_key);
216 : :
217 : : #ifdef S2N_LIBCRYPTO_SUPPORTS_EC_KEY_CHECK_FIPS
218 : : if (s2n_is_in_fips_mode()) {
219 : : RESULT_GUARD_OSSL(EC_KEY_check_fips(ec_key), S2N_ERR_ECDHE_INVALID_PUBLIC_KEY_FIPS);
220 : : return S2N_RESULT_OK;
221 : : }
222 : : #endif
223 : :
224 [ + + ][ + - ]: 10185 : RESULT_GUARD_OSSL(EC_KEY_check_key(ec_key), S2N_ERR_ECDHE_INVALID_PUBLIC_KEY);
225 : :
226 : 10182 : return S2N_RESULT_OK;
227 : 10185 : }
228 : :
229 : : static int s2n_ecc_evp_compute_shared_secret(EVP_PKEY *own_key, EVP_PKEY *peer_public, uint16_t iana_id, struct s2n_blob *shared_secret)
230 : 11432 : {
231 [ - + ][ # # ]: 11432 : POSIX_ENSURE_REF(peer_public);
232 [ - + ][ # # ]: 11432 : POSIX_ENSURE_REF(own_key);
233 : :
234 : : /**
235 : : *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.8.2
236 : : *# For the curves secp256r1, secp384r1, and secp521r1, peers MUST
237 : : *# validate each other's public value Q by ensuring that the point is a
238 : : *# valid point on the elliptic curve.
239 : : *
240 : : *= https://www.rfc-editor.org/rfc/rfc8422#section-5.11
241 : : *# With the NIST curves, each party MUST validate the public key sent by
242 : : *# its peer in the ClientKeyExchange and ServerKeyExchange messages. A
243 : : *# receiving party MUST check that the x and y parameters from the
244 : : *# peer's public value satisfy the curve equation, y^2 = x^3 + ax + b
245 : : *# mod p.
246 : : *
247 : : * The validation requirement for the public key value only applies to NIST curves. The
248 : : * validation is skipped with non-NIST curves for increased performance.
249 : : */
250 [ + + ][ + - ]: 11432 : if (iana_id != TLS_EC_CURVE_ECDH_X25519 && iana_id != TLS_EC_CURVE_ECDH_X448) {
251 : 10185 : DEFER_CLEANUP(EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(peer_public), EC_KEY_free_pointer);
252 [ # # ][ - + ]: 10185 : POSIX_ENSURE(ec_key, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
253 [ + + ]: 10185 : POSIX_GUARD_RESULT(s2n_ecc_check_key(ec_key));
254 : 10185 : }
255 : :
256 : 11429 : size_t shared_secret_size = 0;
257 : :
258 : 11429 : DEFER_CLEANUP(EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(own_key, NULL), EVP_PKEY_CTX_free_pointer);
259 [ - + ][ # # ]: 11429 : S2N_ERROR_IF(ctx == NULL, S2N_ERR_ECDHE_SHARED_SECRET);
260 : :
261 [ - + ][ # # ]: 11429 : POSIX_GUARD_OSSL(EVP_PKEY_derive_init(ctx), S2N_ERR_ECDHE_SHARED_SECRET);
262 [ - + ][ # # ]: 11429 : POSIX_GUARD_OSSL(EVP_PKEY_derive_set_peer(ctx, peer_public), S2N_ERR_ECDHE_SHARED_SECRET);
263 [ - + ][ # # ]: 11429 : POSIX_GUARD_OSSL(EVP_PKEY_derive(ctx, NULL, &shared_secret_size), S2N_ERR_ECDHE_SHARED_SECRET);
264 [ - + ]: 11429 : POSIX_GUARD(s2n_alloc(shared_secret, shared_secret_size));
265 : :
266 [ - + ]: 11429 : if (EVP_PKEY_derive(ctx, shared_secret->data, &shared_secret_size) != 1) {
267 [ # # ]: 0 : POSIX_GUARD(s2n_free(shared_secret));
268 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_ECDHE_SHARED_SECRET);
269 : 0 : }
270 : :
271 : 11429 : return 0;
272 : 11429 : }
273 : :
274 : : int s2n_ecc_evp_generate_ephemeral_key(struct s2n_ecc_evp_params *ecc_evp_params)
275 : 13317 : {
276 [ + + ][ + - ]: 13317 : POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
277 [ - + ][ # # ]: 13313 : S2N_ERROR_IF(ecc_evp_params->evp_pkey != NULL, S2N_ERR_ECDHE_GEN_KEY);
278 [ + + ][ + - ]: 13313 : S2N_ERROR_IF(s2n_ecc_evp_generate_own_key(ecc_evp_params->negotiated_curve, &ecc_evp_params->evp_pkey) != 0,
279 : 13313 : S2N_ERR_ECDHE_GEN_KEY);
280 [ - + ][ # # ]: 13312 : S2N_ERROR_IF(ecc_evp_params->evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY);
281 : 13312 : return 0;
282 : 13312 : }
283 : :
284 : : int s2n_ecc_evp_compute_shared_secret_from_params(struct s2n_ecc_evp_params *private_ecc_evp_params,
285 : : struct s2n_ecc_evp_params *public_ecc_evp_params,
286 : : struct s2n_blob *shared_key)
287 : 9879 : {
288 [ - + ][ # # ]: 9879 : POSIX_ENSURE_REF(private_ecc_evp_params->negotiated_curve);
289 [ - + ][ # # ]: 9879 : POSIX_ENSURE_REF(private_ecc_evp_params->evp_pkey);
290 [ - + ][ # # ]: 9879 : POSIX_ENSURE_REF(public_ecc_evp_params->negotiated_curve);
291 [ + + ][ + - ]: 9879 : POSIX_ENSURE_REF(public_ecc_evp_params->evp_pkey);
292 [ + + ][ + - ]: 9878 : S2N_ERROR_IF(private_ecc_evp_params->negotiated_curve->iana_id != public_ecc_evp_params->negotiated_curve->iana_id,
293 : 9878 : S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
294 [ + + ]: 9854 : POSIX_GUARD(s2n_ecc_evp_compute_shared_secret(private_ecc_evp_params->evp_pkey, public_ecc_evp_params->evp_pkey,
295 : 9851 : private_ecc_evp_params->negotiated_curve->iana_id, shared_key));
296 : 9851 : return 0;
297 : 9854 : }
298 : :
299 : : int s2n_ecc_evp_compute_shared_secret_as_server(struct s2n_ecc_evp_params *ecc_evp_params,
300 : : struct s2n_stuffer *Yc_in, struct s2n_blob *shared_key)
301 : 804 : {
302 [ - + ][ # # ]: 804 : POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
303 [ - + ][ # # ]: 804 : POSIX_ENSURE_REF(ecc_evp_params->evp_pkey);
304 [ - + ][ # # ]: 804 : POSIX_ENSURE_REF(Yc_in);
305 : :
306 : 804 : uint8_t client_public_len = 0;
307 : 804 : struct s2n_blob client_public_blob = { 0 };
308 : :
309 : 804 : DEFER_CLEANUP(EVP_PKEY *peer_key = EVP_PKEY_new(), EVP_PKEY_free_pointer);
310 [ - + ][ # # ]: 804 : S2N_ERROR_IF(peer_key == NULL, S2N_ERR_BAD_MESSAGE);
311 [ - + ]: 804 : POSIX_GUARD(s2n_stuffer_read_uint8(Yc_in, &client_public_len));
312 : 804 : client_public_blob.size = client_public_len;
313 : 804 : client_public_blob.data = s2n_stuffer_raw_read(Yc_in, client_public_blob.size);
314 [ - + ][ # # ]: 804 : POSIX_ENSURE_REF(client_public_blob.data);
315 : :
316 : 804 : #if EVP_APIS_SUPPORTED
317 [ + + ]: 804 : if (ecc_evp_params->negotiated_curve->libcrypto_nid == NID_X25519) {
318 [ - + ]: 361 : POSIX_GUARD(EVP_PKEY_set_type(peer_key, ecc_evp_params->negotiated_curve->libcrypto_nid));
319 : 443 : } else {
320 : 443 : DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL), EVP_PKEY_CTX_free_pointer);
321 [ - + ][ # # ]: 443 : S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_SERIALIZING);
322 [ - + ][ # # ]: 443 : POSIX_GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_SERIALIZING);
323 [ - + ][ # # ]: 443 : POSIX_GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ecc_evp_params->negotiated_curve->libcrypto_nid), S2N_ERR_ECDHE_SERIALIZING);
324 [ # # ][ - + ]: 443 : POSIX_GUARD_OSSL(EVP_PKEY_paramgen(pctx, &peer_key), S2N_ERR_ECDHE_SERIALIZING);
325 : 443 : }
326 [ - + ][ # # ]: 804 : POSIX_GUARD_OSSL(EVP_PKEY_set1_tls_encodedpoint(peer_key, client_public_blob.data, client_public_blob.size),
327 : 804 : S2N_ERR_ECDHE_SERIALIZING);
328 : : #else
329 : : DEFER_CLEANUP(EC_KEY *ec_key = EC_KEY_new_by_curve_name(ecc_evp_params->negotiated_curve->libcrypto_nid),
330 : : EC_KEY_free_pointer);
331 : : S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
332 : :
333 : : DEFER_CLEANUP(EC_POINT *point = s2n_ecc_evp_blob_to_point(&client_public_blob, ec_key), EC_POINT_free_pointer);
334 : : S2N_ERROR_IF(point == NULL, S2N_ERR_BAD_MESSAGE);
335 : :
336 : : int success = EC_KEY_set_public_key(ec_key, point);
337 : : POSIX_GUARD_OSSL(EVP_PKEY_set1_EC_KEY(peer_key, ec_key), S2N_ERR_ECDHE_SERIALIZING);
338 : : S2N_ERROR_IF(success == 0, S2N_ERR_BAD_MESSAGE);
339 : : #endif
340 : :
341 : 804 : return s2n_ecc_evp_compute_shared_secret(ecc_evp_params->evp_pkey, peer_key,
342 : 804 : ecc_evp_params->negotiated_curve->iana_id, shared_key);
343 : 804 : }
344 : :
345 : : int s2n_ecc_evp_compute_shared_secret_as_client(struct s2n_ecc_evp_params *ecc_evp_params,
346 : : struct s2n_stuffer *Yc_out, struct s2n_blob *shared_key)
347 : 774 : {
348 : 774 : DEFER_CLEANUP(struct s2n_ecc_evp_params client_params = { 0 }, s2n_ecc_evp_params_free);
349 : :
350 [ - + ][ # # ]: 774 : POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
351 : 774 : client_params.negotiated_curve = ecc_evp_params->negotiated_curve;
352 [ - + ]: 774 : POSIX_GUARD(s2n_ecc_evp_generate_own_key(client_params.negotiated_curve, &client_params.evp_pkey));
353 [ - + ][ # # ]: 774 : S2N_ERROR_IF(client_params.evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY);
354 : :
355 [ - + ]: 774 : if (s2n_ecc_evp_compute_shared_secret(client_params.evp_pkey, ecc_evp_params->evp_pkey, ecc_evp_params->negotiated_curve->iana_id, shared_key)
356 : 774 : != S2N_SUCCESS) {
357 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_ECDHE_SHARED_SECRET);
358 : 0 : }
359 : :
360 [ - + ]: 774 : POSIX_GUARD(s2n_stuffer_write_uint8(Yc_out, client_params.negotiated_curve->share_size));
361 : :
362 [ - + ]: 774 : if (s2n_ecc_evp_write_params_point(&client_params, Yc_out) != 0) {
363 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_ECDHE_SERIALIZING);
364 : 0 : }
365 : 774 : return 0;
366 : 774 : }
367 : :
368 : : #if (!EVP_APIS_SUPPORTED)
369 : : static int s2n_ecc_evp_calculate_point_length(const EC_POINT *point, const EC_GROUP *group, uint8_t *length)
370 : : {
371 : : size_t ret = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
372 : : S2N_ERROR_IF(ret == 0, S2N_ERR_ECDHE_SERIALIZING);
373 : : S2N_ERROR_IF(ret > UINT8_MAX, S2N_ERR_ECDHE_SERIALIZING);
374 : : *length = (uint8_t) ret;
375 : : return 0;
376 : : }
377 : :
378 : : static int s2n_ecc_evp_write_point_data_snug(const EC_POINT *point, const EC_GROUP *group, struct s2n_blob *out)
379 : : {
380 : : size_t ret = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, out->data, out->size, NULL);
381 : : S2N_ERROR_IF(ret != out->size, S2N_ERR_ECDHE_SERIALIZING);
382 : : return 0;
383 : : }
384 : :
385 : : static EC_POINT *s2n_ecc_evp_blob_to_point(struct s2n_blob *blob, const EC_KEY *ec_key)
386 : : {
387 : : const EC_GROUP *group = EC_KEY_get0_group(ec_key);
388 : : EC_POINT *point = EC_POINT_new(group);
389 : : if (point == NULL) {
390 : : PTR_BAIL(S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
391 : : }
392 : : if (EC_POINT_oct2point(group, point, blob->data, blob->size, NULL) != 1) {
393 : : EC_POINT_free(point);
394 : : PTR_BAIL(S2N_ERR_BAD_MESSAGE);
395 : : }
396 : : return point;
397 : : }
398 : : #endif
399 : :
400 : : int s2n_ecc_evp_read_params_point(struct s2n_stuffer *in, int point_size, struct s2n_blob *point_blob)
401 : 10331 : {
402 [ - + ][ # # ]: 10331 : POSIX_ENSURE_REF(in);
403 [ - + ][ # # ]: 10331 : POSIX_ENSURE_REF(point_blob);
404 [ # # ][ - + ]: 10331 : POSIX_ENSURE_GTE(point_size, 0);
405 : :
406 : : /* Extract point from stuffer */
407 : 10331 : point_blob->size = point_size;
408 : 10331 : point_blob->data = s2n_stuffer_raw_read(in, point_size);
409 [ - + ][ # # ]: 10331 : POSIX_ENSURE_REF(point_blob->data);
410 : :
411 : 10331 : return 0;
412 : 10331 : }
413 : :
414 : : int s2n_ecc_evp_read_params(struct s2n_stuffer *in, struct s2n_blob *data_to_verify,
415 : : struct s2n_ecdhe_raw_server_params *raw_server_ecc_params)
416 : 810 : {
417 [ - + ][ # # ]: 810 : POSIX_ENSURE_REF(in);
418 : 810 : uint8_t curve_type = 0;
419 : 810 : uint8_t point_length = 0;
420 : :
421 : : /* Remember where we started reading the data */
422 : 810 : data_to_verify->data = s2n_stuffer_raw_read(in, 0);
423 [ - + ][ # # ]: 810 : POSIX_ENSURE_REF(data_to_verify->data);
424 : :
425 : : /* Read the curve */
426 [ - + ]: 810 : POSIX_GUARD(s2n_stuffer_read_uint8(in, &curve_type));
427 [ - + ][ # # ]: 810 : S2N_ERROR_IF(curve_type != TLS_EC_CURVE_TYPE_NAMED, S2N_ERR_BAD_MESSAGE);
428 : 810 : raw_server_ecc_params->curve_blob.data = s2n_stuffer_raw_read(in, 2);
429 [ # # ][ - + ]: 810 : POSIX_ENSURE_REF(raw_server_ecc_params->curve_blob.data);
430 : 810 : raw_server_ecc_params->curve_blob.size = 2;
431 : :
432 : : /* Read the point */
433 [ - + ]: 810 : POSIX_GUARD(s2n_stuffer_read_uint8(in, &point_length));
434 : :
435 [ - + ]: 810 : POSIX_GUARD(s2n_ecc_evp_read_params_point(in, point_length, &raw_server_ecc_params->point_blob));
436 : :
437 : : /* curve type (1) + iana (2) + key share size (1) + key share */
438 : 810 : data_to_verify->size = point_length + 4;
439 : :
440 : 810 : return 0;
441 : 810 : }
442 : :
443 : : int s2n_ecc_evp_write_params_point(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out)
444 : 12283 : {
445 [ # # ][ - + ]: 12283 : POSIX_ENSURE_REF(ecc_evp_params);
446 [ - + ][ # # ]: 12283 : POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
447 [ - + ][ # # ]: 12283 : POSIX_ENSURE_REF(ecc_evp_params->evp_pkey);
448 [ # # ][ - + ]: 12283 : POSIX_ENSURE_REF(out);
449 : :
450 : 12283 : #if EVP_APIS_SUPPORTED
451 : 12283 : DEFER_CLEANUP(uint8_t *encoded_point = NULL, OPENSSL_free_pointer);
452 : :
453 : 12283 : size_t size = EVP_PKEY_get1_tls_encodedpoint(ecc_evp_params->evp_pkey, &encoded_point);
454 [ + - ][ + + ]: 12283 : POSIX_ENSURE(size == ecc_evp_params->negotiated_curve->share_size, S2N_ERR_ECDHE_SERIALIZING);
455 [ + + ]: 12282 : POSIX_GUARD(s2n_stuffer_write_bytes(out, encoded_point, size));
456 : : #else
457 : : uint8_t point_len = 0;
458 : : struct s2n_blob point_blob = { 0 };
459 : :
460 : : DEFER_CLEANUP(EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(ecc_evp_params->evp_pkey), EC_KEY_free_pointer);
461 : : S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
462 : : const EC_POINT *point = EC_KEY_get0_public_key(ec_key);
463 : : const EC_GROUP *group = EC_KEY_get0_group(ec_key);
464 : : S2N_ERROR_IF(point == NULL || group == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
465 : :
466 : : POSIX_GUARD(s2n_ecc_evp_calculate_point_length(point, group, &point_len));
467 : : S2N_ERROR_IF(point_len != ecc_evp_params->negotiated_curve->share_size, S2N_ERR_ECDHE_SERIALIZING);
468 : : point_blob.data = s2n_stuffer_raw_write(out, point_len);
469 : : POSIX_ENSURE_REF(point_blob.data);
470 : : point_blob.size = point_len;
471 : :
472 : : POSIX_GUARD(s2n_ecc_evp_write_point_data_snug(point, group, &point_blob));
473 : : #endif
474 : 12278 : return 0;
475 : 12282 : }
476 : :
477 : : int s2n_ecc_evp_write_params(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out,
478 : : struct s2n_blob *written)
479 : 878 : {
480 [ - + ][ # # ]: 878 : POSIX_ENSURE_REF(ecc_evp_params);
481 [ # # ][ - + ]: 878 : POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
482 [ - + ][ # # ]: 878 : POSIX_ENSURE_REF(ecc_evp_params->evp_pkey);
483 [ # # ][ - + ]: 878 : POSIX_ENSURE_REF(out);
484 [ - + ][ # # ]: 878 : POSIX_ENSURE_REF(written);
485 : :
486 : 878 : uint8_t key_share_size = ecc_evp_params->negotiated_curve->share_size;
487 : 878 : uint32_t key_share_offset = out->write_cursor;
488 : :
489 [ - + ]: 878 : POSIX_GUARD(s2n_stuffer_write_uint8(out, TLS_EC_CURVE_TYPE_NAMED));
490 [ - + ]: 878 : POSIX_GUARD(s2n_stuffer_write_uint16(out, ecc_evp_params->negotiated_curve->iana_id));
491 [ - + ]: 878 : POSIX_GUARD(s2n_stuffer_write_uint8(out, key_share_size));
492 : :
493 [ - + ]: 878 : POSIX_GUARD(s2n_ecc_evp_write_params_point(ecc_evp_params, out));
494 : :
495 : : /* key share + key share size (1) + iana (2) + curve type (1) */
496 : 878 : written->size = key_share_size + 4;
497 : 878 : written->data = out->blob.data + key_share_offset;
498 : :
499 : 878 : return written->size;
500 : 878 : }
501 : :
502 : : int s2n_ecc_evp_parse_params_point(struct s2n_blob *point_blob, struct s2n_ecc_evp_params *ecc_evp_params)
503 : 10325 : {
504 [ - + ][ # # ]: 10325 : POSIX_ENSURE_REF(point_blob->data);
505 [ # # ][ - + ]: 10325 : POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve);
506 [ - + ][ # # ]: 10325 : S2N_ERROR_IF(point_blob->size != ecc_evp_params->negotiated_curve->share_size, S2N_ERR_ECDHE_SERIALIZING);
507 : :
508 : 10325 : #if EVP_APIS_SUPPORTED
509 [ + + ]: 10325 : if (ecc_evp_params->negotiated_curve->libcrypto_nid == NID_X25519) {
510 [ + - ]: 818 : if (ecc_evp_params->evp_pkey == NULL) {
511 : 818 : ecc_evp_params->evp_pkey = EVP_PKEY_new();
512 : 818 : }
513 [ - + ][ # # ]: 818 : S2N_ERROR_IF(ecc_evp_params->evp_pkey == NULL, S2N_ERR_BAD_MESSAGE);
514 [ - + ]: 818 : POSIX_GUARD(EVP_PKEY_set_type(ecc_evp_params->evp_pkey, ecc_evp_params->negotiated_curve->libcrypto_nid));
515 : 9507 : } else {
516 : 9507 : DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL), EVP_PKEY_CTX_free_pointer);
517 [ - + ][ # # ]: 9507 : S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_SERIALIZING);
518 [ - + ][ # # ]: 9507 : POSIX_GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_SERIALIZING);
519 [ # # ][ - + ]: 9507 : POSIX_GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ecc_evp_params->negotiated_curve->libcrypto_nid), S2N_ERR_ECDHE_SERIALIZING);
520 [ - + ][ # # ]: 9507 : POSIX_GUARD_OSSL(EVP_PKEY_paramgen(pctx, &ecc_evp_params->evp_pkey), S2N_ERR_ECDHE_SERIALIZING);
521 : 9507 : }
522 [ + + ][ + - ]: 10325 : POSIX_GUARD_OSSL(EVP_PKEY_set1_tls_encodedpoint(ecc_evp_params->evp_pkey, point_blob->data, point_blob->size),
523 : 10323 : S2N_ERR_ECDHE_SERIALIZING);
524 : : #else
525 : : if (ecc_evp_params->evp_pkey == NULL) {
526 : : ecc_evp_params->evp_pkey = EVP_PKEY_new();
527 : : }
528 : : S2N_ERROR_IF(ecc_evp_params->evp_pkey == NULL, S2N_ERR_BAD_MESSAGE);
529 : : /* Create a key to store the point */
530 : : DEFER_CLEANUP(EC_KEY *ec_key = EC_KEY_new_by_curve_name(ecc_evp_params->negotiated_curve->libcrypto_nid),
531 : : EC_KEY_free_pointer);
532 : : S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
533 : :
534 : : /* Parse and store the server public point */
535 : : DEFER_CLEANUP(EC_POINT *point = s2n_ecc_evp_blob_to_point(point_blob, ec_key), EC_POINT_free_pointer);
536 : : S2N_ERROR_IF(point == NULL, S2N_ERR_BAD_MESSAGE);
537 : :
538 : : /* Set the point as the public key */
539 : : int success = EC_KEY_set_public_key(ec_key, point);
540 : :
541 : : POSIX_GUARD_OSSL(EVP_PKEY_set1_EC_KEY(ecc_evp_params->evp_pkey, ec_key), S2N_ERR_ECDHE_SERIALIZING);
542 : :
543 : : /* EC_KEY_set_public_key returns 1 on success, 0 on failure */
544 : : S2N_ERROR_IF(success == 0, S2N_ERR_BAD_MESSAGE);
545 : :
546 : : #endif
547 : 10323 : return 0;
548 : 10325 : }
549 : :
550 : : int s2n_ecc_evp_parse_params(struct s2n_connection *conn, struct s2n_ecdhe_raw_server_params *raw_server_ecc_params,
551 : : struct s2n_ecc_evp_params *ecc_evp_params)
552 : 810 : {
553 [ + + ][ + - ]: 810 : POSIX_ENSURE(s2n_ecc_evp_find_supported_curve(conn, &raw_server_ecc_params->curve_blob, &ecc_evp_params->negotiated_curve) == 0,
554 : 808 : S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
555 : 808 : return s2n_ecc_evp_parse_params_point(&raw_server_ecc_params->point_blob, ecc_evp_params);
556 : 810 : }
557 : :
558 : : int s2n_ecc_evp_find_supported_curve(struct s2n_connection *conn, struct s2n_blob *iana_ids, const struct s2n_ecc_named_curve **found)
559 : 810 : {
560 : 810 : const struct s2n_ecc_preferences *ecc_prefs = NULL;
561 [ - + ]: 810 : POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_prefs));
562 [ - + ][ # # ]: 810 : POSIX_ENSURE_REF(ecc_prefs);
563 : :
564 : 810 : struct s2n_stuffer iana_ids_in = { 0 };
565 : :
566 [ - + ]: 810 : POSIX_GUARD(s2n_stuffer_init(&iana_ids_in, iana_ids));
567 [ - + ]: 810 : POSIX_GUARD(s2n_stuffer_write(&iana_ids_in, iana_ids));
568 [ + + ]: 841 : for (size_t i = 0; i < ecc_prefs->count; i++) {
569 : 839 : const struct s2n_ecc_named_curve *supported_curve = ecc_prefs->ecc_curves[i];
570 [ + + ]: 870 : for (uint32_t j = 0; j < iana_ids->size / 2; j++) {
571 : 839 : uint16_t iana_id = 0;
572 [ - + ]: 839 : POSIX_GUARD(s2n_stuffer_read_uint16(&iana_ids_in, &iana_id));
573 [ + + ]: 839 : if (supported_curve->iana_id == iana_id) {
574 : 808 : *found = supported_curve;
575 : 808 : return 0;
576 : 808 : }
577 : 839 : }
578 [ - + ]: 31 : POSIX_GUARD(s2n_stuffer_reread(&iana_ids_in));
579 : 31 : }
580 : :
581 [ + - ]: 2 : POSIX_BAIL(S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
582 : 2 : }
583 : :
584 : : int s2n_ecc_evp_params_free(struct s2n_ecc_evp_params *ecc_evp_params)
585 : 14250105 : {
586 [ + + ]: 14250105 : if (ecc_evp_params->evp_pkey != NULL) {
587 : 24441 : EVP_PKEY_free(ecc_evp_params->evp_pkey);
588 : 24441 : ecc_evp_params->evp_pkey = NULL;
589 : 24441 : }
590 : 14250105 : return 0;
591 : 14250105 : }
|